Update
This commit is contained in:
parent
a37785b391
commit
33458b2ca3
9915 changed files with 1247019 additions and 0 deletions
|
|
@ -0,0 +1,106 @@
|
|||
@Cache
|
||||
======
|
||||
|
||||
The ``@Cache`` annotation makes it easy to define HTTP caching headers for
|
||||
expiration and validation.
|
||||
|
||||
HTTP Expiration Strategies
|
||||
--------------------------
|
||||
|
||||
The ``@Cache`` annotation makes it easy to define HTTP caching::
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
|
||||
|
||||
/**
|
||||
* @Cache(expires="tomorrow", public=true)
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
}
|
||||
|
||||
You can also use the annotation on a class to define caching for all actions
|
||||
of a controller::
|
||||
|
||||
/**
|
||||
* @Cache(expires="tomorrow", public=true)
|
||||
*/
|
||||
class BlogController extends Controller
|
||||
{
|
||||
}
|
||||
|
||||
When there is a conflict between the class configuration and the method
|
||||
configuration, the latter overrides the former::
|
||||
|
||||
/**
|
||||
* @Cache(expires="tomorrow")
|
||||
*/
|
||||
class BlogController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Cache(expires="+2 days")
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
The ``expires`` attribute takes any valid date understood by the PHP
|
||||
``strtotime()`` function.
|
||||
|
||||
HTTP Validation Strategies
|
||||
--------------------------
|
||||
|
||||
The ``lastModified`` and ``ETag`` attributes manage the HTTP validation cache
|
||||
headers. ``lastModified`` adds a ``Last-Modified`` header to Responses and
|
||||
``ETag`` adds an ``ETag`` header.
|
||||
|
||||
Both automatically trigger the logic to return a 304 response when the
|
||||
response is not modified (in this case, the controller is **not** called)::
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
|
||||
|
||||
/**
|
||||
* @Cache(lastModified="post.getUpdatedAt()", ETag="'Post' ~ post.getId() ~ post.getUpdatedAt().getTimestamp()")
|
||||
*/
|
||||
public function indexAction(Post $post)
|
||||
{
|
||||
// your code
|
||||
// won't be called in case of a 304
|
||||
}
|
||||
|
||||
It's roughly doing the same as the following code::
|
||||
|
||||
public function myAction(Request $request, Post $post)
|
||||
{
|
||||
$response = new Response();
|
||||
$response->setLastModified($post->getUpdatedAt());
|
||||
if ($response->isNotModified($request)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
// your code
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
The ETag HTTP header value is the result of the expression hashed with the
|
||||
``sha256`` algorithm.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
|
||||
Here is a list of accepted attributes and their HTTP header equivalent:
|
||||
|
||||
======================================================================= ================================
|
||||
Annotation Response Method
|
||||
======================================================================= ================================
|
||||
``@Cache(expires="tomorrow")`` ``$response->setExpires()``
|
||||
``@Cache(smaxage="15")`` ``$response->setSharedMaxAge()``
|
||||
``@Cache(maxage="15")`` ``$response->setMaxAge()``
|
||||
``@Cache(vary={"Cookie"})`` ``$response->setVary()``
|
||||
``@Cache(public=true)`` ``$response->setPublic()``
|
||||
``@Cache(lastModified="post.getUpdatedAt()")`` ``$response->setLastModified()``
|
||||
``@Cache(ETag="post.getId() ~ post.getUpdatedAt().getTimestamp()")`` ``$response->setETag()``
|
||||
======================================================================= ================================
|
||||
|
|
@ -0,0 +1,305 @@
|
|||
@ParamConverter
|
||||
===============
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
The ``@ParamConverter`` annotation calls *converters* to convert request
|
||||
parameters to objects. These objects are stored as request attributes and so
|
||||
they can be injected as controller method arguments::
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
|
||||
/**
|
||||
* @Route("/blog/{id}")
|
||||
* @ParamConverter("post", class="SensioBlogBundle:Post")
|
||||
*/
|
||||
public function showAction(Post $post)
|
||||
{
|
||||
}
|
||||
|
||||
Several things happen under the hood:
|
||||
|
||||
* The converter tries to get a ``SensioBlogBundle:Post`` object from the
|
||||
request attributes (request attributes comes from route placeholders -- here
|
||||
``id``);
|
||||
|
||||
* If no ``Post`` object is found, a ``404`` Response is generated;
|
||||
|
||||
* If a ``Post`` object is found, a new ``post`` request attribute is defined
|
||||
(accessible via ``$request->attributes->get('post')``);
|
||||
|
||||
* As for other request attributes, it is automatically injected in the
|
||||
controller when present in the method signature.
|
||||
|
||||
If you use type hinting as in the example above, you can even omit the
|
||||
``@ParamConverter`` annotation altogether::
|
||||
|
||||
// automatic with method signature
|
||||
public function showAction(Post $post)
|
||||
{
|
||||
}
|
||||
|
||||
.. tip::
|
||||
|
||||
You can disable the auto-conversion of type-hinted method arguments feature
|
||||
by setting the ``auto_convert`` flag to ``false``:
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# app/config/config.yml
|
||||
sensio_framework_extra:
|
||||
request:
|
||||
converters: true
|
||||
auto_convert: false
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<sensio-framework-extra:config>
|
||||
<request converters="true" auto-convert="true" />
|
||||
</sensio-framework-extra:config>
|
||||
|
||||
To detect which converter is run on a parameter the following process is run:
|
||||
|
||||
* If an explicit converter choice was made with
|
||||
``@ParamConverter(converter="name")`` the converter with the given name is
|
||||
chosen.
|
||||
|
||||
* Otherwise all registered parameter converters are iterated by priority. The
|
||||
``supports()`` method is invoked to check if a param converter can convert
|
||||
the request into the required parameter. If it returns ``true`` the param
|
||||
converter is invoked.
|
||||
|
||||
Built-in Converters
|
||||
-------------------
|
||||
|
||||
The bundle has two built-in converters, the Doctrine one and a DateTime
|
||||
converter.
|
||||
|
||||
Doctrine Converter
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Converter Name: ``doctrine.orm``
|
||||
|
||||
The Doctrine Converter attempts to convert request attributes to Doctrine
|
||||
entities fetched from the database. Two different approaches are possible:
|
||||
|
||||
- Fetch object by primary key.
|
||||
- Fetch object by one or several fields which contain unique values in the
|
||||
database.
|
||||
|
||||
The following algorithm determines which operation will be performed.
|
||||
|
||||
- If an ``{id}`` parameter is present in the route, find object by primary key.
|
||||
- If an option ``'id'`` is configured and matches route parameters, find object by primary key.
|
||||
- If the previous rules do not apply, attempt to find one entity by matching
|
||||
route parameters to entity fields. You can control this process by
|
||||
configuring ``exclude`` parameters or a attribute to field name ``mapping``.
|
||||
|
||||
By default, the Doctrine converter uses the *default* entity manager. This can
|
||||
be configured with the ``entity_manager`` option::
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
|
||||
/**
|
||||
* @Route("/blog/{id}")
|
||||
* @ParamConverter("post", class="SensioBlogBundle:Post", options={"entity_manager" = "foo"})
|
||||
*/
|
||||
public function showAction(Post $post)
|
||||
{
|
||||
}
|
||||
|
||||
If the placeholder does not have the same name as the primary key, pass the ``id``
|
||||
option::
|
||||
|
||||
/**
|
||||
* @Route("/blog/{post_id}")
|
||||
* @ParamConverter("post", class="SensioBlogBundle:Post", options={"id" = "post_id"})
|
||||
*/
|
||||
public function showAction(Post $post)
|
||||
{
|
||||
}
|
||||
|
||||
.. tip::
|
||||
|
||||
The ``id`` option specifies which placeholder from the route gets passed to the repository
|
||||
method used. If no repository method is specified, ``find()`` is used by default.
|
||||
|
||||
This also allows you to have multiple converters in one action::
|
||||
|
||||
/**
|
||||
* @Route("/blog/{id}/comments/{comment_id}")
|
||||
* @ParamConverter("comment", class="SensioBlogBundle:Comment", options={"id" = "comment_id"})
|
||||
*/
|
||||
public function showAction(Post $post, Comment $comment)
|
||||
{
|
||||
}
|
||||
|
||||
In the example above, the ``$post`` parameter is handled automatically, but ``$comment`` is
|
||||
configured with the annotation since they can not both follow the default convention.
|
||||
|
||||
If you want to match an entity using multiple fields use the ``mapping`` hash
|
||||
option: the key is route placeholder name and the value is the Doctrine
|
||||
field name::
|
||||
|
||||
/**
|
||||
* @Route("/blog/{date}/{slug}/comments/{comment_slug}")
|
||||
* @ParamConverter("post", options={"mapping": {"date": "date", "slug": "slug"}})
|
||||
* @ParamConverter("comment", options={"mapping": {"comment_slug": "slug"}})
|
||||
*/
|
||||
public function showAction(Post $post, Comment $comment)
|
||||
{
|
||||
}
|
||||
|
||||
If you are matching an entity using several fields, but you want to exclude a
|
||||
route parameter from being part of the criteria::
|
||||
|
||||
/**
|
||||
* @Route("/blog/{date}/{slug}")
|
||||
* @ParamConverter("post", options={"exclude": {"date"}})
|
||||
*/
|
||||
public function showAction(Post $post, \DateTime $date)
|
||||
{
|
||||
}
|
||||
|
||||
If you want to specify the repository method to use to find the entity (for example,
|
||||
to add joins to the query), you can add the ``repository_method`` option::
|
||||
|
||||
/**
|
||||
* @Route("/blog/{id}")
|
||||
* @ParamConverter("post", class="SensioBlogBundle:Post", options={"repository_method" = "findWithJoins"})
|
||||
*/
|
||||
public function showAction(Post $post)
|
||||
{
|
||||
}
|
||||
|
||||
The specified repository method will be called with the criteria in an ``array``
|
||||
as parameter. This is a good fit with Doctrine's ``findBy`` and ``findOneBy``
|
||||
methods.
|
||||
|
||||
There are cases where you want to you use your own repository method and you
|
||||
want to map the criteria to the method signature. This is possible when you set
|
||||
the ``map_method_signature`` option to true. The default is false::
|
||||
|
||||
/**
|
||||
* @Route("/user/{first_name}/{last_name}")
|
||||
* @ParamConverter("user", class="AcmeBlogBundle:User", options={
|
||||
* "repository_method" = "findByFullName",
|
||||
* "mapping": {"first_name": "firstName", "last_name": "lastName"},
|
||||
* "map_method_signature" = true
|
||||
* })
|
||||
*/
|
||||
public function showAction(User $user)
|
||||
{
|
||||
}
|
||||
|
||||
class UserRepository
|
||||
{
|
||||
public function findByFullName($firstName, $lastName)
|
||||
{
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
.. tip::
|
||||
|
||||
When ``map_method_signature`` is ``true``, the ``firstName`` and
|
||||
``lastName`` parameters do not have to be Doctrine fields.
|
||||
|
||||
DateTime Converter
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Converter Name: ``datetime``
|
||||
|
||||
The datetime converter converts any route or request attribute into a datetime
|
||||
instance::
|
||||
|
||||
/**
|
||||
* @Route("/blog/archive/{start}/{end}")
|
||||
*/
|
||||
public function archiveAction(\DateTime $start, \DateTime $end)
|
||||
{
|
||||
}
|
||||
|
||||
By default any date format that can be parsed by the ``DateTime`` constructor
|
||||
is accepted. You can be stricter with input given through the options::
|
||||
|
||||
/**
|
||||
* @Route("/blog/archive/{start}/{end}")
|
||||
* @ParamConverter("start", options={"format": "Y-m-d"})
|
||||
* @ParamConverter("end", options={"format": "Y-m-d"})
|
||||
*/
|
||||
public function archiveAction(\DateTime $start, \DateTime $end)
|
||||
{
|
||||
}
|
||||
|
||||
Creating a Converter
|
||||
--------------------
|
||||
|
||||
All converters must implement the ``ParamConverterInterface``::
|
||||
|
||||
namespace Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
interface ParamConverterInterface
|
||||
{
|
||||
function apply(Request $request, ParamConverter $configuration);
|
||||
|
||||
function supports(ParamConverter $configuration);
|
||||
}
|
||||
|
||||
The ``supports()`` method must return ``true`` when it is able to convert the
|
||||
given configuration (a ``ParamConverter`` instance).
|
||||
|
||||
The ``ParamConverter`` instance has three pieces of information about the annotation:
|
||||
|
||||
* ``name``: The attribute name;
|
||||
* ``class``: The attribute class name (can be any string representing a class
|
||||
name);
|
||||
* ``options``: An array of options.
|
||||
|
||||
The ``apply()`` method is called whenever a configuration is supported. Based
|
||||
on the request attributes, it should set an attribute named
|
||||
``$configuration->getName()``, which stores an object of class
|
||||
``$configuration->getClass()``.
|
||||
|
||||
To register your converter service, you must add a tag to your service:
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# app/config/config.yml
|
||||
services:
|
||||
my_converter:
|
||||
class: MyBundle\Request\ParamConverter\MyConverter
|
||||
tags:
|
||||
- { name: request.param_converter, priority: -2, converter: my_converter }
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<service id="my_converter" class="MyBundle\Request\ParamConverter\MyConverter">
|
||||
<tag name="request.param_converter" priority="-2" converter="my_converter" />
|
||||
</service>
|
||||
|
||||
You can register a converter by priority, by name (attribute "converter"), or
|
||||
both. If you don't specify a priority or a name, the converter will be added to
|
||||
the converter stack with a priority of ``0``. To explicitly disable the
|
||||
registration by priority you have to set ``priority="false"`` in your tag
|
||||
definition.
|
||||
|
||||
.. tip::
|
||||
|
||||
If you would like to inject services or additional arguments into a custom
|
||||
param converter, the priority shouldn't be higher than ``1``. Otherwise, the
|
||||
service wouldn't be loaded.
|
||||
|
||||
.. tip::
|
||||
|
||||
Use the ``DoctrineParamConverter`` class as a template for your own converters.
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
@Route and @Method
|
||||
==================
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
The ``@Route`` annotation maps a route pattern with a controller::
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
|
||||
class PostController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Route("/")
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
The ``index`` action of the ``Post`` controller is now mapped to the ``/``
|
||||
URL. This is equivalent to the following YAML configuration:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
blog_home:
|
||||
path: /
|
||||
defaults: { _controller: SensioBlogBundle:Post:index }
|
||||
|
||||
Like any route pattern, you can define placeholders, requirements, and default
|
||||
values::
|
||||
|
||||
/**
|
||||
* @Route("/{id}", requirements={"id" = "\d+"}, defaults={"id" = 1})
|
||||
*/
|
||||
public function showAction($id)
|
||||
{
|
||||
}
|
||||
|
||||
You can also define the default value for a placeholder with
|
||||
the PHP default value::
|
||||
|
||||
/**
|
||||
* @Route("/{id}", requirements={"id" = "\d+"})
|
||||
*/
|
||||
public function showAction($id = 1)
|
||||
{
|
||||
}
|
||||
|
||||
You can also match more than one URL by defining additional ``@Route``
|
||||
annotations::
|
||||
|
||||
/**
|
||||
* @Route("/", defaults={"id" = 1})
|
||||
* @Route("/{id}")
|
||||
*/
|
||||
public function showAction($id)
|
||||
{
|
||||
}
|
||||
|
||||
.. _frameworkextra-annotations-routing-activation:
|
||||
|
||||
Activation
|
||||
----------
|
||||
|
||||
The routes need to be imported to be active as any other routing resources
|
||||
(note the ``annotation`` type):
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# app/config/routing.yml
|
||||
|
||||
# import routes from a controller class
|
||||
post:
|
||||
resource: "@SensioBlogBundle/Controller/PostController.php"
|
||||
type: annotation
|
||||
|
||||
You can also import a whole directory:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# import routes from a controller directory
|
||||
blog:
|
||||
resource: "@SensioBlogBundle/Controller"
|
||||
type: annotation
|
||||
|
||||
As for any other resource, you can "mount" the routes under a given prefix:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
post:
|
||||
resource: "@SensioBlogBundle/Controller/PostController.php"
|
||||
prefix: /blog
|
||||
type: annotation
|
||||
|
||||
Route Name
|
||||
----------
|
||||
|
||||
A route defined with the ``@Route`` annotation is given a default name composed
|
||||
of the bundle name, the controller name and the action name. That would be
|
||||
``sensio_blog_post_index`` for the above example;
|
||||
|
||||
The ``name`` attribute can be used to override this default route name::
|
||||
|
||||
/**
|
||||
* @Route("/", name="blog_home")
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
Route Prefix
|
||||
------------
|
||||
|
||||
A ``@Route`` annotation on a controller class defines a prefix for all action
|
||||
routes (note that you cannot have more than one ``@Route`` annotation on a
|
||||
class)::
|
||||
|
||||
/**
|
||||
* @Route("/blog")
|
||||
*/
|
||||
class PostController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Route("/{id}")
|
||||
*/
|
||||
public function showAction($id)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
The ``show`` action is now mapped to the ``/blog/{id}`` pattern.
|
||||
|
||||
Route Method
|
||||
------------
|
||||
|
||||
There is a shortcut ``@Method`` annotation to specify the HTTP method allowed
|
||||
for the route. To use it, import the ``Method`` annotation namespace::
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
|
||||
|
||||
/**
|
||||
* @Route("/blog")
|
||||
*/
|
||||
class PostController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Route("/edit/{id}")
|
||||
* @Method({"GET", "POST"})
|
||||
*/
|
||||
public function editAction($id)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
The ``edit`` action is now mapped to the ``/blog/edit/{id}`` pattern if the HTTP
|
||||
method used is either GET or POST.
|
||||
|
||||
The ``@Method`` annotation is only considered when an action is annotated with
|
||||
``@Route``.
|
||||
|
||||
Controller as Service
|
||||
---------------------
|
||||
|
||||
The ``@Route`` annotation on a controller class can also be used to assign the
|
||||
controller class to a service so that the controller resolver will instantiate
|
||||
the controller by fetching it from the DI container instead of calling ``new
|
||||
PostController()`` itself::
|
||||
|
||||
/**
|
||||
* @Route(service="my_post_controller_service")
|
||||
*/
|
||||
class PostController
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
.. tip::
|
||||
|
||||
You can also omit the ``service`` option if your service ID is your controller
|
||||
fully-qualified class name (FQCN).
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
@Security
|
||||
=========
|
||||
|
||||
.. caution::
|
||||
|
||||
The ``@Security`` annotation only works as of Symfony 2.4.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
The ``@Security`` annotation restricts access on controllers::
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
|
||||
|
||||
class PostController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Security("has_role('ROLE_ADMIN')")
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
The expression can use all functions that you can use in the ``access_control``
|
||||
section of the security bundle configuration, with the addition of the
|
||||
``is_granted()`` function.
|
||||
|
||||
The expression has access to the following variables:
|
||||
|
||||
* ``token``: The current security token;
|
||||
* ``user``: The current user object;
|
||||
* ``request``: The request instance;
|
||||
* ``roles``: The user roles;
|
||||
* and all request attributes.
|
||||
|
||||
The ``is_granted()`` function allows you to restrict access based on variables
|
||||
passed to the controller::
|
||||
|
||||
/**
|
||||
* @Security("is_granted('POST_SHOW', post)")
|
||||
*/
|
||||
public function showAction(Post $post)
|
||||
{
|
||||
}
|
||||
|
||||
Here is another example, making use of multiple functions in the expression::
|
||||
|
||||
/**
|
||||
* @Security("is_granted('POST_SHOW', post) and has_role('ROLE_ADMIN')")
|
||||
*/
|
||||
public function showAction(Post $post)
|
||||
{
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
Defining a ``Security`` annotation has the same effect as defining an
|
||||
access control rule, but it is more efficient as the check is only done
|
||||
when this specific route is accessed. To create new access control
|
||||
rules, please refer to `the Security Voters page`_.
|
||||
|
||||
.. tip::
|
||||
|
||||
You can also add a ``@Security`` annotation on a controller class.
|
||||
|
||||
.. _`the Security Voters page`: http://symfony.com/doc/current/cookbook/security/voters_data_permission.html
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
@Template
|
||||
=========
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
The ``@Template`` annotation associates a controller with a template name::
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
|
||||
|
||||
/**
|
||||
* @Template("SensioBlogBundle:Post:show.html.twig")
|
||||
*/
|
||||
public function showAction($id)
|
||||
{
|
||||
// get the Post
|
||||
$post = ...;
|
||||
|
||||
return array('post' => $post);
|
||||
}
|
||||
|
||||
When using the ``@Template`` annotation, the controller should return an
|
||||
array of parameters to pass to the view instead of a ``Response`` object.
|
||||
|
||||
.. note::
|
||||
|
||||
If you want to stream your template, you can make it with the following configuration::
|
||||
|
||||
/**
|
||||
* @Template(isStreamable=true)
|
||||
*/
|
||||
public function showAction($id)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
.. tip::
|
||||
If the action returns a ``Response`` object, the ``@Template``
|
||||
annotation is simply ignored.
|
||||
|
||||
If the template is named after the controller and action names, which is the
|
||||
case for the above example, you can even omit the annotation value::
|
||||
|
||||
/**
|
||||
* @Template
|
||||
*/
|
||||
public function showAction($id)
|
||||
{
|
||||
// get the Post
|
||||
$post = ...;
|
||||
|
||||
return array('post' => $post);
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
If you are using PHP as a templating system, you need to make it
|
||||
explicit::
|
||||
|
||||
/**
|
||||
* @Template(engine="php")
|
||||
*/
|
||||
public function showAction($id)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
And if the only parameters to pass to the template are method arguments, you
|
||||
can use the ``vars`` attribute instead of returning an array. This is very
|
||||
useful in combination with the ``@ParamConverter`` :doc:`annotation
|
||||
<converters>`::
|
||||
|
||||
/**
|
||||
* @ParamConverter("post", class="SensioBlogBundle:Post")
|
||||
* @Template("SensioBlogBundle:Post:show.html.twig", vars={"post"})
|
||||
*/
|
||||
public function showAction(Post $post)
|
||||
{
|
||||
}
|
||||
|
||||
which, thanks to conventions, is equivalent to the following configuration::
|
||||
|
||||
/**
|
||||
* @Template(vars={"post"})
|
||||
*/
|
||||
public function showAction(Post $post)
|
||||
{
|
||||
}
|
||||
|
||||
You can make it even more concise as all method arguments are automatically
|
||||
passed to the template if the method returns ``null`` and no ``vars``
|
||||
attribute is defined::
|
||||
|
||||
/**
|
||||
* @Template
|
||||
*/
|
||||
public function showAction(Post $post)
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,231 @@
|
|||
SensioFrameworkExtraBundle
|
||||
==========================
|
||||
|
||||
The default Symfony ``FrameworkBundle`` implements a basic but robust and
|
||||
flexible MVC framework. `SensioFrameworkExtraBundle`_ extends it to add sweet
|
||||
conventions and annotations. It allows for more concise controllers.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Before using this bundle in your project, add it to your ``composer.json`` file:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ composer require sensio/framework-extra-bundle
|
||||
|
||||
Then, like for any other bundle, include it in your Kernel class::
|
||||
|
||||
public function registerBundles()
|
||||
{
|
||||
$bundles = array(
|
||||
// ...
|
||||
|
||||
new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
|
||||
);
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
.. _release-cycle-note:
|
||||
|
||||
.. note::
|
||||
|
||||
Since SensioFrameworkExtraBundle 3.0 its release cycle is out of sync
|
||||
with Symfony's release cycle. This means that you can simply require
|
||||
``sensio/framework-extra-bundle: ~3.0`` in your ``composer.json`` file
|
||||
and Composer will automatically pick the latest bundle version for you.
|
||||
You have to use Symfony 2.3 or later for this workflow. Before Symfony
|
||||
2.3, the required version of the SensioFrameworkExtraBundle should be
|
||||
the same as your Symfony version.
|
||||
|
||||
If you plan to use or create annotations for controllers, make sure to update
|
||||
your ``autoload.php`` by adding the following line::
|
||||
|
||||
Doctrine\Common\Annotations\AnnotationRegistry::registerLoader(array($loader, 'loadClass'));
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
All features provided by the bundle are enabled by default when the bundle is
|
||||
registered in your Kernel class.
|
||||
|
||||
The default configuration is as follow:
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
sensio_framework_extra:
|
||||
router: { annotations: true }
|
||||
request: { converters: true, auto_convert: true }
|
||||
view: { annotations: true }
|
||||
cache: { annotations: true }
|
||||
security: { annotations: true }
|
||||
psr_message: { enabled: false } # Defaults to true if the PSR-7 bridge is installed
|
||||
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- xmlns:sensio-framework-extra="http://symfony.com/schema/dic/symfony_extra" -->
|
||||
<sensio-framework-extra:config>
|
||||
<router annotations="true" />
|
||||
<request converters="true" auto_convert="true" />
|
||||
<view annotations="true" />
|
||||
<cache annotations="true" />
|
||||
<security annotations="true" />
|
||||
<psr-message enabled="false" /> <!-- Defaults to true if the PSR-7 bridge is installed -->
|
||||
</sensio-framework-extra:config>
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
// load the profiler
|
||||
$container->loadFromExtension('sensio_framework_extra', array(
|
||||
'router' => array('annotations' => true),
|
||||
'request' => array('converters' => true, 'auto_convert' => true),
|
||||
'view' => array('annotations' => true),
|
||||
'cache' => array('annotations' => true),
|
||||
'security' => array('annotations' => true),
|
||||
'psr_message' => array('enabled' => false), // Defaults to true if the PSR-7 bridge is installed
|
||||
));
|
||||
|
||||
You can disable some annotations and conventions by defining one or more
|
||||
settings to false.
|
||||
|
||||
Annotations for Controllers
|
||||
---------------------------
|
||||
|
||||
Annotations are a great way to easily configure your controllers, from the
|
||||
routes to the cache configuration.
|
||||
|
||||
Even if annotations are not a native feature of PHP, it still has several
|
||||
advantages over the classic Symfony configuration methods:
|
||||
|
||||
* Code and configuration are in the same place (the controller class);
|
||||
* Simple to learn and to use;
|
||||
* Concise to write;
|
||||
* Makes your Controller thin (as its sole responsibility is to get data from
|
||||
the Model).
|
||||
|
||||
.. tip::
|
||||
|
||||
If you use view classes, annotations are a great way to avoid creating
|
||||
view classes for simple and common use cases.
|
||||
|
||||
The following annotations are defined by the bundle:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
annotations/routing
|
||||
annotations/converters
|
||||
annotations/view
|
||||
annotations/cache
|
||||
annotations/security
|
||||
|
||||
This example shows all the available annotations in action::
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
|
||||
|
||||
/**
|
||||
* @Route("/blog")
|
||||
* @Cache(expires="tomorrow")
|
||||
*/
|
||||
class AnnotController
|
||||
{
|
||||
/**
|
||||
* @Route("/")
|
||||
* @Template
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
$posts = ...;
|
||||
|
||||
return array('posts' => $posts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/{id}")
|
||||
* @Method("GET")
|
||||
* @ParamConverter("post", class="SensioBlogBundle:Post")
|
||||
* @Template("SensioBlogBundle:Annot:show.html.twig", vars={"post"})
|
||||
* @Cache(smaxage="15", lastmodified="post.getUpdatedAt()", etag="'Post' ~ post.getId() ~ post.getUpdatedAt()")
|
||||
* @Security("has_role('ROLE_ADMIN') and is_granted('POST_SHOW', post)")
|
||||
*/
|
||||
public function showAction(Post $post)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
As the ``showAction`` method follows some conventions, you can omit some
|
||||
annotations::
|
||||
|
||||
/**
|
||||
* @Route("/{id}")
|
||||
* @Cache(smaxage="15", lastModified="post.getUpdatedAt()", ETag="'Post' ~ post.getId() ~ post.getUpdatedAt()")
|
||||
* @Security("has_role('ROLE_ADMIN') and is_granted('POST_SHOW', post)")
|
||||
*/
|
||||
public function showAction(Post $post)
|
||||
{
|
||||
}
|
||||
|
||||
The routes need to be imported to be active as any other routing resources, for
|
||||
example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# app/config/routing.yml
|
||||
|
||||
# import routes from a controller directory
|
||||
annot:
|
||||
resource: "@AnnotRoutingBundle/Controller"
|
||||
type: annotation
|
||||
|
||||
see :ref:`Annotated Routes Activation<frameworkextra-annotations-routing-activation>` for more details.
|
||||
|
||||
PSR-7 support
|
||||
-------------
|
||||
|
||||
SensioFrameworkExtraBundle provides support for HTTP messages interfaces defined
|
||||
in `PSR-7`_. It allows to inject instances of ``Psr\Http\Message\ServerRequestInterface``
|
||||
and to return instances of ``Psr\Http\Message\ResponseInterface`` in controllers.
|
||||
|
||||
To enable this feature, `the HttpFoundation to PSR-7 bridge`_ and `Zend Diactoros`_ must be installed:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ composer require symfony/psr-http-message-bridge zendframework/zend-diactoros
|
||||
|
||||
Then, PSR-7 messages can be used directly in controllers like in the following code
|
||||
snippet::
|
||||
|
||||
namespace AppBundle\Controller;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Zend\Diactoros\Response;
|
||||
|
||||
class DefaultController
|
||||
{
|
||||
public function indexAction(ServerRequestInterface $request)
|
||||
{
|
||||
// Interact with the PSR-7 request
|
||||
|
||||
$response = new Response();
|
||||
// Interact with the PSR-7 response
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
Note that internally, Symfony always use :class:`Symfony\\Component\\HttpFoundation\\Request`
|
||||
and :class:`Symfony\\Component\\HttpFoundation\\Response` instances.
|
||||
|
||||
.. _`SensioFrameworkExtraBundle`: https://github.com/sensiolabs/SensioFrameworkExtraBundle
|
||||
.. _`PSR-7`: http://www.php-fig.org/psr/psr-7/
|
||||
.. _`the HttpFoundation to PSR-7 bridge`: https://github.com/symfony/psr-http-message-bridge
|
||||
.. _`Zend Diactoros`: https://github.com/zendframework/zend-diactoros
|
||||
Loading…
Add table
Add a link
Reference in a new issue