init without trunk

This commit is contained in:
Kevin Adametz 2020-07-09 12:49:32 +02:00
parent ed24ac4994
commit bb809e7233
14652 changed files with 177862 additions and 94817 deletions

View file

@ -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()``
======================================================================= ================================

View file

@ -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.

View file

@ -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).

View file

@ -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

View file

@ -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)
{
}