GET / HTTP/1.1
Host: xkcd.com
Accept: text/html
User-Agent: Mozilla/5.0 (Macintosh)
GET | Retrieve the resource from the server |
POST | Create a resource on the server |
PUT | Update the resource on the server |
DELETE | Delete the resource from the server |
GET /blog/15 HTTP/1.1
DELETE /blog/15 HTTP/1.1
POST /blog HTTP/1.1
HTTP/1.1 200 OK
Date: Sat, 02 Apr 2011 21:05:05 GMT
Server: lighttpd/1.4.19
Content-Type: text/html
<html>
<!-- ... HTML for the xkcd comic -->
</html>
$uri = $_SERVER['REQUEST_URI'];
$foo = $_GET['foo'];
header('Content-Type: text/html');
echo 'The URI requested is: '.$uri;
echo 'The value of the "foo" parameter is: '.$foo;
HTTP/1.1 200 OK
Date: Sat, 03 Apr 2011 02:14:33 GMT
Server: Apache/2.2.17 (Unix)
Content-Type: text/html
The URI requested is: /testing?foo=symfony
The value of the "foo" parameter is: symfony
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
$request = Request::createFromGlobals();
$uri = $request->getPathInfo();
$foo = $request->get('foo');
$response = new Response();
$body = 'The URI requested is: '.$uri;
$body .= 'The value of the "foo" parameter is: '.$foo;
$response->setContent($body);
$response->setStatusCode(Response::HTTP_OK);
$response->headers->set('Content-Type', 'text/html');
$response->send();
namespace AppBundle\Controller;
use Symfony\Component\HttpFoundation\Response;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class SampleController
{
/**
* @Route("/sample")
*/
public function indexAction()
{
return new Response('<h1>Some beautiful message!</h1>');
}
}
$ symfony new my_project_name
$ composer create-project symfony/framework-standard-edition my_project_name
$ cd my_project_name/
$ php bin/console server:run
localhost:8000
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;
class LuckyController
{
/**
* @Route("/lucky/number")
*/
public function numberAction()
{
$number = rand(0, 100);
return new Response('Lucky number: '.$number);
}
}
localhost:8000/lucky/number
Prints a variable or the result of an expression to the template.
{{ ... }}
A tag that controls the logic of the template; it is used to execute statements such as for-loops for example.
{% ... %}
{# ... #}
It's the equivalent of the PHP /* comment */ syntax.
<ul>
{% for item in navigation %}
<li><a href="{{ item.href }}">{{ item.caption }}</a></li>
{% endfor %}
</ul>
<ul>
{% for i in 0..10 %}
<li>Number {{ i }}</li>
{% endfor %}
</ul>
<ul>
{% for user in users if user.active %}
<li>{{ user.username }}</li>
{% else %}
<li>No users found</li>
{% endfor %}
</ul>
{% if app.user %}
<div>
Hello {{ app.user }}
</div>
{% else %}
<div>
Please sign in
</div>
{% endif %}
{# app/Resources/views/base.html.twig #}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Template inheritance</title>
</head>
<body>
<div id="content">
{% block body %}
No body defined!!!
{% endblock %}
</div>
</body>
</html>
{# app/Resources/views/blog/index.html.twig #}
{% extends 'base.html.twig' %}
{% block body %}
{% for entry in blog_entries %}
<h2>{{ entry.title }}</h2>
<p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}
{{ myVar | upper }}
{{ myDate | date("m/d/Y") }}
{{ myObj | json_encode }}
{{ myArray | length }}
{{ myVar | raw }}
{{ numbers | reverse | join(',') }}
/**
* @Route("/lucky/number/{count}")
*/
public function numberAction($count)
{
$number = rand(0, 100);
return $this->render('lucky/number.html.twig', [
'luckyNumber' => $number
]);
}
{# app/Resources/views/lucky/number.html.twig #}
{% extends 'base.html.twig' %}
{% block body %}
<h1>Lucky Number: {{ luckyNumber }}</h1>
{% endblock %}
/**
* @Route("/", name="blog_homepage")
*/
public function indexAction()
{
// ...
}
/**
* @Route("/blog/{slug}")
*/
public function showAction($slug)
{
// ...
}
/**
* @Route("/blog/{page}", defaults={"page": 1})
*/
public function indexAction($page)
{
// ...
}
/**
* @Route("/blog/{page}")
*/
public function indexAction($page = 1)
{
// ...
}
/**
* @Route("/blog/{page}", defaults={"page": 1}, requirements={
* "page": "\d+"
* })
*/
public function indexAction($page)
{
// ...
}
/**
* @Route("/{_locale}", defaults={"_locale": "en"}, requirements={
* "_locale": "en|fr"
* })
*/
public function homepageAction($_locale)
{
// ...
}
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
/**
* @Route("/api/posts/{id}")
* @Method({"GET","HEAD"})
*/
public function showAction($id)
{
// ...
}
/**
* @Route("/api/posts/{id}")
* @Method("PUT")
*/
public function editAction($id)
{
// ...
}
/**
* @Route(
* "/articles/{_locale}/{year}/{title}.{_format}",
* defaults={"_format": "html"},
* requirements={
* "_locale": "en|fr",
* "_format": "html|rss",
* "year": "\d+"
* }
* )
* @Method("GET")
*/
public function showAction($_locale, $year, $title)
{
// ...
}
As you've seen, this parameter is used to determine which controller is executed when the route is matched.
Used to set the request format.
Used to set the locale on the request.
$ bin/console debug:router
homepage ANY /
contact GET /contact
contact_process POST /contact
article_show ANY /articles/{_locale}/{year}/{title}.{_format}
blog ANY /blog/{page}
blog_show ANY /blog/{slug}
The goal of a controller is always the same: create and return a Response object
use Symfony\Component\HttpFoundation\Response;
public function helloAction()
{
return new Response('Hello world!');
}
public function helloAction()
{
return $this->render('hello.html.twig');
}
use Symfony/Component/HttpFoundation/JsonResponse;
public function helloAction()
{
return new JsonResponse([
'hello' => 'Hello human!!!'
]);
}
public function helloAction()
{
return new Response('<h1>Response content</h1>');
}
public function helloAction()
{
return $this->redirectToRoute('another_route_name');
}
public function helloAction()
{
return $this->forward('another_route_name');
}
public function helloAction()
{
return $this->redirect('http://symfony.com/doc');
}
use Symfony\Component\HttpFoundation\Request;
public function indexAction(Request $request)
{
$request->isXmlHttpRequest(); // is it an Ajax request?
// request parameter
$request->get('page');
// retrieves an instance of UploadedFile identified by foo
$request->files->get('foo');
// retrieve an HTTP request header, with normalized, lowercase keys
$request->headers->get('host');
$request->headers->get('content_type');
}
use Symfony\Component\HttpFoundation\Request;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
/**
* @Route('/{name}')
*
*/
public function indexAction(Request $request, $name)
{
return $this->render('index.html.twig', [ 'name' => $name ]);
}
use Symfony\Component\HttpFoundation\Request;
public function indexAction(Request $request)
{
$session = $request->getSession();
// store an attribute for reuse during a later user request
$session->set('foo', 'bar');
// get the attribute set by another controller in another request
$foobar = $session->get('foobar');
// use a default value if the attribute doesn't exist
$filters = $session->get('filters', array());
}
$this->addFlash(
'notice',
'Your changes were saved!'
);
{% for message in app.session.flashBag.get('notice') %}
<div class="alert alert-info">
{{ message }}
</div>
{% endfor %}
# app/config/parameters.yml
parameters:
database_host: localhost
database_name: test_project
database_user: root
database_password: password
$ bin/console doctrine:generate:entity
// src/AppBundle/Entity/Product.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="product")
*/
class Product
{
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\Column(type="string", length=100)
*/
private $name;
}
$ bin/console doctrine:schema:update --dump-sql
$ bin/console doctrine:schema:update --force
// src/AppBundle/Controller/DefaultController.php
use AppBundle\Entity\Product;
public function showAction($productId)
{
$product = $this->getDoctrine()
->getRepository(Product::class)
->find($productId);
if (!$product) {
throw $this->createNotFoundException(
'No product found for id '.$productId
);
}
// ... do something, like pass the $product object into a template
}
// src/AppBundle/Controller/DefaultController.php
use AppBundle\Entity\Product;
use Symfony\Component\HttpFoundation\Response;
public function createAction()
{
$product = new Product();
$product->setName('Keyboard');
$product->setPrice(19.99);
$product->setDescription('Ergonomic and stylish!');
$em = $this->getDoctrine()->getManager();
// tells Doctrine you want to (eventually) save the Product (no queries yet)
$em->persist($product);
// actually executes the queries (i.e. the INSERT query)
$em->flush();
return new Response('Saved new product with id '.$product->getId());
}
// src/AppBundle/Controller/DefaultController.php
use AppBundle\Entity\Product;
public function updateAction($productId)
{
$em = $this->getDoctrine()->getManager();
$product = $em->getRepository(Product::class)->find($productId);
if (!$product) {
throw $this->createNotFoundException(
'No product found for id '.$productId
);
}
$product->setName('New product name!');
$em->merge($product);
$em->flush();
return $this->redirectToRoute('homepage');
}
// src/AppBundle/Controller/DefaultController.php
use AppBundle\Entity\Product;
public function deleteAction($productId)
{
$em = $this->getDoctrine()->getManager();
$product = $em->getRepository(Product::class)->find($productId);
if (!$product) {
throw $this->createNotFoundException(
'No product found for id '.$productId
);
}
$em->remove($product);
$em->flush();
return $this->redirectToRoute('homepage');
}
// src/AppBundle/Controller/DefaultController.php
use AppBundle\Entity\Product;
public function searchAction()
{
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
'SELECT p
FROM AppBundle:Product p
WHERE p.price > :price
ORDER BY p.price ASC'
)->setParameter('price', 19.99);
$products = $query->getResult();
// ...
}
// src/AppBundle/Controller/DefaultController.php
use AppBundle\Entity\Product;
public function searchAction()
{
$em = $this->getDoctrine()->getManager();
$query = $em->createQueryBuilder()
->select('p')
->from(Product::class, 'p')
->where('p.price > :price')
->orderBy('p.price', 'ASC')
->setParameter('price', 19.99)
->getQuery();
$products = $query->getResult();
// ...
}
// src/AppBundle/Entity/Product.php
// ...
class Product
{
// ...
/**
* @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
* @ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
private $category;
}
// src/AppBundle/Entity/Category.php
// ...
use Doctrine\Common\Collections\ArrayCollection;
class Category
{
// ...
/**
* @ORM\OneToMany(targetEntity="Product", mappedBy="category")
*/
private $products;
public function __construct()
{
$this->products = new ArrayCollection();
}
}
// controller class
$task = new Task();
$form = $this->createFormBuilder($task)
->add('task', TextType::class)
->add('dueDate', DateType::class)
->add('save', SubmitType::class, ['label' => 'Create Task'])
->getForm();
{# form page #}
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
// controller class
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// ... perform some action, such as saving the task to the database
return $this->redirectToRoute('task_success');
}
{{ form_start(form) }}
{{ form_errors(form) }}
{{ form_row(form.task) }}
{{ form_row(form.dueDate) }}
{{ form_end(form) }}
{{ form_start(form) }}
{{ form_errors(form) }}
<div>
{{ form_label(form.task) }}
{{ form_errors(form.task) }}
{{ form_widget(form.task) }}
</div>
<div>
{{ form_label(form.dueDate) }}
{{ form_errors(form.dueDate) }}
{{ form_widget(form.dueDate) }}
</div>
<div>
{{ form_widget(form.save) }}
</div>
{{ form_end(form) }}
// src/AppBundle/Form/TaskType.php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
class TaskType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('task')
->add('dueDate', null, array('widget' => 'single_text'))
->add('save', SubmitType::class)
;
}
}
// controller
use AppBundle\Form\TaskType;
public function newAction()
{
$task = ...;
$form = $this->createForm(TaskType::class, $task);
// ...
}
$ bin/console doctrine:generate:form AppBundle:Product
# app/config/config.yml
twig:
form_themes: ['bootstrap_3_layout.html.twig']
// src/AppBundle/Entity/Task.php
namespace AppBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
class Task
{
/**
* @Assert\NotBlank()
*/
public $task;
/**
* @Assert\NotBlank()
* @Assert\Type("\DateTime")
*/
protected $dueDate;
}
// src/AppBundle/Form/TaskForm.php
use Symfony\Component\Validator\Constraints as Assert;
$builder
->add('task', null, [
'constraints' => [
new Assert\NotBlank(),
new Assert\Length([ 'min' => 3 ]),
],
])
->add('lastName', null, [
'constraints' => [
new Assert\NotBlank(),
new Assert\Type("\DateTime")
),
])
;
// src/AppBundle/Entity/Product.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
class Product
{
// ...
/**
* @ORM\Column(type="string")
*
* @Assert\NotBlank(message="Please, upload the product brochure as a PDF file.")
* @Assert\File(mimeTypes={ "application/pdf" })
*/
private $brochure;
}
class ProductType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// ...
->add('brochure', FileType::class)
// ...
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Product::class,
));
}
}
$form = $this->createForm(ProductType::class, $product);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** @var Symfony\Component\HttpFoundation\File\UploadedFile $file */
$file = $product->getBrochure();
// Generate a unique name for the file before saving it
$fileName = md5(uniqid()).'.'.$file->guessExtension();
// Move the file to the directory where brochures are stored
$file->move('/upload_directory', $fileName);
// Update the 'brochure' property to store the PDF file name
// instead of its contents
$product->setBrochure($fileName)
}
# app/config/security.yml
security:
providers:
in_memory:
memory: ~
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
default:
anonymous: ~
# app/config/security.yml
security:
# ...
firewalls:
# ...
default:
anonymous: false
http_basic: ~
# app/config/security.yml
security:
providers:
in_memory:
memory:
users:
admin:
password: kitten
roles: 'ROLE_ADMIN'
rogerio:
password: 123456
roles: 'ROLE_USER'
# ...
No encoder has been configured for account "Symfony\Component\Security\Core\User\User"
# app/config/security.yml
security:
# ...
encoders:
Symfony\Component\Security\Core\User\User: plaintext
# ...
# app/config/security.yml
security:
# ...
encoders:
Symfony\Component\Security\Core\User\User:
algorithm: bcrypt
cost: 12
$ php bin/console security:encode-password
// whatever *your* User object is
$user = new AppBundle\Entity\User();
$plainPassword = 'ryanpass';
$encoder = $this->container->get('security.password_encoder');
$encoded = $encoder->encodePassword($user, $plainPassword);
$user->setPassword($encoded);
# app/config/security.yml
security:
# ...
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/admin/users, roles: ROLE_SUPER_ADMIN }
// controller class
public function helloAction($name)
{
// The second parameter is used to specify on what object the role is tested.
$this->denyAccessUnlessGranted(
'ROLE_ADMIN',
null,
'Unable to access this page!'
);
// ...
}
// controller class
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
/**
* @Security("has_role('ROLE_ADMIN')")
*/
public function helloAction($name)
{
// ...
}
// controller class
public function helloAction($name)
{
$checker = $this->get('security.authorization_checker');
if (!$checker->isGranted('IS_AUTHENTICATED_FULLY')) {
throw $this->createAccessDeniedException();
}
// ...
}
{# twig page #}
{% if is_granted('ROLE_ADMIN') %}
<a href="...">Delete</a>
{% endif %}
// controller class
public function indexAction()
{
// via token storage
$user = $this->get('security.token_storage')->getToken()->getUser();
// shortcut
$user = $this->getUser();
}
{# twig page #}
{% if is_granted('IS_AUTHENTICATED_FULLY') %}
<p>Username: {{ app.user.username }}</p>
{% endif %}
# app/config/security.yml
security:
# ...
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
# app/config/security.yml
security:
# ...
firewalls:
main:
anonymous: ~
form_login:
login_path: /login
check_path: /login_check
// src/AppBundle/Controller/SecurityController.php
/**
* @Route("/login", name="login")
*/
public function loginAction(Request $request)
{
$authenticationUtils = $this->get('security.authentication_utils');
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('security/login.html.twig', [
// last username entered by the user
'last_username' => $lastUsername,
'error' => $error,
]);
}
{# app/Resources/views/security/login.html.twig #}
{% if error %}
<div>{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
<form action="{{ path('login_check') }}" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="_username"
value="{{ last_username }}" />
<label for="password">Password:</label>
<input type="password" id="password" name="_password" />
<button type="submit">login</button>
</form>
# app/config/security.yml
security:
# ...
firewalls:
# order matters! This must be before the ^/ firewall
login_firewall:
pattern: ^/login$
anonymous: ~
main:
pattern: ^/
form_login:
login_path: /login
check_path: /login_check
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_ADMIN }
# app/config/security.yml
security:
# ...
firewalls:
main:
# ...
logout:
path: /logout
target: /
# app/config/routing.yml
# ..
login_check:
path: /login_check
logout:
path: /logout
// AppBundle\Entity\User;
use Symfony\Component\Security\Core\User\UserInterface;
class User implements UserInterface, \Serializable
{
// ...
public function serialize()
{
return serialize([
$this->id,
$this->username
]);
}
public function unserialize($serialized)
{
list(
$this->id,
$this->username
) = unserialize($serialized);
}
}
security:
# ...
providers:
my_provider:
entity:
class: AppBundle\Entity\User
property: username
encoders:
AppBundle\Entity\User:
algorithm: bcrypt
cost: 12
firewalls:
# ...
main:
provider: my_provider
# ...
Source: The Symfony Book