diff --git a/book/controller.rst b/book/controller.rst old mode 100644 new mode 100755 index ff9206158c1..80b3ce786fc --- a/book/controller.rst +++ b/book/controller.rst @@ -339,7 +339,7 @@ working with forms, for example:: { $form = $this->createForm(...); - $form->bind($request); + $form->handleRequest($request); // ... } @@ -392,8 +392,13 @@ itself. Extending the base class is *optional* in Symfony; it contains useful shortcuts but nothing mandatory. You can also extend - :class:`Symfony\\Component\\DependencyInjection\\ContainerAware`. The service - container object will then be accessible via the ``container`` property. + :class:`Symfony\\Component\\DependencyInjection\\ContainerAware` or use + the class:`Symfony\\Component\\DependencyInjection\\ContainerAwareTrait` trait + (if you have PHP 5.4). The service container object will then be accessible + via the ``container`` property. + +.. versionadded:: 2.4 + The ``ContainerAwareTrait`` is new in Symfony 2.4. .. note:: @@ -686,7 +691,8 @@ For example, imagine you're processing a form submit:: { $form = $this->createForm(...); - $form->bind($this->getRequest()); + $form->handleRequest($this->getRequest()); + if ($form->isValid()) { // do some sort of processing diff --git a/book/forms.rst b/book/forms.rst index f15d9fac1bd..f5621c51a5b 100644 --- a/book/forms.rst +++ b/book/forms.rst @@ -101,6 +101,7 @@ from inside a controller:: $form = $this->createFormBuilder($task) ->add('task', 'text') ->add('dueDate', 'date') + ->add('save', 'submit') ->getForm(); return $this->render('AcmeTaskBundle:Default:new.html.twig', array( @@ -125,6 +126,11 @@ In this example, you've added two fields to your form - ``task`` and ``dueDate`` corresponding to the ``task`` and ``dueDate`` properties of the ``Task`` class. You've also assigned each a "type" (e.g. ``text``, ``date``), which, among other things, determines which HTML form tag(s) is rendered for that field. +Finally, you added a submit button for submitting the form to the server. + +.. versionadded:: 2.3 + Support for submit buttons was added in Symfony 2.3. Before that, you had + to add buttons to the form's HTML manually. Symfony2 comes with many built-in types that will be discussed shortly (see :ref:`book-forms-type-reference`). @@ -145,35 +151,30 @@ helper functions: .. code-block:: html+jinja {# src/Acme/TaskBundle/Resources/views/Default/new.html.twig #} -
- {{ form_widget(form) }} - -
+ {{ form(form) }} .. code-block:: html+php -
enctype($form) ?> > - widget($form) ?> - -
+ form($form) ?> .. image:: /images/book/form-simple.png :align: center .. note:: - This example assumes that you've created a route called ``task_new`` - that points to the ``AcmeTaskBundle:Default:new`` controller that - was created earlier. + This example assumes that you submit the form in a "POST" request and to + the same URL that it was displayed in. You will learn later how to + change the request method and the target URL of the form. -That's it! By printing ``form_widget(form)``, each field in the form is -rendered, along with a label and error message (if there is one). As easy -as this is, it's not very flexible (yet). Usually, you'll want to render each -form field individually so you can control how the form looks. You'll learn how -to do that in the ":ref:`form-rendering-template`" section. +That's it! By printing ``form(form)``, each field in the form is rendered, along +with a label and error message (if there is one). The ``form`` function also +surrounds everything in the necessary HTML ``form`` tag. As easy as this is, +it's not very flexible (yet). Usually, you'll want to render each form field +individually so you can control how the form looks. You'll learn how to do +that in the ":ref:`form-rendering-template`" section. Before moving on, notice how the rendered ``task`` input field has the value of the ``task`` property from the ``$task`` object (i.e. "Write a blog post"). @@ -190,18 +191,17 @@ it into a format that's suitable for being rendered in an HTML form. (e.g. ``isPublished()`` or ``hasReminder()``) instead of a getter (e.g. ``getPublished()`` or ``getReminder()``). - .. versionadded:: 2.1 - Support for "hasser" methods was added in Symfony 2.1. - .. index:: - single: Forms; Handling form submission + single: Forms; Handling form submissions + +.. _book-form-handling-form-submissions: Handling Form Submissions ~~~~~~~~~~~~~~~~~~~~~~~~~ The second job of a form is to translate user-submitted data back to the properties of an object. To make this happen, the submitted data from the -user must be bound to the form. Add the following functionality to your +user must be written into the form. Add the following functionality to your controller:: // ... @@ -215,55 +215,94 @@ controller:: $form = $this->createFormBuilder($task) ->add('task', 'text') ->add('dueDate', 'date') + ->add('save', 'submit') ->getForm(); - if ($request->isMethod('POST')) { - $form->bind($request); + $form->handleRequest($request); - if ($form->isValid()) { - // perform some action, such as saving the task to the database + if ($form->isValid()) { + // perform some action, such as saving the task to the database - return $this->redirect($this->generateUrl('task_success')); - } + return $this->redirect($this->generateUrl('task_success')); } // ... } -.. versionadded:: 2.1 - The ``bind`` method was made more flexible in Symfony 2.1. It now accepts - the raw client data (same as before) or a Symfony Request object. This - is preferred over the deprecated ``bindRequest`` method. +.. versionadded:: 2.3 + The :method:`Symfony\\Component\\Form\\FormInterface::handleRequest` method was + added in Symfony 2.3. Previously, the ``$request`` was passed to the + ``submit`` method - a strategy which is deprecated and will be removed + in Symfony 3.0. For details on that method, see :ref:`cookbook-form-submit-request`. + +This controller follows a common pattern for handling forms, and has three +possible paths: -Now, when submitting the form, the controller binds the submitted data to the -form, which translates that data back to the ``task`` and ``dueDate`` properties -of the ``$task`` object. This all happens via the ``bind()`` method. +#. When initially loading the page in a browser, the form is simply created and + rendered. :method:`Symfony\\Component\\Form\\FormInterface::handleRequest` + recognizes that the form was not submitted and does nothing. + :method:`Symfony\\Component\\Form\\FormInterface::isValid` returns ``false`` + if the form was not submitted. -.. note:: +#. When the user submits the form, :method:`Symfony\\Component\\Form\\FormInterface::handleRequest` + recognizes this and immediately writes the submitted data back into the + ``task`` and ``dueDate`` properties of the ``$task`` object. Then this object + is validated. If it is invalid (validation is covered in the next section), + :method:`Symfony\\Component\\Form\\FormInterface::isValid` returns ``false`` + again, so the form is rendered together with all validation errors; - As soon as ``bind()`` is called, the submitted data is transferred - to the underlying object immediately. This happens regardless of whether - or not the underlying data is actually valid. + .. note:: -This controller follows a common pattern for handling forms, and has three -possible paths: + You can use the method :method:`Symfony\\Component\\Form\\FormInterface::isSubmitted` + to check whether a form was submitted, regardless of whether or not the + submitted data is actually valid. -#. When initially loading the page in a browser, the request method is ``GET`` - and the form is simply created and rendered; +#. When the user submits the form with valid data, the submitted data is again + written into the form, but this time :method:`Symfony\\Component\\Form\\FormInterface::isValid` + returns ``true``. Now you have the opportunity to perform some actions using + the ``$task`` object (e.g. persisting it to the database) before redirecting + the user to some other page (e.g. a "thank you" or "success" page). -#. When the user submits the form (i.e. the method is ``POST``) with invalid - data (validation is covered in the next section), the form is bound and - then rendered, this time displaying all validation errors; + .. note:: -#. When the user submits the form with valid data, the form is bound and - you have the opportunity to perform some actions using the ``$task`` - object (e.g. persisting it to the database) before redirecting the user - to some other page (e.g. a "thank you" or "success" page). + Redirecting a user after a successful form submission prevents the user + from being able to hit "refresh" and re-post the data. -.. note:: +.. index:: + single: Forms; Multiple Submit Buttons - Redirecting a user after a successful form submission prevents the user - from being able to hit "refresh" and re-post the data. +.. _book-form-submitting-multiple-buttons: + +Submitting Forms with Multiple Buttons +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.3 + Support for buttons in forms was added in Symfony 2.3. + +When your form contains more than one submit button, you will want to check +which of the buttons was clicked to adapt the program flow in your controller. +Let's add a second button with the caption "Save and add" to our form:: + + $form = $this->createFormBuilder($task) + ->add('task', 'text') + ->add('dueDate', 'date') + ->add('save', 'submit') + ->add('saveAndAdd', 'submit') + ->getForm(); + +In your controller, use the button's +:method:`Symfony\\Component\\Form\\ClickableInterface::isClicked` method for +querying if the "Save and add" button was clicked:: + + if ($form->isValid()) { + // ... perform some action, such as saving the task to the database + + $nextAction = $form->get('saveAndAdd')->isClicked() + ? 'task_new' + : 'task_success'; + + return $this->redirect($this->generateUrl($nextAction)); + } .. index:: single: Forms; Validation @@ -415,16 +454,46 @@ method:: In both of these cases, *only* the ``registration`` validation group will be used to validate the underlying object. -Groups based on Submitted Data -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. index:: + single: Forms; Disabling validation + +Disabling Validation +~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.3 + The ability to set ``validation_groups`` to false was added in Symfony 2.3, + although setting it to an empty array achieved the same result in previous + versions. + +Sometimes it is useful to suppress the validation of a form altogether. For +these cases, you can skip the call to :method:`Symfony\\Component\\Form\\FormInterface::isValid` +in your controller. If this is not possible, you can alternatively set the +``validation_groups`` option to ``false`` or an empty array:: + + use Symfony\Component\OptionsResolver\OptionsResolverInterface; + + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'validation_groups' => false, + )); + } + +Note that when you do that, the form will still run basic integrity checks, +for example whether an uploaded file was too large or whether non-existing +fields were submitted. If you want to suppress validation completely, remove +the :method:`Symfony\\Component\\Form\\FormInterface::isValid` call from your +controller. -.. versionadded:: 2.1 - The ability to specify a callback or Closure in ``validation_groups`` - is new to version 2.1 +.. index:: + single: Forms; Validation groups based on submitted data + +Groups based on the Submitted Data +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you need some advanced logic to determine the validation groups (e.g. based on submitted data), you can set the ``validation_groups`` option -to an array callback, or a ``Closure``:: +to an array callback:: use Symfony\Component\OptionsResolver\OptionsResolverInterface; @@ -439,9 +508,9 @@ to an array callback, or a ``Closure``:: } This will call the static method ``determineValidationGroups()`` on the -``Client`` class after the form is bound, but before validation is executed. +``Client`` class after the form is submitted, but before validation is executed. The Form object is passed as an argument to that method (see next example). -You can also define whole logic inline by using a Closure:: +You can also define whole logic inline by using a ``Closure``:: use Symfony\Component\Form\FormInterface; use Symfony\Component\OptionsResolver\OptionsResolverInterface; @@ -460,6 +529,44 @@ You can also define whole logic inline by using a Closure:: )); } +.. index:: + single: Forms; Validation groups based on clicked button + +Groups based on the Clicked Button +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.3 + Support for buttons in forms was added in Symfony 2.3. + +When your form contains multiple submit buttons, you can change the validation +group depending on which button is used to submit the form. For example, +consider a form in a wizard that lets you advance to the next step or go back +to the previous step. Let's assume also that when returning to the previous +step, the data of the form should be saved, but not validated. + +First, we need to add the two buttons to the form:: + + $form = $this->createFormBuilder($task) + // ... + ->add('nextStep', 'submit') + ->add('previousStep', 'submit') + ->getForm(); + +Then, we configure the button for returning to the previous step to run +specific validation groups. In this example, we want it to suppress validation, +so we set its ``validation_groups`` options to false:: + + $form = $this->createFormBuilder($task) + // ... + ->add('previousStep', 'submit', array( + 'validation_groups' => false, + )) + ->getForm(); + +Now the form will skip your validation constraints. It will still validate +basic integrity constraints, such as checking whether an uploaded file was too +large or whether you tried to submit text in a number field. + .. index:: single: Forms; Built-in field types @@ -549,6 +656,7 @@ guess from the validation rules that both the ``task`` field is a normal $form = $this->createFormBuilder($task) ->add('task') ->add('dueDate', null, array('widget' => 'single_text')) + ->add('save', 'submit') ->getForm(); } @@ -616,35 +724,26 @@ of code. Of course, you'll usually need much more flexibility when rendering: .. code-block:: html+jinja {# src/Acme/TaskBundle/Resources/views/Default/new.html.twig #} -
+ {{ form_start(form) }} {{ form_errors(form) }} {{ form_row(form.task) }} {{ form_row(form.dueDate) }} - - {{ form_rest(form) }} - - -
+ {{ form_end(form) }} .. code-block:: html+php -
enctype($form) ?>> + start($form) ?> errors($form) ?> row($form['task']) ?> row($form['dueDate']) ?> - - rest($form) ?> - - -
+ end($form) ?> Take a look at each part: -* ``form_enctype(form)`` - If at least one field is a file upload field, this - renders the obligatory ``enctype="multipart/form-data"``; +* ``form_start(form)`` - Renders the start tag of the form. * ``form_errors(form)`` - Renders any errors global to the whole form (field-specific errors are displayed next to each field); @@ -653,10 +752,8 @@ Take a look at each part: form widget for the given field (e.g. ``dueDate``) inside, by default, a ``div`` element; -* ``form_rest(form)`` - Renders any fields that have not yet been rendered. - It's usually a good idea to place a call to this helper at the bottom of - each form (in case you forgot to output a field or don't want to bother - manually rendering hidden fields). This helper is also useful for taking +* ``form_end()`` - Renders the end tag of the form and any fields that have not + yet been rendered. This is useful for rendering hidden fields and taking advantage of the automatic :ref:`CSRF Protection `. The majority of the work is done by the ``form_row`` helper, which renders @@ -694,39 +791,46 @@ used the ``form_row`` helper: .. code-block:: html+jinja - {{ form_errors(form) }} + {{ form_start(form) }} + {{ form_errors(form) }} -
- {{ form_label(form.task) }} - {{ form_errors(form.task) }} - {{ form_widget(form.task) }} -
+
+ {{ form_label(form.task) }} + {{ form_errors(form.task) }} + {{ form_widget(form.task) }} +
-
- {{ form_label(form.dueDate) }} - {{ form_errors(form.dueDate) }} - {{ form_widget(form.dueDate) }} -
+
+ {{ form_label(form.dueDate) }} + {{ form_errors(form.dueDate) }} + {{ form_widget(form.dueDate) }} +
+ + - {{ form_rest(form) }} + {{ form_end(form) }} .. code-block:: html+php - errors($form) ?> + start($form) ?> -
- label($form['task']) ?> - errors($form['task']) ?> - widget($form['task']) ?> -
+ errors($form) ?> -
- label($form['dueDate']) ?> - errors($form['dueDate']) ?> - widget($form['dueDate']) ?> -
+
+ label($form['task']) ?> + errors($form['task']) ?> + widget($form['task']) ?> +
+ +
+ label($form['dueDate']) ?> + errors($form['dueDate']) ?> + widget($form['dueDate']) ?> +
- rest($form) ?> + + + end($form) ?> If the auto-generated label for a field isn't quite right, you can explicitly specify it: @@ -751,7 +855,7 @@ field: .. code-block:: html+jinja - {{ form_widget(form.task, { 'attr': {'class': 'task_field'} }) }} + {{ form_widget(form.task, {'attr': {'class': 'task_field'}}) }} .. code-block:: html+php @@ -794,6 +898,76 @@ available in the :doc:`reference manual `. Read this to know everything about the helpers available and the options that can be used with each. +.. index:: + single: Forms; Changing the action and method + +.. _book-forms-changing-action-and-method: + +Changing the Action and Method of a Form +---------------------------------------- + +So far, the ``form_start()`` helper has been used to render the form's start +tag and we assumed that each form is submitted to the same URL in a POST request. +Sometimes you want to change these parameters. You can do so in a few different +ways. If you build your form in the controller, you can use ``setAction()`` and +``setMethod()``:: + + $form = $this->createFormBuilder($task) + ->setAction($this->generateUrl('target_route')) + ->setMethod('GET') + ->add('task', 'text') + ->add('dueDate', 'date') + ->add('save', 'submit') + ->getForm(); + +.. note:: + + This example assumes that you've created a route called ``target_route`` + that points to the controller that processes the form. + +In :ref:`book-form-creating-form-classes` you will learn how to move the +form building code into separate classes. When using an external form class +in the controller, you can pass the action and method as form options:: + + $form = $this->createForm(new TaskType(), $task, array( + 'action' => $this->generateUrl('target_route'), + 'method' => 'GET', + )); + +Finally, you can override the action and method in the template by passing them +to the ``form()`` or the ``form_start()`` helper: + +.. configuration-block:: + + .. code-block:: html+jinja + + {# src/Acme/TaskBundle/Resources/views/Default/new.html.twig #} + {{ form(form, {'action': path('target_route'), 'method': 'GET'}) }} + + {{ form_start(form, {'action': path('target_route'), 'method': 'GET'}) }} + + .. code-block:: html+php + + + form($form, array( + 'action' => $view['router']->generate('target_route'), + 'method' => 'GET', + )) ?> + + start($form, array( + 'action' => $view['router']->generate('target_route'), + 'method' => 'GET', + )) ?> + +.. note:: + + If the form's method is not GET or POST, but PUT, PATCH or DELETE, Symfony2 + will insert a hidden field with the name "_method" that stores this method. + The form will be submitted in a normal POST request, but Symfony2's router + is capable of detecting the "_method" parameter and will interpret the + request as PUT, PATCH or DELETE request. Read the cookbook chapter + ":doc:`/cookbook/routing/method_parameters`" for more information. + .. index:: single: Forms; Creating form classes @@ -817,8 +991,9 @@ that will house the logic for building the task form:: { public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->add('task'); - $builder->add('dueDate', null, array('widget' => 'single_text')); + $builder->add('task') + ->add('dueDate', null, array('widget' => 'single_text')) + ->add('save', 'submit'); } public function getName() @@ -883,8 +1058,9 @@ the choice is ultimately up to you. public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->add('task'); - $builder->add('dueDate', null, array('mapped' => false)); + $builder->add('task') + ->add('dueDate', null, array('mapped' => false)) + ->add('save', 'submit'); } Additionally, if there are any fields on the form that aren't included in @@ -1003,7 +1179,7 @@ you can fetch it from the form:: For more information, see the :doc:`Doctrine ORM chapter `. -The key thing to understand is that when the form is bound, the submitted +The key thing to understand is that when the form is submitted, the submitted data is transferred to the underlying object immediately. If you want to persist that data, you simply need to persist the object itself (which already contains the submitted data). @@ -1136,7 +1312,6 @@ as the original ``Task`` fields: {{ form_row(form.category.name) }} - {{ form_rest(form) }} {# ... #} .. code-block:: html+php @@ -1148,7 +1323,6 @@ as the original ``Task`` fields: row($form['category']['name']) ?> - rest($form) ?> When the user submits the form, the submitted data for the ``Category`` fields @@ -1234,7 +1408,7 @@ renders the form: {% form_theme form 'AcmeTaskBundle:Form:fields.html.twig' 'AcmeTaskBundle:Form:fields2.html.twig' %} -
+ {{ form(form) }} .. code-block:: html+php @@ -1243,7 +1417,7 @@ renders the form: setTheme($form, array('AcmeTaskBundle:Form', 'AcmeTaskBundle:Form')) ?> - + form($form) ?> The ``form_theme`` tag (in Twig) "imports" the fragments defined in the given template and uses them when rendering the form. In other words, when the @@ -1262,18 +1436,13 @@ To customize any portion of a form, you just need to override the appropriate fragment. Knowing exactly which block or file to override is the subject of the next section. -.. versionadded:: 2.1 - An alternate Twig syntax for ``form_theme`` has been introduced in 2.1. It accepts - any valid Twig expression (the most noticeable difference is using an array when - using multiple themes). - - .. code-block:: html+jinja +.. code-block:: html+jinja - {# src/Acme/TaskBundle/Resources/views/Default/new.html.twig #} + {# src/Acme/TaskBundle/Resources/views/Default/new.html.twig #} - {% form_theme form with 'AcmeTaskBundle:Form:fields.html.twig' %} + {% form_theme form with 'AcmeTaskBundle:Form:fields.html.twig' %} - {% form_theme form with ['AcmeTaskBundle:Form:fields.html.twig', 'AcmeTaskBundle:Form:fields2.html.twig'] %} + {% form_theme form with ['AcmeTaskBundle:Form:fields.html.twig', 'AcmeTaskBundle:Form:fields2.html.twig'] %} For a more extensive discussion, see :doc:`/cookbook/form/form_customization`. @@ -1322,7 +1491,7 @@ are 4 possible *parts* of a form that can be rendered: .. note:: - There are actually 3 other *parts* - ``rows``, ``rest``, and ``enctype`` - + There are actually 2 other *parts* - ``rows`` and ``rest`` - but you should rarely if ever need to worry about overriding them. By knowing the field type (e.g. ``textarea``) and which part you want to @@ -1531,7 +1700,7 @@ ensures that the user - not some other entity - is submitting the given data. Symfony automatically validates the presence and accuracy of this token. The ``_token`` field is a hidden field and will be automatically rendered -if you include the ``form_rest()`` function in your template, which ensures +if you include the ``form_end()`` function in your template, which ensures that all un-rendered fields are output. The CSRF token can be customized on a form-by-form basis. For example:: @@ -1590,14 +1759,15 @@ an array of the submitted data. This is actually really easy:: ->add('name', 'text') ->add('email', 'email') ->add('message', 'textarea') + ->add('send', 'submit') ->getForm(); - if ($request->isMethod('POST')) { - $form->bind($request); + $form->handleRequest($request); - // data is an array with "name", "email", and "message" keys - $data = $form->getData(); - } + if ($form->isValid()) { + // data is an array with "name", "email", and "message" keys + $data = $form->getData(); + } // ... render the form } @@ -1632,25 +1802,20 @@ Adding Validation The only missing piece is validation. Usually, when you call ``$form->isValid()``, the object is validated by reading the constraints that you applied to that -class. If your form is binding to an object (i.e. you're using the ``data_class`` +class. If your form is mapped to an object (i.e. you're using the ``data_class`` option or passing an object to your form), this is almost always the approach you want to use. See :doc:`/book/validation` for more details. .. _form-option-constraints: -But if you're not binding to an object and are instead retrieving a simple -array of your submitted data, how can you add constraints to the data of your -form? +But if the form is not mapped to an object and you instead want to retrieve a +simple array of your submitted data, how can you add constraints to the data of +your form? The answer is to setup the constraints yourself, and attach them to the individual fields. The overall approach is covered a bit more in the :ref:`validation chapter `, but here's a short example: -.. versionadded:: 2.1 - The ``constraints`` option, which accepts a single constraint or an array - of constraints (before 2.1, the option was called ``validation_constraint``, - and only accepted a single constraint) is new to Symfony 2.1. - .. code-block:: php use Symfony\Component\Validator\Constraints\Length; diff --git a/book/from_flat_php_to_symfony2.rst b/book/from_flat_php_to_symfony2.rst index d3d290d21ad..3590fe44353 100644 --- a/book/from_flat_php_to_symfony2.rst +++ b/book/from_flat_php_to_symfony2.rst @@ -433,7 +433,7 @@ content: { "require": { - "symfony/symfony": "2.2.*" + "symfony/symfony": "2.3.*" }, "autoload": { "files": ["model.php","controllers.php"] diff --git a/book/installation.rst b/book/installation.rst index 167746ddf62..e01c0d942b8 100644 --- a/book/installation.rst +++ b/book/installation.rst @@ -57,12 +57,12 @@ Distribution: .. code-block:: bash - $ php composer.phar create-project symfony/framework-standard-edition /path/to/webroot/Symfony 2.2.0 + $ php composer.phar create-project symfony/framework-standard-edition /path/to/webroot/Symfony 2.3.0 .. tip:: - For an exact version, replace `2.2.0` with the latest Symfony version - (e.g. 2.2.1). For details, see the `Symfony Installation Page`_ + For an exact version, replace "2.3.0" with the latest Symfony version. + For details, see the `Symfony Installation Page`_ .. tip:: @@ -109,10 +109,10 @@ one of the following commands (replacing ``###`` with your actual filename): .. code-block:: bash # for .tgz file - $ tar zxvf Symfony_Standard_Vendors_2.2.###.tgz + $ tar zxvf Symfony_Standard_Vendors_2.3.###.tgz # for a .zip file - $ unzip Symfony_Standard_Vendors_2.2.###.zip + $ unzip Symfony_Standard_Vendors_2.3.###.zip If you've downloaded "without vendors", you'll definitely need to read the next section. diff --git a/book/internals.rst b/book/internals.rst index 399f0d87daf..69078e403e1 100644 --- a/book/internals.rst +++ b/book/internals.rst @@ -367,9 +367,6 @@ The ``FrameworkBundle`` registers several listeners: ``kernel.terminate`` Event .......................... -.. versionadded:: 2.1 - The ``kernel.terminate`` event is new since Symfony 2.1. - The purpose of this event is to perform "heavier" tasks after the response was already served to the client. diff --git a/book/page_creation.rst b/book/page_creation.rst index 415ee3fba94..8d57f4daf43 100644 --- a/book/page_creation.rst +++ b/book/page_creation.rst @@ -625,7 +625,6 @@ method of the ``AppKernel`` class:: new Symfony\Bundle\DoctrineBundle\DoctrineBundle(), new Symfony\Bundle\AsseticBundle\AsseticBundle(), new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), - new JMS\SecurityExtraBundle\JMSSecurityExtraBundle(), ); if (in_array($this->getEnvironment(), array('dev', 'test'))) { @@ -864,9 +863,6 @@ options of each feature. Default Configuration Dump ~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 2.1 - The ``config:dump-reference`` command was added in Symfony 2.1 - You can dump the default configuration for a bundle in yaml to the console using the ``config:dump-reference`` command. Here is an example of dumping the default FrameworkBundle configuration: diff --git a/book/routing.rst b/book/routing.rst index 905bc4be85e..68a9e4c7ce6 100644 --- a/book/routing.rst +++ b/book/routing.rst @@ -807,7 +807,7 @@ a slash. URLs matching this route might look like: .. note:: Sometimes you want to make certain parts of your routes globally configurable. - Symfony2.1 provides you with a way to do this by leveraging service container + Symfony provides you with a way to do this by leveraging service container parameters. Read more about this in ":doc:`/cookbook/routing/service_container_parameters`. Special Routing Parameters diff --git a/book/security.rst b/book/security.rst index 7335d3e784a..e21e32cc438 100644 --- a/book/security.rst +++ b/book/security.rst @@ -412,12 +412,8 @@ submission (i.e. ``/login_check``): You will *not* need to implement a controller for the ``/login_check`` URL as the firewall will automatically catch and process any form submitted - to this URL. - -.. versionadded:: 2.1 - As of Symfony 2.1, you *must* have routes configured for your ``login_path``, - ``check_path`` ``logout`` keys. These keys can be route names (as shown - in this example) or URLs that have routes configured for them. + to this URL. However, you *must* have a route (as shown here) for this + URL, as well as one for your logout path (see :ref:`book-security-logging-out`). Notice that the name of the ``login`` route matches the ``login_path`` config value, as that's where the security system will redirect users that need @@ -770,7 +766,7 @@ access control should be used on this request. The following ``access_control`` options are used for matching: * ``path`` -* ``ip`` +* ``ip`` or ``ips`` * ``host`` * ``methods`` @@ -893,6 +889,11 @@ prevent any direct access to these resources from a web browser (by guessing the ESI URL pattern), the ESI route **must** be secured to be only visible from the trusted reverse proxy cache. +.. versionadded:: 2.3 + Version 2.3 allows multiple IP addresses in a single rule with the ``ips: [a, b]`` + construct. Prior to 2.3, users should create one rule per IP address to match and + use the ``ip`` key instead of ``ips``. + Here is an example of how you might secure all ESI routes that start with a given prefix, ``/esi``, from outside access: @@ -904,14 +905,14 @@ given prefix, ``/esi``, from outside access: security: # ... access_control: - - { path: ^/esi, roles: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 } + - { path: ^/esi, roles: IS_AUTHENTICATED_ANONYMOUSLY, ips: [127.0.0.1, ::1] } - { path: ^/esi, roles: ROLE_NO_ACCESS } .. code-block:: xml + ips="127.0.0.1, ::1" /> @@ -921,11 +922,11 @@ given prefix, ``/esi``, from outside access: array( 'path' => '^/esi', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY', - 'ip' => '127.0.0.1', + 'ips' => '127.0.0.1, ::1' ), array( 'path' => '^/esi', - 'role' => 'ROLE_NO_ACCESS', + 'role' => 'ROLE_NO_ACCESS' ), ), @@ -933,7 +934,7 @@ Here is how it works when the path is ``/esi/something`` coming from the ``10.0.0.1`` IP: * The first access control rule is ignored as the ``path`` matches but the - ``ip`` does not; + ``ip`` does not match either of the IPs listed; * The second access control rule is enabled (the only restriction being the ``path`` and it matches): as the user cannot have the ``ROLE_NO_ACCESS`` @@ -941,7 +942,8 @@ Here is how it works when the path is ``/esi/something`` coming from the be anything that does not match an existing role, it just serves as a trick to always deny access). -Now, if the same request comes from ``127.0.0.1``: +Now, if the same request comes from ``127.0.0.1`` or ``::1`` (the IPv6 loopback +address): * Now, the first access control rule is enabled as both the ``path`` and the ``ip`` match: access is allowed as the user always has the @@ -1021,9 +1023,7 @@ which can secure your controller using annotations:: // ... } -For more information, see the `JMSSecurityExtraBundle`_ documentation. If you're -using Symfony's Standard Distribution, this bundle is available by default. -If not, you can easily download and install it. +For more information, see the `JMSSecurityExtraBundle`_ documentation. Securing other Services ~~~~~~~~~~~~~~~~~~~~~~~ @@ -1196,12 +1196,6 @@ custom user class is that it implements the :class:`Symfony\\Component\\Security interface. This means that your concept of a "user" can be anything, as long as it implements this interface. -.. versionadded:: 2.1 - In Symfony 2.1, the ``equals`` method was removed from ``UserInterface``. - If you need to override the default implementation of comparison logic, - implement the new :class:`Symfony\\Component\\Security\\Core\\User\\EquatableInterface` - interface. - .. note:: The user object will be serialized and saved in the session during requests, @@ -1703,6 +1697,8 @@ In the above configuration, users with ``ROLE_ADMIN`` role will also have the ``ROLE_USER`` role. The ``ROLE_SUPER_ADMIN`` role has ``ROLE_ADMIN``, ``ROLE_ALLOWED_TO_SWITCH`` and ``ROLE_USER`` (inherited from ``ROLE_ADMIN``). +.. _book-security-logging-out: + Logging Out ----------- @@ -1804,11 +1800,6 @@ a route so that you can use it to generate the URL: return $collection; -.. caution:: - - As of Symfony 2.1, you *must* have a route that corresponds to your logout - path. Without this route, logging out will not work. - Once the user has been logged out, he will be redirected to whatever path is defined by the ``target`` parameter above (e.g. the ``homepage``). For more information on configuring the logout, see the diff --git a/book/service_container.rst b/book/service_container.rst index 24526c7319b..9942ea9c523 100644 --- a/book/service_container.rst +++ b/book/service_container.rst @@ -248,10 +248,6 @@ The end result is exactly the same as before - the difference is only in to look for parameters with those names. When the container is built, it looks up the value of each parameter and uses it in the service definition. -.. versionadded:: 2.1 - Escaping the ``@`` character in YAML parameter values is new in Symfony 2.1.9 - and Symfony 2.2.1. - .. note:: If you want to use a string that starts with an ``@`` sign as a parameter @@ -274,14 +270,6 @@ looks up the value of each parameter and uses it in the service definition. http://symfony.com/?foo=%%s&bar=%%d -.. caution:: - - You may receive a - :class:`Symfony\\Component\\DependencyInjection\\Exception\\ScopeWideningInjectionException` - when passing the ``request`` service as an argument. To understand this - problem better and learn how to solve it, refer to the cookbook article - :doc:`/cookbook/service_container/scopes`. - The purpose of parameters is to feed information into services. Of course there was nothing wrong with defining the service without using any parameters. Parameters, however, have several advantages: @@ -766,6 +754,36 @@ Injecting the dependency by the setter method just needs a change of syntax: and "setter injection". The Symfony2 service container also supports "property injection". +Injecting the Request +~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.4 + The ``request_stack`` service was introduced in version 2.4. + +Almost all Symfony2 built-in services behave in the same way: a single +instance is created by the container which it returns whenever you get it or +when it is injected into another service. There is one exception in a standard +Symfony2 application: the ``request`` service. + +If you try to inject the ``request`` into a service, you will probably receive +a +:class:`Symfony\\Component\\DependencyInjection\\Exception\\ScopeWideningInjectionException` +exception. That's because the ``request`` can **change** during the life-time +of a container (when a sub-request is created for instance). + +As of Symfony 2.4, instead of injecting the ``request`` service, you should +inject the ``request_stack`` service instead and access the Request by calling +the ``getCurrentRequest()`` method. For earlier versions, or if you want to +understand this problem better, refer to the cookbook article +:doc:`/cookbook/service_container/scopes`. + +.. tip:: + + If you define a controller as a service then you can get the ``Request`` + object without injecting the container by having it passed in as an + argument of your action method. See + :ref:`book-controller-request-argument` for details. + Making References Optional -------------------------- diff --git a/book/stable_api.rst b/book/stable_api.rst index 0d92777bdd0..8980f0274dc 100644 --- a/book/stable_api.rst +++ b/book/stable_api.rst @@ -22,7 +22,8 @@ everything not tagged explicitly is not part of the stable API. Any third party bundle should also publish its own stable API. -As of Symfony 2.0, the following components have a public tagged API: +As of the latest stable release of Symfony, the following components have +a public tagged API: * BrowserKit * ClassLoader @@ -31,7 +32,7 @@ As of Symfony 2.0, the following components have a public tagged API: * DependencyInjection * DomCrawler * EventDispatcher -* Filesystem (as of Symfony 2.1) +* Filesystem * Finder * HttpFoundation * HttpKernel diff --git a/book/templating.rst b/book/templating.rst index fc16b8c1c39..df6227eef5b 100644 --- a/book/templating.rst +++ b/book/templating.rst @@ -676,9 +676,6 @@ that as much code as possible lives in reusable :doc:`services getRequest(); + + // the BrowserKit request instance + $request = $client->getInternalRequest(); + + // the HttpKernel response instance $response = $client->getResponse(); + + // the BrowserKit response instance + $response = $client->getInternalResponse(); + $crawler = $client->getCrawler(); If your requests are not insulated, you can also access the ``Container`` and diff --git a/book/translation.rst b/book/translation.rst index f4faf08289f..a11dac1c05a 100644 --- a/book/translation.rst +++ b/book/translation.rst @@ -573,11 +573,6 @@ by defining a ``default_locale`` for the framework: 'default_locale' => 'en', )); -.. versionadded:: 2.1 - The ``default_locale`` parameter was defined under the session key - originally, however, as of 2.1 this has been moved. This is because the - locale is now set on the request instead of the session. - .. _book-translation-locale-url: The Locale and the URL @@ -851,9 +846,6 @@ texts* and complex expressions: Note that this only influences the current template, not any "included" templates (in order to avoid side effects). -.. versionadded:: 2.1 - The ``trans_default_domain`` tag is new in Symfony2.1 - PHP Templates ~~~~~~~~~~~~~ diff --git a/book/validation.rst b/book/validation.rst index 158e7cc3c6e..e273caff0a4 100644 --- a/book/validation.rst +++ b/book/validation.rst @@ -203,8 +203,8 @@ Validation and Forms The ``validator`` service can be used at any time to validate any object. In reality, however, you'll usually work with the ``validator`` indirectly when working with forms. Symfony's form library uses the ``validator`` service -internally to validate the underlying object after values have been submitted -and bound. The constraint violations on the object are converted into ``FieldError`` +internally to validate the underlying object after values have been submitted. +The constraint violations on the object are converted into ``FieldError`` objects that can easily be displayed with your form. The typical form submission workflow looks like the following from inside a controller:: @@ -218,14 +218,12 @@ workflow looks like the following from inside a controller:: $author = new Author(); $form = $this->createForm(new AuthorType(), $author); - if ($request->isMethod('POST')) { - $form->bind($request); + $form->handleRequest($request); - if ($form->isValid()) { - // the validation passed, do something with the $author object + if ($form->isValid()) { + // the validation passed, do something with the $author object - return $this->redirect($this->generateUrl(...)); - } + return $this->redirect($this->generateUrl(...)); } return $this->render('BlogBundle:Author:form.html.twig', array( diff --git a/bundles/map.rst.inc b/bundles/map.rst.inc index 44424cc6a1d..92d742ce70c 100644 --- a/bundles/map.rst.inc +++ b/bundles/map.rst.inc @@ -1,10 +1,5 @@ * :doc:`SensioFrameworkExtraBundle ` * :doc:`SensioGeneratorBundle ` -* `JMSSecurityExtraBundle`_ -* `JMSDiExtraBundle`_ * :doc:`DoctrineFixturesBundle ` * :doc:`DoctrineMigrationsBundle ` * :doc:`DoctrineMongoDBBundle ` - -.. _`JMSSecurityExtraBundle`: http://jmsyst.com/bundles/JMSSecurityExtraBundle/1.2 -.. _`JMSDiExtraBundle`: http://jmsyst.com/bundles/JMSDiExtraBundle/1.1 diff --git a/components/class_loader/cache_class_loader.rst b/components/class_loader/cache_class_loader.rst index dbce3ce1929..01a393de216 100644 --- a/components/class_loader/cache_class_loader.rst +++ b/components/class_loader/cache_class_loader.rst @@ -26,9 +26,6 @@ for a class. ApcClassLoader -------------- -.. versionadded:: 2.1 - The ``ApcClassLoader`` class was added in Symfony 2.1. - ``ApcClassLoader`` wraps an existing class loader and caches calls to its ``findFile()`` method using `APC`_:: @@ -49,9 +46,6 @@ ApcClassLoader XcacheClassLoader ----------------- -.. versionadded:: 2.1 - The ``XcacheClassLoader`` class was added in Symfony 2.1. - ``XcacheClassLoader`` uses `XCache`_ to cache a class loader. Registering it is straightforward:: diff --git a/components/class_loader/class_loader.rst b/components/class_loader/class_loader.rst index c5f2d65b70d..44de944443e 100644 --- a/components/class_loader/class_loader.rst +++ b/components/class_loader/class_loader.rst @@ -4,9 +4,6 @@ The PSR-0 Class Loader ====================== -.. versionadded:: 2.1 - The ``ClassLoader`` class was added in Symfony 2.1. - If your classes and third-party libraries follow the `PSR-0`_ standard, you can use the :class:`Symfony\\Component\\ClassLoader\\ClassLoader` class to load all of your project's classes. diff --git a/components/class_loader/debug_class_loader.rst b/components/class_loader/debug_class_loader.rst index 2af2e158401..7533f715b07 100644 --- a/components/class_loader/debug_class_loader.rst +++ b/components/class_loader/debug_class_loader.rst @@ -4,9 +4,6 @@ Debugging a Class Loader ======================== -.. versionadded:: 2.1 - The ``DebugClassLoader`` class was added in Symfony 2.1. - The :class:`Symfony\\Component\\ClassLoader\\DebugClassLoader` attempts to throw more helpful exceptions when a class isn't found by the registered autoloaders. All autoloaders that implement a ``findFile()`` method are replaced diff --git a/components/config/definition.rst b/components/config/definition.rst index 4ca0f790b69..0bd25d19a03 100644 --- a/components/config/definition.rst +++ b/components/config/definition.rst @@ -100,8 +100,8 @@ node definition. Node type are available for: * scalar * boolean * integer (new in 2.2) -* float (new in 2.2) -* enum (new in 2.1) +* float +* enum * array * variable (no validation) @@ -136,9 +136,6 @@ allowing to validate the value:: Enum nodes ~~~~~~~~~~ -.. versionadded:: 2.1 - The enum node is new in Symfony 2.1 - Enum nodes provide a constraint to match the given input against a set of values:: diff --git a/components/console/events.rst b/components/console/events.rst new file mode 100644 index 00000000000..f1dd133d505 --- /dev/null +++ b/components/console/events.rst @@ -0,0 +1,120 @@ +.. index:: + single: Console; Events + +Using Events +============ + +.. versionadded:: 2.3 + Console events were added in Symfony 2.3. + +The Application class of the Console component allows you to optionally hook +into the lifecycle of a console application via events. Instead of reinventing +the wheel, it uses the Symfony EventDispatcher component to do the work:: + + use Symfony\Component\Console\Application; + use Symfony\Component\EventDispatcher\EventDispatcher; + + $dispatcher = new EventDispatcher(); + + $application = new Application(); + $application->setDispatcher($dispatcher); + $application->run(); + +The ``ConsoleEvents::COMMAND`` Event +------------------------------------ + +**Typical Purposes**: Doing something before any command is run (like logging +which command is going to be executed), or displaying something about the event +to be executed. + +Just before executing any command, the ``ConsoleEvents::COMMAND`` event is +dispatched. Listeners receive a +:class:`Symfony\\Component\\Console\\Event\\ConsoleCommandEvent` event:: + + use Symfony\Component\Console\Event\ConsoleCommandEvent; + use Symfony\Component\Console\ConsoleEvents; + + $dispatcher->addListener(ConsoleEvents::COMMAND, function (ConsoleCommandEvent $event) { + // get the input instance + $input = $event->getInput(); + + // get the output instance + $output = $event->getOutput(); + + // get the command to be executed + $command = $event->getCommand(); + + // write something about the command + $output->writeln(sprintf('Before running command %s', $command->getName())); + + // get the application + $application = $command->getApplication(); + }); + +The ``ConsoleEvents::TERMINATE`` event +-------------------------------------- + +**Typical Purposes**: To perform some cleanup actions after the command has +been executed. + +After the command has been executed, the ``ConsoleEvents::TERMINATE`` event is +dispatched. It can be used to do any actions that need to be executed for all +commands or to cleanup what you initiated in a ``ConsoleEvents::COMMAND`` +listener (like sending logs, closing a database connection, sending emails, +...). A listener might also change the exit code. + +Listeners receive a +:class:`Symfony\\Component\\Console\\Event\\ConsoleTerminateEvent` event:: + + use Symfony\Component\Console\Event\ConsoleTerminateEvent; + use Symfony\Component\Console\ConsoleEvents; + + $dispatcher->addListener(ConsoleEvents::TERMINATE, function (ConsoleTerminateEvent $event) { + // get the output + $output = $event->getOutput(); + + // get the command that has been executed + $command = $event->getCommand(); + + // display something + $output->writeln(sprintf('After running command %s', $command->getName())); + + // change the exit code + $event->setExitCode(128); + }); + +.. tip:: + + This event is also dispatched when an exception is thrown by the command. + It is then dispatched just before the ``ConsoleEvents::EXCEPTION`` event. + The exit code received in this case is the exception code. + +The ``ConsoleEvents::EXCEPTION`` event +-------------------------------------- + +**Typical Purposes**: Handle exceptions thrown during the execution of a +command. + +Whenever an exception is thrown by a command, the ``ConsoleEvents::EXCEPTION`` +event is dispatched. A listener can wrap or change the exception or do +anything useful before the exception is thrown by the application. + +Listeners receive a +:class:`Symfony\\Component\\Console\\Event\\ConsoleExceptionEvent` event:: + + use Symfony\Component\Console\Event\ConsoleExceptionEvent; + use Symfony\Component\Console\ConsoleEvents; + + $dispatcher->addListener(ConsoleEvents::EXCEPTION, function (ConsoleExceptionEvent $event) { + $output = $event->getOutput(); + + $command = $event->getCommand(); + + $output->writeln(sprintf('Oops, exception thrown while running command %s', $command->getName())); + + // get the current exit code (the exception code or the exit code set by a ConsoleEvents::TERMINATE event) + $exitCode = $event->getExitCode(); + + // change the exception to another one + $event->setException(new \LogicException('Caught exception', $exitCode, $event->getException())); + }); diff --git a/components/console/helpers/dialoghelper.rst b/components/console/helpers/dialoghelper.rst index 1c910d4106d..1d1215236f1 100644 --- a/components/console/helpers/dialoghelper.rst +++ b/components/console/helpers/dialoghelper.rst @@ -53,6 +53,24 @@ The user will be asked "Please enter the name of the bundle". She can type some name which will be returned by the ``ask`` method. If she leaves it empty, the default value (``AcmeDemoBundle`` here) is returned. +Autocompletion +~~~~~~~~~~~~~~ + +.. versionadded:: 2.2 + Autocompletion for questions was added in Symfony 2.2. + +You can also specify an array of potential answers for a given question. These +will be autocompleted as the user types:: + + $dialog = $this->getHelperSet()->get('dialog'); + $bundleNames = array('AcmeDemoBundle', 'AcmeBlogBundle', 'AcmeStoreBundle'); + $name = $dialog->ask( + $output, + 'Please enter the name of a bundle', + 'FooBundle', + $bundleNames + ); + Hiding the User's Response ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -181,13 +199,43 @@ from a predefined list:: // ... do something with the color The option which should be selected by default is provided with the fourth -parameter. The default is ``null``, which means that no option is the default one. +argument. The default is ``null``, which means that no option is the default one. If the user enters an invalid string, an error message is shown and the user is asked to provide the answer another time, until she enters a valid string or the maximum attempts is reached (which you can define in the fifth -parameter). The default value for the attempts is ``false``, which means infinite -attempts. You can define your own error message in the sixth parameter. +argument). The default value for the attempts is ``false``, which means infinite +attempts. You can define your own error message in the sixth argument. + +.. versionadded:: 2.3 + Multiselect support was added in Symfony 2.3. + +Multiple Choices +................ + +Sometimes, multiple answers can be given. The DialogHelper provides this +feature using comma separated values. This is disabled by default, to enable +this set the seventh argument to ``true``:: + + // ... + + $selected = $dialog->select( + $output, + 'Please select your favorite color (default to red)', + $colors, + 0, + false, + 'Value "%s" is invalid', + true // enable multiselect + ); + + $selectedColors = array_map(function($c) use ($colors) { + return $colors[$c]; + }, $selected); + + $output->writeln('You have just selected: ' . implode(', ', $selectedColors)); + +Now, when the user enters ``1,2``, the result will be: ``You have just selected: blue, yellow``. Testing a Command which expects input ------------------------------------- diff --git a/components/console/helpers/index.rst b/components/console/helpers/index.rst index adb2a4bbc8a..c922e732e64 100644 --- a/components/console/helpers/index.rst +++ b/components/console/helpers/index.rst @@ -10,6 +10,7 @@ The Console Helpers dialoghelper formatterhelper progresshelper + tablehelper The Console Components comes with some useful helpers. These helpers contain function to ease some common tasks. diff --git a/components/console/helpers/map.rst.inc b/components/console/helpers/map.rst.inc index cbc819ad832..60b32c03975 100644 --- a/components/console/helpers/map.rst.inc +++ b/components/console/helpers/map.rst.inc @@ -1,3 +1,4 @@ * :doc:`/components/console/helpers/dialoghelper` * :doc:`/components/console/helpers/formatterhelper` * :doc:`/components/console/helpers/progresshelper` +* :doc:`/components/console/helpers/tablehelper` diff --git a/components/console/helpers/progresshelper.rst b/components/console/helpers/progresshelper.rst index f43f7caeaf2..ccd5d381afd 100644 --- a/components/console/helpers/progresshelper.rst +++ b/components/console/helpers/progresshelper.rst @@ -7,6 +7,12 @@ Progress Helper .. versionadded:: 2.2 The ``progress`` helper was added in Symfony 2.2. +.. versionadded:: 2.3 + The ``setCurrent`` method was added in Symfony 2.3. + +.. versionadded:: 2.4 + The ``clear`` method was added in Symfony 2.4. + When executing longer-running commands, it may be helpful to show progress information, which updates as your command runs: @@ -28,6 +34,18 @@ pass it a total number of units, and advance the progress as your command execut $progress->finish(); +.. tip:: + + You can also set the current progress by calling the + :method:`Symfony\\Component\\Console\\Helper\\ProgressHelper::setCurrent` + method. + +If you want to output something while the progress bar is running, +call :method:`Symfony\\Component\\Console\\Helper\\ProgressHelper::clear` first. +After you're done, call +:method:`Symfony\\Component\\Console\\Helper\\ProgressHelper::display` +to show the progress bar again. + The appearance of the progress output can be customized as well, with a number of different levels of verbosity. Each of these displays different possible items - like percentage completion, a moving progress bar, or current/total diff --git a/components/console/helpers/tablehelper.rst b/components/console/helpers/tablehelper.rst new file mode 100644 index 00000000000..1145dd7b603 --- /dev/null +++ b/components/console/helpers/tablehelper.rst @@ -0,0 +1,55 @@ +.. index:: + single: Console Helpers; Table Helper + +Table Helper +============ + +.. versionadded:: 2.3 + The ``table`` helper was added in Symfony 2.3. + +When building a console application it may be useful to display tabular data: + +.. image:: /images/components/console/table.png + +To display table, use the :class:`Symfony\\Component\\Console\\Helper\\TableHelper`, +set headers, rows and render:: + + $table = $app->getHelperSet()->get('table'); + $table + ->setHeaders(array('ISBN', 'Title', 'Author')) + ->setRows(array( + array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'), + array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'), + array('960-425-059-0', 'The Lord of the Rings', 'J. R. R. Tolkien'), + array('80-902734-1-6', 'And Then There Were None', 'Agatha Christie'), + )) + ; + $table->render($output); + +The table layout can be customized as well. There are two ways to customize +table rendering: using named layouts or by customizing rendering options. + +Customize Table Layout using Named Layouts +------------------------------------------ + +The Table helper ships with two preconfigured table layouts: + +* ``TableHelper::LAYOUT_DEFAULT`` + +* ``TableHelper::LAYOUT_BORDERLESS`` + +Layout can be set using :method:`Symfony\\Component\\Console\\Helper\\TableHelper::setLayout` method. + +Customize Table Layout using Rendering Options +---------------------------------------------- + +You can also control table rendering by setting custom rendering option values: + +* :method:`Symfony\\Component\\Console\\Helper\\TableHelper::setPaddingChar` +* :method:`Symfony\\Component\\Console\\Helper\\TableHelper::setHorizontalBorderChar` +* :method:`Symfony\\Component\\Console\\Helper\\TableHelper::setVerticalBorderChar` +* :method:`Symfony\\Component\\Console\\Helper\\TableHelper::setCrossingChar` +* :method:`Symfony\\Component\\Console\\Helper\\TableHelper::setCellHeaderFormat` +* :method:`Symfony\\Component\\Console\\Helper\\TableHelper::setCellRowFormat` +* :method:`Symfony\\Component\\Console\\Helper\\TableHelper::setBorderFormat` +* :method:`Symfony\\Component\\Console\\Helper\\TableHelper::setPadType` diff --git a/components/console/index.rst b/components/console/index.rst index 4d0a12e4d70..c814942d018 100644 --- a/components/console/index.rst +++ b/components/console/index.rst @@ -7,5 +7,5 @@ Console introduction usage single_command_tool - + events helpers/index diff --git a/components/console/introduction.rst b/components/console/introduction.rst index 8133d071fef..451b6f18722 100755 --- a/components/console/introduction.rst +++ b/components/console/introduction.rst @@ -163,16 +163,22 @@ You can also set these colors and options inside the tagname:: Verbosity Levels ~~~~~~~~~~~~~~~~ -The console has 3 levels of verbosity. These are defined in the +.. versionadded:: 2.3 + The ``VERBOSITY_VERY_VERBOSE`` and ``VERBOSITY_DEBUG`` constants were introduced + in version 2.3 + +The console has 5 levels of verbosity. These are defined in the :class:`Symfony\\Component\\Console\\Output\\OutputInterface`: -================================== =============================== -Mode Value -================================== =============================== -OutputInterface::VERBOSITY_QUIET Do not output any messages -OutputInterface::VERBOSITY_NORMAL The default verbosity level -OutputInterface::VERBOSITY_VERBOSE Increased verbosity of messages -================================== =============================== +======================================= ================================== +Mode Value +======================================= ================================== +OutputInterface::VERBOSITY_QUIET Do not output any messages +OutputInterface::VERBOSITY_NORMAL The default verbosity level +OutputInterface::VERBOSITY_VERBOSE Increased verbosity of messages +OutputInterface::VERBOSITY_VERY_VERBOSE Informative non essential messages +OutputInterface::VERBOSITY_DEBUG Debug messages +======================================= ================================== You can specify the quiet verbosity level with the ``--quiet`` or ``-q`` option. The ``--verbose`` or ``-v`` option is used when you want an increased @@ -181,12 +187,12 @@ level of verbosity. .. tip:: The full exception stacktrace is printed if the ``VERBOSITY_VERBOSE`` - level is used. + level or above is used. It is possible to print a message in a command for only a specific verbosity level. For example:: - if (OutputInterface::VERBOSITY_VERBOSE === $output->getVerbosity()) { + if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $output->writeln(...); } diff --git a/components/console/usage.rst b/components/console/usage.rst index ac7f0b8a2c1..1a73c276ab5 100755 --- a/components/console/usage.rst +++ b/components/console/usage.rst @@ -77,6 +77,14 @@ with: $ php app/console list --verbose $ php app/console list -v +The verbose flag can optionally take a value between 1 (default) and 3 to +output even more verbose messages: + + $ php app/console list --verbose=2 + $ php app/console list -vv + $ php app/console list --verbose=3 + $ php app/console list -vvv + If you set the optional arguments to give your application a name and version:: $application = new Application('Acme Console Application', '1.2'); diff --git a/components/debug.rst b/components/debug.rst new file mode 100644 index 00000000000..ac7e3a1948a --- /dev/null +++ b/components/debug.rst @@ -0,0 +1,75 @@ +.. index:: + single: Debug + single: Components; Debug + +The Debug Component +=================== + + The Debug Component provides tools to ease debugging PHP code. + +.. versionadded:: 2.3 + The Debug Component is new to Symfony 2.3. Previously, the classes were + located in the ``HttpKernel`` component. + +Installation +------------ + +You can install the component in many different ways: + +* Use the official Git repository (https://github.com/symfony/Debug); +* :doc:`Install it via Composer ` (``symfony/debug`` on `Packagist`_). + +Usage +----- + +The Debug component provides several tools to help you debug PHP code. +Enabling them all is as easy as it can get:: + + use Symfony\Component\Debug\Debug; + + Debug::enable(); + +The :method:`Symfony\\Component\\Debug\\Debug::enable` method registers an +error handler and an exception handler. If the :doc:`ClassLoader component +` is available, a special class loader +is also registered. + +Read the following sections for more information about the different available +tools. + +.. caution:: + + You should never enable the debug tools in a production environment as + they might disclose sensitive information to the user. + +Enabling the Error Handler +-------------------------- + +The :class:`Symfony\\Component\\Debug\\ErrorHandler` class catches PHP errors +and converts them to exceptions (of class :phpclass:`ErrorException` or +:class:`Symfony\\Component\\Debug\\Exception\\FatalErrorException` for PHP +fatal errors):: + + use Symfony\Component\Debug\ErrorHandler; + + ErrorHandler::register(); + +Enabling the Exception Handler +------------------------------ + +The :class:`Symfony\\Component\\Debug\\ExceptionHandler` class catches +uncaught PHP exceptions and converts them to a nice PHP response. It is useful +in debug mode to replace the default PHP/XDebug output with something prettier +and more useful:: + + use Symfony\Component\Debug\ExceptionHandler; + + ExceptionHandler::register(); + +.. note:: + + If the :doc:`HttpFoundation component ` is + available, the handler uses a Symfony Response object; if not, it falls + back to a regular PHP response. + +.. _Packagist: https://packagist.org/packages/symfony/debug diff --git a/components/dependency_injection/index.rst b/components/dependency_injection/index.rst index 74b2ac1e445..49088017687 100644 --- a/components/dependency_injection/index.rst +++ b/components/dependency_injection/index.rst @@ -14,4 +14,5 @@ configurators parentservices advanced + lazy_services workflow diff --git a/components/dependency_injection/lazy_services.rst b/components/dependency_injection/lazy_services.rst new file mode 100644 index 00000000000..8f80997777b --- /dev/null +++ b/components/dependency_injection/lazy_services.rst @@ -0,0 +1,110 @@ +.. index:: + single: Dependency Injection; Lazy Services + +Lazy Services +============= + +.. versionadded:: 2.3 + Lazy services were added in Symfony 2.3. + +Why Lazy Services? +------------------ + +In some cases, you may want to inject a service that is a bit heavy to instantiate, +but is not always used inside your object. For example, imagine you have +a ``NewsletterManager`` and you inject a ``mailer`` service into it. Only +a few methods on your ``NewsletterManager`` actually use the ``mailer``, +but even when you don't need it, a ``mailer`` service is always instantiated +in order to construct your ``NewsletterManager``. + +Configuring lazy services is one answer to this. With a lazy service, a "proxy" +of the ``mailer`` service is actually injected. It looks and acts just like +the ``mailer``, except that the ``mailer`` isn't actually instantiated until +you interact with the proxy in some way. + +Installation +------------ + +In order to use the lazy service instantiation, you will first need to install +the `ProxyManager bridge`_: + +.. code-block:: bash + + $ php composer.phar require symfony/proxy-manager-bridge:2.3.* + +.. note:: + + If you're using the full-stack framework, the proxy manager bridge is already + included but the actual proxy manager needs to be included. Therefore add + + .. code-block:: json + + "require": { + "ocramius/proxy-manager": "0.4.*" + } + + to your ``composer.json``. Afterwards compile your container and check + to make sure that you get a proxy for your lazy services. + +Configuration +------------- + +You can mark the service as ``lazy`` by manipulating its definition: + +.. configuration-block:: + + .. code-block:: yaml + + services: + foo: + class: Acme\Foo + lazy: true + + .. code-block:: xml + + + + .. code-block:: php + + $definition = new Definition('Acme\Foo'); + $definition->setLazy(true); + $container->setDefinition('foo', $definition); + +You can then require the service from the container:: + + $service = $container->get('foo'); + +At this point the retrieved ``$service`` should be a virtual `proxy`_ with +the same signature of the class representing the service. You can also inject +the service just like normal into other services. The object that's actually +injected will be the proxy. + +To check if your proxy works you can simply check the interface of the +received object. + +.. code-block:: php + + var_dump(class_implements($service)); + +If the class implements the "ProxyManager\Proxy\LazyLoadingInterface" your lazy +loaded services are working. + +.. note:: + + If you don't install the `ProxyManager bridge`_, the container will just + skip over the ``lazy`` flag and simply instantiate the service as it would + normally do. + +The proxy gets initialized and the actual service is instantiated as soon +as you interact in any way with this object. + +Additional Resources +-------------------- + +You can read more about how proxies are instantiated, generated and initialized +in the `documentation of ProxyManager`_. + + +.. _`ProxyManager bridge`: https://github.com/symfony/symfony/tree/master/src/Symfony/Bridge/ProxyManager +.. _`proxy`: http://en.wikipedia.org/wiki/Proxy_pattern +.. _`documentation of ProxyManager`: https://github.com/Ocramius/ProxyManager/blob/master/docs/lazy-loading-value-holder.md diff --git a/components/dom_crawler.rst b/components/dom_crawler.rst index bb45d6c2beb..b8c3d06c825 100644 --- a/components/dom_crawler.rst +++ b/components/dom_crawler.rst @@ -80,7 +80,10 @@ This allows you to use jQuery-like selectors to traverse:: Anonymous function can be used to filter with more complex criteria:: - $crawler = $crawler->filter('body > p')->reduce(function ($node, $i) { + use Symfony\Component\DomCrawler\Crawler; + // ... + + $crawler = $crawler->filter('body > p')->reduce(function (Crawler $node, $i) { // filter even nodes return ($i % 2) == 0; }); @@ -147,11 +150,19 @@ Extract attribute and/or node values from the list of nodes:: Call an anonymous function on each node of the list:: - $nodeValues = $crawler->filter('p')->each(function ($node, $i) { + use Symfony\Component\DomCrawler\Crawler; + // ... + + $nodeValues = $crawler->filter('p')->each(function (Crawler $node, $i) { return $node->text(); }); -The anonymous function receives the position and the node as arguments. +.. versionadded:: + As seen here, in Symfony 2.3, the ``each`` and ``reduce`` Closure functions + are passed a ``Crawler`` as the first argument. Previously, that argument + was a :phpclass:`DOMNode`. + +The anonymous function receives the position and the node (as a Crawler) as arguments. The result is an array of values returned by the anonymous function calls. Adding the Content @@ -212,6 +223,13 @@ and :phpclass:`DOMNode` objects: $html .= $domElement->ownerDocument->saveHTML($domElement); } + Or you can get the HTML of the first node using + :method:`Symfony\\Component\\DomCrawler\\Crawler::html`:: + + $html = $crawler->html(); + + The ``html`` method is new in Symfony 2.3. + Form and Link support ~~~~~~~~~~~~~~~~~~~~~ diff --git a/components/event_dispatcher/container_aware_dispatcher.rst b/components/event_dispatcher/container_aware_dispatcher.rst index eca7d823870..2d70a2d83c2 100644 --- a/components/event_dispatcher/container_aware_dispatcher.rst +++ b/components/event_dispatcher/container_aware_dispatcher.rst @@ -4,9 +4,6 @@ The Container Aware Event Dispatcher ==================================== -.. versionadded:: 2.1 - This feature was moved into the EventDispatcher component in Symfony 2.1. - Introduction ------------ diff --git a/components/event_dispatcher/generic_event.rst b/components/event_dispatcher/generic_event.rst index 654c2e51236..9ac16d430b1 100644 --- a/components/event_dispatcher/generic_event.rst +++ b/components/event_dispatcher/generic_event.rst @@ -4,9 +4,6 @@ The Generic Event Object ======================== -.. versionadded:: 2.1 - The ``GenericEvent`` event class was added in Symfony 2.1 - The base :class:`Symfony\\Component\\EventDispatcher\\Event` class provided by the ``Event Dispatcher`` component is deliberately sparse to allow the creation of API specific event objects by inheritance using OOP. This allow for elegant and diff --git a/components/event_dispatcher/immutable_dispatcher.rst b/components/event_dispatcher/immutable_dispatcher.rst index c5d17eb6f00..5b01136e558 100644 --- a/components/event_dispatcher/immutable_dispatcher.rst +++ b/components/event_dispatcher/immutable_dispatcher.rst @@ -4,9 +4,6 @@ The Immutable Event Dispatcher ============================== -.. versionadded:: 2.1 - This feature was added in Symfony 2.1. - The :class:`Symfony\\Component\\EventDispatcher\\ImmutableEventDispatcher` is a locked or frozen event dispatcher. The dispatcher cannot register new listeners or subscribers. diff --git a/components/event_dispatcher/introduction.rst b/components/event_dispatcher/introduction.rst index d03ee05364e..1b92fabea02 100644 --- a/components/event_dispatcher/introduction.rst +++ b/components/event_dispatcher/introduction.rst @@ -440,9 +440,6 @@ which returns a boolean value:: EventDispatcher aware Events and Listeners ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 2.1 - The ``Event`` object contains a reference to the invoking dispatcher since Symfony 2.1 - The ``EventDispatcher`` always injects a reference to itself in the passed event object. This means that all listeners have direct access to the ``EventDispatcher`` object that notified the listener via the passed ``Event`` @@ -535,9 +532,6 @@ can be the way to go, especially for optional dependencies. Dispatcher Shortcuts ~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 2.1 - ``EventDispatcher::dispatch()`` method returns the event since Symfony 2.1. - The :method:`EventDispatcher::dispatch ` method always returns an :class:`Symfony\\Component\\EventDispatcher\\Event` object. This allows for various shortcuts. For example if one does not need @@ -575,9 +569,6 @@ and so on... Event Name Introspection ~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 2.1 - Added event name to the ``Event`` object since Symfony 2.1 - Since the ``EventDispatcher`` already knows the name of the event when dispatching it, the event name is also injected into the :class:`Symfony\\Component\\EventDispatcher\\Event` objects, making it available diff --git a/components/filesystem.rst b/components/filesystem.rst index 5b1dc701217..9a50e256e2b 100644 --- a/components/filesystem.rst +++ b/components/filesystem.rst @@ -6,10 +6,6 @@ The Filesystem Component The Filesystem components provides basic utilities for the filesystem. -.. versionadded:: 2.1 - The Filesystem Component is new to Symfony 2.1. Previously, the ``Filesystem`` - class was located in the ``HttpKernel`` component. - Installation ------------ @@ -25,16 +21,20 @@ The :class:`Symfony\\Component\\Filesystem\\Filesystem` class is the unique endpoint for filesystem operations:: use Symfony\Component\Filesystem\Filesystem; - use Symfony\Component\Filesystem\Exception\IOException; + use Symfony\Component\Filesystem\Exception\IOExceptionInterface; $fs = new Filesystem(); try { $fs->mkdir('/tmp/random/dir/' . mt_rand()); - } catch (IOException $e) { - echo "An error occurred while creating your directory"; + } catch (IOExceptionInterface $e) { + echo "An error occurred while creating your directory at ".$e->getPath(); } +.. versionadded:: 2.4 + The ``IOExceptionInterface`` and its ``getPath`` method are new in Symfony + 2.4. Prior to 2.4, you would catch the ``IOException`` class. + .. note:: Methods :method:`Symfony\\Component\\Filesystem\\Filesystem::mkdir`, @@ -233,18 +233,34 @@ isAbsolutePath // return false $fs->isAbsolutePath('../dir'); +.. versionadded:: 2.3 + ``dumpFile`` is new in Symfony 2.3 + +dumpFile +~~~~~~~~ + +:method:`Symfony\\Component\\Filesystem\\Filesystem::dumpFile` allows you to +dump contents to a file. It does this in an atomic manner: it writes a temporary +file first and then moves it to the new file location when it's finished. +This means that the user will always see either the complete old file or +complete new file (but never a partially-written file):: + + $fs->dumpFile('file.txt', 'Hello World'); + +The ``file.txt`` file contains ``Hello World`` now. + +A desired file mode can be passed as the third argument. + Error Handling -------------- Whenever something wrong happens, an exception implementing -:class:`Symfony\\Component\\Filesystem\\Exception\\ExceptionInterface` is -thrown. +:class:`Symfony\\Component\\Filesystem\\Exception\\ExceptionInterface` or +:class:`Symfony\\Component\\Filesystem\\Exception\\IOExceptionInterface` is thrown. .. note:: - Prior to version 2.1, ``mkdir`` returned a boolean and did not throw - exceptions. As of 2.1, a - :class:`Symfony\\Component\\Filesystem\\Exception\\IOException` is thrown - if a directory creation fails. + An :class:`Symfony\\Component\\Filesystem\\Exception\\IOException` is + thrown if directory creation fails. .. _`Packagist`: https://packagist.org/packages/symfony/filesystem diff --git a/components/finder.rst b/components/finder.rst index f9473e077f1..c63d624e6c6 100644 --- a/components/finder.rst +++ b/components/finder.rst @@ -96,6 +96,14 @@ Exclude directories from matching with the $finder->in(__DIR__)->exclude('ruby'); +.. versionadded:: 2.3 + The :method:`Symfony\\Component\\Finder\\Finder::ignoreUnreadableDirs` + method was added in Symfony 2.3. + +It's also possible to ignore directories that you don't have permission to read:: + + $finder->ignoreUnreadableDirs()->in(__DIR__); + As the Finder uses PHP iterators, you can pass any URL with a supported `protocol`_:: @@ -182,9 +190,6 @@ The ``notName()`` method excludes files matching a pattern:: File Contents ~~~~~~~~~~~~~ -.. versionadded:: 2.1 - The ``contains()`` and ``notContains()`` methods were added in version 2.1 - Restrict files by contents with the :method:`Symfony\\Component\\Finder\\Finder::contains` method:: @@ -243,9 +248,6 @@ Restrict by a size range by chaining calls:: The comparison operator can be any of the following: ``>``, ``>=``, ``<``, ``<=``, ``==``, ``!=``. -.. versionadded:: 2.1 - The operator ``!=`` was added in version 2.1. - The target value may use magnitudes of kilobytes (``k``, ``ki``), megabytes (``m``, ``mi``), or gigabytes (``g``, ``gi``). Those suffixed with an ``i`` use the appropriate ``2**n`` version in accordance with the `IEC standard`_. @@ -296,9 +298,6 @@ instance. The file is excluded from the result set if the Closure returns Reading contents of returned files ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 2.1 - Method ``getContents()`` have been introduced in version 2.1. - The contents of returned files can be read with :method:`Symfony\\Component\\Finder\\SplFileInfo::getContents`:: diff --git a/components/http_foundation/index.rst b/components/http_foundation/index.rst index 9937c960776..348f8e50ca4 100644 --- a/components/http_foundation/index.rst +++ b/components/http_foundation/index.rst @@ -8,4 +8,5 @@ HTTP Foundation sessions session_configuration session_testing + session_php_bridge trusting_proxies diff --git a/components/http_foundation/introduction.rst b/components/http_foundation/introduction.rst index 604e12972ea..93102db56bf 100644 --- a/components/http_foundation/introduction.rst +++ b/components/http_foundation/introduction.rst @@ -240,7 +240,13 @@ by using the following methods: returns the list of accepted languages ordered by descending quality; * :method:`Symfony\\Component\\HttpFoundation\\Request::getCharsets`: - returns the list of accepted charsets ordered by descending quality. + returns the list of accepted charsets ordered by descending quality; + +* :method:`Symfony\\Component\\HttpFoundation\\Request::getEncodings`: + returns the list of accepted charsets ordered by descending quality; + + .. versionadded:: 2.4 + The ``getEncodings()`` method was added in Symfony 2.4. .. versionadded:: 2.2 The :class:`Symfony\\Component\\HttpFoundation\\AcceptHeader` class is new in Symfony 2.2. @@ -393,9 +399,6 @@ To redirect the client to another URL, you can use the Streaming a Response ~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 2.1 - Support for streamed responses was added in Symfony 2.1. - The :class:`Symfony\\Component\\HttpFoundation\\StreamedResponse` class allows you to stream the Response back to the client. The response content is represented by a PHP callable instead of a string:: @@ -427,9 +430,6 @@ represented by a PHP callable instead of a string:: Serving Files ~~~~~~~~~~~~~ -.. versionadded:: 2.1 - The ``makeDisposition`` method was added in Symfony 2.1. - When sending a file, you must add a ``Content-Disposition`` header to your response. While creating this header for basic file downloads is easy, using non-ASCII filenames is more involving. The @@ -485,10 +485,6 @@ right content and headers. A JSON response might look like this:: ))); $response->headers->set('Content-Type', 'application/json'); -.. versionadded:: 2.1 - The :class:`Symfony\\Component\\HttpFoundation\\JsonResponse` - class was added in Symfony 2.1. - There is also a helpful :class:`Symfony\\Component\\HttpFoundation\\JsonResponse` class, which can make this even easier:: diff --git a/components/http_foundation/session_configuration.rst b/components/http_foundation/session_configuration.rst index dcd55298de6..5cb032c526d 100644 --- a/components/http_foundation/session_configuration.rst +++ b/components/http_foundation/session_configuration.rst @@ -218,7 +218,7 @@ PHP 5.4 compatibility ~~~~~~~~~~~~~~~~~~~~~ Since PHP 5.4.0, :phpclass:`SessionHandler` and :phpclass:`SessionHandlerInterface` -are available. Symfony 2.1 provides forward compatibility for the :phpclass:`SessionHandlerInterface` +are available. Symfony provides forward compatibility for the :phpclass:`SessionHandlerInterface` so it can be used under PHP 5.3. This greatly improves inter-operability with other libraries. diff --git a/components/http_foundation/session_php_bridge.rst b/components/http_foundation/session_php_bridge.rst new file mode 100644 index 00000000000..5b55417d983 --- /dev/null +++ b/components/http_foundation/session_php_bridge.rst @@ -0,0 +1,49 @@ +.. index:: + single: HTTP + single: HttpFoundation, Sessions + +Integrating with Legacy Sessions +================================ + +Sometimes it may be necessary to integrate Symfony into a legacy application +where you do not initially have the level of control you require. + +As stated elsewhere, Symfony Sessions are designed to replace the use of +PHP's native ``session_*()`` functions and use of the ``$_SESSION`` +superglobal. Additionally, it is mandatory for Symfony to start the session. + +However when there really are circumstances where this is not possible, you +can use a special storage bridge +:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\PhpBridgeSessionStorage` +which is designed to allow Symfony to work with a session started outside of +the Symfony Session framework. You are warned that things can interrupt this +use-case unless you are careful: for example the legacy application erases +``$_SESSION``. + +A typical use of this might look like this:: + + use Symfony\Component\HttpFoundation\Session\Session; + use Symfony\Component\HttpFoundation\Session\Storage\PhpBridgeSessionStorage; + + // legacy application configures session + ini_set('session.save_handler', 'files'); + ini_set('session.save_path', '/tmp'); + session_start(); + + // Get Symfony to interface with this existing session + $session = new Session(new PhpBridgeSessionStorage()); + + // symfony will now interface with the existing PHP session + $session->start(); + +This will allow you to start using the Symfony Session API and allow migration +of your application to Symfony sessions. + +.. note:: + + Symfony sessions store data like attributes in special 'Bags' which use a + key in the ``$_SESSION`` superglobal. This means that a Symfony session + cannot access arbitrary keys in ``$_SESSION`` that may be set by the legacy + application, although all the ``$_SESSION`` contents will be saved when + the session is saved. + diff --git a/components/http_foundation/sessions.rst b/components/http_foundation/sessions.rst index c8efc9f3af7..e7b165e821f 100644 --- a/components/http_foundation/sessions.rst +++ b/components/http_foundation/sessions.rst @@ -9,10 +9,6 @@ The Symfony2 HttpFoundation Component has a very powerful and flexible session subsystem which is designed to provide session management through a simple object-oriented interface using a variety of session storage drivers. -.. versionadded:: 2.1 - The :class:`Symfony\\Component\\HttpFoundation\\Session\\SessionInterface` interface, - as well as a number of other changes, are new as of Symfony 2.1. - Sessions are used via the simple :class:`Symfony\\Component\\HttpFoundation\\Session\\Session` implementation of :class:`Symfony\\Component\\HttpFoundation\\Session\\SessionInterface` interface. diff --git a/components/http_foundation/trusting_proxies.rst b/components/http_foundation/trusting_proxies.rst index b3023ddada8..1606e496156 100644 --- a/components/http_foundation/trusting_proxies.rst +++ b/components/http_foundation/trusting_proxies.rst @@ -12,13 +12,20 @@ stored in a ``X-Forwarded-Host`` header. Since HTTP headers can be spoofed, Symfony2 does *not* trust these proxy headers by default. If you are behind a proxy, you should manually whitelist -your proxy:: +your proxy. + +.. versionadded:: 2.3 + CIDR notation support was introduced, so you can whitelist whole + subnets (e.g. ``10.0.0.0/8``, ``fc00::/7``). + +.. code-block:: php use Symfony\Component\HttpFoundation\Request; $request = Request::createFromGlobals(); - // only trust proxy headers coming from this IP address - $request->setTrustedProxies(array('192.0.0.1')); + + // only trust proxy headers coming from this IP addresses + $request->setTrustedProxies(array('192.0.0.1', '10.0.0.0/8')); Configuring Header Names ------------------------ diff --git a/components/http_kernel/introduction.rst b/components/http_kernel/introduction.rst index f8cea723364..1674f4d369e 100644 --- a/components/http_kernel/introduction.rst +++ b/components/http_kernel/introduction.rst @@ -451,9 +451,6 @@ method, which sends the headers and prints the ``Response`` content. 8) The ``kernel.terminate`` event ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 2.1 - The ``kernel.terminate`` event is new to Symfony 2.1. - **Typical Purposes**: To perform some "heavy" action after the response has been streamed to the user diff --git a/components/index.rst b/components/index.rst index 302aa30f5a1..e5dffc58cd6 100644 --- a/components/index.rst +++ b/components/index.rst @@ -9,6 +9,7 @@ The Components config/index console/index css_selector + debug dom_crawler dependency_injection/index event_dispatcher/index @@ -17,7 +18,7 @@ The Components form/index http_foundation/index http_kernel/index - locale + intl options_resolver process property_access/index diff --git a/components/intl.rst b/components/intl.rst new file mode 100644 index 00000000000..5466f317521 --- /dev/null +++ b/components/intl.rst @@ -0,0 +1,414 @@ +.. index:: + single: Intl + single: Components; Intl + +The Intl Component +================== + + A PHP replacement layer for the C `intl extension`_ that also provides + access to the localization data of the `ICU library`_. + +.. versionadded:: 2.3 + + The Intl component was added in Symfony 2.3. In earlier versions of Symfony, + you should use the Locale component instead. + +.. caution:: + + The replacement layer is limited to the locale "en". If you want to use + other locales, you should `install the intl extension`_ instead. + +Installation +------------ + +You can install the component in two different ways: + +* Using the official Git repository (https://github.com/symfony/Intl); +* :doc:`Install it via Composer` (``symfony/intl`` on `Packagist`_). + +If you install the component via Composer, the following classes and functions +of the intl extension will be automatically provided if the intl extension is +not loaded: + +* :phpclass:`Collator` +* :phpclass:`IntlDateFormatter` +* :phpclass:`Locale` +* :phpclass:`NumberFormatter` +* :phpfunction:`intl_error_name` +* :phpfunction:`intl_is_failure` +* :phpfunction:`intl_get_error_code` +* :phpfunction:`intl_get_error_message` + +When the intl extension is not available, the following classes are used to +replace the intl classes: + +* :class:`Symfony\\Component\\Intl\\Collator\\Collator` +* :class:`Symfony\\Component\\Intl\\DateFormatter\\IntlDateFormatter` +* :class:`Symfony\\Component\\Intl\\Locale\\Locale` +* :class:`Symfony\\Component\\Intl\\NumberFormatter\\NumberFormatter` +* :class:`Symfony\\Component\\Intl\\Globals\\IntlGlobals` + +Composer automatically exposes these classes in the global namespace. + +If you don't use Composer but the +:doc:`Symfony ClassLoader component `, +you need to expose them manually by adding the following lines to your autoload +code:: + + if (!function_exists('intl_is_failure')) { + require '/path/to/Icu/Resources/stubs/functions.php'; + + $loader->registerPrefixFallback('/path/to/Icu/Resources/stubs'); + } + +.. sidebar:: ICU and Deployment Problems + + The intl extension internally uses the `ICU library`_ to obtain localization + data such as number formats in different languages, country names and more. + To make this data accessible to userland PHP libraries, Symfony2 ships a copy + in the `ICU component`_. + + Depending on the ICU version compiled with your intl extension, a matching + version of that component needs to be installed. It sounds complicated, + but usually Composer does this for you automatically: + + * 1.0.*: when the intl extension is not available + * 1.1.*: when intl is compiled with ICU 3.8 or higher + * 1.2.*: when intl is compiled with ICU 4.4 or higher + + These versions are important when you deploy your application to a **server with + a lower ICU version** than your development machines, because deployment will + fail if + + * the development machines are compiled with ICU 4.4 or higher, but the + server is compiled with a lower ICU version than 4.4; + * the intl extension is available on the development machines but not on + the server. + + For example, consider that your development machines ship ICU 4.8 and the server + ICU 4.2. When you run ``php composer.phar update`` on the development machine, version + 1.2.* of the ICU component will be installed. But after deploying the + application, ``php composer.phar install`` will fail with the following error: + + .. code-block:: bash + + $ php composer.phar install + Loading composer repositories with package information + Installing dependencies from lock file + Your requirements could not be resolved to an installable set of packages. + + Problem 1 + - symfony/icu 1.2.x requires lib-icu >=4.4 -> the requested linked + library icu has the wrong version installed or is missing from your + system, make sure to have the extension providing it. + + The error tells you that the requested version of the ICU component, version + 1.2, is not compatible with PHP's ICU version 4.2. + + One solution to this problem is to run ``php composer.phar update`` instead of + ``php composer.phar install``. It is highly recommended **not** to do this. The + ``update`` command will install the latest versions of each Composer dependency + to your production server and potentially break the application. + + A better solution is to fix your composer.json to the version required by the + production server. First, determine the ICU version on the server: + + .. code-block:: bash + + $ php -i | grep ICU + ICU version => 4.2.1 + + Then fix the ICU component in your composer.json file to a matching version: + + .. code-block:: json + + "require: { + "symfony/icu": "1.1.*" + } + + Set the version to + + * "1.0.*" if the server does not have the intl extension installed; + * "1.1.*" if the server is compiled with ICU 4.2 or lower. + + Finally, run ``php composer.phar update symfony/icu`` on your development machine, test + extensively and deploy again. The installation of the dependencies will now + succeed. + +Writing and Reading Resource Bundles +------------------------------------ + +The :phpclass:`ResourceBundle` class is not currently supported by this component. +Instead, it includes a set of readers and writers for reading and writing +arrays (or array-like objects) from/to resource bundle files. The following +classes are supported: + +* `TextBundleWriter`_ +* `PhpBundleWriter`_ +* `BinaryBundleReader`_ +* `PhpBundleReader`_ +* `BufferedBundleReader`_ +* `StructuredBundleReader`_ + +Continue reading if you are interested in how to use these classes. Otherwise +skip this section and jump to `Accessing ICU Data`_. + +TextBundleWriter +~~~~~~~~~~~~~~~~ + +The :class:`Symfony\\Component\\Intl\\ResourceBundle\\Writer\\TextBundleWriter` +writes an array or an array-like object to a plain-text resource bundle. The +resulting .txt file can be converted to a binary .res file with the +:class:`Symfony\\Component\\Intl\\ResourceBundle\\Compiler\\BundleCompiler` +class:: + + use Symfony\Component\Intl\ResourceBundle\Writer\TextBundleWriter; + use Symfony\Component\Intl\ResourceBundle\Compiler\BundleCompiler; + + $writer = new TextBundleWriter(); + $writer->write('/path/to/bundle', 'en', array( + 'Data' => array( + 'entry1', + 'entry2', + // ... + ), + )); + + $compiler = new BundleCompiler(); + $compiler->compile('/path/to/bundle', '/path/to/binary/bundle'); + +The command "genrb" must be available for the +:class:`Symfony\\Component\\Intl\\ResourceBundle\\Compiler\\BundleCompiler` to +work. If the command is located in a non-standard location, you can pass its +path to the +:class:`Symfony\\Component\\Intl\\ResourceBundle\\Compiler\\BundleCompiler` +constructor. + +PhpBundleWriter +~~~~~~~~~~~~~~~ + +The :class:`Symfony\\Component\\Intl\\ResourceBundle\\Writer\\PhpBundleWriter` +writes an array or an array-like object to a .php resource bundle:: + + use Symfony\Component\Intl\ResourceBundle\Writer\PhpBundleWriter; + + $writer = new PhpBundleWriter(); + $writer->write('/path/to/bundle', 'en', array( + 'Data' => array( + 'entry1', + 'entry2', + // ... + ), + )); + +BinaryBundleReader +~~~~~~~~~~~~~~~~~~ + +The :class:`Symfony\\Component\\Intl\\ResourceBundle\\Reader\\BinaryBundleReader` +reads binary resource bundle files and returns an array or an array-like object. +This class currently only works with the `intl extension`_ installed:: + + use Symfony\Component\Intl\ResourceBundle\Reader\BinaryBundleReader; + + $reader = new BinaryBundleReader(); + $data = $reader->read('/path/to/bundle', 'en'); + + echo $data['Data']['entry1']; + +PhpBundleReader +~~~~~~~~~~~~~~~ + +The :class:`Symfony\\Component\\Intl\\ResourceBundle\\Reader\\PhpBundleReader` +reads resource bundles from .php files and returns an array or an array-like +object:: + + use Symfony\Component\Intl\ResourceBundle\Reader\PhpBundleReader; + + $reader = new PhpBundleReader(); + $data = $reader->read('/path/to/bundle', 'en'); + + echo $data['Data']['entry1']; + +BufferedBundleReader +~~~~~~~~~~~~~~~~~~~~ + +The :class:`Symfony\\Component\\Intl\\ResourceBundle\\Reader\\BufferedBundleReader` +wraps another reader, but keeps the last N reads in a buffer, where N is a +buffer size passed to the constructor:: + + use Symfony\Component\Intl\ResourceBundle\Reader\BinaryBundleReader; + use Symfony\Component\Intl\ResourceBundle\Reader\BufferedBundleReader; + + $reader = new BufferedBundleReader(new BinaryBundleReader(), 10); + + // actually reads the file + $data = $reader->read('/path/to/bundle', 'en'); + + // returns data from the buffer + $data = $reader->read('/path/to/bundle', 'en'); + + // actually reads the file + $data = $reader->read('/path/to/bundle', 'fr'); + +StructuredBundleReader +~~~~~~~~~~~~~~~~~~~~~~ + +The :class:`Symfony\\Component\\Intl\\ResourceBundle\\Reader\\StructuredBundleReader` +wraps another reader and offers a +:method:`Symfony\\Component\\Intl\\ResourceBundle\\Reader\\StructuredBundleReaderInterface::readEntry` +method for reading an entry of the resource bundle without having to worry +whether array keys are set or not. If a path cannot be resolved, ``null`` is +returned:: + + use Symfony\Component\Intl\ResourceBundle\Reader\BinaryBundleReader; + use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReader; + + $reader = new StructuredBundleReader(new BinaryBundleReader()); + + $data = $reader->read('/path/to/bundle', 'en'); + + // Produces an error if the key "Data" does not exist + echo $data['Data']['entry1']; + + // Returns null if the key "Data" does not exist + echo $reader->readEntry('/path/to/bundle', 'en', array('Data', 'entry1')); + +Additionally, the +:method:`Symfony\\Component\\Intl\\ResourceBundle\\Reader\\StructuredBundleReaderInterface::readEntry` +method resolves fallback locales. For example, the fallback locale of "en_GB" is +"en". For single-valued entries (strings, numbers etc.), the entry will be read +from the fallback locale if it cannot be found in the more specific locale. For +multi-valued entries (arrays), the values of the more specific and the fallback +locale will be merged. In order to suppress this behavior, the last parameter +``$fallback`` can be set to ``false``:: + + echo $reader->readEntry('/path/to/bundle', 'en', array('Data', 'entry1'), false); + +Accessing ICU Data +------------------ + +The ICU data is located in several "resource bundles". You can access a PHP +wrapper of these bundles through the static +:class:`Symfony\\Component\\Intl\\Intl` class. At the moment, the following +data is supported: + +* `Language and Script Names`_ +* `Country Names`_ +* `Locales`_ +* `Currencies`_ + +Language and Script Names +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The translations of language and script names can be found in the language +bundle:: + + use Symfony\Component\Intl\Intl; + + \Locale::setDefault('en'); + + $languages = Intl::getLanguageBundle()->getLanguageNames(); + // => array('ab' => 'Abkhazian', ...) + + $language = Intl::getLanguageBundle()->getLanguageName('de'); + // => 'German' + + $language = Intl::getLanguageBundle()->getLanguageName('de', 'AT'); + // => 'Austrian German' + + $scripts = Intl::getLanguageBundle()->getScriptNames(); + // => array('Arab' => 'Arabic', ...) + + $script = Intl::getLanguageBundle()->getScriptName('Hans'); + // => 'Simplified' + +All methods accept the translation locale as the last, optional parameter, +which defaults to the current default locale:: + + $languages = Intl::getLanguageBundle()->getLanguageNames('de'); + // => array('ab' => 'Abchasisch', ...) + +Country Names +~~~~~~~~~~~~~ + +The translations of country names can be found in the region bundle:: + + use Symfony\Component\Intl\Intl; + + \Locale::setDefault('en'); + + $countries = Intl::getRegionBundle()->getCountryNames(); + // => array('AF' => 'Afghanistan', ...) + + $country = Intl::getRegionBundle()->getCountryName('GB'); + // => 'United Kingdom' + +All methods accept the translation locale as the last, optional parameter, +which defaults to the current default locale:: + + $countries = Intl::getRegionBundle()->getCountryNames('de'); + // => array('AF' => 'Afghanistan', ...) + +Locales +~~~~~~~ + +The translations of locale names can be found in the locale bundle:: + + use Symfony\Component\Intl\Intl; + + \Locale::setDefault('en'); + + $locales = Intl::getLocaleBundle()->getLocaleNames(); + // => array('af' => 'Afrikaans', ...) + + $locale = Intl::getLocaleBundle()->getLocaleName('zh_Hans_MO'); + // => 'Chinese (Simplified, Macau SAR China)' + +All methods accept the translation locale as the last, optional parameter, +which defaults to the current default locale:: + + $locales = Intl::getLocaleBundle()->getLocaleNames('de'); + // => array('af' => 'Afrikaans', ...) + +Currencies +~~~~~~~~~~ + +The translations of currency names and other currency-related information can +be found in the currency bundle:: + + use Symfony\Component\Intl\Intl; + + \Locale::setDefault('en'); + + $currencies = Intl::getCurrencyBundle()->getCurrencyNames(); + // => array('AFN' => 'Afghan Afghani', ...) + + $currency = Intl::getCurrencyBundle()->getCurrencyName('INR'); + // => 'Indian Rupee' + + $symbol = Intl::getCurrencyBundle()->getCurrencySymbol('INR'); + // => '₹' + + $fractionDigits = Intl::getCurrencyBundle()->getFractionDigits('INR'); + // => 2 + + $roundingIncrement = Intl::getCurrencyBundle()->getRoundingIncrement('INR'); + // => 0 + +All methods (except for +:method:`Symfony\\Component\\Intl\\ResourceBundle\\CurrencyBundleInterface::getFractionDigits` +and +:method:`Symfony\\Component\\Intl\\ResourceBundle\\CurrencyBundleInterface::getRoundingIncrement`) +accept the translation locale as the last, optional parameter, which defaults +to the current default locale:: + + $currencies = Intl::getCurrencyBundle()->getCurrencyNames('de'); + // => array('AFN' => 'Afghanische Afghani', ...) + +That's all you need to know for now. Have fun coding! + +.. _Packagist: https://packagist.org/packages/symfony/intl +.. _ICU component: https://packagist.org/packages/symfony/icu +.. _intl extension: http://www.php.net/manual/en/book.intl.php +.. _install the intl extension: http://www.php.net/manual/en/intl.setup.php +.. _ICU library: http://site.icu-project.org/ diff --git a/components/locale.rst b/components/locale.rst deleted file mode 100644 index 8c52cb9e490..00000000000 --- a/components/locale.rst +++ /dev/null @@ -1,72 +0,0 @@ -.. index:: - single: Locale - single: Components; Locale - -The Locale Component -==================== - - Locale component provides fallback code to handle cases when the ``intl`` extension is missing. - Additionally it extends the implementation of a native :phpclass:`Locale` class with several handy methods. - -Replacement for the following functions and classes is provided: - -* :phpfunction:`intl_is_failure` -* :phpfunction:`intl_get_error_code` -* :phpfunction:`intl_get_error_message` -* :phpclass:`Collator` -* :phpclass:`IntlDateFormatter` -* :phpclass:`Locale` -* :phpclass:`NumberFormatter` - -.. note:: - - Stub implementation only supports the ``en`` locale. - -Installation ------------- - -You can install the component in 2 different ways: - -* Use the official Git repository (https://github.com/symfony/Locale); -* :doc:`Install it via Composer ` (``symfony/locale`` on `Packagist`_). - -Usage ------ - -Taking advantage of the fallback code includes requiring function stubs and adding class stubs to the autoloader. - -When using the ClassLoader component following code is sufficient to supplement missing ``intl`` extension: - -.. code-block:: php - - if (!function_exists('intl_get_error_code')) { - require __DIR__.'/path/to/src/Symfony/Component/Locale/Resources/stubs/functions.php'; - - $loader->registerPrefixFallbacks( - array(__DIR__.'/path/to/src/Symfony/Component/Locale/Resources/stubs') - ); - } - -:class:`Symfony\\Component\\Locale\\Locale` class enriches native :phpclass:`Locale` class with additional features: - -.. code-block:: php - - use Symfony\Component\Locale\Locale; - - // Get the country names for a locale or get all country codes - $countries = Locale::getDisplayCountries('pl'); - $countryCodes = Locale::getCountries(); - - // Get the language names for a locale or get all language codes - $languages = Locale::getDisplayLanguages('fr'); - $languageCodes = Locale::getLanguages(); - - // Get the locale names for a given code or get all locale codes - $locales = Locale::getDisplayLocales('en'); - $localeCodes = Locale::getLocales(); - - // Get ICU versions - $icuVersion = Locale::getIntlIcuVersion(); - $icuDataVersion = Locale::getIcuDataVersion(); - -.. _Packagist: https://packagist.org/packages/symfony/locale diff --git a/components/map.rst.inc b/components/map.rst.inc index a3a21843fb2..a915310cde1 100644 --- a/components/map.rst.inc +++ b/components/map.rst.inc @@ -20,12 +20,17 @@ * :doc:`/components/console/introduction` * :doc:`/components/console/usage` * :doc:`/components/console/single_command_tool` + * :doc:`/components/console/events` * :doc:`/components/console/helpers/index` * **CSS Selector** * :doc:`/components/css_selector` +* **Debug** + + * :doc:`/components/debug` + * :doc:`/components/dependency_injection/index` * :doc:`/components/dependency_injection/introduction` @@ -38,6 +43,7 @@ * :doc:`/components/dependency_injection/configurators` * :doc:`/components/dependency_injection/parentservices` * :doc:`/components/dependency_injection/advanced` + * :doc:`/components/dependency_injection/lazy_services` * :doc:`/components/dependency_injection/workflow` * **DOM Crawler** @@ -69,15 +75,16 @@ * :doc:`/components/http_foundation/sessions` * :doc:`/components/http_foundation/session_configuration` * :doc:`/components/http_foundation/session_testing` + * :doc:`/components/http_foundation/session_php_bridge` * :doc:`/components/http_foundation/trusting_proxies` * :doc:`/components/http_kernel/index` * :doc:`/components/http_kernel/introduction` -* **Locale** +* **Intl** - * :doc:`/components/locale` + * :doc:`/components/intl` * **Options Resolver** diff --git a/components/process.rst b/components/process.rst index 868673cfa55..981ec69e493 100644 --- a/components/process.rst +++ b/components/process.rst @@ -45,6 +45,14 @@ output. Alternatively, the :method:`Symfony\\Component\\Process\\Process::getInc and :method:`Symfony\\Component\\Process\\Process::getIncrementalErrorOutput` methods returns the new outputs since the last call. +.. versionadded:: 2.4 + The ``flushOutput()`` and ``flushErrorOutput()`` methods were added in Symfony 2.4. + +The :method:`Symfony\\Component\\Process\\Process::flushOutput` method flushes +the contents of the output and +:method:`Symfony\\Component\\Process\\Process::flushErrorOutput` flushes +the contents of the error output. + Getting real-time Process Output -------------------------------- @@ -64,9 +72,6 @@ anonymous function to the } }); -.. versionadded:: 2.1 - The non-blocking feature was added in 2.1. - Running Processes Asynchronously -------------------------------- @@ -102,19 +107,31 @@ are done doing other stuff:: } }); +.. note:: + + The :method:`Symfony\\Component\\Process\\Process::wait` method is blocking, + which means that your code will halt at this line until the external + process is completed. + Stopping a Process ------------------ +.. versionadded:: 2.3 + The ``signal`` parameter of the ``stop`` method was added in Symfony 2.3. + Any asynchronous process can be stopped at any time with the :method:`Symfony\\Component\\Process\\Process::stop` method. This method takes -a timeout as its argument. Once the timeout is reached, the process is terminated. +two arguments : a timeout and a signal. Once the timeout is reached, the signal +is sent to the running process. The default signal sent to a process is ``SIGKILL``. +Please read the :ref:`signal documentation below` +to find out more about signal handling in the Process component:: $process = new Process('ls -lsa'); $process->start(); // ... do other things - $process->stop(3); + $process->stop(3, SIGINT); Executing PHP Code in Isolation ------------------------------- @@ -130,9 +147,6 @@ instead:: ); $process->run(); -.. versionadded:: 2.1 - The ``ProcessBuilder`` class was added in Symfony 2.1. - To make your code work better on all platforms, you might want to use the :class:`Symfony\\Component\\Process\\ProcessBuilder` class instead:: @@ -141,6 +155,34 @@ To make your code work better on all platforms, you might want to use the $builder = new ProcessBuilder(array('ls', '-lsa')); $builder->getProcess()->run(); +.. versionadded:: 2.3 + The :method:`ProcessBuilder::setPrefix` + method was added in Symfony 2.3. + +In case you are building a binary driver, you can use the +:method:`Symfony\\Component\\Process\\Process::setPrefix` method to prefix all +the generated process commands. + +The following example will generate two process commands for a tar binary +adapter:: + + use Symfony\Component\Process\ProcessBuilder; + + $builder = new ProcessBuilder(); + $builder->setPrefix('/usr/bin/tar'); + + // '/usr/bin/tar' '--list' '--file=archive.tar.gz' + echo $builder + ->setArguments(array('--list', '--file=archive.tar.gz')) + ->getProcess() + ->getCommandLine(); + + // '/usr/bin/tar' '-xzf' 'archive.tar.gz' + echo $builder + ->setArguments(array('-xzf', 'archive.tar.gz')) + ->getProcess() + ->getCommandLine(); + Process Timeout --------------- @@ -171,4 +213,80 @@ check regularly:: usleep(200000); } +.. _reference-process-signal: + +Process Idle Timeout +-------------------- + +.. versionadded:: 2.4 + The :method:`Symfony\\Component\\Process\\Process::setIdleTimeout` method was added in Symfony 2.4. + +In contrast to the timeout of the previous paragraph, the idle timeout only +considers the time since the last output was produced by the process:: + + use Symfony\Component\Process\Process; + + $process = new Process('something-with-variable-runtime'); + $process->setTimeout(3600); + $process->setIdleTimeout(60); + $process->run(); + +In the case above, a process is considered timed out, when either the total runtime +exceeds 3600 seconds, or the process does not produce any output for 60 seconds. + +Process Signals +--------------- + +.. versionadded:: 2.3 + The ``signal`` method was added in Symfony 2.3. + +When running a program asynchronously, you can send it posix signals with the +:method:`Symfony\\Component\\Process\\Process::signal` method:: + + use Symfony\Component\Process\Process; + + $process = new Process('find / -name "rabbit"'); + $process->start(); + + // will send a SIGKILL to the process + $process->signal(SIGKILL); + +.. caution:: + + Due to some limitations in PHP, if you're using signals with the Process + component, you may have to prefix your commands with `exec`_. Please read + `Symfony Issue#5759`_ and `PHP Bug#39992`_ to understand why this is happening. + + POSIX signals are not available on Windows platforms, please refer to the + `PHP documentation`_ for available signals. + +Process Pid +----------- + +.. versionadded:: 2.3 + The ``getPid`` method was added in Symfony 2.3. + +You can access the `pid`_ of a running process with the +:method:`Symfony\\Component\\Process\\Process::getPid` method. + +.. code-block:: php + + use Symfony\Component\Process\Process; + + $process = new Process('/usr/bin/php worker.php'); + $process->start(); + + $pid = $process->getPid(); + +.. caution:: + + Due to some limitations in PHP, if you want to get the pid of a symfony Process, + you may have to prefix your commands with `exec`_. Please read + `Symfony Issue#5759`_ to understand why this is happening. + +.. _`Symfony Issue#5759`: https://github.com/symfony/symfony/issues/5759 +.. _`PHP Bug#39992`: https://bugs.php.net/bug.php?id=39992 +.. _`exec`: http://en.wikipedia.org/wiki/Exec_(operating_system) +.. _`pid`: http://en.wikipedia.org/wiki/Process_identifier +.. _`PHP Documentation`: http://php.net/manual/en/pcntl.constants.php .. _Packagist: https://packagist.org/packages/symfony/process diff --git a/components/property_access/introduction.rst b/components/property_access/introduction.rst index 26991f046e9..767097f8dfd 100644 --- a/components/property_access/introduction.rst +++ b/components/property_access/introduction.rst @@ -24,14 +24,18 @@ Usage ----- The entry point of this component is the -:method:`PropertyAccess::getPropertyAccessor` +:method:`PropertyAccess::createPropertyAccessor` factory. This factory will create a new instance of the :class:`Symfony\\Component\\PropertyAccess\\PropertyAccessor` class with the default configuration:: use Symfony\Component\PropertyAccess\PropertyAccess; - $accessor = PropertyAccess::getPropertyAccessor(); + $accessor = PropertyAccess::createPropertyAccessor(); + +.. versionadded:: 2.3 + Before Symfony 2.3, the :method:`Symfony\\Component\\PropertyAccess\\PropertyAccess::createPropertyAccessor` + was called ``getPropertyAccessor()``. Reading from Arrays ------------------- @@ -153,10 +157,10 @@ getters, this means that you can do something like this:: This will produce: ``He is an author`` -Magic Methods -~~~~~~~~~~~~~ +Magic ``__get()`` Method +~~~~~~~~~~~~~~~~~~~~~~~~ -At last, ``getValue`` can use the magic ``__get`` method too:: +The ``getValue`` method can also use the magic ``__get`` method:: // ... class Person @@ -175,6 +179,49 @@ At last, ``getValue`` can use the magic ``__get`` method too:: echo $accessor->getValue($person, 'Wouter'); // array(...) +Magic ``__call()`` Method +~~~~~~~~~~~~~~~~~~~~~~~~~ + +At last, ``getValue`` can use the magic ``__call`` method, but you need to +enable this feature by using :class:`Symfony\\Component\\PropertyAccess\\PropertyAccessorBuilder`:: + + // ... + class Person + { + private $children = array( + 'wouter' => array(...), + ); + + public function __call($name, $args) + { + $property = lcfirst(substr($name, 3)); + if ('get' === substr($name, 0, 3)) { + return isset($this->children[$property]) ? $this->children[$property] : null; + } elseif ('set' === substr($name, 0, 3)) { + $value = 1 == count($args) ? $args[0] : null; + $this->children[$property] = $value; + } + } + } + + $person = new Person(); + + // Enable magic __call + $accessor = PropertyAccess::getPropertyAccessorBuilder() + ->enableMagicCall() + ->getPropertyAccessor(); + + echo $accessor->getValue($person, 'wouter'); // array(...) + +.. versionadded:: 2.3 + The use of magic ``__call()`` method was added in Symfony 2.3. + +.. caution:: + + The ``__call`` feature is disabled by default, you can enable it by calling + :method:`PropertyAccessorBuilder::enableMagicCallEnabled` + see `Enable other Features`_. + Writing to Arrays ----------------- @@ -228,6 +275,40 @@ can use setters, the magic ``__set`` or properties to set values:: echo $person->getLastName(); // 'de Jong' echo $person->children; // array(Person()); +You can also use ``__call`` to set values but you need to enable the feature, +see `Enable other Features`_. + +.. code-block:: php + + // ... + class Person + { + private $children = array(); + + public function __call($name, $args) + { + $property = lcfirst(substr($name, 3)); + if ('get' === substr($name, 0, 3)) { + return isset($this->children[$property]) ? $this->children[$property] : null; + } elseif ('set' === substr($name, 0, 3)) { + $value = 1 == count($args) ? $args[0] : null; + $this->children[$property] = $value; + } + } + + } + + $person = new Person(); + + // Enable magic __call + $accessor = PropertyAccess::getPropertyAccessorBuilder() + ->enableMagicCall() + ->getPropertyAccessor(); + + $accessor->setValue($person, 'wouter', array(...)); + + echo $person->getWouter() // array(...) + Mixing Objects and Arrays ------------------------- @@ -261,4 +342,37 @@ You can also mix objects and arrays:: echo 'Hello '.$accessor->getValue($person, 'children[0].firstName'); // 'Wouter' // equal to $person->getChildren()[0]->firstName +Enable other Features +~~~~~~~~~~~~~~~~~~~~~ + +The :class:`Symfony\\Component\\PropertyAccess\\PropertyAccessor` can be +configured to enable extra features. To do that you could use the +:class:`Symfony\\Component\\PropertyAccess\\PropertyAccessorBuilder`:: + + // ... + $accessorBuilder = PropertyAccess::getPropertyAccessorBuilder(); + + // Enable magic __call + $accessorBuilder->enableMagicCall(); + + // Disable magic __call + $accessorBuilder->disableMagicCall(); + + // Check if magic __call handling is enabled + $accessorBuilder->isMagicCallEnabled() // true or false + + // At the end get the configured property accessor + $accessor = $accessorBuilder->getPropertyAccessor(); + + // Or all in one + $accessor = PropertyAccess::getPropertyAccessorBuilder() + ->enableMagicCall() + ->getPropertyAccessor(); + +Or you can pass parameters directly to the constructor (not the recommended way):: + + // ... + $accessor = new PropertyAccessor(true) // this enable handling of magic __call + + .. _Packagist: https://packagist.org/packages/symfony/property-access diff --git a/components/security/authentication.rst b/components/security/authentication.rst index 016dde98c46..0f7c63d523b 100644 --- a/components/security/authentication.rst +++ b/components/security/authentication.rst @@ -198,10 +198,8 @@ own, it just needs to follow these rules: #. The class must implement :class:`Symfony\\Component\\Security\\Core\\Encoder\\PasswordEncoderInterface`; -#. The first line in ``encodePassword`` and ``isPasswordValid`` must check - to make sure the password is not too long (e.g. 4096). This is for security - (see `CVE-2013-5750`_), and you can copy the `BasePasswordEncoder::checkPasswordLength`_ - implementation from Symfony 2.4. +#. ``$this->checkPasswordLength($raw);`` must be the first code executed in + ``encodePassword()`` and ``isPasswordValid()`` (see `CVE-2013-5750`_). Using Password Encoders ~~~~~~~~~~~~~~~~~~~~~~~ @@ -227,5 +225,4 @@ which should be used to encode this user's password:: $password, $user->getSalt()); -.. _`CVE-2013-5750`: http://symfony.com/blog/cve-2013-5750-security-issue-in-fosuserbundle-login-form -.. _`BasePasswordEncoder::checkPasswordLength`: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Security/Core/Encoder/BasePasswordEncoder.php \ No newline at end of file +.. _`CVE-2013-5750`: http://symfony.com/blog/cve-2013-5750-security-issue-in-fosuserbundle-login-form \ No newline at end of file diff --git a/components/serializer.rst b/components/serializer.rst index c6740878841..dd386d5b936 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -11,6 +11,9 @@ The Serializer Component In order to do so, the Serializer Component follows the following simple schema. +.. _component-serializer-encoders: +.. _component-serializer-normalizers: + .. image:: /images/components/serializer/serializer_workflow.png As you can see in the picture above, an array is used as a man in @@ -47,8 +50,8 @@ which Encoders and Normalizer are going to be available:: $serializer = new Serializer($normalizers, $encoders); -Serializing an object -~~~~~~~~~~~~~~~~~~~~~ +Serializing an Object +--------------------- For the sake of this example, assume the following class already exists in your project:: @@ -100,8 +103,31 @@ The first parameter of the :method:`Symfony\\Component\\Serializer\\Serializer:: is the object to be serialized and the second is used to choose the proper encoder, in this case :class:`Symfony\\Component\\Serializer\\Encoder\\JsonEncoder`. +Ignoring Attributes when Serializing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.3 + The :method:`GetSetMethodNormalizer::setIgnoredAttributes` + method was added in Symfony 2.3. + +As an option, there's a way to ignore attributes from the origin object when +serializing. To remove those attributes use the +:method:`Symfony\\Component\\Serializer\\Normalizer\\GetSetMethodNormalizer::setIgnoredAttributes` +method on the normalizer definition:: + + use Symfony\Component\Serializer\Serializer; + use Symfony\Component\Serializer\Encoder\JsonEncoder; + use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer; + + $normalizer = new GetSetMethodNormalizer(); + $normalizer->setIgnoredAttributes(array('age')); + $encoder = new JsonEncoder(); + + $serializer = new Serializer(array($normalizer), array($encoder)); + $serializer->serialize($person, 'json'); // Output: {"name":"foo"} + Deserializing an Object -~~~~~~~~~~~~~~~~~~~~~~~ +----------------------- Let's see now how to do the exactly the opposite. This time, the information of the `People` class would be encoded in XML format:: @@ -122,6 +148,39 @@ needs three parameters: 2. The name of the class this information will be decoded to 3. The encoder used to convert that information into an array +Using Camelized Method Names for Underscored Attributes +------------------------------------------------------- + +.. versionadded:: 2.3 + The :method:`GetSetMethodNormalizer::setCamelizedAttributes` + method was added in Symfony 2.3. + +Sometimes property names from the serialized content are underscored (e.g. +``first_name``). Normally, these attributes will use get/set methods like +``getFirst_name``, when ``getFirstName`` method is what you really want. To +change that behavior use the +:method:`Symfony\\Component\\Serializer\\Normalizer\\GetSetMethodNormalizer::setCamelizedAttributes` +method on the normalizer definition:: + + $encoder = new JsonEncoder(); + $normalizer = new GetSetMethodNormalizer(); + $normalizer->setCamelizedAttributes(array('first_name')); + + $serializer = new Serializer(array($normalizer), array($encoder)); + + $json = <<deserialize($json, 'Acme\Person', 'json'); + +As a final result, the deserializer uses the ``first_name`` attribute as if +it were ``firstName`` and uses the ``getFirstName`` and ``setFirstName`` methods. + JMSSerializer ------------- diff --git a/components/stopwatch.rst b/components/stopwatch.rst index 261f47b1d6a..c7347a4ad5c 100644 --- a/components/stopwatch.rst +++ b/components/stopwatch.rst @@ -9,7 +9,7 @@ The Stopwatch Component .. versionadded:: 2.2 The Stopwatch Component is new to Symfony 2.2. Previously, the ``Stopwatch`` - class was located in the ``HttpKernel`` component (and was new in 2.1). + class was located in the ``HttpKernel`` component. Installation ------------ diff --git a/components/using_components.rst b/components/using_components.rst index c020270e76b..bf8f260ac87 100644 --- a/components/using_components.rst +++ b/components/using_components.rst @@ -24,12 +24,12 @@ Using the Finder Component { "require": { - "symfony/finder": "2.2.*" + "symfony/finder": "2.3.*" } } If you already have a ``composer.json`` file, just add this line to it. You -may also need to adjust the version (e.g. ``2.1.1`` or ``2.2.*``). +may also need to adjust the version (e.g. ``2.2.2`` or ``2.3.*``). You can research the component names and versions at `packagist.org`_. @@ -69,9 +69,9 @@ immediately:: { "require": { - "symfony/finder": "2.2.*", - "symfony/dom-crawler": "2.2.*", - "symfony/css-selector": "2.2.*" + "symfony/finder": "2.3.*", + "symfony/dom-crawler": "2.3.*", + "symfony/css-selector": "2.3.*" } } @@ -81,7 +81,7 @@ immediately:: { "require": { - "symfony/symfony": "2.2.*" + "symfony/symfony": "2.3.*" } } diff --git a/components/yaml/introduction.rst b/components/yaml/introduction.rst index 1652316dcdd..f5ba3092d7e 100644 --- a/components/yaml/introduction.rst +++ b/components/yaml/introduction.rst @@ -140,20 +140,6 @@ error if something goes wrong by adding the filename to the message. must validate the input first. Passing a filename is deprecated in Symfony 2.2, and will be removed in Symfony 3.0. -Executing PHP Inside YAML Files -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. versionadded:: 2.1 - The ``Yaml::enablePhpParsing()`` method is new to Symfony 2.1. Prior to 2.1, - PHP was *always* executed when calling the ``parse()`` function. - -By default, if you include PHP inside a YAML file, it will not be parsed. -If you do want PHP to be parsed, you must call ``Yaml::enablePhpParsing()`` -before parsing the file to activate this mode. If you only want to allow -PHP code for a single YAML file, be sure to disable PHP parsing after parsing -the single file by calling ``Yaml::$enablePhpParsing = false;`` (``$enablePhpParsing`` -is a public property). - Writing YAML Files ~~~~~~~~~~~~~~~~~~ diff --git a/contributing/documentation/overview.rst b/contributing/documentation/overview.rst index 3c538295a93..60f93d72178 100644 --- a/contributing/documentation/overview.rst +++ b/contributing/documentation/overview.rst @@ -26,9 +26,8 @@ then clone your fork: $ git clone git://github.com/YOURUSERNAME/symfony-docs.git Consistent with Symfony's source code, the documentation repository is split into -multiple branches: ``2.2``, ``2.3`` corresponding to the different versions of -Symfony itself. The ``master`` branch holds the documentation for the development -branch of the code. +multiple branches, corresponding to the different versions of Symfony itself. +The ``master`` branch holds the documentation for the development branch of the code. Unless you're documenting a feature that was introduced *after* Symfony 2.2 (e.g. in Symfony 2.3), your changes should always be based on the 2.2 branch. diff --git a/cookbook/bundles/best_practices.rst b/cookbook/bundles/best_practices.rst index 237ae87c29e..556fb99d604 100644 --- a/cookbook/bundles/best_practices.rst +++ b/cookbook/bundles/best_practices.rst @@ -134,6 +134,12 @@ The following classes and files have specific emplacements: | Unit and Functional Tests | ``Tests/`` | +------------------------------+-----------------------------+ +.. note:: + + When building a reusable bundle, model classes should be placed in the + ``Model`` namespace. See :doc:`/cookbook/doctrine/mapping_model_classes` for + how to handle the mapping with a compiler pass. + Classes ------- diff --git a/cookbook/bundles/extension.rst b/cookbook/bundles/extension.rst index 27b733e85cf..6ed4cf2fa90 100644 --- a/cookbook/bundles/extension.rst +++ b/cookbook/bundles/extension.rst @@ -511,9 +511,6 @@ For more details, see :doc:`/cookbook/bundles/prepend_extension`. Default Configuration Dump ~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 2.1 - The ``config:dump-reference`` command was added in Symfony 2.1 - The ``config:dump-reference`` command allows a bundle's default configuration to be output to the console in yaml. diff --git a/cookbook/bundles/installation.rst b/cookbook/bundles/installation.rst index 12e6faa5efc..9fc9e268353 100644 --- a/cookbook/bundles/installation.rst +++ b/cookbook/bundles/installation.rst @@ -10,8 +10,8 @@ basic steps for installing a bundle are the same. Add Composer Dependencies ------------------------- -Starting from Symfony 2.1, dependencies are managed with Composer. It's -a good idea to learn some basics of Composer in `their documentation`_. +In Symfony, dependencies are managed with Composer. It's a good idea to learn +some basics of Composer in `their documentation`_. Before you can use composer to install a bundle, you should look for a `Packagist`_ package of that bundle. For example, if you search for the popular @@ -33,11 +33,6 @@ file. If it isn't, you can use the version you want. If you choose an incompatib version, Composer will throw dependency errors when you try to install. If this happens, you can try a different version. -In the case of the FOSUserBundle, the ``README`` file has a caution that version -1.2.0 must be used for Symfony 2.0 and 1.3+ for Symfony 2.1+. Packagist displays -example ``require`` statements for all existing versions of a package. The -current development version of FOSUserBundle is ``"friendsofsymfony/user-bundle": "2.0.*@dev"``. - Now you can add the bundle to your ``composer.json`` file and update the dependencies. You can do this manually: diff --git a/cookbook/bundles/remove.rst b/cookbook/bundles/remove.rst index 57118b22b72..1f24c612b92 100644 --- a/cookbook/bundles/remove.rst +++ b/cookbook/bundles/remove.rst @@ -48,9 +48,8 @@ that refers to the bundle. 2.1 Remove bundle routing ~~~~~~~~~~~~~~~~~~~~~~~~~ -The routing for the AcmeDemoBundle can be found in -``app/config/routing_dev.yml``. The routes are ``_welcome``, ``_demo_secured`` -and ``_demo``. Remove all three of these entries. +The routing for the AcmeDemoBundle can be found in ``app/config/routing_dev.yml``. +Remove the ``_acme_demo`` entry at the bottom of this file. 2.2 Remove bundle configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -103,4 +102,4 @@ rely on the bundle you are about to remove. .. tip:: If a third party bundle relies on another bundle, you can find that bundle - mentioned in the ``composer.json`` file included in the bundle directory. \ No newline at end of file + mentioned in the ``composer.json`` file included in the bundle directory. diff --git a/cookbook/configuration/environments.rst b/cookbook/configuration/environments.rst index c75638c74ba..f42cd4d8c9e 100644 --- a/cookbook/configuration/environments.rst +++ b/cookbook/configuration/environments.rst @@ -177,10 +177,9 @@ environment by using this code and changing the environment string. not the application should run in "debug mode". Regardless of the environment, a Symfony2 application can be run with debug mode set to ``true`` or ``false``. This affects many things in the application, such as whether - or not errors should be displayed or if cache files are dynamically rebuilt - on each request. Though not a requirement, debug mode is generally set - to ``true`` for the ``dev`` and ``test`` environments and ``false`` for - the ``prod`` environment. + or not the cache files are dynamically rebuilt on each request. Though not + a requirement, debug mode is generally set to ``true`` for the ``dev`` and + ``test`` environments and ``false`` for the ``prod`` environment. Internally, the value of the debug mode becomes the ``kernel.debug`` parameter used inside the :doc:`service container `. @@ -206,12 +205,15 @@ environment by using this code and changing the environment string. $container->loadFromExtension('doctrine', array( 'dbal' => array( 'logging' => '%kernel.debug%', - // ... ), // ... )); + As of Symfony 2.3, showing errors or not no longer depends on the debug + mode. You'll need to enable that in your front controller by calling + :method:`Symfony\\Component\\Debug\\Debug::enable`. + .. index:: single: Environments; Creating a new environment diff --git a/cookbook/configuration/front_controllers_and_kernel.rst b/cookbook/configuration/front_controllers_and_kernel.rst index 5cd3d647938..38526a08823 100644 --- a/cookbook/configuration/front_controllers_and_kernel.rst +++ b/cookbook/configuration/front_controllers_and_kernel.rst @@ -44,7 +44,9 @@ to `decorate`_ the kernel with additional features. Examples include: * Configuring the autoloader or adding additional autoloading mechanisms; * Adding HTTP level caching by wrapping the kernel with an instance of - :ref:`AppCache `. + :ref:`AppCache `; +* Enabling (or skipping) the :doc:`ClassCache ` +* Enabling the :doc:`Debug Component `. The front controller can be chosen by requesting URLs like: diff --git a/cookbook/configuration/override_dir_structure.rst b/cookbook/configuration/override_dir_structure.rst index 31aeb973847..6112b67edde 100644 --- a/cookbook/configuration/override_dir_structure.rst +++ b/cookbook/configuration/override_dir_structure.rst @@ -91,8 +91,8 @@ may need to modify the paths inside these files:: require_once __DIR__.'/../Symfony/app/bootstrap.php.cache'; require_once __DIR__.'/../Symfony/app/AppKernel.php'; -Since Symfony 2.1 (in which Composer is introduced), you also need to change -the ``extra.symfony-web-dir`` option in the ``composer.json`` file: +You also need to change the ``extra.symfony-web-dir`` option in the ``composer.json`` +file: .. code-block:: json diff --git a/cookbook/configuration/pdo_session_storage.rst b/cookbook/configuration/pdo_session_storage.rst index a6821ea95f9..a6b1886682b 100644 --- a/cookbook/configuration/pdo_session_storage.rst +++ b/cookbook/configuration/pdo_session_storage.rst @@ -14,13 +14,6 @@ Symfony2 has a built-in solution for database session storage called To use it, you just need to change some parameters in ``config.yml`` (or the configuration format of your choice): -.. versionadded:: 2.1 - In Symfony2.1 the class and namespace are slightly modified. You can now - find the session storage classes in the `Session\\Storage` namespace: - ``Symfony\Component\HttpFoundation\Session\Storage``. Also - note that in Symfony2.1 you should configure ``handler_id`` not ``storage_id`` like in Symfony2.0. - Below, you'll notice that ``%session.storage.options%`` is not used anymore. - .. configuration-block:: .. code-block:: yaml @@ -203,16 +196,16 @@ For MSSQL, the statement might look like the following: .. code-block:: sql CREATE TABLE [dbo].[session]( - [session_id] [nvarchar](255) NOT NULL, - [session_value] [ntext] NOT NULL, + [session_id] [nvarchar](255) NOT NULL, + [session_value] [ntext] NOT NULL, [session_time] [int] NOT NULL, - PRIMARY KEY CLUSTERED( - [session_id] ASC - ) WITH ( - PAD_INDEX = OFF, - STATISTICS_NORECOMPUTE = OFF, - IGNORE_DUP_KEY = OFF, - ALLOW_ROW_LOCKS = ON, - ALLOW_PAGE_LOCKS = ON - ) ON [PRIMARY] + PRIMARY KEY CLUSTERED( + [session_id] ASC + ) WITH ( + PAD_INDEX = OFF, + STATISTICS_NORECOMPUTE = OFF, + IGNORE_DUP_KEY = OFF, + ALLOW_ROW_LOCKS = ON, + ALLOW_PAGE_LOCKS = ON + ) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] diff --git a/cookbook/console/console_command.rst b/cookbook/console/console_command.rst index 83033761feb..fcd33d42419 100644 --- a/cookbook/console/console_command.rst +++ b/cookbook/console/console_command.rst @@ -105,10 +105,11 @@ instead of $command = $application->find('demo:greet'); $commandTester = new CommandTester($command); $commandTester->execute( - array( - 'name' => 'Fabien', - '--yell' => true, - ) + array( + 'command' => $command->getName(), + 'name' => 'Fabien', + '--yell' => true, + ) ); $this->assertRegExp('/.../', $commandTester->getDisplay()); @@ -145,10 +146,11 @@ you can extend your test from $command = $application->find('demo:greet'); $commandTester = new CommandTester($command); $commandTester->execute( - array( - 'name' => 'Fabien', - '--yell' => true, - ) + array( + 'command' => $command->getName(), + 'name' => 'Fabien', + '--yell' => true, + ) ); $this->assertRegExp('/.../', $commandTester->getDisplay()); diff --git a/cookbook/console/sending_emails.rst b/cookbook/console/sending_emails.rst index 60194fe5904..d8f99472efa 100644 --- a/cookbook/console/sending_emails.rst +++ b/cookbook/console/sending_emails.rst @@ -20,9 +20,6 @@ and per Command. Configuring the Request Context globally ---------------------------------------- -.. versionadded:: 2.1 - The ``host`` and ``scheme`` parameters are available since Symfony 2.1 - .. versionadded: 2.2 The ``base_url`` parameter is available since Symfony 2.2 diff --git a/cookbook/doctrine/file_uploads.rst b/cookbook/doctrine/file_uploads.rst index 362d06cf8ec..8436a98cac6 100644 --- a/cookbook/doctrine/file_uploads.rst +++ b/cookbook/doctrine/file_uploads.rst @@ -222,61 +222,34 @@ The following controller shows you how to handle the entire process:: // ... use Acme\DemoBundle\Entity\Document; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; + use Symfony\Component\HttpFoundation\Request; // ... /** * @Template() */ - public function uploadAction() + public function uploadAction(Request $request) { $document = new Document(); $form = $this->createFormBuilder($document) ->add('name') ->add('file') - ->getForm() - ; + ->getForm(); - if ($this->getRequest()->isMethod('POST')) { - $form->bind($this->getRequest()); - if ($form->isValid()) { - $em = $this->getDoctrine()->getManager(); + $form->handleRequest($request); - $em->persist($document); - $em->flush(); + if ($form->isValid()) { + $em = $this->getDoctrine()->getManager(); - return $this->redirect($this->generateUrl(...)); - } + $em->persist($document); + $em->flush(); + + return $this->redirect($this->generateUrl(...)); } return array('form' => $form->createView()); } -.. note:: - - When writing the template, don't forget to set the ``enctype`` attribute: - - .. configuration-block:: - - .. code-block:: html+jinja - -

Upload File

- - - {{ form_widget(form) }} - - - - - .. code-block:: html+php - -

Upload File

- -
enctype($form) ?>> - widget($form) ?> - - -
- The previous controller will automatically persist the ``Document`` entity with the submitted name, but it will do nothing about the file and the ``path`` property will be blank. diff --git a/cookbook/doctrine/index.rst b/cookbook/doctrine/index.rst index 170a5f2d718..7f19ef7d4fe 100644 --- a/cookbook/doctrine/index.rst +++ b/cookbook/doctrine/index.rst @@ -12,4 +12,5 @@ Doctrine multiple_entity_managers custom_dql_functions resolve_target_entity + mapping_model_classes registration_form diff --git a/cookbook/doctrine/mapping_model_classes.rst b/cookbook/doctrine/mapping_model_classes.rst new file mode 100644 index 00000000000..619c5da835f --- /dev/null +++ b/cookbook/doctrine/mapping_model_classes.rst @@ -0,0 +1,149 @@ +.. index:: + single: Doctrine; Mapping Model classes + +How to provide model classes for several Doctrine implementations +================================================================= + +When building a bundle that could be used not only with Doctrine ORM but +also the CouchDB ODM, MongoDB ODM or PHPCR ODM, you should still only +write one model class. The Doctrine bundles provide a compiler pass to +register the mappings for your model classes. + +.. note:: + + For non-reusable bundles, the easiest option is to put your model classes + in the default locations: ``Entity`` for the Doctrine ORM or ``Document`` + for one of the ODMs. For reusable bundles, rather than duplicate model classes + just to get the auto mapping, use the compiler pass. + +.. versionadded:: 2.3 + The base mapping compiler pass was added in Symfony 2.3. The Doctrine bundles + support it from DoctrineBundle >= 1.2.1, MongoDBBundle >= 3.0.0, + PHPCRBundle >= 1.0.0-alpha2 and the (unversioned) CouchDBBundle supports the + compiler pass since the `CouchDB Mapping Compiler Pass pull request`_ + was merged. + + If you want your bundle to support older versions of Symfony and + Doctrine, you can provide a copy of the compiler pass in your bundle. + See for example the `FOSUserBundle mapping configuration`_ + ``addRegisterMappingsPass``. + + +In your bundle class, write the following code to register the compiler pass. +This one is written for the FOSUserBundle, so parts of it will need to +be adapted for your case:: + + use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass; + use Doctrine\Bundle\MongoDBBundle\DependencyInjection\Compiler\DoctrineMongoDBMappingsPass; + use Doctrine\Bundle\CouchDBBundle\DependencyInjection\Compiler\DoctrineCouchDBMappingsPass; + use Doctrine\Bundle\PHPCRBundle\DependencyInjection\Compiler\DoctrinePhpcrMappingsPass; + + class FOSUserBundle extends Bundle + { + public function build(ContainerBuilder $container) + { + parent::build($container); + // ... + + $modelDir = realpath(__DIR__.'/Resources/config/doctrine/model'); + $mappings = array( + $modelDir => 'FOS\UserBundle\Model', + ); + + $ormCompilerClass = 'Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass'; + if (class_exists($ormCompilerClass)) { + $container->addCompilerPass( + DoctrineOrmMappingsPass::createXmlMappingDriver( + $mappings, + array('fos_user.model_manager_name'), + 'fos_user.backend_type_orm' + )); + } + + $mongoCompilerClass = 'Doctrine\Bundle\MongoDBBundle\DependencyInjection\Compiler\DoctrineMongoDBMappingsPass'; + if (class_exists($mongoCompilerClass)) { + $container->addCompilerPass( + DoctrineMongoDBMappingsPass::createXmlMappingDriver( + $mappings, + array('fos_user.model_manager_name'), + 'fos_user.backend_type_mongodb' + )); + } + + $couchCompilerClass = 'Doctrine\Bundle\CouchDBBundle\DependencyInjection\Compiler\DoctrineCouchDBMappingsPass'; + if (class_exists($couchCompilerClass)) { + $container->addCompilerPass( + DoctrineCouchDBMappingsPass::createXmlMappingDriver( + $mappings, + array('fos_user.model_manager_name'), + 'fos_user.backend_type_couchdb' + )); + } + + $phpcrCompilerClass = 'Doctrine\Bundle\PHPCRBundle\DependencyInjection\Compiler\DoctrinePhpcrMappingsPass'; + if (class_exists($phpcrCompilerClass)) { + $container->addCompilerPass( + DoctrinePhpcrMappingsPass::createXmlMappingDriver( + $mappings, + array('fos_user.model_manager_name'), + 'fos_user.backend_type_phpcr' + )); + } + } + } + +Note the :phpfunction:`class_exists` check. This is crucial, as you do not want your +bundle to have a hard dependency on all Doctrine bundles but let the user +decide which to use. + +The compiler pass provides factory methods for all drivers provided by Doctrine: +Annotations, XML, Yaml, PHP and StaticPHP. The arguments are: + +* a map/hash of absolute directory path to namespace; +* an array of container parameters that your bundle uses to specify the name of + the Doctrine manager that it is using. In the above example, the FOSUserBundle + stores the manager name that's being used under the ``fos_user.model_manager_name`` + parameter. The compiler pass will append the parameter Doctrine is using + to specify the name of the default manager. The first parameter found is + used and the mappings are registered with that manager; +* an optional container parameter name that will be used by the compiler + pass to determine if this Doctrine type is used at all (this is relevant if + your user has more than one type of Doctrine bundle installed, but your + bundle is only used with one type of Doctrine. + +.. note:: + + The factory method is using the ``SymfonyFileLocator`` of Doctrine, meaning + it will only see XML and YML mapping files if they do not contain the + full namespace as the filename. This is by design: the ``SymfonyFileLocator`` + simplifies things by assuming the files are just the "short" version + of the class as their filename (e.g. ``BlogPost.orm.xml``) + + If you also need to map a base class, you can register a compiler pass + with the ``DefaultFileLocator`` like this. This code is simply taken from the + ``DoctrineOrmMappingsPass`` and adapted to use the ``DefaultFileLocator`` + instead of the ``SymfonyFileLocator``:: + + private function buildMappingCompilerPass() + { + $arguments = array(array(realpath(__DIR__ . '/Resources/config/doctrine-base')), '.orm.xml'); + $locator = new Definition('Doctrine\Common\Persistence\Mapping\Driver\DefaultFileLocator', $arguments); + $driver = new Definition('Doctrine\ORM\Mapping\Driver\XmlDriver', array($locator)); + + return new DoctrineOrmMappingsPass( + $driver, + array('Full\Namespace'), + array('your_bundle.manager_name'), + 'your_bundle.orm_enabled' + ); + } + + Now place your mapping file into ``/Resources/config/doctrine-base`` with the + fully qualified class name, separated by ``.`` instead of ``\``, for example + ``Other.Namespace.Model.Name.orm.xml``. You may not mix the two as otherwise + the SymfonyFileLocator will get confused. + + Adjust accordingly for the other Doctrine implementations. + +.. _`CouchDB Mapping Compiler Pass pull request`: https://github.com/doctrine/DoctrineCouchDBBundle/pull/27 +.. _`FOSUserBundle mapping configuration`: https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/FOSUserBundle.php diff --git a/cookbook/doctrine/registration_form.rst b/cookbook/doctrine/registration_form.rst index 0392341683e..f2a6ce23e0e 100644 --- a/cookbook/doctrine/registration_form.rst +++ b/cookbook/doctrine/registration_form.rst @@ -248,10 +248,10 @@ controller for displaying the registration form:: { public function registerAction() { - $form = $this->createForm( - new RegistrationType(), - new Registration() - ); + $registration = new Registration(); + $form = $this->createForm(new RegistrationType(), $registration, array( + 'action' => $this->generateUrl('account_create'), + )); return $this->render( 'AcmeAccountBundle:Account:register.html.twig', @@ -265,22 +265,18 @@ and its template: .. code-block:: html+jinja {# src/Acme/AccountBundle/Resources/views/Account/register.html.twig #} -
- {{ form_widget(form) }} - - -
+ {{ form(form) }} Next, create the controller which handles the form submission. This performs the validation and saves the data into the database:: - public function createAction() + public function createAction(Request $request) { $em = $this->getDoctrine()->getEntityManager(); $form = $this->createForm(new RegistrationType(), new Registration()); - $form->bind($this->getRequest()); + $form->handleRequest($request); if ($form->isValid()) { $registration = $form->getData(); diff --git a/cookbook/doctrine/resolve_target_entity.rst b/cookbook/doctrine/resolve_target_entity.rst index 9fbe7b7176c..6d7439582ec 100644 --- a/cookbook/doctrine/resolve_target_entity.rst +++ b/cookbook/doctrine/resolve_target_entity.rst @@ -5,10 +5,6 @@ How to Define Relationships with Abstract Classes and Interfaces ================================================================ -.. versionadded:: 2.1 - The ResolveTargetEntityListener is new to Doctrine 2.2, which was first - packaged with Symfony 2.1. - One of the goals of bundles is to create discreet bundles of functionality that do not have many (if any) dependencies, allowing you to use that functionality in other applications without including unnecessary items. diff --git a/cookbook/form/create_form_type_extension.rst b/cookbook/form/create_form_type_extension.rst index c9ab81a401a..0e673a40a4e 100644 --- a/cookbook/form/create_form_type_extension.rst +++ b/cookbook/form/create_form_type_extension.rst @@ -232,7 +232,7 @@ it in the view:: $parentData = $form->getParent()->getData(); if (null !== $parentData) { - $accessor = PropertyAccess::getPropertyAccessor(); + $accessor = PropertyAccess::createPropertyAccessor(); $imageUrl = $accessor->getValue($parentData, $options['image_path']); } else { $imageUrl = null; diff --git a/cookbook/form/data_transformers.rst b/cookbook/form/data_transformers.rst index 802581c1ff8..49c7b02f5bd 100644 --- a/cookbook/form/data_transformers.rst +++ b/cookbook/form/data_transformers.rst @@ -157,7 +157,7 @@ when creating your form. Later, you'll learn how you could create a custom Cool, you're done! Your user will be able to enter an issue number into the text field and it will be transformed back into an Issue object. This means -that, after a successful bind, the Form framework will pass a real Issue +that, after a successful submission, the Form framework will pass a real Issue object to ``Task::setIssue()`` instead of the issue number. If the issue isn't found, a form error will be created for that field and @@ -177,11 +177,6 @@ its error message can be controlled with the ``invalid_message`` field option. Model and View Transformers ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 2.1 - The names and method of the transformers were changed in Symfony 2.1. - ``prependNormTransformer`` became ``addModelTransformer`` and ``appendClientTransformer`` - became ``addViewTransformer``. - In the above example, the transformer was used as a "model" transformer. In fact, there are two different types of transformers and three different types of underlying data. @@ -201,7 +196,7 @@ used directly. 3) **View Data** - This is the format that's used to fill in the form fields themselves. It's also the format in which the user will submit the data. When -you call ``Form::bind($data)``, the ``$data`` is in the "view" data format. +you call ``Form::submit($data)``, the ``$data`` is in the "view" data format. The 2 different types of transformers help convert to and from each of these types of data: diff --git a/cookbook/form/direct_submit.rst b/cookbook/form/direct_submit.rst new file mode 100644 index 00000000000..f2472f0b7d1 --- /dev/null +++ b/cookbook/form/direct_submit.rst @@ -0,0 +1,123 @@ +.. index:: + single: Form; Form::submit() + +How to use the submit() Function to handle Form Submissions +=========================================================== + +.. versionadded:: 2.3 + The ``handleRequest()`` method was added in Symfony 2.3. + +In Symfony 2.3, a new :method:`Symfony\Component\Form\FormInterface::handleRequest` +method was added, which makes handling form submissions easier than ever:: + + use Symfony\Component\HttpFoundation\Request; + // ... + + public function newAction(Request $request) + { + $form = $this->createFormBuilder() + // ... + ->getForm(); + + $form->handleRequest($request); + + if ($form->isValid()) { + // perform some action... + + return $this->redirect($this->generateUrl('task_success')); + } + + return $this->render('AcmeTaskBundle:Default:new.html.twig', array( + 'form' => $form->createView(), + )); + } + +.. tip:: + + To see more about this method, read :ref:`book-form-handling-form-submissions`. + +Calling Form::submit() manually +------------------------------- + +.. versionadded:: 2.3 + Before Symfony 2.3, the ``submit()`` method was known as ``bind()``. + +In some cases, you want better control over when exactly your form is submitted +and what data is passed to it. Instead of using the +:method:`Symfony\Component\Form\FormInterface::handleRequest` +method, pass the submitted data directly to +:method:`Symfony\Component\Form\FormInterface::submit`:: + + use Symfony\Component\HttpFoundation\Request; + // ... + + public function newAction(Request $request) + { + $form = $this->createFormBuilder() + // ... + ->getForm(); + + if ($request->isMethod('POST')) { + $form->submit($request->request->get($form->getName())); + + if ($form->isValid()) { + // perform some action... + + return $this->redirect($this->generateUrl('task_success')); + } + } + + return $this->render('AcmeTaskBundle:Default:new.html.twig', array( + 'form' => $form->createView(), + )); + } + +.. tip:: + + Forms consisting of nested fields expect an array in + :method:`Symfony\Component\Form\FormInterface::submit`. You can also submit + individual fields by calling :method:`Symfony\Component\Form\FormInterface::submit` + directly on the field:: + + $form->get('firstName')->submit('Fabien'); + +.. _cookbook-form-submit-request: + +Passing a Request to Form::submit() (deprecated) +------------------------------------------------ + +.. versionadded:: + Before Symfony 2.3, the ``submit`` method was known as ``bind``. + +Before Symfony 2.3, the :method:`Symfony\Component\Form\FormInterface::submit` +method accepted a :class:`Symfony\\Component\\HttpFoundation\\Request` object as +a convenient shortcut to the previous example:: + + use Symfony\Component\HttpFoundation\Request; + // ... + + public function newAction(Request $request) + { + $form = $this->createFormBuilder() + // ... + ->getForm(); + + if ($request->isMethod('POST')) { + $form->submit($request); + + if ($form->isValid()) { + // perform some action... + + return $this->redirect($this->generateUrl('task_success')); + } + } + + return $this->render('AcmeTaskBundle:Default:new.html.twig', array( + 'form' => $form->createView(), + )); + } + +Passing the :class:`Symfony\\Component\HttpFoundation\\Request` directly to +:method:`Symfony\\Component\\Form\\FormInterface::submit` still works, but is +deprecated and will be removed in Symfony 3.0. You should use the method +:method:`Symfony\Component\Form\FormInterface::handleRequest` instead. diff --git a/cookbook/form/dynamic_form_modification.rst b/cookbook/form/dynamic_form_modification.rst index 14c8cd8a1fd..e358d39bb96 100644 --- a/cookbook/form/dynamic_form_modification.rst +++ b/cookbook/form/dynamic_form_modification.rst @@ -461,16 +461,20 @@ On a form, we can usually listen to the following events: * ``PRE_SET_DATA`` * ``POST_SET_DATA`` -* ``PRE_BIND`` -* ``BIND`` -* ``POST_BIND`` +* ``PRE_SUBMIT`` +* ``SUBMIT`` +* ``POST_SUBMIT`` + +.. versionadded:: 2.3 + The events ``PRE_SUBMIT``, ``SUBMIT`` and ``POST_SUBMIT`` were added in + Symfony 2.3. Before, they were named ``PRE_BIND``, ``BIND`` and ``POST_BIND``. .. versionadded:: 2.2.6 - The behavior of the ``POST_BIND`` event changed slightly in 2.2.6, which the + The behavior of the ``POST_SUBMIT`` event changed slightly in 2.2.6, which the below example uses. -The key is to add a ``POST_BIND`` listener to the field that your new field -depends on. If you add a ``POST_BIND`` listener to a form child (e.g. ``sport``), +The key is to add a ``POST_SUBMIT`` listener to the field that your new field +depends on. If you add a ``POST_SUBMIT`` listener to a form child (e.g. ``sport``), and add new children to the parent form, the Form component will detect the new field automatically and map it to the submitted client data. @@ -508,7 +512,7 @@ The type would now look like:: ); $builder->get('sport')->addEventListener( - FormEvents::POST_BIND, + FormEvents::POST_SUBMIT, function(FormEvent $event) use ($formModifier) { // It's important here to fetch $event->getForm()->getData(), as // $event->getData() will get you the client data (that is, the ID) @@ -528,6 +532,6 @@ Other than that, the listeners always perform exactly the same things on a given One piece that may still be missing is the client-side updating of your form after the sport is selected. This should be handled by making an AJAX call -back to your application. In that controller, you can bind your form, but -instead of processing it, simply use the bound form to render the updated +back to your application. In that controller, you can submit your form, but +instead of processing it, simply use the submitted form to render the updated fields. The response from the AJAX call can then be used to update the view. diff --git a/cookbook/form/form_collections.rst b/cookbook/form/form_collections.rst index 2210c9f5b16..0e583ff2e0c 100755 --- a/cookbook/form/form_collections.rst +++ b/cookbook/form/form_collections.rst @@ -172,12 +172,10 @@ In your controller, you'll now initialize a new instance of ``TaskType``:: $form = $this->createForm(new TaskType(), $task); - // process the form on POST - if ($request->isMethod('POST')) { - $form->bind($request); - if ($form->isValid()) { - // ... maybe do some form processing, like saving the Task and Tag objects - } + $form->handleRequest($request); + + if ($form->isValid()) { + // ... maybe do some form processing, like saving the Task and Tag objects } return $this->render('AcmeTaskBundle:Task:new.html.twig', array( @@ -200,7 +198,7 @@ zero tags when first created). {# ... #} -
+ {{ form_start(form) }} {# render the task's only field: description #} {{ form_row(form.description) }} @@ -211,10 +209,9 @@ zero tags when first created).
  • {{ form_row(tag.name) }}
  • {% endfor %} + {{ form_end(form) }} - {{ form_rest(form) }} - {# ... #} -
    + {# ... #} .. code-block:: html+php @@ -222,16 +219,17 @@ zero tags when first created). -
    + start($form) ?> + + row($form['description']) ?> +

    Tags

    • row($tag['name']) ?>
    - - rest($form) ?> -
    + end($form) ?> @@ -381,9 +379,6 @@ HTML contains the tag ``text`` input element with a name of ``task[tags][__name_ and id of ``task_tags___name___name``. The ``__name__`` is a little "placeholder", which you'll replace with a unique, incrementing number (e.g. ``task[tags][3][name]``). -.. versionadded:: 2.1 - The placeholder was changed from ``$$name$$`` to ``__name__`` in Symfony 2.1 - The actual code needed to make this all work can vary quite a bit, but here's one example: @@ -688,40 +683,38 @@ the relationship between the removed ``Tag`` and ``Task`` object. $editForm = $this->createForm(new TaskType(), $task); - if ($request->isMethod('POST')) { - $editForm->bind($this->getRequest()); + $editForm->handleRequest($request); - if ($editForm->isValid()) { + if ($editForm->isValid()) { - // filter $originalTags to contain tags no longer present - foreach ($task->getTags() as $tag) { - foreach ($originalTags as $key => $toDel) { - if ($toDel->getId() === $tag->getId()) { - unset($originalTags[$key]); - } + // filter $originalTags to contain tags no longer present + foreach ($task->getTags() as $tag) { + foreach ($originalTags as $key => $toDel) { + if ($toDel->getId() === $tag->getId()) { + unset($originalTags[$key]); } } + } - // remove the relationship between the tag and the Task - foreach ($originalTags as $tag) { - // remove the Task from the Tag - $tag->getTasks()->removeElement($task); + // remove the relationship between the tag and the Task + foreach ($originalTags as $tag) { + // remove the Task from the Tag + $tag->getTasks()->removeElement($task); - // if it were a ManyToOne relationship, remove the relationship like this - // $tag->setTask(null); + // if it were a ManyToOne relationship, remove the relationship like this + // $tag->setTask(null); - $em->persist($tag); + $em->persist($tag); - // if you wanted to delete the Tag entirely, you can also do that - // $em->remove($tag); - } + // if you wanted to delete the Tag entirely, you can also do that + // $em->remove($tag); + } - $em->persist($task); - $em->flush(); + $em->persist($task); + $em->flush(); - // redirect back to some edit page - return $this->redirect($this->generateUrl('task_edit', array('id' => $id))); - } + // redirect back to some edit page + return $this->redirect($this->generateUrl('task_edit', array('id' => $id))); } // render some form template diff --git a/cookbook/form/form_customization.rst b/cookbook/form/form_customization.rst index 20ac50db40e..de03ba219c5 100644 --- a/cookbook/form/form_customization.rst +++ b/cookbook/form/form_customization.rst @@ -716,13 +716,9 @@ and customize the ``form_errors`` fragment. {% block form_errors %} {% spaceless %} {% if errors|length > 0 %} -
      +
        {% for error in errors %} -
      • {{ - error.messagePluralization is null - ? error.messageTemplate|trans(error.messageParameters, 'validators') - : error.messageTemplate|transchoice(error.messagePluralization, error.messageParameters, 'validators') - }}
      • +
      • {{ error.message }}
      • {% endfor %}
      {% endif %} @@ -733,23 +729,9 @@ and customize the ``form_errors`` fragment. -
        +
          -
        • getMessagePluralization()) { - echo $view['translator']->trans( - $error->getMessageTemplate(), - $error->getMessageParameters(), - 'validators' - ); - } else { - echo $view['translator']->transChoice( - $error->getMessageTemplate(), - $error->getMessagePluralization(), - $error->getMessageParameters(), - 'validators' - ); - }?>
        • +
        • getMessage() ?>
        @@ -966,4 +948,4 @@ customizations directly. Look at the following example: The array passed as the second argument contains form "variables". For more details about this concept in Twig, see :ref:`twig-reference-form-variables`. -.. _`form_div_layout.html.twig`: https://github.com/symfony/symfony/blob/2.2/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +.. _`form_div_layout.html.twig`: https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig diff --git a/cookbook/form/index.rst b/cookbook/form/index.rst index 9086e7d6b3e..5aea7405d4c 100644 --- a/cookbook/form/index.rst +++ b/cookbook/form/index.rst @@ -10,6 +10,12 @@ Form form_collections create_custom_field_type create_form_type_extension - use_virtuals_forms + inherit_data_option unit_testing use_empty_data + direct_submit + +.. toctree:: + :hidden: + + use_virtuals_forms diff --git a/cookbook/form/inherit_data_option.rst b/cookbook/form/inherit_data_option.rst new file mode 100644 index 00000000000..102d391c1f9 --- /dev/null +++ b/cookbook/form/inherit_data_option.rst @@ -0,0 +1,155 @@ +.. index:: + single: Form; The "inherit_data" option + +How to Reduce Code Duplication with "inherit_data" +================================================== + +.. versionadded:: 2.3 + This ``inherit_data`` option was known as ``virtual`` before Symfony 2.3. + +The ``inherit_data`` form field option can be very useful when you have some +duplicated fields in different entities. For example, imagine you have two +entities, a ``Company`` and a ``Customer``:: + + // src/Acme/HelloBundle/Entity/Company.php + namespace Acme\HelloBundle\Entity; + + class Company + { + private $name; + private $website; + + private $address; + private $zipcode; + private $city; + private $country; + } + +.. code-block:: php + + // src/Acme/HelloBundle/Entity/Customer.php + namespace Acme\HelloBundle\Entity; + + class Customer + { + private $firstName; + private $lastName; + + private $address; + private $zipcode; + private $city; + private $country; + } + +As you can see, each entity shares a few of the same fields: ``address``, +``zipcode``, ``city``, ``country``. + +Let's build two forms for these entities, ``CompanyType`` and ``CustomerType``:: + + // src/Acme/HelloBundle/Form/Type/CompanyType.php + namespace Acme\HelloBundle\Form\Type; + + use Symfony\Component\Form\AbstractType; + use Symfony\Component\Form\FormBuilderInterface; + + class CompanyType extends AbstractType + { + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->add('name', 'text') + ->add('website', 'text'); + } + } + +.. code-block:: php + + // src/Acme/HelloBundle/Form/Type/CustomerType.php + namespace Acme\HelloBundle\Form\Type; + + use Symfony\Component\Form\FormBuilderInterface; + use Symfony\Component\Form\AbstractType; + + class CustomerType extends AbstractType + { + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->add('firstName', 'text') + ->add('lastName', 'text'); + } + } + +Instead of including the duplicated fields ``address``, ``zipcode``, ``city`` +and ``country`` in both of these forms, we will create a third form for that. +We will call this form simply ``LocationType``:: + + // src/Acme/HelloBundle/Form/Type/LocationType.php + namespace Acme\HelloBundle\Form\Type; + + use Symfony\Component\Form\AbstractType; + use Symfony\Component\Form\FormBuilderInterface; + use Symfony\Component\OptionsResolver\OptionsResolverInterface; + + class LocationType extends AbstractType + { + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->add('address', 'textarea') + ->add('zipcode', 'text') + ->add('city', 'text') + ->add('country', 'text'); + } + + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'inherit_data' => true + )); + } + + public function getName() + { + return 'location'; + } + } + +The location form has an interesting option set, namely ``inherit_data``. This +option lets the form inherit its data from its parent form. If embedded in +the company form, the fields of the location form will access the properties of +the ``Company`` instance. If embedded in the customer form, the fields will +access the properties of the ``Customer`` instance instead. Easy, eh? + +.. note:: + + Instead of setting the ``inherit_data`` option inside ``LocationType``, you + can also (just like with any option) pass it in the third argument of + ``$builder->add()``. + +Let's make this work by adding the location form to our two original forms:: + + // src/Acme/HelloBundle/Form/Type/CompanyType.php + public function buildForm(FormBuilderInterface $builder, array $options) + { + // ... + + $builder->add('foo', new LocationType(), array( + 'data_class' => 'Acme\HelloBundle\Entity\Company' + )); + } + +.. code-block:: php + + // src/Acme/HelloBundle/Form/Type/CustomerType.php + public function buildForm(FormBuilderInterface $builder, array $options) + { + // ... + + $builder->add('bar', new LocationType(), array( + 'data_class' => 'Acme\HelloBundle\Entity\Customer' + )); + } + +That's it! You have extracted duplicated field definitions to a separate +location form that you can reuse wherever you need it. diff --git a/cookbook/form/unit_testing.rst b/cookbook/form/unit_testing.rst index c7e4d8993ca..6e8978fc9d5 100644 --- a/cookbook/form/unit_testing.rst +++ b/cookbook/form/unit_testing.rst @@ -17,14 +17,13 @@ is done in a real application. It is simple to bootstrap and you can trust the Symfony components enough to use them as a testing base. There is already a class that you can benefit from for simple FormTypes -testing: :class:`Symfony\\Component\\Form\\Tests\\Extension\\Core\\Type\\TypeTestCase`. -It is used to test the core types and you can use it to test your types too. +testing: :class:`Symfony\\Component\\Form\\Test\\TypeTestCase`. It is used to +test the core types and you can use it to test your types too. -.. note:: - - Depending on the way you installed your Symfony or Symfony Form Component - the tests may not be downloaded. Use the --prefer-source option with - composer if this is the case. +.. versionadded:: 2.3 + The ``TypeTestCase`` has moved to the ``Symfony\Component\Form\Test`` + namespace in 2.3. Previously, the class was located in + ``Symfony\Component\Form\Tests\Extension\Core\Type``. The Basics ---------- @@ -36,11 +35,11 @@ The simplest ``TypeTestCase`` implementation looks like the following:: use Acme\TestBundle\Form\Type\TestedType; use Acme\TestBundle\Model\TestObject; - use Symfony\Component\Form\Tests\Extension\Core\Type\TypeTestCase; + use Symfony\Component\Form\Test\TypeTestCase; class TestedTypeTest extends TypeTestCase { - public function testBindValidData() + public function testSubmitValidData() { $formData = array( 'test' => 'test', @@ -53,7 +52,8 @@ The simplest ``TypeTestCase`` implementation looks like the following:: $object = new TestObject(); $object->fromArray($formData); - $form->bind($formData); + // submit the data to the form directly + $form->submit($formData); $this->assertTrue($form->isSynchronized()); $this->assertEquals($object, $form->getData()); @@ -80,7 +80,7 @@ This test checks that none of your data transformers used by the form failed. The :method:`Symfony\\Component\\Form\\FormInterface::isSynchronized` method is only set to ``false`` if a data transformer throws an exception:: - $form->bind($formData); + $form->submit($formData); $this->assertTrue($form->isSynchronized()); .. note:: @@ -89,7 +89,7 @@ method is only set to ``false`` if a data transformer throws an exception:: active in the test case and it relies on validation configuration. Instead, unit test your custom constraints directly. -Next, verify the binding and mapping of the form. The test below +Next, verify the submission and mapping of the form. The test below checks if all the fields are correctly specified:: $this->assertEquals($object, $form->getData()); @@ -137,7 +137,7 @@ before creating the parent form using PreloadedExtension class:: ), array())); } - public function testBindValidData() + public function testSubmitValidData() { $type = new TestedType(); $form = $this->factory->create($type); @@ -167,7 +167,7 @@ on other extensions. You need add those extensions to the factory object:: use Acme\TestBundle\Form\Type\TestedType; use Acme\TestBundle\Model\TestObject; - use Symfony\Component\Form\Tests\Extension\Core\Type\TypeTestCase; + use Symfony\Component\Form\Test\TypeTestCase; class TestedTypeTest extends TypeTestCase { @@ -208,7 +208,7 @@ a good opportunity to use them:: use Acme\TestBundle\Form\Type\TestedType; use Acme\TestBundle\Model\TestObject; - use Symfony\Component\Form\Tests\Extension\Core\Type\TypeTestCase; + use Symfony\Component\Form\Test\TypeTestCase; class TestedTypeTest extends TypeTestCase { diff --git a/cookbook/form/use_empty_data.rst b/cookbook/form/use_empty_data.rst index 2824d7a0e9b..0b09ac3cf62 100644 --- a/cookbook/form/use_empty_data.rst +++ b/cookbook/form/use_empty_data.rst @@ -5,7 +5,7 @@ How to configure Empty Data for a Form Class ============================================ The ``empty_data`` option allows you to specify an empty data set for your -form class. This empty data set would be used if you bind your form, but +form class. This empty data set would be used if you submit your form, but haven't called ``setData()`` on your form or passed in data when you created you form. For example:: diff --git a/cookbook/form/use_virtuals_forms.rst b/cookbook/form/use_virtuals_forms.rst index ab5fa6405f3..9f8ed394cff 100644 --- a/cookbook/form/use_virtuals_forms.rst +++ b/cookbook/form/use_virtuals_forms.rst @@ -1,163 +1,5 @@ -.. index:: - single: Form; Virtual forms - How to use the Virtual Form Field Option ======================================== -The ``virtual`` form field option can be very useful when you have some -duplicated fields in different entities. - -For example, imagine you have two entities, a ``Company`` and a ``Customer``:: - - // src/Acme/HelloBundle/Entity/Company.php - namespace Acme\HelloBundle\Entity; - - class Company - { - private $name; - private $website; - - private $address; - private $zipcode; - private $city; - private $country; - } - -.. code-block:: php - - // src/Acme/HelloBundle/Entity/Customer.php - namespace Acme\HelloBundle\Entity; - - class Customer - { - private $firstName; - private $lastName; - - private $address; - private $zipcode; - private $city; - private $country; - } - -Like you can see, each entity shares a few of the same fields: ``address``, -``zipcode``, ``city``, ``country``. - -Now, you want to build two forms: one for a ``Company`` and the second for -a ``Customer``. - -Start by creating a very simple ``CompanyType`` and ``CustomerType``:: - - // src/Acme/HelloBundle/Form/Type/CompanyType.php - namespace Acme\HelloBundle\Form\Type; - - use Symfony\Component\Form\AbstractType; - use Symfony\Component\Form\FormBuilder; - - use Symfony\Component\Form\AbstractType; - use Symfony\Component\Form\FormBuilderInterface; - - class CompanyType extends AbstractType - { - public function buildForm(FormBuilderInterface $builder, array $options) - { - $builder - ->add('name', 'text') - ->add('website', 'text'); - } - } - -.. code-block:: php - - // src/Acme/HelloBundle/Form/Type/CustomerType.php - namespace Acme\HelloBundle\Form\Type; - - use Symfony\Component\Form\FormBuilderInterface; - use Symfony\Component\Form\AbstractType; - - class CustomerType extends AbstractType - { - public function buildForm(FormBuilderInterface $builder, array $options) - { - $builder - ->add('firstName', 'text') - ->add('lastName', 'text'); - } - } - -Now, to deal with the four duplicated fields. Here is a (simple) -location form type:: - - // src/Acme/HelloBundle/Form/Type/LocationType.php - namespace Acme\HelloBundle\Form\Type; - - use Symfony\Component\Form\AbstractType; - use Symfony\Component\Form\FormBuilderInterface; - use Symfony\Component\OptionsResolver\OptionsResolverInterface; - - class LocationType extends AbstractType - { - public function buildForm(FormBuilderInterface $builder, array $options) - { - $builder - ->add('address', 'textarea') - ->add('zipcode', 'text') - ->add('city', 'text') - ->add('country', 'text'); - } - - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'virtual' => true - )); - } - - public function getName() - { - return 'location'; - } - } - -You don't *actually* have a location field in each of your entities, so you -can't directly link ``LocationType`` to ``CompanyType`` or ``CustomerType``. -But you absolutely want to have a dedicated form type to deal with location (remember, DRY!). - -The ``virtual`` form field option is the solution. - -You can set the option ``'virtual' => true`` in the ``setDefaultOptions()`` method -of ``LocationType`` and directly start using it in the two original form types. - -Look at the result:: - - // CompanyType - public function buildForm(FormBuilderInterface $builder, array $options) - { - $builder->add('foo', new LocationType(), array( - 'data_class' => 'Acme\HelloBundle\Entity\Company' - )); - } - -.. code-block:: php - - // CustomerType - public function buildForm(FormBuilderInterface $builder, array $options) - { - $builder->add('bar', new LocationType(), array( - 'data_class' => 'Acme\HelloBundle\Entity\Customer' - )); - } - -With the virtual option set to false (default behavior), the Form Component -expects each underlying object to have a ``foo`` (or ``bar``) property that -is either some object or array which contains the four location fields. -Of course, you don't have this object/array in your entities and you don't want it! - -With the virtual option set to true, the Form component skips the ``foo`` (or ``bar``) -property, and instead "gets" and "sets" the 4 location fields directly -on the underlying object! - -.. note:: - - Instead of setting the ``virtual`` option inside ``LocationType``, you - can (just like with any options) also pass it in as an array option to - the third argument of ``$builder->add()``. +As of Symfony 2.3, the ``virtual`` option is renamed to ``inherit_data``. You +can read everything about the new option in ":doc:`/cookbook/form/inherit_data_option`". diff --git a/cookbook/index.rst b/cookbook/index.rst index a7d3a45e3d3..1622d75cdc4 100644 --- a/cookbook/index.rst +++ b/cookbook/index.rst @@ -12,6 +12,7 @@ The Cookbook form/index validation/index configuration/index + serializer service_container/index session/index bundles/index @@ -25,6 +26,7 @@ The Cookbook debugging event_dispatcher/index request/index + session/index profiler/index web_services/index symfony1 diff --git a/cookbook/logging/channels_handlers.rst b/cookbook/logging/channels_handlers.rst index 08161091004..18e99350d5d 100644 --- a/cookbook/logging/channels_handlers.rst +++ b/cookbook/logging/channels_handlers.rst @@ -4,10 +4,6 @@ How to log Messages to different Files ====================================== -.. versionadded:: 2.1 - The ability to specify channels for a specific handler was added to - the MonologBundle for Symfony 2.1. - The Symfony Standard Edition contains a bunch of channels for logging: ``doctrine``, ``event``, ``security`` and ``request``. Each channel corresponds to a logger service (``monolog.logger.XXX``) in the container and is injected to the diff --git a/cookbook/map.rst.inc b/cookbook/map.rst.inc index e5405c98cac..c4196b0b035 100644 --- a/cookbook/map.rst.inc +++ b/cookbook/map.rst.inc @@ -60,6 +60,7 @@ * :doc:`/cookbook/doctrine/multiple_entity_managers` * :doc:`/cookbook/doctrine/custom_dql_functions` * :doc:`/cookbook/doctrine/resolve_target_entity` + * :doc:`/cookbook/doctrine/mapping_model_classes` * :doc:`/cookbook/doctrine/registration_form` * :doc:`/cookbook/email/index` @@ -85,9 +86,10 @@ * :doc:`/cookbook/form/form_collections` * :doc:`/cookbook/form/create_custom_field_type` * :doc:`/cookbook/form/create_form_type_extension` - * :doc:`/cookbook/form/use_virtuals_forms` + * :doc:`/cookbook/form/inherit_data_option` * :doc:`/cookbook/form/unit_testing` * :doc:`/cookbook/form/use_empty_data` + * :doc:`/cookbook/form/direct_submit` * (validation) :doc:`/cookbook/validation/custom_constraint` * (doctrine) :doc:`/cookbook/doctrine/file_uploads` @@ -130,6 +132,10 @@ * :doc:`/cookbook/security/custom_authentication_provider` * :doc:`/cookbook/security/target_path` +* **Serializer** + + * :doc:`/cookbook/serializer` + * :doc:`/cookbook/service_container/index` * :doc:`/cookbook/service_container/event_listener` @@ -141,6 +147,7 @@ * :doc:`/cookbook/session/proxy_examples` * :doc:`/cookbook/session/locale_sticky_session` * :doc:`/cookbook/session/sessions_directory` + * :doc:`/cookbook/session/php_bridge` * **symfony1** diff --git a/cookbook/routing/custom_route_loader.rst b/cookbook/routing/custom_route_loader.rst index 2e2f1ab5086..d328728a001 100644 --- a/cookbook/routing/custom_route_loader.rst +++ b/cookbook/routing/custom_route_loader.rst @@ -35,10 +35,12 @@ and therefore have two important methods: :method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::supports` and :method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::load`. -Take these lines from ``routing.yml``: +Take these lines from the ``routing.yml`` in the AcmeDemoBundle of the Standard +Edition: .. code-block:: yaml + # src/Acme/DemoBundle/Resources/config/routing.yml _demo: resource: "@AcmeDemoBundle/Controller/DemoController.php" type: annotation diff --git a/cookbook/routing/method_parameters.rst b/cookbook/routing/method_parameters.rst index f6f6ca8d1db..ecf152ecc47 100644 --- a/cookbook/routing/method_parameters.rst +++ b/cookbook/routing/method_parameters.rst @@ -76,36 +76,17 @@ Faking the Method with _method .. note:: - The ``_method`` functionality shown here is disabled by default in Symfony 2.2. - To enable it, you must call :method:`Request::enableHttpMethodParameterOverride ` - before you handle the request (e.g. in your front controller). + The ``_method`` functionality shown here is disabled by default in Symfony 2.2 + and enabled by default in Symfony 2.3. To control it in Symfony 2.2, you + must call :method:`Request::enableHttpMethodParameterOverride ` + before you handle the request (e.g. in your front controller). In Symfony + 2.3, use the :ref:`configuration-framework-http_method_override` option. Unfortunately, life isn't quite this simple, since most browsers do not support sending PUT and DELETE requests. Fortunately Symfony2 provides you with a simple way of working around this limitation. By including a ``_method`` parameter in the query string or parameters of an HTTP request, Symfony2 will -use this as the method when matching routes. This can be done easily in forms -with a hidden field. Suppose you have a form for editing a blog post: - -.. code-block:: html+jinja - -
        - - {{ form_widget(form) }} - -
        - -The submitted request will now match the ``blog_update`` route and the ``updateAction`` -will be used to process the form. - -Likewise the delete form could be changed to look like this: - -.. code-block:: html+jinja - -
        - - {{ form_widget(delete_form) }} - -
        - -It will then match the ``blog_delete`` route. +use this as the method when matching routes. Forms automatically include a +hidden field for this parameter if their submission method is not GET or POST. +See :ref:`the related chapter in the forms documentation` +for more information. diff --git a/cookbook/routing/service_container_parameters.rst b/cookbook/routing/service_container_parameters.rst index 29edf772c1c..39a7e838df9 100644 --- a/cookbook/routing/service_container_parameters.rst +++ b/cookbook/routing/service_container_parameters.rst @@ -4,9 +4,6 @@ How to use Service Container Parameters in your Routes ====================================================== -.. versionadded:: 2.1 - The ability to use parameters in your routes was added in Symfony 2.1. - Sometimes you may find it useful to make some parts of your routes globally configurable. For instance, if you build an internationalized site, you'll probably start with one or two locales. Surely you'll diff --git a/cookbook/security/acl.rst b/cookbook/security/acl.rst index 3d889bd6d74..3f145a4e829 100644 --- a/cookbook/security/acl.rst +++ b/cookbook/security/acl.rst @@ -112,7 +112,7 @@ Creating an ACL, and adding an ACE { $comment = new Comment(); - // ... setup $form, and bind data + // ... setup $form, and submit data if ($form->isValid()) { $entityManager = $this->getDoctrine()->getManager(); diff --git a/cookbook/security/custom_authentication_provider.rst b/cookbook/security/custom_authentication_provider.rst index af15a6b1d37..26e3219c062 100644 --- a/cookbook/security/custom_authentication_provider.rst +++ b/cookbook/security/custom_authentication_provider.rst @@ -430,9 +430,6 @@ to service ids that do not exist yet: ``wsse.security.authentication.provider`` Now that your services are defined, tell your security context about your factory in your bundle class: -.. versionadded:: 2.1 - Before 2.1, the factory below was added via ``security.yml`` instead. - .. code-block:: php // src/Acme/DemoBundle/AcmeDemoBundle.php diff --git a/cookbook/security/custom_provider.rst b/cookbook/security/custom_provider.rst index 6d1dbfc51b2..bf7a1faeefe 100644 --- a/cookbook/security/custom_provider.rst +++ b/cookbook/security/custom_provider.rst @@ -102,10 +102,6 @@ Let's see this in action:: } } -.. versionadded:: 2.1 - The ``EquatableInterface`` was added in Symfony 2.1. Use the ``equals()`` - method of the ``UserInterface`` in Symfony 2.0. - If you have more information about your users - like a "first name" - then you can add a ``firstName`` field to hold that data. diff --git a/cookbook/security/entity_provider.rst b/cookbook/security/entity_provider.rst index 61b27ea4310..8595c0a6260 100644 --- a/cookbook/security/entity_provider.rst +++ b/cookbook/security/entity_provider.rst @@ -185,27 +185,6 @@ interface forces the class to implement the five following methods: For more details on each of these, see :class:`Symfony\\Component\\Security\\Core\\User\\UserInterface`. -.. versionadded:: 2.1 - In Symfony 2.1, the ``equals`` method was removed from ``UserInterface``. - If you need to override the default implementation of comparison logic, - implement the new :class:`Symfony\\Component\\Security\\Core\\User\\EquatableInterface` - interface and implement the ``isEqualTo`` method. - -.. code-block:: php - - // src/Acme/UserBundle/Entity/User.php - - namespace Acme\UserBundle\Entity; - - use Symfony\Component\Security\Core\User\EquatableInterface; - - // ... - - public function isEqualTo(UserInterface $user) - { - return $this->id === $user->getId(); - } - .. note:: The :phpclass:`Serializable` interface and its ``serialize`` and ``unserialize`` diff --git a/cookbook/security/form_login.rst b/cookbook/security/form_login.rst index 6d6290e995c..cc7030d7a2c 100644 --- a/cookbook/security/form_login.rst +++ b/cookbook/security/form_login.rst @@ -180,10 +180,6 @@ this by setting ``use_referer`` to true (it defaults to false): ), )); -.. versionadded:: 2.1 - As of 2.1, if the referer is equal to the ``login_path`` option, the - user will be redirected to the ``default_target_path``. - Control the Redirect URL from inside the Form ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/cookbook/security/securing_services.rst b/cookbook/security/securing_services.rst index d83b33b94cc..958f46d4d80 100644 --- a/cookbook/security/securing_services.rst +++ b/cookbook/security/securing_services.rst @@ -145,8 +145,8 @@ Securing Methods Using Annotations ---------------------------------- You can also secure method calls in any service with annotations by using the -optional `JMSSecurityExtraBundle`_ bundle. This bundle is included in the -Symfony2 Standard Distribution. +optional `JMSSecurityExtraBundle`_ bundle. This bundle is not included in the +Symfony2 Standard Distribution, but you can choose to install it. To enable the annotations functionality, :ref:`tag ` the service you want to secure with the ``security.secure_service`` tag diff --git a/cookbook/serializer.rst b/cookbook/serializer.rst new file mode 100644 index 00000000000..d4e9baeab00 --- /dev/null +++ b/cookbook/serializer.rst @@ -0,0 +1,111 @@ +.. index:: + single: Serializer + +How to use the Serializer +========================= + +Serializing and deserializing to and from objects and different formats (e.g. +JSON or XML) is a very complex topic. Symfony comes with a +:doc:`Serializer Component`, which gives you some +tools that you can leverage for your solution. + +In fact, before you start, get familiar with the serializer, normalizers +and encoders by reading the :doc:`Serializer Component`. +You should also check out the `JMSSerializerBundle`_, which expands on the +functionality offered by Symfony's core serializer. + +Activating the Serializer +------------------------- + +.. versionadded:: 2.3 + The Serializer has always existed in Symfony, but prior to Symfony 2.3, + you needed to build the ``serializer`` service yourself. + +The ``serializer`` service is not available by default. To turn it on, activate +it in your configuration: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + framework: + # ... + serializer: + enabled: true + + .. code-block:: xml + + + + + + + + .. code-block:: php + + // app/config/config.php + $container->loadFromExtension('framework', array( + // ... + 'serializer' => array( + 'enabled' => true + ), + )); + +Adding Normalizers and Encoders +------------------------------- + +Once enabled, the ``serializer`` service will be available in the container +and will be loaded with two :ref:`encoders` +(:class:`Symfony\\Component\\Serializer\\Encoder\\JsonEncoder` and +:class:`Symfony\\Component\\Serializer\\Encoder\\XmlEncoder`) +but no :ref:`normalizers`, meaning you'll +need to load your own. + +You can load normalizers and/or encoders by tagging them as +:ref:`serializer.normalizer` and +:ref:`serializer.encoder`. It's also +possible to set the priority of the tag in order to decide the matching order. + +Here an example on how to load the load +the :class:`Symfony\\Component\\Serializer\\Normalizer\\GetSetMethodNormalizer`: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + services: + get_set_method_normalizer: + class: Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer + tags: + - { name: serializer.normalizer } + + .. code-block:: xml + + + + + + + + + .. code-block:: php + + // app/config/config.php + use Symfony\Component\DependencyInjection\Definition; + + $definition = new Definition( + 'Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer' + )); + $definition->addTag('serializer.normalizer'); + $container->setDefinition('get_set_method_normalizer', $definition); + +.. note:: + + The :class:`Symfony\\Component\\Serializer\\Normalizer\\GetSetMethodNormalizer` + is broken by design. As soon as you have a circular object graph, an + infinite loop is created when calling the getters. You're encouraged + to add your own normalizers that fit your use-case. + +.. _JMSSerializerBundle: http://jmsyst.com/bundles/JMSSerializerBundle \ No newline at end of file diff --git a/cookbook/service_container/scopes.rst b/cookbook/service_container/scopes.rst index aee6710636f..f305a97837d 100644 --- a/cookbook/service_container/scopes.rst +++ b/cookbook/service_container/scopes.rst @@ -6,8 +6,13 @@ How to work with Scopes This entry is all about scopes, a somewhat advanced topic related to the :doc:`/book/service_container`. If you've ever gotten an error mentioning -"scopes" when creating services, or need to create a service that depends -on the ``request`` service, then this entry is for you. +"scopes" when creating services, then this entry is for you. + +.. note:: + + If you are trying to inject the ``request`` service, the simple solution + is to inject the ``request_stack`` service instead and access the current + Request by calling the ``getCurrentRequest()`` method. Understanding Scopes -------------------- @@ -21,13 +26,15 @@ scopes: - ``prototype``: A new instance is created each time you request the service. -The FrameworkBundle also defines a third scope: ``request``. This scope is -tied to the request, meaning a new instance is created for each subrequest -and is unavailable outside the request (for instance in the CLI). +The +:class:`Symfony\\Component\\HttpKernel\\DependencyInjection\\ContainerAwareHttpKernel` +also defines a third scope: ``request``. This scope is tied to the request, +meaning a new instance is created for each subrequest and is unavailable +outside the request (for instance in the CLI). Scopes add a constraint on the dependencies of a service: a service cannot depend on services from a narrower scope. For example, if you create a generic -``my_foo`` service, but try to inject the ``request`` component, you'll receive +``my_foo`` service, but try to inject the ``request`` service, you will receive a :class:`Symfony\\Component\\DependencyInjection\\Exception\\ScopeWideningInjectionException` when compiling the container. Read the sidebar below for more details. @@ -69,10 +76,76 @@ when compiling the container. Read the sidebar below for more details. A service can of course depend on a service from a wider scope without any issue. -Setting the Scope in the Definition ------------------------------------ +Using a Service from a narrower Scope +------------------------------------- + +The most common problem with "scope" is when your service has a dependency +on the ``request`` service. The *easiest* way to solve this is to instead +inject the ``request_stack`` service and access the current Request by calling +the ``getCurrentRequest()`` method. + +This solution is great, but there are also others: + +* Use setter injection if the dependency is "synchronized"; (see + :ref:`using-synchronized-service`). + +* Put your service in the same scope as the dependency (or a narrower one). If + you depend on the ``request`` service, this means putting your new service + in the ``request`` scope (see :ref:`changing-service-scope`); + +* Pass the entire container to your service and retrieve your dependency from + the container each time you need it to be sure you have the right instance + -- your service can live in the default ``container`` scope (see + :ref:`passing-container`); + +Each scenario is detailed in the following sections. + +.. _using-synchronized-service: + +Using a synchronized Service +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.3 + Synchronized services are new in Symfony 2.3. + +Injecting the container or setting your service to a narrower scope have +drawbacks. For synchronized services (like the ``request``), using setter +injection is a nice option as it has no drawbacks and everything works +without any special code in your service or in your definition:: + + // src/Acme/HelloBundle/Mail/Mailer.php + namespace Acme\HelloBundle\Mail; + + use Symfony\Component\HttpFoundation\Request; -The scope of a service is set in the definition of the service: + class Mailer + { + protected $request; + + public function setRequest(Request $request = null) + { + $this->request = $request; + } + + public function sendEmail() + { + if (null === $this->request) { + // throw an error? + } + + // ... do something using the request here + } + } + +Whenever the ``request`` scope is entered or left, the service container will +automatically call the ``setRequest()`` method with the current ``request`` +instance. + +You might have noticed that the ``setRequest()`` method accepts ``null`` as a +valid value for the ``request`` argument. That's because when leaving the +``request`` scope, the ``request`` instance can be ``null`` (for the master +request for instance). Of course, you should take care of this possibility in +your code. This should also be taken into account when declaring your service: .. configuration-block:: @@ -82,42 +155,118 @@ The scope of a service is set in the definition of the service: services: greeting_card_manager: class: Acme\HelloBundle\Mail\GreetingCardManager - scope: request + calls: + - [setRequest, ['@?request=']] .. code-block:: xml - + + + + + .. code-block:: php // src/Acme/HelloBundle/Resources/config/services.php use Symfony\Component\DependencyInjection\Definition; + use Symfony\Component\DependencyInjection\ContainerInterface; - $container->setDefinition( + $definition = $container->setDefinition( 'greeting_card_manager', new Definition('Acme\HelloBundle\Mail\GreetingCardManager') - )->setScope('request'); + ) + ->addMethodCall('setRequest', array( + new Reference('request', ContainerInterface::NULL_ON_INVALID_REFERENCE, false) + )); -If you don't specify the scope, it defaults to ``container``, which is what -you want most of the time. Unless your service depends on another service -that's scoped to a narrower scope (most commonly, the ``request`` service), -you probably don't need to set the scope. +.. tip:: -Using a Service from a narrower Scope -------------------------------------- + You can declare your own ``synchronized`` services very easily; here is + the declaration of the ``request`` service for reference: + + .. configuration-block:: + + .. code-block:: yaml + + services: + request: + scope: request + synthetic: true + synchronized: true + + .. code-block:: xml + + + + + + .. code-block:: php + + use Symfony\Component\DependencyInjection\Definition; + use Symfony\Component\DependencyInjection\ContainerInterface; + + $definition = $container->setDefinition('request') + ->setScope('request') + ->setSynthetic(true) + ->setSynchronized(true); + +.. _changing-service-scope: + +Changing the Scope of your Service +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Changing the scope of a service should be done in its definition: + +.. configuration-block:: + + .. code-block:: yaml + + # src/Acme/HelloBundle/Resources/config/services.yml + services: + greeting_card_manager: + class: Acme\HelloBundle\Mail\GreetingCardManager + scope: request + arguments: [@request] + + .. code-block:: xml -If your service depends on a scoped service, the best solution is to put -it in the same scope (or a narrower one). Usually, this means putting your -new service in the ``request`` scope. + + + + + -But this is not always possible (for instance, a twig extension must be in -the ``container`` scope as the Twig environment needs it as a dependency). -In these cases, you should pass the entire container into your service and -retrieve your dependency from the container each time you need it to be sure -you have the right instance:: + .. code-block:: php + + // src/Acme/HelloBundle/Resources/config/services.php + use Symfony\Component\DependencyInjection\Definition; + + $definition = $container->setDefinition( + 'greeting_card_manager', + new Definition( + 'Acme\HelloBundle\Mail\GreetingCardManager', + array(new Reference('request'), + )) + )->setScope('request'); + +.. _passing-container: + +Passing the Container as a Dependency of your Service +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Setting the scope to a narrower one is not always possible (for instance, a +twig extension must be in the ``container`` scope as the Twig environment +needs it as a dependency). In these cases, you can pass the entire container +into your service:: // src/Acme/HelloBundle/Mail/Mailer.php namespace Acme\HelloBundle\Mail; @@ -160,8 +309,7 @@ The service config for this class would look something like this: services: my_mailer: class: "%my_mailer.class%" - arguments: - - "@service_container" + arguments: ["@service_container"] # scope: container can be omitted as it is the default .. code-block:: xml @@ -195,10 +343,4 @@ The service config for this class would look something like this: .. note:: Injecting the whole container into a service is generally not a good - idea (only inject what you need). In some rare cases, it's necessary - when you have a service in the ``container`` scope that needs a service - in the ``request`` scope. - -If you define a controller as a service then you can get the ``Request`` object -without injecting the container by having it passed in as an argument of your -action method. See :ref:`book-controller-request-argument` for details. + idea (only inject what you need). diff --git a/cookbook/session/index.rst b/cookbook/session/index.rst index f0b0df2514c..536ad02c3d8 100644 --- a/cookbook/session/index.rst +++ b/cookbook/session/index.rst @@ -7,3 +7,4 @@ Sessions proxy_examples locale_sticky_session sessions_directory + php_bridge \ No newline at end of file diff --git a/cookbook/session/php_bridge.rst b/cookbook/session/php_bridge.rst new file mode 100644 index 00000000000..fefdd26e73f --- /dev/null +++ b/cookbook/session/php_bridge.rst @@ -0,0 +1,47 @@ +.. index:: + single: Sessions + +Bridge a legacy application with Symfony Sessions +================================================= + +.. versionadded:: 2.3 + The ability to integrate with a legacy PHP session was added in Symfony 2.3. + +If you're integrating the Symfony full-stack Framework into a legacy application +that starts the session with ``session_start()``, you may still be able to +use Symfony's session management by using the PHP Bridge session. + +If the application has sets it's own PHP save handler, you can specify null +for the ``handler_id``: + +.. code-block:: yaml + + framework: + session: + storage_id: session.storage.php_bridge + handler_id: ~ + +Otherwise, if the problem is simply that you cannot avoid the application +starting the session with ``session_start()``, you can still make use of +a Symfony based session save handler by specifying the save handler as in +the example below: + +.. code-block:: yaml + + framework: + session: + storage_id: session.storage.php_bridge + handler_id: session.handler.native_file + +.. note:: + + If the legacy application requires its own session save-handler, do not + override this. Instead set ``handler_id: ~``. Note that a save handler + cannot be changed once the session has been started. If the application + starts the session before Symfony is initialized, the save-handler will + have already been set. In this case, you will need ``handler_id: ~``. + Only override the save-handler if you are sure the legacy application + can use the Symfony save-handler without side effects and that the session + has not been started before Symfony is initialized. + +For more details, see :doc:`/components/http_foundation/session_php_bridge`. diff --git a/cookbook/templating/PHP.rst b/cookbook/templating/PHP.rst index a3454abbb29..3db2f9b23fb 100644 --- a/cookbook/templating/PHP.rst +++ b/cookbook/templating/PHP.rst @@ -310,6 +310,21 @@ portable. Thanks to this helper, you can move the application root directory anywhere under your web root directory without changing anything in your template's code. +Profiling Templates +~~~~~~~~~~~~~~~~~~~ + +By using the ``stopwatch`` helper, you are able to time parts of your template +and display it on the timeline of the WebProfilerBundle:: + + start('foo') ?> + ... things that get timed + stop('foo') ?> + +.. tip:: + + If you use the same name more than once in your template, the times are + grouped on the same line in the timeline. + Output Escaping --------------- diff --git a/cookbook/validation/custom_constraint.rst b/cookbook/validation/custom_constraint.rst index 9d76e0d3f42..6cb2f45f581 100644 --- a/cookbook/validation/custom_constraint.rst +++ b/cookbook/validation/custom_constraint.rst @@ -79,11 +79,6 @@ The validator class is also simple, and only has one required method ``validate( The first parameter of the ``addViolation`` call is the error message to use for that violation. -.. versionadded:: 2.1 - The ``isValid`` method was renamed to ``validate`` in Symfony 2.1. The - ``setMessage`` method was also deprecated, in favor of calling ``addViolation`` - on the context. - Using the new Validator ----------------------- diff --git a/images/components/console/table.png b/images/components/console/table.png new file mode 100644 index 00000000000..ba1e3ae79b9 Binary files /dev/null and b/images/components/console/table.png differ diff --git a/quick_tour/the_architecture.rst b/quick_tour/the_architecture.rst index bce41d873a8..7b19f5dc2aa 100644 --- a/quick_tour/the_architecture.rst +++ b/quick_tour/the_architecture.rst @@ -105,7 +105,6 @@ a single ``Bundle`` class that describes it:: new Symfony\Bundle\DoctrineBundle\DoctrineBundle(), new Symfony\Bundle\AsseticBundle\AsseticBundle(), new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), - new JMS\SecurityExtraBundle\JMSSecurityExtraBundle(), ); if (in_array($this->getEnvironment(), array('dev', 'test'))) { diff --git a/quick_tour/the_big_picture.rst b/quick_tour/the_big_picture.rst index c29318cae92..9ba1161c7a6 100644 --- a/quick_tour/the_big_picture.rst +++ b/quick_tour/the_big_picture.rst @@ -62,11 +62,11 @@ have a ``Symfony/`` directory that looks like this: If you are familiar with `Composer`_, you can download Composer and then run the following command instead of downloading the archive (replacing - ``2.2.0`` with the latest Symfony release like ``2.2.1``): + ``2.3.0`` with the latest Symfony release like ``2.3.1``): .. code-block:: bash - $ php composer.phar create-project symfony/framework-standard-edition Symfony 2.2.0 + $ php composer.phar create-project symfony/framework-standard-edition Symfony 2.3.0 .. _`quick-tour-big-picture-built-in-server`: @@ -177,11 +177,22 @@ these paths (called routes) are defined in the ``app/config/routing.yml`` config file. When you're in the ``dev`` :ref:`environment` - indicated by the app_**dev**.php front controller - the ``app/config/routing_dev.yml`` configuration file is also loaded. In the Standard Edition, the routes to -these "demo" pages are placed in that file: +these "demo" pages are imported from this file: .. code-block:: yaml # app/config/routing_dev.yml + # ... + + # AcmeDemoBundle routes (to be removed) + _acme_demo: + resource: "@AcmeDemoBundle/Resources/config/routing.yml" + +This imports a ``routing.yml`` file that lives inside the AcmeDemoBundle: + +.. code-block:: yaml + + # src/Acme/DemoBundle/Resources/config/routing.yml _welcome: path: / defaults: { _controller: AcmeDemoBundle:Welcome:index } @@ -292,7 +303,8 @@ key: .. code-block:: yaml - # app/config/routing_dev.yml + # src/Acme/DemoBundle/Resources/config/routing.yml + # ... _demo: resource: "@AcmeDemoBundle/Controller/DemoController.php" type: annotation diff --git a/quick_tour/the_controller.rst b/quick_tour/the_controller.rst index 51a160204be..e1d840c0d1d 100755 --- a/quick_tour/the_controller.rst +++ b/quick_tour/the_controller.rst @@ -207,28 +207,6 @@ Going to the ``http://localhost/app_dev.php/demo/secured/hello`` URL will automatically redirect you to the login form because this resource is protected by a ``firewall``. -You can also force the action to require a given role by using the ``@Secure`` -annotation on the controller:: - - use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; - use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; - use JMS\SecurityExtraBundle\Annotation\Secure; - - /** - * @Route("/hello/admin/{name}", name="_demo_secured_hello_admin") - * @Secure(roles="ROLE_ADMIN") - * @Template() - */ - public function helloAdminAction($name) - { - return array('name' => $name); - } - -Now, log in as ``user`` (who does *not* have the ``ROLE_ADMIN`` role) and -from the secured hello page, click on the "Hello resource secured" link. -Symfony2 should return a 403 HTTP status code, indicating that the user -is "forbidden" from accessing that resource. - .. note:: The Symfony2 security layer is very flexible and comes with many different diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index b9187691f2f..05d707e370d 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -16,9 +16,9 @@ Configuration ------------- * `secret`_ +* `http_method_override`_ * `ide`_ * `test`_ -* `trust_proxy_headers`_ * `trusted_proxies`_ * `form`_ * enabled @@ -36,11 +36,14 @@ Configuration * `gc_probability`_ * `gc_maxlifetime`_ * `save_path`_ +* `serializer`_ + * :ref:`enabled` * `templating`_ * `assets_base_urls`_ * `assets_version`_ * `assets_version_format`_ * `profiler`_ + * `collect`_ * :ref:`enabled ` secret @@ -53,6 +56,23 @@ it's used for generating the CSRF tokens, but it could be used in any other context where having a unique string is useful. It becomes the service container parameter named ``kernel.secret``. +.. _configuration-framework-http_method_override: + +http_method_override +~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.3 + The ``http_method_override`` option is new in Symfony 2.3. + +**type**: ``Boolean`` **default**: ``true`` + +This determines whether the ``_method`` request parameter is used as the intended +HTTP method on POST requests. If enabled, the +:method:`Request::enableHttpMethodParameterOverride ` +gets called automatically. It becomes the service container parameter named +``kernel.http_method_override``. For more information, see +:doc:`/cookbook/routing/method_parameters`. + ide ~~~ @@ -104,42 +124,29 @@ trusted_proxies Configures the IP addresses that should be trusted as proxies. For more details, see :doc:`/components/http_foundation/trusting_proxies`. +.. versionadded:: 2.3 + CIDR notation support was introduced, so you can whitelist whole + subnets (e.g. ``10.0.0.0/8``, ``fc00::/7``). + .. configuration-block:: .. code-block:: yaml framework: - trusted_proxies: [192.0.0.1] + trusted_proxies: [192.0.0.1, 10.0.0.0/8] .. code-block:: xml - + .. code-block:: php $container->loadFromExtension('framework', array( - 'trusted_proxies' => array('192.0.0.1'), + 'trusted_proxies' => array('192.0.0.1', '10.0.0.0/8'), )); -trust_proxy_headers -~~~~~~~~~~~~~~~~~~~ - -.. caution:: - - The ``trust_proxy_headers`` option is deprecated and will be removed in - Symfony 2.3. See `trusted_proxies`_ and :doc:`/components/http_foundation/trusting_proxies` - for details on how to properly trust proxy data. - -**type**: ``Boolean`` - -Configures if HTTP headers (like ``HTTP_X_FORWARDED_FOR``, ``X_FORWARDED_PROTO``, and -``X_FORWARDED_HOST``) are trusted as an indication for an SSL connection. By default, it is -set to ``false`` and only SSL_HTTPS connections are indicated as secure. - -You should enable this setting if your application is behind a reverse proxy. - .. _reference-framework-form: form @@ -162,9 +169,6 @@ name which is defined in the ``php.ini`` with the ``session.name`` directive. cookie_lifetime ............... -.. versionadded:: 2.1 - This option was formerly known as ``lifetime`` - **type**: ``integer`` **default**: ``0`` This determines the lifetime of the session - in seconds. By default it will use @@ -173,9 +177,6 @@ This determines the lifetime of the session - in seconds. By default it will use cookie_path ........... -.. versionadded:: 2.1 - This option was formerly known as ``path`` - **type**: ``string`` **default**: ``/`` This determines the path to set in the session cookie. By default it will use ``/``. @@ -183,9 +184,6 @@ This determines the path to set in the session cookie. By default it will use `` cookie_domain ............. -.. versionadded:: 2.1 - This option was formerly known as ``domain`` - **type**: ``string`` **default**: ``''`` This determines the domain to set in the session cookie. By default it's blank, @@ -195,9 +193,6 @@ to the cookie specification. cookie_secure ............. -.. versionadded:: 2.1 - This option was formerly known as ``secure`` - **type**: ``Boolean`` **default**: ``false`` This determines whether cookies should only be sent over secure connections. @@ -205,9 +200,6 @@ This determines whether cookies should only be sent over secure connections. cookie_httponly ............... -.. versionadded:: 2.1 - This option was formerly known as ``httponly`` - **type**: ``Boolean`` **default**: ``false`` This determines whether cookies should only accessible through the HTTP protocol. @@ -218,9 +210,6 @@ through XSS attacks. gc_probability .............. -.. versionadded:: 2.1 - The ``gc_probability`` option is new in version 2.1 - **type**: ``integer`` **default**: ``1`` This defines the probability that the garbage collector (GC) process is started @@ -231,9 +220,6 @@ that the GC process will start on each request. gc_divisor .......... -.. versionadded:: 2.1 - The ``gc_divisor`` option is new in version 2.1 - **type**: ``integer`` **default**: ``100`` See `gc_probability`_. @@ -241,9 +227,6 @@ See `gc_probability`_. gc_maxlifetime .............. -.. versionadded:: 2.1 - The ``gc_maxlifetime`` option is new in version 2.1 - **type**: ``integer`` **default**: ``1440`` This determines the number of seconds after which data will be seen as "garbage" @@ -287,6 +270,22 @@ the value to ``null``: ), )); +.. _configuration-framework-serializer: + +serializer +~~~~~~~~~~ + +.. _serializer.enabled: + +enabled +....... + +**type**: ``boolean`` **default**: ``false`` + +Whether to enable the ``serializer`` service or not in the service container. + +For more details, see :doc:`/cookbook/serializer`. + templating ~~~~~~~~~~ @@ -307,15 +306,6 @@ is `protocol-relative`_ (i.e. starts with `//`) it will be added to both collections. URLs starting with ``http://`` will only be added to the ``http`` collection. -.. versionadded:: 2.1 - Unlike most configuration blocks, successive values for ``assets_base_urls`` - will overwrite each other instead of being merged. This behavior was chosen - because developers will typically define base URL's for each environment. - Given that most projects tend to inherit configurations - (e.g. ``config_test.yml`` imports ``config_dev.yml``) and/or share a common - base configuration (i.e. ``config.yml``), merging could yield a set of base - URL's for multiple environments. - .. _ref-framework-assets-version: assets_version @@ -427,8 +417,25 @@ enabled **default**: ``true`` in the ``dev`` and ``test`` environments -The profiler can be disabled by setting this key to ``false``. In reality, -the profiler still exists, but the data collectors are not activated. +The profiler can be disabled by setting this key to ``false``. + +.. versionadded:: 2.3 + + The ``collect`` option is new in Symfony 2.3. Previously, when ``profiler.enabled`` + was false, the profiler *was* actually enabled, but the collectors were + disabled. Now the profiler and collectors can be controller independently. + +collect +....... + +**default**: ``true`` + +This option configures the way the profiler behaves when it is enabled. If set +to ``true``, the profiler collects data for all requests. If you want to only +collect information on-demand, you can set the ``collect`` flag to ``false`` +and activate the data collectors by hand:: + + $profiler->enable(); Full Default Configuration -------------------------- @@ -438,9 +445,8 @@ Full Default Configuration .. code-block:: yaml framework: - charset: ~ secret: ~ - trust_proxy_headers: false + http_method_override: true trusted_proxies: [] ide: ~ test: ~ @@ -465,8 +471,9 @@ Full Default Configuration # profiler configuration profiler: enabled: false + collect: true only_exceptions: false - only_master_requests: false + only_master_requests: false dsn: file:%kernel.cache_dir%/profiler username: password: @@ -493,8 +500,6 @@ Full Default Configuration # session configuration session: - # DEPRECATED! Session starts on demand - auto_start: false storage_id: session.storage.native handler_id: session.handler.native_file name: ~ @@ -508,20 +513,9 @@ Full Default Configuration gc_maxlifetime: ~ save_path: %kernel.cache_dir%/sessions - # DEPRECATED! Please use: cookie_lifetime - lifetime: ~ - - # DEPRECATED! Please use: cookie_path - path: ~ - - # DEPRECATED! Please use: cookie_domain - domain: ~ - - # DEPRECATED! Please use: cookie_secure - secure: ~ - - # DEPRECATED! Please use: cookie_httponly - httponly: ~ + # serializer configuration + serializer: + enabled: false # templating configuration templating: @@ -570,9 +564,4 @@ Full Default Configuration file_cache_dir: %kernel.cache_dir%/annotations debug: %kernel.debug% - -.. versionadded:: 2.1 - The ```framework.session.auto_start`` setting has been removed in Symfony2.1, - it will start on demand now. - .. _`protocol-relative`: http://tools.ietf.org/html/rfc3986#section-4.2 diff --git a/reference/configuration/kernel.rst b/reference/configuration/kernel.rst index 24566753ebb..2a8544aff22 100644 --- a/reference/configuration/kernel.rst +++ b/reference/configuration/kernel.rst @@ -17,10 +17,6 @@ Configuration * `Cache Directory`_ * `Log Directory`_ -.. versionadded:: 2.1 - The :method:`Symfony\\Component\\HttpKernel\\Kernel::getCharset` method is new - in Symfony 2.1 - Charset ~~~~~~~ diff --git a/reference/configuration/monolog.rst b/reference/configuration/monolog.rst index 69cb053dca3..a41f120115c 100644 --- a/reference/configuration/monolog.rst +++ b/reference/configuration/monolog.rst @@ -52,6 +52,7 @@ Monolog Configuration Reference from_email: ~ to_email: ~ subject: ~ + mailer: ~ email_prototype: id: ~ # Required (when the email_prototype is used) method: ~ diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index dc41ad19f6a..dce75e06451 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -148,6 +148,12 @@ Each part will be explained in the next section. # by default, the login form *must* be a POST, not a GET post_only: true remember_me: false + + # by default, a session must exist before submitting an authentication request + # if false, then Request::hasPreviousSession is not called during authentication + # new in Symfony 2.3 + require_previous_session: true + remember_me: token_provider: name key: someS3cretKey @@ -298,6 +304,11 @@ for the hash algorithm. Using the BCrypt Password Encoder --------------------------------- +.. caution:: + + To use this encoder, you either need to use PHP Version 5.5 or install + the `ircmaxell/password-compat`_ library via Composer. + .. versionadded:: 2.2 The BCrypt password encoder was added in Symfony 2.2. @@ -462,3 +473,4 @@ To use HTTP-Digest authentication you need to provide a realm and a key: )); .. _`PBKDF2`: http://en.wikipedia.org/wiki/PBKDF2 +.. _`ircmaxell/password-compat`: https://packagist.org/packages/ircmaxell/password-compat diff --git a/reference/configuration/twig.rst b/reference/configuration/twig.rst index 5977ce092fb..f6f860b5c22 100644 --- a/reference/configuration/twig.rst +++ b/reference/configuration/twig.rst @@ -31,14 +31,19 @@ TwigBundle Configuration Reference # set to service or leave blank type: ~ value: ~ - autoescape: ~ - base_template_class: ~ # Example: Twig_Template - cache: "%kernel.cache_dir%/twig" - charset: "%kernel.charset%" - debug: "%kernel.debug%" - strict_variables: ~ - auto_reload: ~ - optimizations: ~ + autoescape: ~ + + # The following were added in Symfony 2.3. + # See http://twig.sensiolabs.org/doc/recipes.html#using-the-template-name-to-set-the-default-escaping-strategy + autoescape_service: ~ # Example: @my_service + autoescape_service_method: ~ # use in combination with autoescape_service option + base_template_class: ~ # Example: Twig_Template + cache: "%kernel.cache_dir%/twig" + charset: "%kernel.charset%" + debug: "%kernel.debug%" + strict_variables: ~ + auto_reload: ~ + optimizations: ~ .. code-block:: xml diff --git a/reference/constraints.rst b/reference/constraints.rst index 1069b0ea3e0..efbc0e554a6 100644 --- a/reference/constraints.rst +++ b/reference/constraints.rst @@ -14,17 +14,22 @@ Validation Constraints Reference constraints/Type constraints/Email - constraints/MinLength - constraints/MaxLength constraints/Length constraints/Url constraints/Regex constraints/Ip - constraints/Max - constraints/Min constraints/Range + constraints/EqualTo + constraints/NotEqualTo + constraints/IdenticalTo + constraints/NotIdenticalTo + constraints/LessThan + constraints/LessThanOrEqual + constraints/GreaterThan + constraints/GreaterThanOrEqual + constraints/Date constraints/DateTime constraints/Time @@ -41,7 +46,11 @@ Validation Constraints Reference constraints/Image constraints/CardScheme + constraints/Currency constraints/Luhn + constraints/Iban + constraints/Isbn + constraints/Issn constraints/Callback constraints/All diff --git a/reference/constraints/Collection.rst b/reference/constraints/Collection.rst index ae25d16bb87..d0e1a10046c 100644 --- a/reference/constraints/Collection.rst +++ b/reference/constraints/Collection.rst @@ -169,8 +169,9 @@ the above example, the ``allowMissingFields`` option was set to true, meaning that if either of the ``personal_email`` or ``short_bio`` elements were missing from the ``$personalData`` property, no validation error would occur. -.. versionadded:: 2.1 - The ``Required`` and ``Optional`` constraints are new to Symfony 2.1. +.. versionadded:: 2.3 + The ``Required`` and ``Optional`` constraints were moved to the namespace + ``Symfony\Component\Validator\Constraints\`` in Symfony 2.3. Required and Optional Field Constraints ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -213,8 +214,8 @@ field is optional but must be a valid email if supplied, you can do the followin /** * @Assert\Collection( * fields={ - * "personal_email" = @Assert\Collection\Required({@Assert\NotBlank, @Assert\Email}), - * "alternate_email" = @Assert\Collection\Optional({@Assert\Email}), + * "personal_email" = @Assert\Required({@Assert\NotBlank, @Assert\Email}), + * "alternate_email" = @Assert\Optional(@Assert\Email), * } * ) */ @@ -268,8 +269,8 @@ field is optional but must be a valid email if supplied, you can do the followin { $metadata->addPropertyConstraint('profileData', new Assert\Collection(array( 'fields' => array( - 'personal_email' => new Assert\Collection\Required(array(new Assert\NotBlank(), new Assert\Email())), - 'alternate_email' => new Assert\Collection\Optional(array(new Assert\Email())), + 'personal_email' => new Assert\Required(array(new Assert\NotBlank(), new Assert\Email())), + 'alternate_email' => new Assert\Optional(new Assert\Email()), ), ))); } diff --git a/reference/constraints/Count.rst b/reference/constraints/Count.rst index fe37a3e54f7..e527ad49975 100644 --- a/reference/constraints/Count.rst +++ b/reference/constraints/Count.rst @@ -4,9 +4,6 @@ Count Validates that a given collection's (i.e. an array or an object that implements Countable) element count is *between* some minimum and maximum value. -.. versionadded:: 2.1 - The Count constraint was added in Symfony 2.1. - +----------------+---------------------------------------------------------------------+ | Applies to | :ref:`property or method ` | +----------------+---------------------------------------------------------------------+ diff --git a/reference/constraints/Currency.rst b/reference/constraints/Currency.rst new file mode 100644 index 00000000000..3a2a3b1b8cf --- /dev/null +++ b/reference/constraints/Currency.rst @@ -0,0 +1,85 @@ +Currency +======== + +.. versionadded:: 2.3 + This constraint is new in version 2.3. + +Validates that a value is a valid `3-letter ISO 4217`_ currency name. + ++----------------+---------------------------------------------------------------------------+ +| Applies to | :ref:`property or method` | ++----------------+---------------------------------------------------------------------------+ +| Options | - `message`_ | ++----------------+---------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Validator\\Constraints\\Currency` | ++----------------+---------------------------------------------------------------------------+ +| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\CurrencyValidator` | ++----------------+---------------------------------------------------------------------------+ + +Basic Usage +----------- + +If you want to ensure that the ``currency`` property of an ``Order`` is a valid +currency, you could do the following: + +.. configuration-block:: + + .. code-block:: yaml + + # src/EcommerceBundle/Resources/config/validation.yml + Acme\EcommerceBundle\Entity\Order: + properties: + currency: + - Currency: ~ + + .. code-block:: php-annotations + + // src/Acme/EcommerceBundle/Entity/Order.php + namespace Acme\EcommerceBundle\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + /** + * @Assert\Currency + */ + protected $currency; + } + + .. code-block:: xml + + + + + + + + + .. code-block:: php + + // src/Acme/EcommerceBundle/Entity/Order.php + namespace Acme\SocialBundle\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('currency', new Assert\Currency()); + } + } + +Options +------- + +message +~~~~~~~ + +**type**: ``string`` **default**: ``This value is not a valid currency.`` + +This is the message that will be shown if the value is not a valid currency. + +.. _`3-letter ISO 4217`: http://en.wikipedia.org/wiki/ISO_4217 diff --git a/reference/constraints/Email.rst b/reference/constraints/Email.rst index d4be658f92c..ecdb8216b2f 100644 --- a/reference/constraints/Email.rst +++ b/reference/constraints/Email.rst @@ -107,9 +107,6 @@ check the validity of the MX record of the host of the given email. checkHost ~~~~~~~~~ -.. versionadded:: 2.1 - The ``checkHost`` option was added in Symfony 2.1 - **type**: ``Boolean`` **default**: ``false`` If true, then the :phpfunction:`checkdnsrr` PHP function will be used to diff --git a/reference/constraints/EqualTo.rst b/reference/constraints/EqualTo.rst new file mode 100644 index 00000000000..f698223e721 --- /dev/null +++ b/reference/constraints/EqualTo.rst @@ -0,0 +1,100 @@ +EqualTo +======= + +.. versionadded:: 2.3 + This constraint is new in version 2.3. + +Validates that a value is equal to another value, defined in the options. To +force that a value is *not* equal, see :doc:`/reference/constraints/NotEqualTo`. + +.. caution:: + + This constraint compares using ``==``, so ``3`` and ``"3"`` are considered + equal. Use :doc:`/reference/constraints/IdenticalTo` to compare with + ``===``. + ++----------------+-----------------------------------------------------------------------+ +| Applies to | :ref:`property or method` | ++----------------+-----------------------------------------------------------------------+ +| Options | - `value`_ | +| | - `message`_ | ++----------------+-----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Validator\\Constraints\\EqualTo` | ++----------------+-----------------------------------------------------------------------+ +| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\EqualToValidator` | ++----------------+-----------------------------------------------------------------------+ + +Basic Usage +----------- + +If you want to ensure that the ``age`` of a ``Person`` class is equal to +``20``, you could do the following: + +.. configuration-block:: + + .. code-block:: yaml + + # src/SocialBundle/Resources/config/validation.yml + Acme\SocialBundle\Entity\Person: + properties: + age: + - EqualTo: + value: 20 + + .. code-block:: php-annotations + + // src/Acme/SocialBundle/Entity/Person.php + namespace Acme\SocialBundle\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + /** + * @Assert\EqualTo( + * value = 20 + * ) + */ + protected $age; + } + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // src/Acme/SocialBundle/Entity/Person.php + namespace Acme\SocialBundle\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('age', new Assert\EqualTo(array( + 'value' => 20, + ))); + } + } + +Options +------- + +.. include:: /reference/constraints/_comparison-value-option.rst.inc + +message +~~~~~~~ + +**type**: ``string`` **default**: ``This value should be equal to {{ compared_value }}`` + +This is the message that will be shown if the value is not equal. diff --git a/reference/constraints/GreaterThan.rst b/reference/constraints/GreaterThan.rst new file mode 100644 index 00000000000..b3f4f42df79 --- /dev/null +++ b/reference/constraints/GreaterThan.rst @@ -0,0 +1,97 @@ +GreaterThan +=========== + +.. versionadded:: 2.3 + This constraint is new in version 2.3. + +Validates that a value is greater than another value, defined in the options. To +force that a value is greater than or equal to another value, see +:doc:`/reference/constraints/GreaterThanOrEqual`. To force a value is less +than another value, see :doc:`/reference/constraints/LessThan`. + ++----------------+---------------------------------------------------------------------------+ +| Applies to | :ref:`property or method` | ++----------------+---------------------------------------------------------------------------+ +| Options | - `value`_ | +| | - `message`_ | ++----------------+---------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Validator\\Constraints\\GreaterThan` | ++----------------+---------------------------------------------------------------------------+ +| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\GreaterThanValidator` | ++----------------+---------------------------------------------------------------------------+ + +Basic Usage +----------- + +If you want to ensure that the ``age`` of a ``Person`` class is greater than +``18``, you could do the following: + +.. configuration-block:: + + .. code-block:: yaml + + # src/SocialBundle/Resources/config/validation.yml + Acme\SocialBundle\Entity\Person: + properties: + age: + - GreaterThan: + value: 18 + + .. code-block:: php-annotations + + // src/Acme/SocialBundle/Entity/Person.php + namespace Acme\SocialBundle\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + /** + * @Assert\GreaterThan( + * value = 18 + * ) + */ + protected $age; + } + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // src/Acme/SocialBundle/Entity/Person.php + namespace Acme\SocialBundle\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('age', new Assert\GreaterThan(array( + 'value' => 18, + ))); + } + } + +Options +------- + +.. include:: /reference/constraints/_comparison-value-option.rst.inc + +message +~~~~~~~ + +**type**: ``string`` **default**: ``This value should be greater than {{ compared_value }}`` + +This is the message that will be shown if the value is not greather than the +comparison value. diff --git a/reference/constraints/GreaterThanOrEqual.rst b/reference/constraints/GreaterThanOrEqual.rst new file mode 100644 index 00000000000..cb71925f8e4 --- /dev/null +++ b/reference/constraints/GreaterThanOrEqual.rst @@ -0,0 +1,96 @@ +GreaterThanOrEqual +================== + +.. versionadded:: 2.3 + This constraint is new in version 2.3. + +Validates that a value is greater than or equal to another value, defined in +the options. To force that a value is greater than another value, see +:doc:`/reference/constraints/GreaterThan`. + ++----------------+----------------------------------------------------------------------------------+ +| Applies to | :ref:`property or method` | ++----------------+----------------------------------------------------------------------------------+ +| Options | - `value`_ | +| | - `message`_ | ++----------------+----------------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Validator\\Constraints\\GreaterThanOrEqual` | ++----------------+----------------------------------------------------------------------------------+ +| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\GreaterThanOrEqualValidator` | ++----------------+----------------------------------------------------------------------------------+ + +Basic Usage +----------- + +If you want to ensure that the ``age`` of a ``Person`` class is greater than +or equal to ``18``, you could do the following: + +.. configuration-block:: + + .. code-block:: yaml + + # src/SocialBundle/Resources/config/validation.yml + Acme\SocialBundle\Entity\Person: + properties: + age: + - GreaterThanOrEqual: + value: 18 + + .. code-block:: php-annotations + + // src/Acme/SocialBundle/Entity/Person.php + namespace Acme\SocialBundle\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + /** + * @Assert\GreaterThanOrEqual( + * value = 18 + * ) + */ + protected $age; + } + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // src/Acme/SocialBundle/Entity/Person.php + namespace Acme\SocialBundle\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('age', new Assert\GreaterThanOrEqual(array( + 'value' => 18, + ))); + } + } + +Options +------- + +.. include:: /reference/constraints/_comparison-value-option.rst.inc + +message +~~~~~~~ + +**type**: ``string`` **default**: ``This value should be greater than or equal to {{ compared_value }}`` + +This is the message that will be shown if the value is not greater than or equal +to the comparison value. diff --git a/reference/constraints/Iban.rst b/reference/constraints/Iban.rst new file mode 100644 index 00000000000..9f52ee766e6 --- /dev/null +++ b/reference/constraints/Iban.rst @@ -0,0 +1,95 @@ +Iban +==== + +.. versionadded:: 2.3 + The Iban constraint was added in Symfony 2.3. + +This constraint is used to ensure that a bank account number has the proper format of +an `International Bank Account Number (IBAN)`_. IBAN is an internationally agreed means +of identifying bank accounts across national borders with a reduced risk of propagating +transcription errors. + ++----------------+-----------------------------------------------------------------------+ +| Applies to | :ref:`property or method` | ++----------------+-----------------------------------------------------------------------+ +| Options | - `message`_ | ++----------------+-----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Validator\\Constraints\\Iban` | ++----------------+-----------------------------------------------------------------------+ +| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\IbanValidator` | ++----------------+-----------------------------------------------------------------------+ + +Basic Usage +----------- + +To use the Iban validator, simply apply it to a property on an object that +will contain an International Bank Account Number. + +.. configuration-block:: + + .. code-block:: yaml + + # src/Acme/SubscriptionBundle/Resources/config/validation.yml + Acme\SubscriptionBundle\Entity\Transaction: + properties: + bankAccountNumber: + - Iban: + message: This is not a valid International Bank Account Number (IBAN). + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php-annotations + + // src/Acme/SubscriptionBundle/Entity/Transaction.php + namespace Acme\SubscriptionBundle\Entity\Transaction; + + use Symfony\Component\Validator\Constraints as Assert; + + class Transaction + { + /** + * @Assert\Iban(message = "This is not a valid International Bank Account Number (IBAN).") + */ + protected $bankAccountNumber; + } + + .. code-block:: php + + // src/Acme/SubscriptionBundle/Entity/Transaction.php + namespace Acme\SubscriptionBundle\Entity\Transaction; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Transaction + { + protected $bankAccountNumber; + + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('bankAccountNumber', new Assert\Iban(array( + 'message' => 'This is not a valid International Bank Account Number (IBAN).', + ))); + } + } + +Available Options +----------------- + +message +~~~~~~~ + +**type**: ``string`` **default**: ``This is not a valid International Bank Account Number (IBAN).`` + +The default message supplied when the value does not pass the Iban check. + +.. _`International Bank Account Number (IBAN)`: http://en.wikipedia.org/wiki/International_Bank_Account_Number diff --git a/reference/constraints/IdenticalTo.rst b/reference/constraints/IdenticalTo.rst new file mode 100644 index 00000000000..9c9dbaba783 --- /dev/null +++ b/reference/constraints/IdenticalTo.rst @@ -0,0 +1,101 @@ +IdenticalTo +=========== + +.. versionadded:: 2.3 + This constraint is new in version 2.3. + +Validates that a value is identical to another value, defined in the options. +To force that a value is *not* identical, see +:doc:`/reference/constraints/NotIdenticalTo`. + +.. caution:: + + This constraint compares using ``===``, so ``3`` and ``"3"`` are *not* + considered equal. Use :doc:`/reference/constraints/EqualTo` to compare + with ``==``. + ++----------------+--------------------------------------------------------------------------+ +| Applies to | :ref:`property or method` | ++----------------+--------------------------------------------------------------------------+ +| Options | - `value`_ | +| | - `message`_ | ++----------------+--------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Validator\\Constraints\\IdenticalTo` | ++----------------+--------------------------------------------------------------------------+ +| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\IdenticalToValidator`| ++----------------+--------------------------------------------------------------------------+ + +Basic Usage +----------- + +If you want to ensure that the ``age`` of a ``Person`` class is equal to +``20`` and an integer, you could do the following: + +.. configuration-block:: + + .. code-block:: yaml + + # src/SocialBundle/Resources/config/validation.yml + Acme\SocialBundle\Entity\Person: + properties: + age: + - IdenticalTo: + value: 20 + + .. code-block:: php-annotations + + // src/Acme/SocialBundle/Entity/Person.php + namespace Acme\SocialBundle\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + /** + * @Assert\IdenticalTo( + * value = 20 + * ) + */ + protected $age; + } + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // src/Acme/SocialBundle/Entity/Person.php + namespace Acme\SocialBundle\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('age', new Assert\IdenticalTo(array( + 'value' => 20, + ))); + } + } + +Options +------- + +.. include:: /reference/constraints/_comparison-value-option.rst.inc + +message +~~~~~~~ + +**type**: ``string`` **default**: ``This value should be identical to {{ compared_value_type }} {{ compared_value }}`` + +This is the message that will be shown if the value is not identical. diff --git a/reference/constraints/Image.rst b/reference/constraints/Image.rst index 844bfc35c4c..e450acd8f0c 100644 --- a/reference/constraints/Image.rst +++ b/reference/constraints/Image.rst @@ -5,8 +5,13 @@ The Image constraint works exactly like the :doc:`File ` constraint for the bulk of the documentation on this constraint. @@ -19,12 +24,22 @@ the documentation on this constraint. | | - `maxWidth`_ | | | - `maxHeight`_ | | | - `minHeight`_ | +| | - `maxRatio`_ | +| | - `minRatio`_ | +| | - `allowSquare`_ | +| | - `allowLandscape`_ | +| | - `allowPortrait`_ | | | - `mimeTypesMessage`_ | | | - `sizeNotDetectedMessage`_ | | | - `maxWidthMessage`_ | | | - `minWidthMessage`_ | | | - `maxHeightMessage`_ | | | - `minHeightMessage`_ | +| | - `maxRatioMessage`_ | +| | - `minRatioMessage`_ | +| | - `allowSquareMessage`_ | +| | - `allowLandscapeMessage`_ | +| | - `allowPortraitMessage`_ | | | - See :doc:`File ` for inherited options | +----------------+-----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\File` | @@ -82,6 +97,8 @@ it is between a certain size, add the following: .. code-block:: php-annotations // src/Acme/BlogBundle/Entity/Author.php + namespace Acme\BlogBundle\Entity; + use Symfony\Component\Validator\Constraints as Assert; class Author @@ -120,10 +137,10 @@ it is between a certain size, add the following: .. code-block:: php // src/Acme/BlogBundle/Entity/Author.php - // ... + namespace Acme/BlogBundle/Entity use Symfony\Component\Validator\Mapping\ClassMetadata; - use Symfony\Component\Validator\Constraints\Image; + use Symfony\Component\Validator\Constraints as Assert; class Author { @@ -131,7 +148,7 @@ it is between a certain size, add the following: public static function loadValidatorMetadata(ClassMetadata $metadata) { - $metadata->addPropertyConstraint('headshot', new Image(array( + $metadata->addPropertyConstraint('headshot', new Assert\Image(array( 'minWidth' => 200, 'maxWidth' => 400, 'minHeight' => 200, @@ -143,6 +160,76 @@ it is between a certain size, add the following: The ``headshot`` property is validated to guarantee that it is a real image and that it is between a certain width and height. +You may also want to guarantee the ``headshot`` image to be square. In this +case you can disable portrait and landscape orientations as shown in the +following code: + +.. configuration-block:: + + .. code-block:: yaml + + # src/Acme/BlogBundle/Resources/config/validation.yml + Acme\BlogBundle\Entity\Author + properties: + headshot: + - Image: + allowLandscape: false + allowPortrait: false + + + .. code-block:: php-annotations + + // src/Acme/BlogBundle/Entity/Author.php + namespace Acme\BlogBundle\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + /** + * @Assert\Image( + * allowLandscape = false + * allowPortrait = false + * ) + */ + protected $headshot; + } + + .. code-block:: xml + + + + + + + + + + + + .. code-block:: php + + // src/Acme/BlogBundle/Entity/Author.php + namespace Acme\BlogBundle\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + // ... + + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('headshot', new Assert\Image(array( + 'allowLandscape' => false, + 'allowPortrait' => false, + ))); + } + } + +You can mix all the constraint options to create powerful validation rules. + Options ------- @@ -162,9 +249,6 @@ mimeTypesMessage **type**: ``string`` **default**: ``This file is not a valid image`` -.. versionadded:: 2.1 - All of the min/max width/height options are new to Symfony 2.1. - minWidth ~~~~~~~~ @@ -197,41 +281,124 @@ maxHeight If set, the height of the image file must be less than or equal to this value in pixels. +maxRatio +~~~~~~~~ + +**type**: ``float`` + +If set, the aspect ratio (``width / height``) of the image file must be less +than or equal to this value. + +minRatio +~~~~~~~~ + +**type**: ``float`` + +If set, the aspect ratio (``width / height``) of the image file must be greater +than or equal to this value. + +allowSquare +~~~~~~~~~~~ + +**type**: ``Boolean`` **default**: ``true`` + +If this option is false, the image cannot be a square. If you want to force +a square image, then set leave this option as its default ``true`` value +and set `allowLandscape`_ and `allowPortrait`_ both to ``false``. + +allowLandscape +~~~~~~~~~~~~~~ + +**type**: ``Boolean`` **default**: ``true`` + +If this option is false, the image cannot be landscape oriented. + +allowPortrait +~~~~~~~~~~~~~ + +**type**: ``Boolean`` **default**: ``true`` + +If this option is false, the image cannot be portrait oriented. + sizeNotDetectedMessage ~~~~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``The size of the image could not be detected`` If the system is unable to determine the size of the image, this error will -be displayed. This will only occur when at least one of the four size constraint +be displayed. This will only occur when at least one of the size constraint options has been set. maxWidthMessage ~~~~~~~~~~~~~~~ -**type**: ``string`` **default**: ``The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px`` +**type**: ``string`` **default**: ``The image width is too big ({{ width }}px). +Allowed maximum width is {{ max_width }}px`` The error message if the width of the image exceeds `maxWidth`_. minWidthMessage ~~~~~~~~~~~~~~~ -**type**: ``string`` **default**: ``The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px`` +**type**: ``string`` **default**: ``The image width is too small ({{ width }}px). +Minimum width expected is {{ min_width }}px`` The error message if the width of the image is less than `minWidth`_. maxHeightMessage ~~~~~~~~~~~~~~~~ -**type**: ``string`` **default**: ``The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px`` +**type**: ``string`` **default**: ``The image height is too big ({{ height }}px). +Allowed maximum height is {{ max_height }}px`` The error message if the height of the image exceeds `maxHeight`_. minHeightMessage ~~~~~~~~~~~~~~~~ -**type**: ``string`` **default**: ``The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px`` +**type**: ``string`` **default**: ``The image height is too small ({{ height }}px). +Minimum height expected is {{ min_height }}px`` The error message if the height of the image is less than `minHeight`_. +maxRatioMessage +~~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``The image ratio is too big ({{ ratio }}). +Allowed maximum ratio is {{ max_ratio }}`` + +The error message if the aspect ratio of the image exceeds `maxRatio`_. + +minRatioMessage +~~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``The image ratio is too small ({{ ratio }}). +Minimum ratio expected is {{ min_ratio }}`` + +The error message if the aspect ratio of the image is less than `minRatio`_. + +allowSquareMessage +~~~~~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``The image is square ({{ width }}x{{ height }}px). +Square images are not allowed`` + +The error message if the image is square and you set `allowSquare`_ to ``false``. + +allowLandscapeMessage +~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``The image is landscape oriented ({{ width }}x{{ height }}px). +Landscape oriented images are not allowed`` + +The error message if the image is landscape oriented and you set `allowLandscape`_ to ``false``. + +allowPortraitMessage +~~~~~~~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``The image is portrait oriented ({{ width }}x{{ height }}px). +Portrait oriented images are not allowed`` + +The error message if the image is portrait oriented and you set `allowPortrait`_ to ``false``. + .. _`IANA website`: http://www.iana.org/assignments/media-types/image/index.html diff --git a/reference/constraints/Isbn.rst b/reference/constraints/Isbn.rst new file mode 100644 index 00000000000..48aa7ab9744 --- /dev/null +++ b/reference/constraints/Isbn.rst @@ -0,0 +1,136 @@ +Isbn +==== + +.. versionadded:: 2.3 + The Isbn constraint was added in Symfony 2.3. + +This constraint validates that an ISBN (International Standard Book Numbers) +number is either a valid ISBN-10, a valid ISBN-13 or both. + ++----------------+----------------------------------------------------------------------+ +| Applies to | :ref:`property or method` | ++----------------+----------------------------------------------------------------------+ +| Options | - `isbn10`_ | +| | - `isbn13`_ | +| | - `isbn10Message`_ | +| | - `isbn13Message`_ | +| | - `bothIsbnMessage`_ | ++----------------+----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Validator\\Constraints\\Isbn` | ++----------------+----------------------------------------------------------------------+ +| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\IsbnValidator` | ++----------------+----------------------------------------------------------------------+ + +Basic Usage +----------- + +To use the ``Isbn`` validator, simply apply it to a property or method +on an object that will contain a ISBN number. + +.. configuration-block:: + + .. code-block:: yaml + + # src/Acme/BookcaseBunlde/Resources/config/validation.yml + Acme\BookcaseBunlde\Entity\Book: + properties: + isbn: + - Isbn: + isbn10: true + isbn13: true + bothIsbnMessage: This value is neither a valid ISBN-10 nor a valid ISBN-13. + + .. code-block:: php-annotations + + // src/Acme/BookcaseBunlde/Entity/Book.php + use Symfony\Component\Validator\Constraints as Assert; + + class Book + { + /** + * @Assert\Isbn( + * isbn10 = true, + * isbn13 = true, + * bothIsbnMessage = "This value is neither a valid ISBN-10 nor a valid ISBN-13." + * ) + */ + protected $isbn; + } + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // src/Acme/BookcaseBunlde/Entity/Book.php + namespace Acme\BookcaseBunlde\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Book + { + protected $isbn; + + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('isbn', new Assert\Isbn(array( + 'isbn10' => true, + 'isbn13' => true, + 'bothIsbnMessage' => 'This value is neither a valid ISBN-10 nor a valid ISBN-13.' + ))); + } + } + +Available Options +----------------- + +isbn10 +~~~~~~ + +**type**: ``boolean`` [:ref:`default option`] + +If this required option is set to ``true`` the constraint will check if the +code is a valid ISBN-10 code. + +isbn13 +~~~~~~ + +**type**: ``boolean`` [:ref:`default option`] + +If this required option is set to ``true`` the constraint will check if the +code is a valid ISBN-13 code. + +isbn10Message +~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``This value is not a valid ISBN-10.`` + +The message that will be shown if the `isbn10`_ option is true and the given +value does not pass the ISBN-10 check. + +isbn13Message +~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``This value is not a valid ISBN-13.`` + +The message that will be shown if the `isbn13`_ option is true and the given +value does not pass the ISBN-13 check. + +bothIsbnMessage +~~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``This value is neither a valid ISBN-10 nor a valid ISBN-13.`` + +The message that will be shown if both the `isbn10`_ and `isbn13`_ options +are true and the given value does not pass the ISBN-13 nor the ISBN-13 check. diff --git a/reference/constraints/Issn.rst b/reference/constraints/Issn.rst new file mode 100644 index 00000000000..62e7ef64323 --- /dev/null +++ b/reference/constraints/Issn.rst @@ -0,0 +1,101 @@ +Issn +==== + +.. versionadded:: 2.3 + The ISSN validation is new in Symfony 2.3. + +Validates that a value is a valid `ISSN`_. + ++----------------+-----------------------------------------------------------------------+ +| Applies to | :ref:`property or method` | ++----------------+-----------------------------------------------------------------------+ +| Options | - `message`_ | +| | - `caseSensitive`_ | +| | - `requireHyphen`_ | ++----------------+-----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Validator\\Constraints\\Issn` | ++----------------+-----------------------------------------------------------------------+ +| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\IssnValidator` | ++----------------+-----------------------------------------------------------------------+ + +Basic Usage +----------- + +.. configuration-block:: + + .. code-block:: yaml + + # src/JournalBundle/Resources/config/validation.yml + Acme\JournalBundle\Entity\Journal: + properties: + issn: + - Issn: ~ + + .. code-block:: php-annotations + + // src/Acme/JournalBundle/Entity/Journal.php + namespace Acme\JournalBundle\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Journal + { + /** + * @Assert\Issn + */ + protected $issn; + } + + .. code-block:: xml + + + + + + + + + .. code-block:: php + + // src/Acme/JournalBundle/Entity/Journal.php + namespace Acme\JournalBundle\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Journal + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('issn', new Assert\Issn()); + } + } + +Options +------- + +message +~~~~~~~ + +**type**: ``String`` default: ``This value is not a valid ISSN.`` + +The message shown if the given value is not a valid ISSN. + +caseSensitive +~~~~~~~~~~~~~ + +**type**: ``Boolean`` default: ``false`` + +The validator will allow ISSN values to end with a lower case 'x' by default. +When switching this to ``true``, the validator requires an upper case 'X'. + +requireHyphen +~~~~~~~~~~~~~ + +**type**: ``Boolean`` default: ``false`` + +The validator will allow non hyphenated ISSN values by default. When switching +this to ``true``, the validator requires a hyphenated ISSN value. + +.. _`ISSN`: http://en.wikipedia.org/wiki/Issn + diff --git a/reference/constraints/Length.rst b/reference/constraints/Length.rst index 309d715be5e..f49d194fdd3 100644 --- a/reference/constraints/Length.rst +++ b/reference/constraints/Length.rst @@ -3,9 +3,6 @@ Length Validates that a given string length is *between* some minimum and maximum value. -.. versionadded:: 2.1 - The Length constraint was added in Symfony 2.1. - +----------------+----------------------------------------------------------------------+ | Applies to | :ref:`property or method ` | +----------------+----------------------------------------------------------------------+ diff --git a/reference/constraints/LessThan.rst b/reference/constraints/LessThan.rst new file mode 100644 index 00000000000..ba449062d5a --- /dev/null +++ b/reference/constraints/LessThan.rst @@ -0,0 +1,97 @@ +LessThan +======== + +.. versionadded:: 2.3 + This constraint is new in version 2.3. + +Validates that a value is less than another value, defined in the options. To +force that a value is less than or equal to another value, see +:doc:`/reference/constraints/LessThanOrEqual`. To force a value is greater +than another value, see :doc:`/reference/constraints/GreaterThan`. + ++----------------+------------------------------------------------------------------------+ +| Applies to | :ref:`property or method` | ++----------------+------------------------------------------------------------------------+ +| Options | - `value`_ | +| | - `message`_ | ++----------------+------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Validator\\Constraints\\LessThan` | ++----------------+------------------------------------------------------------------------+ +| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\LessThanValidator` | ++----------------+------------------------------------------------------------------------+ + +Basic Usage +----------- + +If you want to ensure that the ``age`` of a ``Person`` class is less than +``80``, you could do the following: + +.. configuration-block:: + + .. code-block:: yaml + + # src/SocialBundle/Resources/config/validation.yml + Acme\SocialBundle\Entity\Person: + properties: + age: + - LessThan: + value: 80 + + .. code-block:: php-annotations + + // src/Acme/SocialBundle/Entity/Person.php + namespace Acme\SocialBundle\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + /** + * @Assert\LessThan( + * value = 80 + * ) + */ + protected $age; + } + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // src/Acme/SocialBundle/Entity/Person.php + namespace Acme\SocialBundle\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('age', new Assert\LessThan(array( + 'value' => 80, + ))); + } + } + +Options +------- + +.. include:: /reference/constraints/_comparison-value-option.rst.inc + +message +~~~~~~~ + +**type**: ``string`` **default**: ``This value should be less than {{ compared_value }}`` + +This is the message that will be shown if the value is not less than the +comparison value. diff --git a/reference/constraints/LessThanOrEqual.rst b/reference/constraints/LessThanOrEqual.rst new file mode 100644 index 00000000000..1376d918de4 --- /dev/null +++ b/reference/constraints/LessThanOrEqual.rst @@ -0,0 +1,96 @@ +LessThanOrEqual +=============== + +.. versionadded:: 2.3 + This constraint is new in version 2.3. + +Validates that a value is less than or equal to another value, defined in the +options. To force that a value is less than another value, see +:doc:`/reference/constraints/LessThan`. + ++----------------+-------------------------------------------------------------------------------+ +| Applies to | :ref:`property or method` | ++----------------+-------------------------------------------------------------------------------+ +| Options | - `value`_ | +| | - `message`_ | ++----------------+-------------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Validator\\Constraints\\LessThanOrEqual` | ++----------------+-------------------------------------------------------------------------------+ +| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\LessThanOrEqualValidator` | ++----------------+-------------------------------------------------------------------------------+ + +Basic Usage +----------- + +If you want to ensure that the ``age`` of a ``Person`` class is less than or +equal to ``80``, you could do the following: + +.. configuration-block:: + + .. code-block:: yaml + + # src/SocialBundle/Resources/config/validation.yml + Acme\SocialBundle\Entity\Person: + properties: + age: + - LessThanOrEqual: + value: 80 + + .. code-block:: php-annotations + + // src/Acme/SocialBundle/Entity/Person.php + namespace Acme\SocialBundle\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + /** + * @Assert\LessThanOrEqual( + * value = 80 + * ) + */ + protected $age; + } + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // src/Acme/SocialBundle/Entity/Person.php + namespace Acme\SocialBundle\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('age', new Assert\LessThanOrEqual(array( + 'value' => 80, + ))); + } + } + +Options +------- + +.. include:: /reference/constraints/_comparison-value-option.rst.inc + +message +~~~~~~~ + +**type**: ``string`` **default**: ``This value should be less than or equal to {{ compared_value }}`` + +This is the message that will be shown if the value is not less than or equal +to the comparison value. diff --git a/reference/constraints/Max.rst b/reference/constraints/Max.rst deleted file mode 100644 index 6e4e723dbe6..00000000000 --- a/reference/constraints/Max.rst +++ /dev/null @@ -1,117 +0,0 @@ -Max -=== - -.. caution:: - - The Max constraint is deprecated since version 2.1 and will be removed - in Symfony 2.3. Use :doc:`/reference/constraints/Range` with the ``max`` - option instead. - -Validates that a given number is *less* than some maximum number. - -+----------------+--------------------------------------------------------------------+ -| Applies to | :ref:`property or method ` | -+----------------+--------------------------------------------------------------------+ -| Options | - `limit`_ | -| | - `message`_ | -| | - `invalidMessage`_ | -+----------------+--------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Validator\\Constraints\\Max` | -+----------------+--------------------------------------------------------------------+ -| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\MaxValidator` | -+----------------+--------------------------------------------------------------------+ - -Basic Usage ------------ - -To verify that the "age" field of a class is not greater than "50", you might -add the following: - -.. configuration-block:: - - .. code-block:: yaml - - # src/Acme/EventBundle/Resources/config/validation.yml - Acme\EventBundle\Entity\Participant: - properties: - age: - - Max: { limit: 50, message: You must be 50 or under to enter. } - - .. code-block:: php-annotations - - // src/Acme/EventBundle/Entity/Participant.php - namespace Acme\EventBundle\Entity; - - use Symfony\Component\Validator\Constraints as Assert; - - class Participant - { - /** - * @Assert\Max(limit = 50, message = "You must be 50 or under to enter.") - */ - protected $age; - } - - .. code-block:: xml - - - - - - - - - - - - - - - - .. code-block:: php - - // src/Acme/EventBundle/Entity/Participant.php - namespace Acme\EventBundle\Entity; - - use Symfony\Component\Validator\Mapping\ClassMetadata; - use Symfony\Component\Validator\Constraints as Assert; - - class Participant - { - public static function loadValidatorMetadata(ClassMetadata $metadata) - { - $metadata->addPropertyConstraint('age', new Assert\Max(array( - 'limit' => 50, - 'message' => 'You must be 50 or under to enter.', - ))); - } - } - -Options -------- - -limit -~~~~~ - -**type**: ``integer`` [:ref:`default option `] - -This required option is the "max" value. Validation will fail if the given -value is **greater** than this max value. - -message -~~~~~~~ - -**type**: ``string`` **default**: ``This value should be {{ limit }} or less`` - -The message that will be shown if the underlying value is greater than the -`limit`_ option. - -invalidMessage -~~~~~~~~~~~~~~ - -**type**: ``string`` **default**: ``This value should be a valid number`` - -The message that will be shown if the underlying value is not a number (per -the :phpfunction:`is_numeric` PHP function). diff --git a/reference/constraints/MaxLength.rst b/reference/constraints/MaxLength.rst deleted file mode 100644 index f3630abb21c..00000000000 --- a/reference/constraints/MaxLength.rst +++ /dev/null @@ -1,113 +0,0 @@ -MaxLength -========= - -.. caution:: - - The MaxLength constraint is deprecated since version 2.1 and will be removed - in Symfony 2.3. Use :doc:`/reference/constraints/Length` with the ``max`` - option instead. - -Validates that the length of a string is not larger than the given limit. - -+----------------+-------------------------------------------------------------------------+ -| Applies to | :ref:`property or method ` | -+----------------+-------------------------------------------------------------------------+ -| Options | - `limit`_ | -| | - `message`_ | -| | - `charset`_ | -+----------------+-------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Validator\\Constraints\\MaxLength` | -+----------------+-------------------------------------------------------------------------+ -| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\MaxLengthValidator` | -+----------------+-------------------------------------------------------------------------+ - -Basic Usage ------------ - -.. configuration-block:: - - .. code-block:: yaml - - # src/Acme/BlogBundle/Resources/config/validation.yml - Acme\BlogBundle\Entity\Blog: - properties: - summary: - - MaxLength: 100 - - .. code-block:: php-annotations - - // src/Acme/BlogBundle/Entity/Blog.php - namespace Acme\BlogBundle\Entity; - - use Symfony\Component\Validator\Constraints as Assert; - - class Blog - { - /** - * @Assert\MaxLength(100) - */ - protected $summary; - } - - .. code-block:: xml - - - - - - - - - - - - - - - .. code-block:: php - - // src/Acme/BlogBundle/Entity/Blog.php - namespace Acme\BlogBundle\Entity; - - use Symfony\Component\Validator\Mapping\ClassMetadata; - use Symfony\Component\Validator\Constraints as Assert; - - class Blog - { - public static function loadValidatorMetadata(ClassMetadata $metadata) - { - $metadata->addPropertyConstraint('summary', new Assert\MaxLength(array( - 'limit' => 100, - ))); - } - } - -Options -------- - -limit -~~~~~ - -**type**: ``integer`` [:ref:`default option `] - -This required option is the "max" value. Validation will fail if the length -of the give string is **greater** than this number. - -message -~~~~~~~ - -**type**: ``string`` **default**: ``This value is too long. It should have {{ limit }} characters or less`` - -The message that will be shown if the underlying string has a length that -is longer than the `limit`_ option. - -charset -~~~~~~~ - -**type**: ``charset`` **default**: ``UTF-8`` - -If the PHP extension "mbstring" is installed, then the PHP function :phpfunction:`mb_strlen` -will be used to calculate the length of the string. The value of the ``charset`` -option is passed as the second argument to that function. diff --git a/reference/constraints/Min.rst b/reference/constraints/Min.rst deleted file mode 100644 index 2a9e3679fab..00000000000 --- a/reference/constraints/Min.rst +++ /dev/null @@ -1,117 +0,0 @@ -Min -=== - -.. caution:: - - The Min constraint is deprecated since version 2.1 and will be removed - in Symfony 2.3. Use :doc:`/reference/constraints/Range` with the ``min`` - option instead. - -Validates that a given number is *greater* than some minimum number. - -+----------------+--------------------------------------------------------------------+ -| Applies to | :ref:`property or method ` | -+----------------+--------------------------------------------------------------------+ -| Options | - `limit`_ | -| | - `message`_ | -| | - `invalidMessage`_ | -+----------------+--------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Validator\\Constraints\\Min` | -+----------------+--------------------------------------------------------------------+ -| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\MinValidator` | -+----------------+--------------------------------------------------------------------+ - -Basic Usage ------------ - -To verify that the "age" field of a class is "18" or greater, you might add -the following: - -.. configuration-block:: - - .. code-block:: yaml - - # src/Acme/EventBundle/Resources/config/validation.yml - Acme\EventBundle\Entity\Participant: - properties: - age: - - Min: { limit: 18, message: You must be 18 or older to enter. } - - .. code-block:: php-annotations - - // src/Acme/EventBundle/Entity/Participant.php - namespace Acme\EventBundle\Entity; - - use Symfony\Component\Validator\Constraints as Assert; - - class Participant - { - /** - * @Assert\Min(limit = "18", message = "You must be 18 or older to enter.") - */ - protected $age; - } - - .. code-block:: xml - - - - - - - - - - - - - - - - .. code-block:: php - - // src/Acme/EventBundle/Entity/Participant.php - namespace Acme\EventBundle\Entity\Participant; - - use Symfony\Component\Validator\Mapping\ClassMetadata; - use Symfony\Component\Validator\Constraints as Assert; - - class Participant - { - public static function loadValidatorMetadata(ClassMetadata $metadata) - { - $metadata->addPropertyConstraint('age', new Assert\Min(array( - 'limit' => '18', - 'message' => 'You must be 18 or older to enter.', - ))); - } - } - -Options -------- - -limit -~~~~~ - -**type**: ``integer`` [:ref:`default option `] - -This required option is the "min" value. Validation will fail if the given -value is **less** than this min value. - -message -~~~~~~~ - -**type**: ``string`` **default**: ``This value should be {{ limit }} or more`` - -The message that will be shown if the underlying value is less than the `limit`_ -option. - -invalidMessage -~~~~~~~~~~~~~~ - -**type**: ``string`` **default**: ``This value should be a valid number`` - -The message that will be shown if the underlying value is not a number (per -the :phpfunction:`is_numeric` PHP function). diff --git a/reference/constraints/MinLength.rst b/reference/constraints/MinLength.rst deleted file mode 100644 index 9ce206e93c6..00000000000 --- a/reference/constraints/MinLength.rst +++ /dev/null @@ -1,118 +0,0 @@ -MinLength -========= - -.. caution:: - - The MinLength constraint is deprecated since version 2.1 and will be removed - in Symfony 2.3. Use :doc:`/reference/constraints/Length` with the ``min`` - option instead. - -Validates that the length of a string is at least as long as the given limit. - -+----------------+-------------------------------------------------------------------------+ -| Applies to | :ref:`property or method ` | -+----------------+-------------------------------------------------------------------------+ -| Options | - `limit`_ | -| | - `message`_ | -| | - `charset`_ | -+----------------+-------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Validator\\Constraints\\MinLength` | -+----------------+-------------------------------------------------------------------------+ -| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\MinLengthValidator` | -+----------------+-------------------------------------------------------------------------+ - -Basic Usage ------------ - -.. configuration-block:: - - .. code-block:: yaml - - # src/Acme/BlogBundle/Resources/config/validation.yml - Acme\BlogBundle\Entity\Blog: - properties: - firstName: - - MinLength: { limit: 3, message: "Your name must have at least {{ limit }} characters." } - - .. code-block:: php-annotations - - // src/Acme/BlogBundle/Entity/Blog.php - namespace Acme\BlogBundle\Entity; - - use Symfony\Component\Validator\Constraints as Assert; - - class Blog - { - /** - * @Assert\MinLength( - * limit=3, - * message="Your name must have at least {{ limit }} characters." - * ) - */ - protected $summary; - } - - .. code-block:: xml - - - - - - - - - - - - - - - - .. code-block:: php - - // src/Acme/BlogBundle/Entity/Blog.php - namespace Acme\BlogBundle\Entity; - - use Symfony\Component\Validator\Mapping\ClassMetadata; - use Symfony\Component\Validator\Constraints as Assert; - - class Blog - { - public static function loadValidatorMetadata(ClassMetadata $metadata) - { - $metadata->addPropertyConstraint('summary', new Assert\MinLength(array( - 'limit' => 3, - 'message' => 'Your name must have at least {{ limit }} characters.', - ))); - } - } - -Options -------- - -limit -~~~~~ - -**type**: ``integer`` [:ref:`default option `] - -This required option is the "min" value. Validation will fail if the length -of the give string is **less** than this number. - -message -~~~~~~~ - -**type**: ``string`` **default**: ``This value is too short. It should have {{ limit }} characters or more`` - -The message that will be shown if the underlying string has a length that -is shorter than the `limit`_ option. - -charset -~~~~~~~ - -**type**: ``charset`` **default**: ``UTF-8`` - -If the PHP extension "mbstring" is installed, then the PHP function :phpfunction:`mb_strlen` -will be used to calculate the length of the string. The value of the ``charset`` -option is passed as the second argument to that function. diff --git a/reference/constraints/NotEqualTo.rst b/reference/constraints/NotEqualTo.rst new file mode 100644 index 00000000000..bea2bf6eb38 --- /dev/null +++ b/reference/constraints/NotEqualTo.rst @@ -0,0 +1,101 @@ +NotEqualTo +========== + +.. versionadded:: 2.3 + This constraint is new in version 2.3. + +Validates that a value is **not** equal to another value, defined in the +options. To force that a value is equal, see +:doc:`/reference/constraints/EqualTo`. + +.. caution:: + + This constraint compares using ``!=``, so ``3`` and ``"3"`` are considered + equal. Use :doc:`/reference/constraints/NotIdenticalTo` to compare with + ``!==``. + ++----------------+-------------------------------------------------------------------------+ +| Applies to | :ref:`property or method` | ++----------------+-------------------------------------------------------------------------+ +| Options | - `value`_ | +| | - `message`_ | ++----------------+-------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Validator\\Constraints\\NotEqualTo` | ++----------------+-------------------------------------------------------------------------+ +| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\NotEqualToValidator`| ++----------------+-------------------------------------------------------------------------+ + +Basic Usage +----------- + +If you want to ensure that the ``age`` of a ``Person`` class is not equal to +``15``, you could do the following: + +.. configuration-block:: + + .. code-block:: yaml + + # src/SocialBundle/Resources/config/validation.yml + Acme\SocialBundle\Entity\Person: + properties: + age: + - NotEqualTo: + value: 15 + + .. code-block:: php-annotations + + // src/Acme/SocialBundle/Entity/Person.php + namespace Acme\SocialBundle\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + /** + * @Assert\NotEqualTo( + * value = 15 + * ) + */ + protected $age; + } + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // src/Acme/SocialBundle/Entity/Person.php + namespace Acme\SocialBundle\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('age', new Assert\NotEqualTo(array( + 'value' => 15, + ))); + } + } + +Options +------- + +.. include:: /reference/constraints/_comparison-value-option.rst.inc + +message +~~~~~~~ + +**type**: ``string`` **default**: ``This value should not be equal to {{ compared_value }}`` + +This is the message that will be shown if the value is not equal. diff --git a/reference/constraints/NotIdenticalTo.rst b/reference/constraints/NotIdenticalTo.rst new file mode 100644 index 00000000000..09eb35607fe --- /dev/null +++ b/reference/constraints/NotIdenticalTo.rst @@ -0,0 +1,101 @@ +NotIdenticalTo +============== + +.. versionadded:: 2.3 + This constraint is new in version 2.3. + +Validates that a value is **not** identical to another value, defined in the +options. To force that a value is identical, see +:doc:`/reference/constraints/IdenticalTo`. + +.. caution:: + + This constraint compares using ``!==``, so ``3`` and ``"3"`` are + considered not equal. Use :doc:`/reference/constraints/NotEqualTo` to compare + with ``!=``. + ++----------------+-----------------------------------------------------------------------------+ +| Applies to | :ref:`property or method` | ++----------------+-----------------------------------------------------------------------------+ +| Options | - `value`_ | +| | - `message`_ | ++----------------+-----------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Validator\\Constraints\\NotIdenticalTo` | ++----------------+-----------------------------------------------------------------------------+ +| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\NotIdenticalToValidator`| ++----------------+-----------------------------------------------------------------------------+ + +Basic Usage +----------- + +If you want to ensure that the ``age`` of a ``Person`` class is *not* equal to +``15`` and *not* an integer, you could do the following: + +.. configuration-block:: + + .. code-block:: yaml + + # src/SocialBundle/Resources/config/validation.yml + Acme\SocialBundle\Entity\Person: + properties: + age: + - NotIdenticalTo: + value: 15 + + .. code-block:: php-annotations + + // src/Acme/SocialBundle/Entity/Person.php + namespace Acme\SocialBundle\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + /** + * @Assert\NotIdenticalTo( + * value = 15 + * ) + */ + protected $age; + } + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // src/Acme/SocialBundle/Entity/Person.php + namespace Acme\SocialBundle\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('age', new Assert\NotIdenticalTo(array( + 'value' => 15, + ))); + } + } + +Options +------- + +.. include:: /reference/constraints/_comparison-value-option.rst.inc + +message +~~~~~~~ + +**type**: ``string`` **default**: ``This value should not be identical to {{ compared_value_type }} {{ compared_value }}`` + +This is the message that will be shown if the value is not equal. diff --git a/reference/constraints/Range.rst b/reference/constraints/Range.rst index 913c7fed292..057c3b7f62b 100644 --- a/reference/constraints/Range.rst +++ b/reference/constraints/Range.rst @@ -3,9 +3,6 @@ Range Validates that a given number is *between* some minimum and maximum number. -.. versionadded:: 2.1 - The Range constraint was added in Symfony 2.1. - +----------------+---------------------------------------------------------------------+ | Applies to | :ref:`property or method ` | +----------------+---------------------------------------------------------------------+ diff --git a/reference/constraints/Regex.rst b/reference/constraints/Regex.rst index 1595ff4c042..2dd50f3f067 100644 --- a/reference/constraints/Regex.rst +++ b/reference/constraints/Regex.rst @@ -177,9 +177,6 @@ string *does* match this pattern. htmlPattern ~~~~~~~~~~~ -.. versionadded:: 2.1 - The ``htmlPattern`` option was added in Symfony 2.1 - **type**: ``string|Boolean`` **default**: null This option specifies the pattern to use in the HTML5 ``pattern`` attribute. diff --git a/reference/constraints/UniqueEntity.rst b/reference/constraints/UniqueEntity.rst index 276d19c64aa..92b20f77f83 100644 --- a/reference/constraints/UniqueEntity.rst +++ b/reference/constraints/UniqueEntity.rst @@ -151,10 +151,6 @@ repositoryMethod **type**: ``string`` **default**: ``findBy`` -.. versionadded:: 2.1 - The ``repositoryMethod`` option was added in Symfony 2.1. Before, it - always used the ``findBy`` method. - The name of the repository method to use for making the query to determine the uniqueness. If it's left blank, the ``findBy`` method will be used. This method should return a countable result. @@ -164,9 +160,6 @@ errorPath **type**: ``string`` **default**: The name of the first field in `fields`_ -.. versionadded:: 2.1 - The ``errorPath`` option was added in Symfony 2.1. - If the entity violates constraint the error message is bound to the first field in `fields`_. If there are more than one fields, you may want to map the error message to another field. @@ -260,15 +253,11 @@ Consider this example: Now, the message would be bound to the ``port`` field with this configuration. - ignoreNull ~~~~~~~~~~ **type**: ``Boolean`` **default**: ``true`` -.. versionadded:: 2.1 - The ``ignoreNull`` option was added in Symfony 2.1. - If this option is set to ``true``, then the constraint will allow multiple entities to have a ``null`` value for a field without failing validation. If set to ``false``, only one ``null`` value is allowed - if a second entity diff --git a/reference/constraints/UserPassword.rst b/reference/constraints/UserPassword.rst index caa3fed7a72..e5e1baea42d 100644 --- a/reference/constraints/UserPassword.rst +++ b/reference/constraints/UserPassword.rst @@ -1,9 +1,6 @@ UserPassword ============ -.. versionadded:: 2.1 - This constraint is new in version 2.1. - .. note:: Since Symfony 2.2, the ``UserPassword*`` classes in the diff --git a/reference/constraints/_comparison-value-option.rst.inc b/reference/constraints/_comparison-value-option.rst.inc new file mode 100644 index 00000000000..9d799c27dc7 --- /dev/null +++ b/reference/constraints/_comparison-value-option.rst.inc @@ -0,0 +1,7 @@ +value +~~~~~ + +**type**: ``mixed`` + +This option is required. It defines the value to compare to. It can be a +string, number or object. diff --git a/reference/constraints/map.rst.inc b/reference/constraints/map.rst.inc index 0482c4c5447..84186b01d25 100644 --- a/reference/constraints/map.rst.inc +++ b/reference/constraints/map.rst.inc @@ -16,8 +16,6 @@ String Constraints ~~~~~~~~~~~~~~~~~~ * :doc:`Email ` -* :doc:`MinLength ` -* :doc:`MaxLength ` * :doc:`Length ` * :doc:`Url ` * :doc:`Regex ` @@ -26,10 +24,20 @@ String Constraints Number Constraints ~~~~~~~~~~~~~~~~~~ -* :doc:`Max ` -* :doc:`Min ` * :doc:`Range ` +Comparison Constraints +~~~~~~~~~~~~~~~~~~~~~~ + +* :doc:`EqualTo ` +* :doc:`NotEqualTo ` +* :doc:`IdenticalTo ` +* :doc:`NotIdenticalTo ` +* :doc:`LessThan ` +* :doc:`LessThanOrEqual ` +* :doc:`GreaterThan ` +* :doc:`GreaterThanOrEqual ` + Date Constraints ~~~~~~~~~~~~~~~~ @@ -54,11 +62,15 @@ File Constraints * :doc:`File ` * :doc:`Image ` -Financial Constraints -~~~~~~~~~~~~~~~~~~~~~ +Financial and other Number Constraints +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * :doc:`CardScheme ` +* :doc:`Currency ` * :doc:`Luhn ` +* :doc:`Iban ` +* :doc:`Isbn ` +* :doc:`Issn ` Other Constraints ~~~~~~~~~~~~~~~~~ diff --git a/reference/dic_tags.rst b/reference/dic_tags.rst index 1fb0e452c25..d5c9af66861 100644 --- a/reference/dic_tags.rst +++ b/reference/dic_tags.rst @@ -61,6 +61,10 @@ may also be tags in other bundles you use that aren't listed here. +-----------------------------------+---------------------------------------------------------------------------+ | `security.remember_me_aware`_ | To allow remember me authentication | +-----------------------------------+---------------------------------------------------------------------------+ +| `serializer.encoder`_ | Register a new encoder in the ``serializer`` service | ++-----------------------------------+---------------------------------------------------------------------------+ +| `serializer.normalizer`_ | Register a new normalizer in the ``serializer`` service | ++-----------------------------------+---------------------------------------------------------------------------+ | `swiftmailer.plugin`_ | Register a custom SwiftMailer Plugin | +-----------------------------------+---------------------------------------------------------------------------+ | `templating.helper`_ | Make your service available in PHP templates | @@ -564,9 +568,6 @@ kernel.event_subscriber **Purpose**: To subscribe to a set of different events/hooks in Symfony -.. versionadded:: 2.1 - The ability to add kernel event subscribers is new to 2.1. - To enable a custom subscriber, add it as a regular service in one of your configuration, and tag it with ``kernel.event_subscriber``: @@ -808,6 +809,30 @@ is used behind the scenes to determine if the user should have access. The For more information, read the cookbook article: :doc:`/cookbook/security/voters`. +.. _reference-dic-tags-serializer-encoder: + +serializer.encoder +------------------ + +**Purpose**: Register a new encoder in the ``serializer`` service + +The class that's tagged should implement the :class:`Symfony\\Component\\Serializer\\Encoder\\EncoderInterface` +and :class:`Symfony\\Component\\Serializer\\Encoder\\DecoderInterface`. + +For more details, see :doc:`/cookbook/serializer`. + +.. _reference-dic-tags-serializer-normalizer: + +serializer.normalizer +--------------------- + +**Purpose**: Register a new normalizer in the Serializer service + +The class that's tagged should implement the :class:`Symfony\\Component\\Serializer\\Normalizer\\NormalizerInterface` +and :class:`Symfony\\Component\\Serializer\\Normalizer\\DenormalizerInterface`. + +For more details, see :doc:`/cookbook/serializer`. + swiftmailer.plugin ------------------ @@ -936,9 +961,6 @@ translation.extractor **Purpose**: To register a custom service that extracts messages from a file -.. versionadded:: 2.1 - The ability to add message extractors is new in Symfony 2.1. - When executing the ``translation:update`` command, it uses extractors to extract translation messages from a file. By default, the Symfony2 framework has a :class:`Symfony\\Bridge\\Twig\\Translation\\TwigExtractor` and a @@ -1007,9 +1029,6 @@ translation.dumper **Purpose**: To register a custom service that dumps messages to a file -.. versionadded:: 2.1 - The ability to add message dumpers is new in Symfony 2.1. - After an `Extractor `_ has extracted all messages from the templates, the dumpers are executed to dump the messages to a translation file in a specific format. diff --git a/reference/forms/twig_reference.rst b/reference/forms/twig_reference.rst index e01ecd05d41..20156e5a8f8 100644 --- a/reference/forms/twig_reference.rst +++ b/reference/forms/twig_reference.rst @@ -24,6 +24,66 @@ rendering forms. There are several different functions available, and each is responsible for rendering a different part of a form (e.g. labels, errors, widgets, etc). +.. _reference-forms-twig-form: + +form(view, variables) +--------------------- + +Renders the HTML of a complete form. + +.. code-block:: jinja + + {# render the form and change the submission method #} + {{ form(form, {'method': 'GET'}) }} + +You will mostly use this helper for prototyping or if you use custom form +themes. If you need more flexibility in rendering the form, you should use +the other helpers to render individual parts of the form instead: + +.. code-block:: jinja + + {{ form_start(form) }} + {{ form_errors(form) }} + + {{ form_row(form.name) }} + {{ form_row(form.dueDate) }} + + + {{ form_end(form) }} + +.. _reference-forms-twig-start: + +form_start(view, variables) +--------------------------- + +Renders the start tag of a form. This helper takes care of printing the +configured method and target action of the form. It will also include the +correct ``enctype`` property if the form contains upload fields. + +.. code-block:: jinja + + {# render the start tag and change the submission method #} + {{ form_start(form, {'method': 'GET'}) }} + +.. _reference-forms-twig-end: + +form_end(view, variables) +------------------------- + +Renders the end tag of a form. + +.. code-block:: jinja + + {{ form_end(form) }} + +This helper also outputs ``form_rest()`` unless you set ``render_rest`` to +false: + +.. code-block:: jinja + + {# don't render unrendered fields #} + {{ form_end(form, {'render_rest': false}) }} + .. _reference-forms-twig-label: form_label(view, label, variables) @@ -119,6 +179,11 @@ obvious (since it'll render the field for you). form_enctype(view) ------------------ +.. note:: + + This helper was deprecated in Symfony 2.3 and will be removed in Symfony 3.0. + You should use ``form_start()`` instead. + If the form contains at least one file upload field, this will render the required ``enctype="multipart/form-data"`` form attribute. It's always a good idea to include this in your form tag: @@ -230,10 +295,6 @@ object: get('name')->vars['label'] ?> -.. versionadded:: 2.1 - The ``valid``, ``label_attr``, ``compound``, and ``disabled`` variables - are new in Symfony 2.1. - +-----------------+-----------------------------------------------------------------------------------------+ | Variable | Usage | +=================+=========================================================================================+ @@ -277,4 +338,4 @@ object: | | (for example, a ``choice`` field, which is actually a group of checkboxes | +-----------------+-----------------------------------------------------------------------------------------+ -.. _`form_div_layout.html.twig`: https://github.com/symfony/symfony/blob/2.1/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +.. _`form_div_layout.html.twig`: https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig diff --git a/reference/forms/types.rst b/reference/forms/types.rst index 36b471c9e6f..0a00023ac33 100644 --- a/reference/forms/types.rst +++ b/reference/forms/types.rst @@ -9,16 +9,17 @@ Form Types Reference :hidden: types/birthday + types/button types/checkbox types/choice types/collection types/country + types/currency types/date types/datetime types/email types/entity types/file - types/field types/form types/hidden types/integer @@ -30,7 +31,9 @@ Form Types Reference types/percent types/radio types/repeated + types/reset types/search + types/submit types/text types/textarea types/time diff --git a/reference/forms/types/birthday.rst b/reference/forms/types/birthday.rst index 39f3beb6da0..2bd8c7330d2 100644 --- a/reference/forms/types/birthday.rst +++ b/reference/forms/types/birthday.rst @@ -28,14 +28,14 @@ option defaults to 120 years ago to the current year. | | - `months`_ | | | - `days`_ | | | - `format`_ | -| | - `data_timezone`_ | -| | - `user_timezone`_ | +| | - `model_timezone`_ | +| | - `view_timezone`_ | | | - `invalid_message`_ | | | - `invalid_message_parameters`_ | | | - `read_only`_ | | | - `disabled`_ | | | - `mapped`_ | -| | - `virtual`_ | +| | - `inherit_data`_ | +----------------------+-------------------------------------------------------------------------------+ | Parent type | :doc:`date ` | +----------------------+-------------------------------------------------------------------------------+ @@ -70,9 +70,9 @@ These options inherit from the :doc:`date ` type: .. include:: /reference/forms/types/options/date_format.rst.inc -.. include:: /reference/forms/types/options/data_timezone.rst.inc +.. include:: /reference/forms/types/options/model_timezone.rst.inc -.. include:: /reference/forms/types/options/user_timezone.rst.inc +.. include:: /reference/forms/types/options/view_timezone.rst.inc These options inherit from the :doc:`date ` type: @@ -86,4 +86,4 @@ These options inherit from the :doc:`date ` type: .. include:: /reference/forms/types/options/mapped.rst.inc -.. include:: /reference/forms/types/options/virtual.rst.inc +.. include:: /reference/forms/types/options/inherit_data.rst.inc diff --git a/reference/forms/types/button.rst b/reference/forms/types/button.rst new file mode 100644 index 00000000000..6e8cce6ed57 --- /dev/null +++ b/reference/forms/types/button.rst @@ -0,0 +1,34 @@ +.. index:: + single: Forms; Fields; button + +button Field Type +================= + +.. versionadded:: 2.3 + The ``button`` type was added in Symfony 2.3 + +A simple, non-responsive button. + ++----------------------+----------------------------------------------------------------------+ +| Rendered as | ``button`` tag | ++----------------------+----------------------------------------------------------------------+ +| Options | - `attr`_ | +| | - `disabled`_ | +| | - `label`_ | +| | - `translation_domain`_ | ++----------------------+----------------------------------------------------------------------+ +| Parent type | none | ++----------------------+----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\ButtonType` | ++----------------------+----------------------------------------------------------------------+ + +Options +------- + +.. include:: /reference/forms/types/options/button_attr.rst.inc + +.. include:: /reference/forms/types/options/button_disabled.rst.inc + +.. include:: /reference/forms/types/options/button_label.rst.inc + +.. include:: /reference/forms/types/options/button_translation_domain.rst.inc diff --git a/reference/forms/types/choice.rst b/reference/forms/types/choice.rst index 7e4a17bbbee..ea7e7efac0f 100644 --- a/reference/forms/types/choice.rst +++ b/reference/forms/types/choice.rst @@ -27,7 +27,7 @@ option. | | - `error_bubbling`_ | | | - `error_mapping`_ | | | - `mapped`_ | -| | - `virtual`_ | +| | - `inherit_data`_ | | | - `by_reference`_ | | | - `empty_data`_ | +-------------+------------------------------------------------------------------------------+ @@ -126,7 +126,7 @@ These options inherit from the :doc:`field ` type: .. include:: /reference/forms/types/options/mapped.rst.inc -.. include:: /reference/forms/types/options/virtual.rst.inc +.. include:: /reference/forms/types/options/inherit_data.rst.inc .. include:: /reference/forms/types/options/by_reference.rst.inc diff --git a/reference/forms/types/collection.rst b/reference/forms/types/collection.rst index 484e68dd2a4..9fdd1a265e4 100644 --- a/reference/forms/types/collection.rst +++ b/reference/forms/types/collection.rst @@ -153,7 +153,7 @@ you need is the JavaScript: .. code-block:: html+jinja -
        + {{ form_start(form) }} {# ... #} {# store the prototype on the data-prototype attribute #} @@ -169,7 +169,7 @@ you need is the JavaScript: Add another email {# ... #} -
        + {{ form_end(form) }}