diff --git a/best_practices/business-logic.rst b/best_practices/business-logic.rst index 55305165436..3f1022a10d1 100644 --- a/best_practices/business-logic.rst +++ b/best_practices/business-logic.rst @@ -21,8 +21,6 @@ Inside here, you can create whatever directories you want to organize things: │ └─ AppBundle/ │ └─ Utils/ │ └─ MyClass.php - ├─ tests/ - ├─ var/ ├─ vendor/ └─ web/ @@ -42,8 +40,6 @@ and put things there: │ │ └─ Utils/ │ │ └─ MyClass.php │ └─ AppBundle/ - ├─ tests/ - ├─ var/ ├─ vendor/ └─ web/ @@ -322,7 +318,7 @@ command: .. code-block:: bash - $ php bin/console doctrine:fixtures:load + $ php app/console doctrine:fixtures:load Careful, database will be purged. Do you want to continue Y/N ? Y > purging database diff --git a/best_practices/configuration.rst b/best_practices/configuration.rst index 1bfa758b8a8..76aac62de31 100644 --- a/best_practices/configuration.rst +++ b/best_practices/configuration.rst @@ -52,8 +52,8 @@ Canonical Parameters Define all your application's parameters in the ``app/config/parameters.yml.dist`` file. -Symfony includes a configuration file called ``parameters.yml.dist``, which -stores the canonical list of configuration parameters for the application. +Since version 2.3, Symfony includes a configuration file called ``parameters.yml.dist``, +which stores the canonical list of configuration parameters for the application. Whenever a new configuration parameter is defined for the application, you should also add it to this file and submit the changes to your version control diff --git a/best_practices/creating-the-project.rst b/best_practices/creating-the-project.rst index 06e277b8cb6..45dcc987220 100644 --- a/best_practices/creating-the-project.rst +++ b/best_practices/creating-the-project.rst @@ -27,6 +27,7 @@ to create files and execute the following commands: .. code-block:: bash + # Linux, Mac OS X $ cd projects/ $ symfony new blog @@ -62,18 +63,13 @@ number of files and directories generated automatically: blog/ ├─ app/ + │ ├─ console + │ ├─ cache/ │ ├─ config/ + │ ├─ logs/ │ └─ Resources/ - ├─ bin - │ └─ console ├─ src/ │ └─ AppBundle/ - ├─ var/ - │ ├─ cache/ - │ ├─ logs/ - │ └─ sessions/ - ├─ tests/ - │ └─ AppBundle/ ├─ vendor/ └─ web/ @@ -81,16 +77,13 @@ This file and directory hierarchy is the convention proposed by Symfony to structure your applications. The recommended purpose of each directory is the following: +* ``app/cache/``, stores all the cache files generated by the application; * ``app/config/``, stores all the configuration defined for any environment; +* ``app/logs/``, stores all the log files generated by the application; * ``app/Resources/``, stores all the templates and the translation files for the application; * ``src/AppBundle/``, stores the Symfony specific code (controllers and routes), your domain code (e.g. Doctrine classes) and all your business logic; -* ``var/cache/``, stores all the cache files generated by the application; -* ``var/logs/``, stores all the log files generated by the application; -* ``var/sessions/``, stores all the session files generated by the application; -* ``tests/AppBundle/``, stores the automatic tests (e.g. Unit tests) of the - application. * ``vendor/``, this is the directory where Composer installs the application's dependencies and you should never modify any of its contents; * ``web/``, stores all the front controller files and all the web assets, such @@ -114,7 +107,8 @@ ProductBundle, then there's no advantage to having two separate bundles. Create only one bundle called AppBundle for your application logic. Implementing a single AppBundle bundle in your projects will make your code -more concise and easier to understand. +more concise and easier to understand. Starting in Symfony 2.6, the official +Symfony documentation uses the AppBundle name. .. note:: @@ -134,18 +128,13 @@ that follows these best practices: blog/ ├─ app/ + │ ├─ console + │ ├─ cache/ │ ├─ config/ + │ ├─ logs/ │ └─ Resources/ - ├─ bin/ - │ └─ console ├─ src/ │ └─ AppBundle/ - ├─ tests/ - │ └─ AppBundle/ - ├─ var/ - │ ├─ cache/ - │ ├─ logs/ - └─ sessions/ ├─ vendor/ └─ web/ ├─ app.php @@ -158,7 +147,7 @@ that follows these best practices: .. code-block:: bash - $ php bin/console generate:bundle --namespace=AppBundle --dir=src --format=annotation --no-interaction + $ php app/console generate:bundle --namespace=AppBundle --dir=src --format=annotation --no-interaction Extending the Directory Structure --------------------------------- @@ -168,6 +157,27 @@ structure of Symfony, you can :doc:`override the location of the main directories `: ``cache/``, ``logs/`` and ``web/``. +In addition, Symfony3 will use a slightly different directory structure when +it's released: + +.. code-block:: text + + blog-symfony3/ + ├─ app/ + │ ├─ config/ + │ └─ Resources/ + ├─ bin/ + │ └─ console + ├─ src/ + ├─ var/ + │ ├─ cache/ + │ └─ logs/ + ├─ vendor/ + └─ web/ + +The changes are pretty superficial, but for now, we recommend that you use +the Symfony directory structure. + .. _`Composer`: https://getcomposer.org/ .. _`Phar extension`: http://php.net/manual/en/intro.phar.php .. _`public checksums repository`: https://github.com/sensiolabs/checksums diff --git a/best_practices/forms.rst b/best_practices/forms.rst index 5c5f25b2d96..968fb078bfc 100644 --- a/best_practices/forms.rst +++ b/best_practices/forms.rst @@ -22,9 +22,6 @@ form in its own PHP class:: use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; - use Symfony\Component\Form\Extension\Core\Type\TextareaType; - use Symfony\Component\Form\Extension\Core\Type\EmailType; - use Symfony\Component\Form\Extension\Core\Type\DateTimeType; class PostType extends AbstractType { @@ -32,10 +29,10 @@ form in its own PHP class:: { $builder ->add('title') - ->add('summary', TextareaType::class) - ->add('content', TextareaType::class) - ->add('authorEmail', EmailType::class) - ->add('publishedAt', DateTimeType::class) + ->add('summary', 'textarea') + ->add('content', 'textarea') + ->add('authorEmail', 'email') + ->add('publishedAt', 'datetime') ; } @@ -45,6 +42,11 @@ form in its own PHP class:: 'data_class' => 'AppBundle\Entity\Post' )); } + + public function getName() + { + return 'post'; + } } .. best-practice:: @@ -52,7 +54,7 @@ form in its own PHP class:: Put the form type classes in the ``AppBundle\Form`` namespace, unless you use other custom form classes like data transformers. -To use the class, use ``createForm()`` and pass the fully qualified class name:: +To use the class, use ``createForm()`` and instantiate the new class:: // ... use AppBundle\Form\PostType; @@ -61,7 +63,7 @@ To use the class, use ``createForm()`` and pass the fully qualified class name:: public function newAction(Request $request) { $post = new Post(); - $form = $this->createForm(PostType::class, $post); + $form = $this->createForm(new PostType(), $post); // ... } @@ -71,9 +73,13 @@ Registering Forms as Services You can also :ref:`register your form type as a service `. -This is only needed if your form type requires some dependencies to be injected -by the container, otherwise it is unnecessary overhead and therefore *not* -recommended to do this for all form type classes. +But this is *not* recommended unless you plan to reuse the new form type in many +places or embed it in other forms directly or via the +:doc:`collection type `. + +For most forms that are used only to edit or create something, registering +the form as a service is over-kill, and makes it more difficult to figure +out exactly which form class is being used in a controller. Form Button Configuration ------------------------- @@ -85,10 +91,9 @@ makes them easier to re-use later. Add buttons in the templates, not in the form classes or the controllers. -The Symfony Form component allows you to add buttons as fields on your form. -This is a nice way to simplify the template that renders your form. But if you -add the buttons directly in your form class, this would effectively limit the -scope of that form: +Since Symfony 2.3, you can add buttons as fields on your form. This is a nice +way to simplify the template that renders your form. But if you add the buttons +directly in your form class, this would effectively limit the scope of that form: .. code-block:: php @@ -98,7 +103,7 @@ scope of that form: { $builder // ... - ->add('save', SubmitType::class, array('label' => 'Create Post')) + ->add('save', 'submit', array('label' => 'Create Post')) ; } @@ -113,7 +118,6 @@ some developers configure form buttons in the controller:: use Symfony\Component\HttpFoundation\Request; use Symfony\Bundle\FrameworkBundle\Controller\Controller; - use Symfony\Component\Form\Extension\Core\Type\SubmitType; use AppBundle\Entity\Post; use AppBundle\Form\PostType; @@ -124,8 +128,8 @@ some developers configure form buttons in the controller:: public function newAction(Request $request) { $post = new Post(); - $form = $this->createForm(PostType::class, $post); - $form->add('submit', SubmitType::class, array( + $form = $this->createForm(new PostType(), $post); + $form->add('submit', 'submit', array( 'label' => 'Create', 'attr' => array('class' => 'btn btn-default pull-right') )); @@ -209,3 +213,21 @@ Second, we recommend using ``$form->isSubmitted()`` in the ``if`` statement for clarity. This isn't technically needed, since ``isValid()`` first calls ``isSubmitted()``. But without this, the flow doesn't read well as it *looks* like the form is *always* processed (even on the GET request). + +Custom Form Field Types +----------------------- + +.. best-practice:: + + Add the ``app_`` prefix to your custom form field types to avoid collisions. + +Custom form field types inherit from the ``AbstractType`` class, which defines the +``getName()`` method to configure the name of that form type. These names must +be unique in the application. + +If a custom form type uses the same name as any of the Symfony's built-in form +types, it will override it. The same happens when the custom form type matches +any of the types defined by the third-party bundles installed in your application. + +Add the ``app_`` prefix to your custom form field types to avoid name collisions +that can lead to hard to debug errors. diff --git a/best_practices/i18n.rst b/best_practices/i18n.rst index 39473373df1..cfbd5fb47e2 100644 --- a/best_practices/i18n.rst +++ b/best_practices/i18n.rst @@ -32,9 +32,9 @@ Of all the available translation formats, only XLIFF and gettext have broad support in the tools used by professional translators. And since it's based on XML, you can validate XLIFF file contents as you write them. -Symfony supports notes in XLIFF files, making them more user-friendly for -translators. At the end, good translations are all about context, and these -XLIFF notes allow you to define that context. +Symfony 2.6 added support for notes inside XLIFF files, making them more +user-friendly for translators. At the end, good translations are all about +context, and these XLIFF notes allow you to define that context. .. tip:: diff --git a/best_practices/introduction.rst b/best_practices/introduction.rst index dad135249e6..2c5661c6671 100644 --- a/best_practices/introduction.rst +++ b/best_practices/introduction.rst @@ -76,8 +76,12 @@ installer and then execute this command to download the demo application: .. code-block:: bash + # Linux and Mac OS X $ symfony demo + # Windows + c:\> php symfony demo + **The demo application is a simple blog engine**, because that will allow us to focus on the Symfony concepts and features without getting buried in difficult implementation details. Instead of developing the application step by step in diff --git a/best_practices/security.rst b/best_practices/security.rst index 37f3bfd254a..eb3367da146 100644 --- a/best_practices/security.rst +++ b/best_practices/security.rst @@ -264,65 +264,37 @@ the same ``getAuthorEmail`` logic you used above: namespace AppBundle\Security; - use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; - use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; - use Symfony\Component\Security\Core\Authorization\Voter\Voter; + use Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter; use Symfony\Component\Security\Core\User\UserInterface; - use AppBundle\Entity\Post; - class PostVoter extends Voter + // AbstractVoter class requires Symfony 2.6 or higher version + class PostVoter extends AbstractVoter { const CREATE = 'create'; const EDIT = 'edit'; - /** - * @var AccessDecisionManagerInterface - */ - private $decisionManager; - - public function __construct(AccessDecisionManagerInterface $decisionManager) + protected function getSupportedAttributes() { - $this->decisionManager = $decisionManager; + return array(self::CREATE, self::EDIT); } - protected function supports($attribute, $subject) + protected function getSupportedClasses() { - if (!in_array($attribute, array(self::CREATE, self::EDIT))) { - return false; - } - - if (!$subject instanceof Post) { - return false; - } - - return true; + return array('AppBundle\Entity\Post'); } - protected function voteOnAttribute($attribute, $subject, TokenInterface $token) + protected function isGranted($attribute, $post, $user = null) { - $user = $token->getUser(); - /** @var Post */ - $post = $subject; // $subject must be a Post instance, thanks to the supports method - if (!$user instanceof UserInterface) { return false; } - switch ($attribute) { - case self::CREATE: - // if the user is an admin, allow them to create new posts - if ($this->decisionManager->decide($token, array('ROLE_ADMIN'))) { - return true; - } - - break; - case self::EDIT: - // if the user is the author of the post, allow them to edit the posts - if ($user->getEmail() === $post->getAuthorEmail()) { - return true; - } - - break; + if ($attribute === self::CREATE && in_array('ROLE_ADMIN', $user->getRoles(), true)) { + return true; + } + + if ($attribute === self::EDIT && $user->getEmail() === $post->getAuthorEmail()) { + return true; } return false; @@ -338,7 +310,6 @@ To enable the security voter in the application, define a new service: # ... post_voter: class: AppBundle\Security\PostVoter - arguments: ['@security.access.decision_manager'] public: false tags: - { name: security.voter } @@ -366,7 +337,7 @@ via the even easier shortcut in a controller: */ public function editAction($id) { - $post = ...; // query for the post + $post = // query for the post ... $this->denyAccessUnlessGranted('edit', $post); diff --git a/best_practices/tests.rst b/best_practices/tests.rst index 1e9490d7aac..1f41afb9de7 100644 --- a/best_practices/tests.rst +++ b/best_practices/tests.rst @@ -28,8 +28,8 @@ functional tests, you can quickly spot any big errors before you deploy them: A functional test can be as easy as this:: - // tests/AppBundle/ApplicationAvailabilityFunctionalTest.php - namespace Tests\AppBundle; + // src/AppBundle/Tests/ApplicationAvailabilityFunctionalTest.php + namespace AppBundle\Tests; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; diff --git a/best_practices/web-assets.rst b/best_practices/web-assets.rst index f569c6df53a..a4160d62e2e 100644 --- a/best_practices/web-assets.rst +++ b/best_practices/web-assets.rst @@ -35,8 +35,6 @@ much more concise: Using Assetic ------------- -.. include:: /cookbook/assetic/_standard_edition_warning.inc - These days, you probably can't simply create static CSS and JavaScript files and include them in your template. Instead, you'll probably want to combine and minify these to improve client-side performance. You may also want to diff --git a/book/bundles.rst b/book/bundles.rst index db7994795c2..ff09cc6fc3e 100644 --- a/book/bundles.rst +++ b/book/bundles.rst @@ -107,7 +107,6 @@ Now that you've created the bundle, enable it via the ``AppKernel`` class:: { $bundles = array( // ... - // register your bundle new Acme\TestBundle\AcmeTestBundle(), ); @@ -123,7 +122,7 @@ generating a basic bundle skeleton: .. code-block:: bash - $ php bin/console generate:bundle --namespace=Acme/TestBundle + $ php app/console generate:bundle --namespace=Acme/TestBundle The bundle skeleton generates a basic controller, template and routing resource that can be customized. You'll learn more about Symfony's command-line diff --git a/book/configuration.rst b/book/configuration.rst index 073a658cda1..6562832ef09 100644 --- a/book/configuration.rst +++ b/book/configuration.rst @@ -122,13 +122,13 @@ FrameworkBundle configuration: .. code-block:: bash - $ php bin/console config:dump-reference FrameworkBundle + $ php app/console config:dump-reference FrameworkBundle The extension alias (configuration key) can also be used: .. code-block:: bash - $ php bin/console config:dump-reference framework + $ php app/console config:dump-reference framework .. note:: @@ -177,7 +177,7 @@ cached files and allow them to rebuild: .. code-block:: bash - $ php bin/console cache:clear --env=prod --no-debug + $ php app/console cache:clear --env=prod --no-debug .. note:: diff --git a/book/controller.rst b/book/controller.rst index c768b33407d..4515304d27c 100644 --- a/book/controller.rst +++ b/book/controller.rst @@ -533,7 +533,10 @@ console command: .. code-block:: bash - $ php bin/console debug:container + $ php app/console debug:container + +.. versionadded:: 2.6 + Prior to Symfony 2.6, this command was called ``container:debug``. For more information, see the :doc:`/book/service_container` chapter. @@ -840,10 +843,16 @@ method to check the CSRF token:: // ... do something, like deleting an object } - // isCsrfTokenValid() is equivalent to: - // $this->get('security.csrf.token_manager')->isTokenValid( - // new \Symfony\Component\Security\Csrf\CsrfToken\CsrfToken('token_id', $token) - // ); +.. versionadded:: 2.6 + The ``isCsrfTokenValid()`` shortcut method was introduced in Symfony 2.6. + It is equivalent to executing the following code: + + .. code-block:: php + + use Symfony\Component\Security\Csrf\CsrfToken; + + $this->get('security.csrf.token_manager') + ->isTokenValid(new CsrfToken('token_id', 'TOKEN')); Final Thoughts -------------- diff --git a/book/doctrine.rst b/book/doctrine.rst index cdb6025adc5..6287f49ecdb 100644 --- a/book/doctrine.rst +++ b/book/doctrine.rst @@ -116,7 +116,7 @@ can automatically generate an empty ``test_project`` database for you: .. code-block:: bash - $ php bin/console doctrine:database:create + $ php app/console doctrine:database:create .. sidebar:: Setting up the Database to be UTF8 @@ -128,8 +128,12 @@ can automatically generate an empty ``test_project`` database for you: .. code-block:: bash - $ php bin/console doctrine:database:drop --force - $ php bin/console doctrine:database:create + $ php app/console doctrine:database:drop --force + $ php app/console doctrine:database:create + + There's no way to configure these defaults inside Doctrine, as it tries to be + as agnostic as possible in terms of environment configuration. One way to solve + this problem is to configure server-level defaults. Setting UTF8 defaults for MySQL is as simple as adding a few lines to your configuration file (typically ``my.cnf``): @@ -141,55 +145,6 @@ can automatically generate an empty ``test_project`` database for you: collation-server = utf8mb4_general_ci # Replaces utf8_general_ci character-set-server = utf8mb4 # Replaces utf8 - You can also change the defaults for Doctrine so that the generated SQL - uses the correct character set. - - .. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - doctrine: - dbal: - charset: utf8mb4 - default_table_options: - charset: utf8mb4 - collate: utf8mb4_unicode_ci - - .. code-block:: xml - - - - - - - - utf8mb4 - utf8mb4_unicode_ci - - - - - .. code-block:: php - - // app/config/config.php - $configuration->loadFromExtension('doctrine', array( - 'dbal' => array( - 'charset' => 'utf8mb4', - 'default_table_options' => array( - 'charset' => 'utf8mb4' - 'collate' => 'utf8mb4_unicode_ci' - ) - ), - )); - We recommend against MySQL's ``utf8`` character set, since it does not support 4-byte unicode characters, and strings containing them will be truncated. This is fixed by the `newer utf8mb4 character set`_. @@ -272,7 +227,7 @@ just a simple PHP class. .. code-block:: bash - $ php bin/console doctrine:generate:entity + $ php app/console doctrine:generate:entity .. index:: single: Doctrine; Adding mapping metadata @@ -441,7 +396,7 @@ the following command can generate these boilerplate methods automatically: .. code-block:: bash - $ php bin/console doctrine:generate:entities AppBundle/Entity/Product + $ php app/console doctrine:generate:entities AppBundle/Entity/Product This command makes sure that all the getters and setters are generated for the ``Product`` class. This is a safe command - you can run it over and @@ -482,10 +437,10 @@ mapping information) of a bundle or an entire namespace: .. code-block:: bash # generates all entities in the AppBundle - $ php bin/console doctrine:generate:entities AppBundle + $ php app/console doctrine:generate:entities AppBundle # generates all entities of bundles in the Acme namespace - $ php bin/console doctrine:generate:entities Acme + $ php app/console doctrine:generate:entities Acme .. _book-doctrine-creating-the-database-tables-schema: @@ -500,7 +455,7 @@ in your application. To do this, run: .. code-block:: bash - $ php bin/console doctrine:schema:update --force + $ php app/console doctrine:schema:update --force .. tip:: @@ -723,7 +678,7 @@ you have a route that maps a product id to an update action in a controller:: $product->setName('New product name!'); $em->flush(); - return $this->redirectToRoute('homepage'); + return $this->redirect($this->generateUrl('homepage')); } Updating an object involves just three steps: @@ -897,7 +852,7 @@ used earlier to generate the missing getter and setter methods: .. code-block:: bash - $ php bin/console doctrine:generate:entities AppBundle + $ php app/console doctrine:generate:entities AppBundle Next, add a new method - ``findAllOrderedByName()`` - to the newly generated repository class. This method will query for all the ``Product`` entities, @@ -951,7 +906,7 @@ you can let Doctrine create the class for you. .. code-block:: bash - $ php bin/console doctrine:generate:entity --no-interaction \ + $ php app/console doctrine:generate:entity --no-interaction \ --entity="AppBundle:Category" \ --fields="name:string(255)" @@ -1108,7 +1063,7 @@ methods for you: .. code-block:: bash - $ php bin/console doctrine:generate:entities AppBundle + $ php app/console doctrine:generate:entities AppBundle Ignore the Doctrine metadata for a moment. You now have two classes - ``Category`` and ``Product`` with a natural one-to-many relationship. The ``Category`` @@ -1137,7 +1092,7 @@ table, and ``product.category_id`` column, and new foreign key: .. code-block:: bash - $ php bin/console doctrine:schema:update --force + $ php app/console doctrine:schema:update --force .. note:: @@ -1252,8 +1207,7 @@ to the given ``Category`` object via their ``category_id`` value. $category = $product->getCategory(); // prints "Proxies\AppBundleEntityCategoryProxy" - dump(get_class($category)); - die(); + var_dump(get_class($category)); This proxy object extends the true ``Category`` object, and looks and acts exactly like it. The difference is that, by using a proxy object, diff --git a/book/forms.rst b/book/forms.rst index 0fde7985056..b1c88f77da5 100644 --- a/book/forms.rst +++ b/book/forms.rst @@ -80,9 +80,6 @@ from inside a controller:: use AppBundle\Entity\Task; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\Form\Extension\Core\Type\TextType; - use Symfony\Component\Form\Extension\Core\Type\DateType; - use Symfony\Component\Form\Extension\Core\Type\SubmitType; class DefaultController extends Controller { @@ -94,9 +91,9 @@ from inside a controller:: $task->setDueDate(new \DateTime('tomorrow')); $form = $this->createFormBuilder($task) - ->add('task', TextType::class) - ->add('dueDate', DateType::class) - ->add('save', SubmitType::class, array('label' => 'Create Task')) + ->add('task', 'text') + ->add('dueDate', 'date') + ->add('save', 'submit', array('label' => 'Create Task')) ->getForm(); return $this->render('default/new.html.twig', array( @@ -119,13 +116,16 @@ building the form. 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. ``TextType`` and ``DateType``), -represented by its fully qualified class name. Among other things, it determines -which HTML form tag(s) is rendered for that field. +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 with a custom label for submitting the form to the server. +.. versionadded:: 2.3 + Support for submit buttons was introduced in Symfony 2.3. Before that, you had + to add buttons to the form's HTML manually. + Symfony comes with many built-in types that will be discussed shortly (see :ref:`book-forms-type-reference`). @@ -224,9 +224,9 @@ your controller:: $task = new Task(); $form = $this->createFormBuilder($task) - ->add('task', TextType::class) - ->add('dueDate', DateType::class) - ->add('save', SubmitType::class, array('label' => 'Create Task')) + ->add('task', 'text') + ->add('dueDate', 'date') + ->add('save', 'submit', array('label' => 'Create Task')) ->getForm(); $form->handleRequest($request); @@ -241,13 +241,19 @@ your controller:: 'form' => $form->createView(), )); } - + .. caution:: Be aware that the ``createView()`` method should be called *after* ``handleRequest`` is called. Otherwise, changes done in the ``*_SUBMIT`` events aren't applied to the view (like validation errors). +.. versionadded:: 2.3 + The :method:`Symfony\\Component\\Form\\FormInterface::handleRequest` method + was introduced 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: @@ -290,15 +296,18 @@ possible paths: Submitting Forms with Multiple Buttons ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. versionadded:: 2.3 + Support for buttons in forms was introduced 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. To do this, add a second button with the caption "Save and add" to your form:: $form = $this->createFormBuilder($task) - ->add('task', TextType::class) - ->add('dueDate', DateType::class) - ->add('save', SubmitType::class, array('label' => 'Create Task')) - ->add('saveAndAdd', SubmitType::class, array('label' => 'Save and Add')) + ->add('task', 'text') + ->add('dueDate', 'date') + ->add('save', 'submit', array('label' => 'Create Task')) + ->add('saveAndAdd', 'submit', array('label' => 'Save and Add')) ->getForm(); In your controller, use the button's @@ -465,6 +474,10 @@ you'll need to specify which validation group(s) your form should use:: 'validation_groups' => array('registration'), ))->add(...); +.. versionadded:: 2.7 + The ``configureOptions()`` method was introduced in Symfony 2.7. Previously, + the method was called ``setDefaultOptions()``. + If you're creating :ref:`form classes ` (a good practice), then you'll need to add the following to the ``configureOptions()`` method:: @@ -487,6 +500,9 @@ be used to validate the underlying object. Disabling Validation ~~~~~~~~~~~~~~~~~~~~ +.. versionadded:: 2.3 + The ability to set ``validation_groups`` to false was introduced in Symfony 2.3. + Sometimes it is useful to suppress the validation of a form altogether. For these cases you can set the ``validation_groups`` option to ``false``:: @@ -587,6 +603,9 @@ work in the book section about :ref:`validation groups createFormBuilder($task) // ... - ->add('nextStep', SubmitType::class) - ->add('previousStep', SubmitType::class) + ->add('nextStep', 'submit') + ->add('previousStep', 'submit') ->getForm(); Then, we configure the button for returning to the previous step to run @@ -607,7 +626,7 @@ so we set its ``validation_groups`` option to false:: $form = $this->createFormBuilder($task) // ... - ->add('previousStep', SubmitType::class, array( + ->add('previousStep', 'submit', array( 'validation_groups' => false, )) ->getForm(); @@ -640,11 +659,11 @@ Field Type Options Each field type has a number of options that can be used to configure it. For example, the ``dueDate`` field is currently being rendered as 3 select -boxes. However, the :doc:`DateType ` can be +boxes. However, the :doc:`date field ` can be configured to be rendered as a single text box (where the user would enter the date as a string in the box):: - ->add('dueDate', DateType::class, array('widget' => 'single_text')) + ->add('dueDate', 'date', array('widget' => 'single_text')) .. image:: /images/book/form-simple2.png :align: center @@ -662,7 +681,7 @@ the documentation for each type. :ref:`disable HTML5 validation ` or set the ``required`` option on your field to ``false``:: - ->add('dueDate', DateType::class, array( + ->add('dueDate', 'date', array( 'widget' => 'single_text', 'required' => false )) @@ -681,7 +700,7 @@ the documentation for each type. The label for the form field can be set using the ``label`` option, which can be applied to any field:: - ->add('dueDate', DateType::class, array( + ->add('dueDate', 'date', array( 'widget' => 'single_text', 'label' => 'Due Date', )) @@ -702,7 +721,7 @@ Now that you've added validation metadata to the ``Task`` class, Symfony already knows a bit about your fields. If you allow it, Symfony can "guess" the type of your field and set it up for you. In this example, Symfony can guess from the validation rules that both the ``task`` field is a normal -``TextType`` field and the ``dueDate`` field is a ``DateType`` field:: +``text`` field and the ``dueDate`` field is a ``date`` field:: public function newAction() { @@ -711,7 +730,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', SubmitType::class) + ->add('save', 'submit') ->getForm(); } @@ -972,9 +991,9 @@ ways. If you build your form in the controller, you can use ``setAction()`` and $form = $this->createFormBuilder($task) ->setAction($this->generateUrl('target_route')) ->setMethod('GET') - ->add('task', TextType::class) - ->add('dueDate', DateType::class) - ->add('save', SubmitType::class) + ->add('task', 'text') + ->add('dueDate', 'date') + ->add('save', 'submit') ->getForm(); .. note:: @@ -986,10 +1005,7 @@ 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:: - use AppBundle\Form\Type\TaskType; - // ... - - $form = $this->createForm(TaskType::class, $task, array( + $form = $this->createForm(new TaskType(), $task, array( 'action' => $this->generateUrl('target_route'), 'method' => 'GET', )); @@ -1008,7 +1024,7 @@ to the ``form()`` or the ``form_start()`` helper: start($form, array( - 'action' => $view['router']->path('target_route'), + 'action' => $view['router']->generate('target_route'), 'method' => 'GET', )) ?> @@ -1039,7 +1055,6 @@ that will house the logic for building the task form:: use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; - use Symfony\Component\Form\Extension\Core\Type\SubmitType; class TaskType extends AbstractType { @@ -1048,21 +1063,36 @@ that will house the logic for building the task form:: $builder ->add('task') ->add('dueDate', null, array('widget' => 'single_text')) - ->add('save', SubmitType::class) + ->add('save', 'submit') ; } + + public function getName() + { + return 'app_task'; + } } +.. caution:: + + The ``getName()`` method returns the identifier of this form "type". These + identifiers must be unique in the application. Unless you want to override + a built-in type, they should be different from the default Symfony types + and from any type defined by a third-party bundle installed in your application. + Consider prefixing your types with ``app_`` to avoid identifier collisions. + This new class contains all the directions needed to create the task form. It can be used to quickly build a form object in the controller:: // src/AppBundle/Controller/DefaultController.php + + // add this new use statement at the top of the class use AppBundle\Form\Type\TaskType; public function newAction() { $task = ...; - $form = $this->createForm(TaskType::class, $task); + $form = $this->createForm(new TaskType(), $task); // ... } @@ -1109,7 +1139,7 @@ the choice is ultimately up to you. $builder ->add('task') ->add('dueDate', null, array('mapped' => false)) - ->add('save', SubmitType::class) + ->add('save', 'submit') ; } @@ -1129,8 +1159,8 @@ the choice is ultimately up to you. Defining your Forms as Services ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Your form type might have some external dependencies. You can define your form -type as a service, and inject all dependencies you need. +Defining your form type as a service is a good practice and makes it really +easy to use in your application. .. note:: @@ -1138,39 +1168,6 @@ type as a service, and inject all dependencies you need. :doc:`later on in this book `. Things will be more clear after reading that chapter. -You might want to use a service defined as ``app.my_service`` in your form -type. Create a constructor to your form type to receive the service:: - - // src/AppBundle/Form/Type/TaskType.php - namespace AppBundle\Form\Type; - - use App\Utility\MyService; - use Symfony\Component\Form\AbstractType; - use Symfony\Component\Form\FormBuilderInterface; - use Symfony\Component\Form\Extension\Core\Type\SubmitType; - - class TaskType extends AbstractType - { - private $myService; - - public function __construct(MyService $myService) - { - $this->myService = $myService; - } - - public function buildForm(FormBuilderInterface $builder, array $options) - { - // You can now use myService. - $builder - ->add('task') - ->add('dueDate', null, array('widget' => 'single_text')) - ->add('save', SubmitType::class) - ; - } - } - -Define your form type as a service. - .. configuration-block:: .. code-block:: yaml @@ -1179,9 +1176,8 @@ Define your form type as a service. services: app.form.type.task: class: AppBundle\Form\Type\TaskType - arguments: ["@app.my_service"] tags: - - { name: form.type } + - { name: form.type, alias: app_task } .. code-block:: xml @@ -1193,8 +1189,7 @@ Define your form type as a service. - - + @@ -1202,11 +1197,43 @@ Define your form type as a service. .. code-block:: php // src/AppBundle/Resources/config/services.php - use Symfony\Component\DependencyInjection\Reference; + $container + ->register( + 'app.form.type.task', + 'AppBundle\Form\Type\TaskType' + ) + ->addTag('form.type', array( + 'alias' => 'app_task', + )) + ; + +That's it! Now you can use your form type directly in a controller:: + + // src/AppBundle/Controller/DefaultController.php + // ... + + public function newAction() + { + $task = ...; + $form = $this->createForm('task', $task); - $container->register('app.form.type.task', 'AppBundle\Form\Type\TaskType') - ->addArgument(new Reference('app.my_service')) - ->addTag('form.type') + // ... + } + +or even use from within the form type of another form:: + + // src/AppBundle/Form/Type/ListType.php + // ... + + class ListType extends AbstractType + { + public function buildForm(FormBuilderInterface $builder, array $options) + { + // ... + + $builder->add('someTask', 'task'); + } + } Read :ref:`form-cookbook-form-field-service` for more information. @@ -1332,6 +1359,11 @@ create a form class so that a ``Category`` object can be modified by the user:: 'data_class' => 'AppBundle\Entity\Category', )); } + + public function getName() + { + return 'category'; + } } The end goal is to allow the ``Category`` of a ``Task`` to be modified right @@ -1342,13 +1374,12 @@ class: .. code-block:: php use Symfony\Component\Form\FormBuilderInterface; - use AppBundle\Form\Type\CategoryType; public function buildForm(FormBuilderInterface $builder, array $options) { // ... - $builder->add('category', CategoryType::class); + $builder->add('category', new CategoryType()); } The fields from ``CategoryType`` can now be rendered alongside those from @@ -1395,7 +1426,7 @@ form with many ``Product`` sub-forms). This is done by using the ``collection`` field type. For more information see the ":doc:`/cookbook/form/form_collections`" cookbook -entry and the :doc:`CollectionType ` reference. +entry and the :doc:`collection ` field type reference. .. index:: single: Forms; Theming @@ -1819,10 +1850,10 @@ an array of the submitted data. This is actually really easy:: { $defaultData = array('message' => 'Type your message here'); $form = $this->createFormBuilder($defaultData) - ->add('name', TextType::class) - ->add('email', EmailType::class) - ->add('message', TextareaType::class) - ->add('send', SubmitType::class) + ->add('name', 'text') + ->add('email', 'email') + ->add('message', 'textarea') + ->add('send', 'submit') ->getForm(); $form->handleRequest($request); @@ -1883,13 +1914,12 @@ but here's a short example: use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\NotBlank; - use Symfony\Component\Form\Extension\Core\Type\TextType; $builder - ->add('firstName', TextType::class, array( + ->add('firstName', 'text', array( 'constraints' => new Length(array('min' => 3)), )) - ->add('lastName', TextType::class, array( + ->add('lastName', 'text', array( 'constraints' => array( new NotBlank(), new Length(array('min' => 3)), @@ -1929,7 +1959,7 @@ Learn more from the Cookbook ---------------------------- * :doc:`/cookbook/doctrine/file_uploads` -* :doc:`FileType Reference ` +* :doc:`File Field Reference ` * :doc:`Creating Custom Field Types ` * :doc:`/cookbook/form/form_customization` * :doc:`/cookbook/form/dynamic_form_modification` diff --git a/book/from_flat_php_to_symfony2.rst b/book/from_flat_php_to_symfony2.rst index 6c87f84e4f4..899f8280f43 100644 --- a/book/from_flat_php_to_symfony2.rst +++ b/book/from_flat_php_to_symfony2.rst @@ -417,7 +417,7 @@ content: { "require": { - "symfony/symfony": "3.0.*" + "symfony/symfony": "2.6.*" }, "autoload": { "files": ["model.php","controllers.php"] @@ -573,7 +573,7 @@ database and the Templating component to render a template and return a
  • - generate( 'blog_show', array('id' => $post->getId()) ) ?>"> diff --git a/book/http_cache.rst b/book/http_cache.rst index 76879a288a6..2e3d803fa2a 100644 --- a/book/http_cache.rst +++ b/book/http_cache.rst @@ -145,9 +145,12 @@ To enable caching, modify the code of a front controller to use the caching kernel:: // web/app.php + require_once __DIR__.'/../app/bootstrap.php.cache'; + require_once __DIR__.'/../app/AppKernel.php'; + require_once __DIR__.'/../app/AppCache.php'; + use Symfony\Component\HttpFoundation\Request; - // ... $kernel = new AppKernel('prod', false); $kernel->loadClassCache(); // wrap the default AppKernel with the AppCache one @@ -909,7 +912,7 @@ Here is how you can configure the Symfony reverse proxy to support the if ('127.0.0.1' !== $request->getClientIp()) { return new Response( 'Invalid HTTP method', - Response::HTTP_BAD_REQUEST + 400 ); } @@ -1084,18 +1087,24 @@ matter), Symfony uses the standard ``render`` helper to configure ESI tags: - + // you can use a controller reference + use Symfony\Component\HttpKernel\Controller\ControllerReference; render( - new \Symfony\Component\HttpKernel\Controller\ControllerReference( + new ControllerReference( 'AppBundle:News:latest', array('maxPerPage' => 5) ), array('strategy' => 'esi') ) ?> - + // ... or a URL + use Symfony\Component\Routing\Generator\UrlGeneratorInterface; render( - $view['router']->url('latest_news', array('maxPerPage' => 5)), + $view['router']->generate( + 'latest_news', + array('maxPerPage' => 5), + UrlGeneratorInterface::ABSOLUTE_URL + ), array('strategy' => 'esi'), ) ?> diff --git a/book/http_fundamentals.rst b/book/http_fundamentals.rst index 97c9e346323..8f8da7213cc 100644 --- a/book/http_fundamentals.rst +++ b/book/http_fundamentals.rst @@ -282,7 +282,7 @@ interface to construct the response that needs to be returned to the client:: $response = new Response(); $response->setContent('

    Hello world!

    '); - $response->setStatusCode(Response::HTTP_OK); + $response->setStatusCode(200); $response->headers->set('Content-Type', 'text/html'); // prints the HTTP headers followed by the content @@ -377,7 +377,7 @@ on that value. This can get ugly quickly:: } elseif ('/contact' === $path) { $response = new Response('Contact us'); } else { - $response = new Response('Page not found.', Response::HTTP_NOT_FOUND); + $response = new Response('Page not found.', 404); } $response->send(); diff --git a/book/includes/_service_container_my_mailer.rst.inc b/book/includes/_service_container_my_mailer.rst.inc deleted file mode 100644 index f14c2fbe282..00000000000 --- a/book/includes/_service_container_my_mailer.rst.inc +++ /dev/null @@ -1,35 +0,0 @@ -.. configuration-block:: - - .. code-block:: yaml - - # app/config/services.yml - services: - app.mailer: - class: AppBundle\Mailer - arguments: [sendmail] - - .. code-block:: xml - - - - - - - - sendmail - - - - - .. code-block:: php - - // app/config/services.php - use Symfony\Component\DependencyInjection\Definition; - - $container->setDefinition('app.mailer', new Definition( - 'AppBundle\Mailer', - array('sendmail') - )); diff --git a/book/installation.rst b/book/installation.rst index 7adbdc415fc..68ceeba99a5 100644 --- a/book/installation.rst +++ b/book/installation.rst @@ -4,16 +4,9 @@ Installing and Configuring Symfony ================================== -Welcome to Symfony! Starting a new Symfony project is easy. In fact, you'll have -your first working Symfony application up and running in just a few short minutes. - -.. seealso:: - - Do you prefer video tutorials? Check out the `Joyful Development with Symfony`_ - screencast series from KnpUniversity. - -To make creating new applications even simpler, Symfony provides an installer. -Downloading it is your first step. +The goal of this chapter is to get you up and running with a working application +built on top of Symfony. In order to simplify the process of creating new +applications, Symfony provides an installer application. Installing the Symfony Installer -------------------------------- @@ -61,8 +54,6 @@ execute it as follows: c:\> move symfony c:\projects c:\projects\> php symfony -.. _installation-creating-the-app: - Creating the Symfony Application -------------------------------- @@ -104,15 +95,15 @@ optional second argument of the ``new`` command: .. code-block:: bash # use the most recent version in any Symfony branch - $ symfony new my_project_name 2.8 - $ symfony new my_project_name 3.0 + $ symfony new my_project_name 2.6 + $ symfony new my_project_name 2.7 # use a specific Symfony version + $ symfony new my_project_name 2.6.5 $ symfony new my_project_name 2.7.3 - $ symfony new my_project_name 2.8.1 # use a beta or RC version (useful for testing new Symfony versions) - $ symfony new my_project 3.0.0-BETA1 + $ symfony new my_project 2.7.0-BETA1 $ symfony new my_project 2.7.0-RC1 The installer also supports a special version called ``lts`` which installs the @@ -159,7 +150,7 @@ version as the second argument of the ``create-project`` command: .. code-block:: bash - $ composer create-project symfony/framework-standard-edition my_project_name "3.0.*" + $ composer create-project symfony/framework-standard-edition my_project_name "2.7.*" .. tip:: @@ -177,7 +168,7 @@ browsing the project directory and executing this command: .. code-block:: bash $ cd my_project_name/ - $ php bin/console server:run + $ php app/console server:run Then, open your browser and access the ``http://localhost:8000/`` URL to see the Welcome Page of Symfony: @@ -223,10 +214,10 @@ If there are any issues, correct them now before moving on. .. sidebar:: Setting up Permissions - One common issue when installing Symfony is that the ``var`` directory must - be writable both by the web server and the command line user. On a UNIX - system, if your web server user is different from your command line user - who owns the files, you can try one of the following solutions. + One common issue when installing Symfony is that the ``app/cache`` and + ``app/logs`` directories must be writable both by the web server and the + command line user. On a UNIX system, if your web server user is different + from your command line user, you can try one of the following solutions. **1. Use the same user for the CLI and the web server** @@ -245,11 +236,12 @@ If there are any issues, correct them now before moving on. .. code-block:: bash - $ rm -rf var/cache/* var/logs/* var/sessions/* + $ rm -rf app/cache/* + $ rm -rf app/logs/* $ HTTPDUSER=`ps axo user,comm | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\ -f1` - $ sudo chmod -R +a "$HTTPDUSER allow delete,write,append,file_inherit,directory_inherit" var - $ sudo chmod -R +a "`whoami` allow delete,write,append,file_inherit,directory_inherit" var + $ sudo chmod +a "$HTTPDUSER allow delete,write,append,file_inherit,directory_inherit" app/cache app/logs + $ sudo chmod +a "`whoami` allow delete,write,append,file_inherit,directory_inherit" app/cache app/logs **3. Using ACL on a system that does not support chmod +a** @@ -263,8 +255,8 @@ If there are any issues, correct them now before moving on. .. code-block:: bash $ HTTPDUSER=`ps axo user,comm | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\ -f1` - $ sudo setfacl -R -m u:"$HTTPDUSER":rwX -m u:`whoami`:rwX var - $ sudo setfacl -dR -m u:"$HTTPDUSER":rwX -m u:`whoami`:rwX var + $ sudo setfacl -R -m u:"$HTTPDUSER":rwX -m u:`whoami`:rwX app/cache app/logs + $ sudo setfacl -dR -m u:"$HTTPDUSER":rwX -m u:`whoami`:rwX app/cache app/logs If this doesn't work, try adding ``-n`` option. @@ -273,7 +265,7 @@ If there are any issues, correct them now before moving on. If none of the previous methods work for you, change the umask so that the cache and log directories will be group-writable or world-writable (depending if the web server user and the command line user are in the same group or not). - To achieve this, put the following line at the beginning of the ``bin/console``, + To achieve this, put the following line at the beginning of the ``app/console``, ``web/app.php`` and ``web/app_dev.php`` files:: umask(0002); // This will let the permissions be 0775 @@ -314,7 +306,7 @@ several minutes to complete. .. code-block:: bash - $ php bin/console security:check + $ php app/console security:check A good security practice is to execute this command regularly to be able to update or replace compromised dependencies as soon as possible. @@ -339,7 +331,7 @@ of the Symfony Installer anywhere in your system: c:\projects\> php symfony demo Once downloaded, enter into the ``symfony_demo/`` directory and run the PHP's -built-in web server executing the ``php bin/console server:run`` command. Access +built-in web server executing the ``php app/console server:run`` command. Access to the ``http://localhost:8000`` URL in your browser to start using the Symfony Demo application. @@ -414,7 +406,6 @@ need in your new application. Be sure to also check out the :doc:`Cookbook `, which contains a wide variety of articles about solving specific problems with Symfony. -.. _`Joyful Development with Symfony`: http://knpuniversity.com/screencast/symfony .. _`explained in this post`: http://fabien.potencier.org/signing-project-releases.html .. _`Composer`: https://getcomposer.org/ .. _`Composer download page`: https://getcomposer.org/download/ diff --git a/book/page_creation.rst b/book/page_creation.rst index cc32869e341..ce3be3ce65b 100644 --- a/book/page_creation.rst +++ b/book/page_creation.rst @@ -21,11 +21,6 @@ simple two-step process: Just like on the web, every interaction is initiated by an HTTP request. Your job is pure and simple: understand that request and return a response. -.. seealso:: - - Do you prefer video tutorials? Check out the `Joyful Development with Symfony`_ - screencast series from KnpUniversity. - .. index:: single: Page creation; Example @@ -97,8 +92,8 @@ Suppose you want to create a JSON endpoint that returns the lucky number. Just add a second method to ``LuckyController``:: // src/AppBundle/Controller/LuckyController.php - // ... + class LuckyController { // ... @@ -127,8 +122,8 @@ Try this out in your browser: You can even shorten this with the handy :class:`Symfony\\Component\\HttpFoundation\\JsonResponse`:: // src/AppBundle/Controller/LuckyController.php - // ... + // --> don't forget this new use statement use Symfony\Component\HttpFoundation\JsonResponse; @@ -163,8 +158,8 @@ at the end: .. code-block:: php-annotations // src/AppBundle/Controller/LuckyController.php - // ... + class LuckyController { /** @@ -269,8 +264,8 @@ to use Twig - or many other tools in Symfony - is to extend Symfony's base :class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller` class:: // src/AppBundle/Controller/LuckyController.php - // ... + // --> add this new use statement use Symfony\Bundle\FrameworkBundle\Controller\Controller; @@ -291,8 +286,8 @@ Twig templates, another that can log messages and many more. To render a Twig template, use a service called ``templating``:: // src/AppBundle/Controller/LuckyController.php - // ... + class LuckyController extends Controller { /** @@ -324,8 +319,8 @@ But this can get even easier! By extending the ``Controller`` class, you also get a lot of shortcut methods, like ``render()``:: // src/AppBundle/Controller/LuckyController.php - // ... + /** * @Route("/lucky/number/{count}") */ @@ -429,41 +424,30 @@ worked inside the two most important directories: else). As you get more advanced, you'll learn what can be done inside each of these. -The ``app/`` directory also holds some other things, like ``app/AppKernel.php``, -which you'll use to enable new bundles (this is one of a *very* short list of +The ``app/`` directory also holds a few other things, like the cache directory +``app/cache/``, the logs directory ``app/logs/`` and ``app/AppKernel.php``, +which you'll use to enable new bundles (and one of a *very* short list of PHP files in ``app/``). The ``src/`` directory has just one directory - ``src/AppBundle`` - and everything lives inside of it. A bundle is like a "plugin" and you can `find open source bundles`_ and install them into your project. But even -*your* code lives in a bundle - typically *AppBundle* (though there's -nothing special about AppBundle). To find out more about bundles and +*your* code lives in a bundle - typically ``AppBundle`` (though there's +nothing special about ``AppBundle``). To find out more about bundles and why you might create multiple bundles (hint: sharing code between projects), see the :doc:`Bundles ` chapter. So what about the other directories in the project? +``vendor/`` + Vendor (i.e. third-party) libraries and bundles are downloaded here by + the `Composer`_ package manager. + ``web/`` This is the document root for the project and contains any publicly accessible files, like CSS, images and the Symfony front controllers that execute the app (``app_dev.php`` and ``app.php``). -``tests/`` - The automatic tests (e.g. Unit tests) of your application live here. - -``bin/`` - The "binary" files live here. The most important one is the ``console`` - file which is used to execute Symfony commands via the console. - -``var/`` - This is where automatically created files are stored, like cache files - (``var/cache/``) and logs (``var/logs/``). - -``vendor/`` - Third-party libraries, packages and bundles are downloaded here by - the `Composer`_ package manager. You should never edit something in this - directory. - .. seealso:: Symfony is flexible. If you need to, you can easily override the default @@ -481,8 +465,8 @@ is ``app/config/config.yml``: .. code-block:: yaml # app/config/config.yml - # ... + framework: secret: '%secret%' router: @@ -550,11 +534,11 @@ by changing one option in this configuration file. To find out how, see the :doc:`Configuration Reference ` section. Or, to get a big example dump of all of the valid configuration under a key, -use the handy ``bin/console`` command: +use the handy ``app/console`` command: .. code-block:: bash - $ php bin/console config:dump-reference framework + $ app/console config:dump-reference framework There's a lot more power behind Symfony's configuration system, including environments, imports and parameters. To learn all of it, see the @@ -581,7 +565,6 @@ There's also a :doc:`Cookbook ` *packed* with more advanced Have fun! -.. _`Joyful Development with Symfony`: http://knpuniversity.com/screencast/symfony/first-page -.. _`app/Resources/views/base.html.twig`: https://github.com/symfony/symfony-standard/blob/3.0/app/Resources/views/base.html.twig +.. _`app/Resources/views/base.html.twig`: https://github.com/symfony/symfony-standard/blob/2.7/app/Resources/views/base.html.twig .. _`Composer`: https://getcomposer.org .. _`find open source bundles`: http://knpbundles.com diff --git a/book/performance.rst b/book/performance.rst index c60554015b8..c73ed68c1ee 100644 --- a/book/performance.rst +++ b/book/performance.rst @@ -75,18 +75,16 @@ If you're using the Standard Distribution, this code should already be available as comments in this file:: // app.php - // ... - $loader = require __DIR__.'/../app/autoload.php'; - include_once __DIR__.'/../var/bootstrap.php.cache'; - // Enable APC for autoloading to improve performance. - // You should change the ApcClassLoader first argument to a unique prefix - // in order to prevent cache key conflicts with other applications - // also using APC. + + $loader = require_once __DIR__.'/../app/bootstrap.php.cache'; + + // Use APC for autoloading to improve performance + // Change 'sf2' by the prefix you want in order + // to prevent key conflict with another application /* - $apcLoader = new Symfony\Component\ClassLoader\ApcClassLoader(sha1(__FILE__), $loader); - $loader->unregister(); - $apcLoader->register(true); + $loader = new ApcClassLoader('sf2', $loader); + $loader->register(true); */ // ... @@ -121,7 +119,7 @@ If you're using the Symfony Standard Edition, then you're probably already using the bootstrap file. To be sure, open your front controller (usually ``app.php``) and check to make sure that the following line exists:: - include_once __DIR__.'/../var/bootstrap.php.cache'; + require_once __DIR__.'/../app/bootstrap.php.cache'; Note that there are two disadvantages when using a bootstrap file: diff --git a/book/routing.rst b/book/routing.rst index 30453bee220..5d6fedff601 100644 --- a/book/routing.rst +++ b/book/routing.rst @@ -1402,7 +1402,10 @@ the command by running the following from the root of your project. .. code-block:: bash - $ php bin/console debug:router + $ php app/console debug:router + +.. versionadded:: 2.6 + Prior to Symfony 2.6, this command was called ``router:debug``. This command will print a helpful list of *all* the configured routes in your application: @@ -1421,14 +1424,14 @@ the route name after the command: .. code-block:: bash - $ php bin/console debug:router article_show + $ php app/console debug:router article_show Likewise, if you want to test whether a URL matches a given route, you can use the ``router:match`` console command: .. code-block:: bash - $ php bin/console router:match /blog/my-latest-post + $ php app/console router:match /blog/my-latest-post This command will print which route the URL matches. @@ -1537,7 +1540,7 @@ a template helper function: .. code-block:: html+php -
    generate('blog_show', array( 'slug' => 'my-blog-post', )) ?>"> Read this blog post. @@ -1558,8 +1561,9 @@ method:: $this->generateUrl('blog_show', array('slug' => 'my-blog-post'), UrlGeneratorInterface::ABSOLUTE_URL); // http://www.example.com/blog/my-blog-post -From a template, simply use the ``url()`` function (which generates an absolute -URL) rather than the ``path()`` function (which generates a relative URL): +From a template, in Twig, simply use the ``url()`` function (which generates an absolute URL) +rather than the ``path()`` function (which generates a relative URL). In PHP, pass ``true`` +to ``generate()``: .. configuration-block:: @@ -1571,9 +1575,13 @@ URL) rather than the ``path()`` function (which generates a relative URL): .. code-block:: html+php - generate('blog_show', array( 'slug' => 'my-blog-post', - )) ?>"> + ), UrlGeneratorInterface::ABSOLUTE_URL) ?>"> Read this blog post. diff --git a/book/security.rst b/book/security.rst index e81df02bff7..5021eb14406 100644 --- a/book/security.rst +++ b/book/security.rst @@ -510,12 +510,14 @@ else, you'll want to encode their passwords. The best algorithm to use is // ... )); +.. include:: /cookbook/security/_ircmaxwell_password-compat.rst.inc + Of course, your users' passwords now need to be encoded with this exact algorithm. -For hardcoded users, you can use the built-in command: +For hardcoded users, since 2.7 you can use the built-in command: .. code-block:: bash - $ php bin/console security:encode-password + $ php app/console security:encode-password It will give you something like this: @@ -844,6 +846,15 @@ You can easily deny access from inside a controller:: // ... } +.. versionadded:: 2.6 + The ``denyAccessUnlessGranted()`` method was introduced in Symfony 2.6. Previously (and + still now), you could check access directly and throw the ``AccessDeniedException`` as shown + in the example above). + +.. versionadded:: 2.6 + The ``security.authorization_checker`` service was introduced in Symfony 2.6. Prior + to Symfony 2.6, you had to use the ``isGranted()`` method of the ``security.context`` service. + In both cases, a special :class:`Symfony\\Component\\Security\\Core\\Exception\\AccessDeniedException` is thrown, which ultimately triggers a 403 HTTP response inside Symfony. @@ -878,7 +889,7 @@ Access Control in Templates ........................... If you want to check if the current user has a role inside a template, use -the built-in ``is_granted()`` helper function: +the built-in helper function: .. configuration-block:: @@ -894,6 +905,20 @@ the built-in ``is_granted()`` helper function: Delete +If you use this function and you are *not* behind a firewall, an exception will +be thrown. Again, it's almost always a good idea to have a main firewall that +covers all URLs (as shown before in this chapter). + +.. caution:: + + Be careful with this in your base layout or on your error pages! Because of + some internal Symfony details, to avoid broken error pages in the ``prod`` + environment, wrap calls in these templates with a check for ``app.user``: + + .. code-block:: html+twig + + {% if app.user and is_granted('ROLE_ADMIN') %} + Securing other Services ....................... @@ -996,6 +1021,10 @@ shown above. Retrieving the User Object -------------------------- +.. versionadded:: 2.6 + The ``security.token_storage`` service was introduced in Symfony 2.6. Prior + to Symfony 2.6, you had to use the ``getToken()`` method of the ``security.context`` service. + After authentication, the ``User`` object of the current user can be accessed via the ``security.token_storage`` service. From inside a controller, this will look like:: @@ -1204,6 +1233,9 @@ in the following way from a controller:: $user->setPassword($encoded); +.. versionadded:: 2.6 + The ``security.password_encoder`` service was introduced in Symfony 2.6. + In order for this to work, just make sure that you have the encoder for your user class (e.g. ``AppBundle\Entity\User``) configured under the ``encoders`` key in ``app/config/security.yml``. @@ -1346,7 +1378,7 @@ security vulnerability in your installed dependencies: .. code-block:: bash - $ php bin/console security:check + $ php app/console security:check A good security practice is to execute this command regularly to be able to update or replace compromised dependencies as soon as possible. Internally, diff --git a/book/service_container.rst b/book/service_container.rst index a3439ff7a46..3e411f6a9dc 100644 --- a/book/service_container.rst +++ b/book/service_container.rst @@ -145,7 +145,7 @@ As a bonus, the ``Mailer`` service is only created once and the same instance is returned each time you ask for the service. This is almost always the behavior you'll need (it's more flexible and powerful), but you'll learn later how you can configure a service that has multiple instances in the -":doc:`/cookbook/service_container/shared`" cookbook article. +":doc:`/cookbook/service_container/scopes`" cookbook article. .. note:: @@ -811,15 +811,13 @@ Injecting the dependency by the setter method just needs a change of syntax: "property injection". .. _book-container-request-stack: -.. _injecting-the-request: -Accessing the Request in a Service -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Injecting the Request +~~~~~~~~~~~~~~~~~~~~~ -Whenever you need to access the current request in a service, you can either -add it as an argument to the methods that need the request or inject the -``request_stack`` service and access the ``Request`` by calling the -:method:`Symfony\\Component\\HttpFoundation\\RequestStack::getCurrentRequest` +As of Symfony 2.4, instead of injecting the ``request`` service, you should +inject the ``request_stack`` service and access the ``Request`` by calling +the :method:`Symfony\\Component\\HttpFoundation\\RequestStack::getCurrentRequest` method:: namespace Acme\HelloBundle\Newsletter; @@ -886,6 +884,20 @@ Now, just inject the ``request_stack``, which behaves like any normal service: array(new Reference('request_stack')) )); +.. sidebar:: Why not Inject the ``request`` Service? + + 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). + + .. tip:: If you define a controller as a service then you can get the ``Request`` @@ -982,7 +994,7 @@ which you can access inside a standard controller as follows:: In Symfony, you'll constantly use services provided by the Symfony core or other third-party bundles to perform tasks such as rendering templates (``templating``), -sending emails (``mailer``), or accessing information on the request through the request stack (``request_stack``). +sending emails (``mailer``), or accessing information on the request (``request``). You can take this a step further by using these services inside services that you've created for your application. Beginning by modifying the ``NewsletterManager`` @@ -1136,13 +1148,16 @@ console. To show all services and the class for each service, run: .. code-block:: bash - $ php bin/console debug:container + $ php app/console debug:container + +.. versionadded:: 2.6 + Prior to Symfony 2.6, this command was called ``container:debug``. By default, only public services are shown, but you can also view private services: .. code-block:: bash - $ php bin/console debug:container --show-private + $ php app/console debug:container --show-private .. note:: @@ -1156,7 +1171,7 @@ its id: .. code-block:: bash - $ php bin/console debug:container app.mailer + $ php app/console debug:container app.mailer Learn more ---------- @@ -1168,6 +1183,7 @@ Learn more * :doc:`/components/dependency_injection/parentservices` * :doc:`/components/dependency_injection/tags` * :doc:`/cookbook/controller/service` +* :doc:`/cookbook/service_container/scopes` * :doc:`/cookbook/service_container/compiler_passes` * :doc:`/components/dependency_injection/advanced` diff --git a/book/templating.rst b/book/templating.rst index be8167e5a89..23dbfab869a 100644 --- a/book/templating.rst +++ b/book/templating.rst @@ -159,7 +159,7 @@ Twig Template Caching Twig is fast. Each Twig template is compiled down to a native PHP class that is rendered at runtime. The compiled classes are located in the -``var/cache/{environment}/twig`` directory (where ``{environment}`` is the +``app/cache/{environment}/twig`` directory (where ``{environment}`` is the environment, such as ``dev`` or ``prod``) and in some cases can be useful while debugging. See :ref:`environments-summary` for more information on environments. @@ -579,6 +579,10 @@ you set `with_context`_ to false). maps (i.e. an array with named keys). If you needed to pass in multiple elements, it would look like this: ``{'foo': foo, 'bar': bar}``. +.. versionadded:: 2.3 + The `include() function`_ is available since Symfony 2.3. Prior, the + `{% include %} tag`_ was used. + .. index:: single: Templating; Embedding action @@ -706,7 +710,7 @@ tags: ) ?> render( - $view['router']->url('...'), + $view['router']->generate('...'), array('renderer' => 'hinclude') ) ?> @@ -914,7 +918,7 @@ To link to the page, just use the ``path`` Twig function and refer to the route: .. code-block:: html+php - Home + Home As expected, this will generate the URL ``/``. Now, for a more complicated route: @@ -993,7 +997,7 @@ correctly: - generate('article_show', array( 'slug' => $article->getSlug(), )) ?>"> getTitle() ?> @@ -1002,20 +1006,26 @@ correctly: .. tip:: - You can also generate an absolute URL by using the ``url`` function: + You can also generate an absolute URL by using the ``url`` Twig function: - .. configuration-block:: + .. code-block:: html+twig - .. code-block:: html+twig + Home - Home + The same can be done in PHP templates by passing a third argument to + the ``generate()`` method: - .. code-block:: html+php + .. code-block:: html+php + + - Home + Home .. index:: single: Templating; Linking to assets @@ -1113,9 +1123,9 @@ advantage of Symfony's template inheritance. .. tip:: This section will teach you the philosophy behind including stylesheet - and JavaScript assets in Symfony. Symfony is also compatible with another - library, called Assetic, which follows this philosophy but allows you to do - much more interesting things with those assets. For more information on + and JavaScript assets in Symfony. Symfony also packages another library, + called Assetic, which follows this philosophy but allows you to do much + more interesting things with those assets. For more information on using Assetic see :doc:`/cookbook/assetic/asset_management`. Start by adding two blocks to your base template that will hold your assets: @@ -1201,7 +1211,7 @@ should use the ``parent()`` Twig function to include everything from the ``style block of the base template. You can also include assets located in your bundles' ``Resources/public`` folder. -You will need to run the ``php bin/console assets:install target [--symlink]`` +You will need to run the ``php app/console assets:install target [--symlink]`` command, which moves (or symlinks) files into the correct location. (target is by default "web"). @@ -1221,6 +1231,8 @@ is a :class:`Symfony\\Bundle\\FrameworkBundle\\Templating\\GlobalVariables` instance which will give you access to some application specific variables automatically: +``app.security`` (deprecated as of 2.6) + The security context. ``app.user`` The current user object. ``app.request`` @@ -1250,6 +1262,12 @@ automatically:

    Application Environment: getEnvironment() ?>

    +.. versionadded:: 2.6 + The global ``app.security`` variable (or the ``$app->getSecurity()`` + method in PHP templates) is deprecated as of Symfony 2.6. Use ``app.user`` + (``$app->getUser()``) and ``is_granted()`` (``$view['security']->isGranted()``) + instead. + .. tip:: You can add your own global template variables. See the cookbook example @@ -1373,7 +1391,7 @@ to create it). You're now free to customize the template. .. caution:: If you add a template in a new location, you *may* need to clear your - cache (``php bin/console cache:clear``), even if you are in debug mode. + cache (``php app/console cache:clear``), even if you are in debug mode. This logic also applies to base bundle templates. Suppose also that each template in AcmeBlogBundle inherits from a base template called @@ -1623,10 +1641,10 @@ console command: .. code-block:: bash # You can check by filename: - $ php bin/console lint:twig app/Resources/views/article/recent_list.html.twig + $ php app/console lint:twig app/Resources/views/article/recent_list.html.twig # or by directory: - $ php bin/console lint:twig app/Resources/views + $ php app/console lint:twig app/Resources/views .. _template-formats: @@ -1678,7 +1696,7 @@ key in the parameter hash: .. code-block:: html+php - generate('article_show', array( 'id' => 123, '_format' => 'pdf', )) ?>"> diff --git a/book/testing.rst b/book/testing.rst index fc9a66f6cd7..1e63c9e23f1 100644 --- a/book/testing.rst +++ b/book/testing.rst @@ -21,16 +21,18 @@ it has its own excellent `documentation`_. to use version 4.2 or higher to test the Symfony core code itself). Each test - whether it's a unit test or a functional test - is a PHP class -that should live in the ``tests/`` directory of your application. If you follow +that should live in the ``Tests/`` subdirectory of your bundles. If you follow this rule, then you can run all of your application's tests with the following command: .. code-block:: bash - $ phpunit + # specify the configuration directory on the command line + $ phpunit -c app/ -PHPunit is configured by the ``phpunit.xml.dist`` file in the root of your -Symfony application. +The ``-c`` option tells PHPUnit to look in the ``app/`` directory for a configuration +file. If you're curious about the PHPUnit options, check out the ``app/phpunit.xml.dist`` +file. .. tip:: @@ -62,11 +64,11 @@ called ``Calculator`` in the ``Util/`` directory of the app bundle:: } } -To test this, create a ``CalculatorTest`` file in the ``tests/AppBundle/Util`` directory +To test this, create a ``CalculatorTest`` file in the ``Tests/Util`` directory of your bundle:: - // tests/AppBundle/Util/CalculatorTest.php - namespace Tests\AppBundle\Util; + // src/AppBundle/Tests/Util/CalculatorTest.php + namespace AppBundle\Tests\Util; use AppBundle\Util\Calculator; @@ -84,30 +86,30 @@ of your bundle:: .. note:: - By convention, the ``Tests/AppBundle`` directory should replicate the directory - of your bundle for unit tests. So, if you're testing a class in the - ``AppBundle/Util/`` directory, put the test in the ``tests/AppBundle/Util/`` + By convention, the ``Tests/`` sub-directory should replicate the directory + of your bundle for unit tests. So, if you're testing a class in your + bundle's ``Util/`` directory, put the test in the ``Tests/Util/`` directory. Just like in your real application - autoloading is automatically enabled -via the ``autoload.php`` file (as configured by default in the -``phpunit.xml.dist`` file). +via the ``bootstrap.php.cache`` file (as configured by default in the +``app/phpunit.xml.dist`` file). Running tests for a given file or directory is also very easy: .. code-block:: bash # run all tests of the application - $ phpunit + $ phpunit -c app # run all tests in the Util directory - $ phpunit tests/AppBundle/Util + $ phpunit -c app src/AppBundle/Tests/Util # run tests for the Calculator class - $ phpunit tests/AppBundle/Util/CalculatorTest.php + $ phpunit -c app src/AppBundle/Tests/Util/CalculatorTest.php # run all tests for the entire Bundle - $ phpunit tests/AppBundle/ + $ phpunit -c app src/AppBundle/ .. index:: single: Tests; Functional tests @@ -128,15 +130,15 @@ tests as far as PHPUnit is concerned, but they have a very specific workflow: Your First Functional Test ~~~~~~~~~~~~~~~~~~~~~~~~~~ -Functional tests are simple PHP files that typically live in the ``tests/AppBundle/Controller`` -directory for your bundle. If you want to test the pages handled by your +Functional tests are simple PHP files that typically live in the ``Tests/Controller`` +directory of your bundle. If you want to test the pages handled by your ``PostController`` class, start by creating a new ``PostControllerTest.php`` file that extends a special ``WebTestCase`` class. As an example, a test could look like this:: - // tests/AppBundle/Controller/PostControllerTest.php - namespace Tests\AppBundle\Controller; + // src/AppBundle/Tests/Controller/PostControllerTest.php + namespace AppBundle\Tests\Controller; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; @@ -242,10 +244,6 @@ document:: To get you started faster, here is a list of the most common and useful test assertions:: - use Symfony\Component\HttpFoundation\Response; - - // ... - // Assert that there is at least one h2 tag // with the class "subtitle" $this->assertGreaterThan( @@ -275,7 +273,7 @@ document:: $this->assertTrue($client->getResponse()->isNotFound()); // Assert a specific 200 status code $this->assertEquals( - 200, // or Symfony\Component\HttpFoundation\Response::HTTP_OK + 200, $client->getResponse()->getStatusCode() ); @@ -420,6 +418,11 @@ The Client supports many operations that can be done in a real browser:: Accessing Internal Objects ~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. versionadded:: 2.3 + The :method:`Symfony\\Component\\BrowserKit\\Client::getInternalRequest` + and :method:`Symfony\\Component\\BrowserKit\\Client::getInternalResponse` + methods were introduced in Symfony 2.3. + If you use the client to test your application, you might want to access the client's internal objects:: @@ -460,7 +463,10 @@ Injection Container:: Be warned that this does not work if you insulate the client or if you use an HTTP layer. For a list of services available in your application, use the -``debug:container`` console task. +``container:debug`` console task. + +.. versionadded:: 2.6 + Prior to Symfony 2.6, this command was called ``container:debug``. .. tip:: @@ -687,11 +693,6 @@ their type:: // Upload a file $form['photo']->upload('/path/to/lucas.jpg'); -.. tip:: - - If you purposefully want to select "invalid" select/radio values, see - :ref:`components-dom-crawler-invalid`. - .. tip:: You can get the values that will be submitted by calling the ``getValues()`` @@ -789,26 +790,30 @@ PHPUnit Configuration ~~~~~~~~~~~~~~~~~~~~~ Each application has its own PHPUnit configuration, stored in the -``phpunit.xml.dist`` file. You can edit this file to change the defaults or -create an ``phpunit.xml`` file to set up a configuration for your local machine -only. +``app/phpunit.xml.dist`` file. You can edit this file to change the defaults or +create an ``app/phpunit.xml`` file to set up a configuration for your local +machine only. .. tip:: - Store the ``phpunit.xml.dist`` file in your code repository and ignore - the ``phpunit.xml`` file. + Store the ``app/phpunit.xml.dist`` file in your code repository and ignore + the ``app/phpunit.xml`` file. -By default, only the tests stored in ``/tests`` are run via the ``phpunit`` command, -as configured in the ``phpunit.xml.dist`` file: +By default, only the tests from your own custom bundles stored in the standard +directories ``src/*/*Bundle/Tests``, ``src/*/Bundle/*Bundle/Tests``, +``src/*Bundle/Tests`` are run by the ``phpunit`` command, as configured +in the ``app/phpunit.xml.dist`` file: .. code-block:: xml - + - tests + ../src/*/*Bundle/Tests + ../src/*/Bundle/*Bundle/Tests + ../src/*Bundle/Tests @@ -819,7 +824,7 @@ configuration adds tests from a custom ``lib/tests`` directory: .. code-block:: xml - + @@ -836,7 +841,7 @@ section: .. code-block:: xml - + diff --git a/book/translation.rst b/book/translation.rst index e21f5b7084d..cfb0a753a24 100644 --- a/book/translation.rst +++ b/book/translation.rst @@ -334,7 +334,7 @@ The translator service is accessible in PHP templates through the Translation Resource/File Names and Locations --------------------------------------------- -Symfony looks for message files (i.e. translations) in the following default locations: +Symfony looks for message files (i.e. translations) in the following locations: * the ``app/Resources/translations`` directory; @@ -372,51 +372,6 @@ The choice of which loader to use is entirely up to you and is a matter of taste. The recommended option is to use ``xlf`` for translations. For more options, see :ref:`component-translator-message-catalogs`. -.. note:: - - You can add other directories with the ``paths`` option in the configuration: - - .. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - framework: - translator: - paths: - - '%kernel.root_dir%/../translations' - - .. code-block:: xml - - - - - - - - %kernel.root_dir%/../translations - - - - - .. code-block:: php - - // app/config/config.php - $container->loadFromExtension('framework', array( - 'translator' => array( - 'paths' => array( - '%kernel.root_dir%/../translations', - ), - ), - )); - .. note:: You can also store translations in a database, or any other storage by @@ -432,7 +387,7 @@ For more options, see :ref:`component-translator-message-catalogs`. .. code-block:: bash - $ php bin/console cache:clear + $ php app/console cache:clear .. _book-translation-fallback: @@ -452,6 +407,9 @@ checks translation resources for several locales: #. If the translation still isn't found, Symfony uses the ``fallbacks`` configuration parameter, which defaults to ``en`` (see `Configuration`_). +.. versionadded:: 2.6 + The ability to log missing translations was introduced in Symfony 2.6. + .. note:: When Symfony doesn't find a translation in the given locale, it will @@ -743,6 +701,9 @@ For more information, see the documentation for these libraries. Debugging Translations ---------------------- +.. versionadded:: 2.6 + Prior to Symfony 2.6, this command was called ``translation:debug``. + When maintaining a bundle, you may use or remove the usage of a translation message without updating all message catalogues. The ``debug:translation`` command helps you to find these missing or unused translation messages for a @@ -854,7 +815,7 @@ To inspect all messages in the ``fr`` locale for the AcmeDemoBundle, run: .. code-block:: bash - $ php bin/console debug:translation fr AcmeDemoBundle + $ php app/console debug:translation fr AcmeDemoBundle You will get this output: @@ -895,15 +856,15 @@ By default all domains are inspected, but it is possible to specify a single dom .. code-block:: bash - $ php bin/console debug:translation en AcmeDemoBundle --domain=messages + $ php app/console debug:translation en AcmeDemoBundle --domain=messages When bundles have a lot of messages, it is useful to display only the unused or only the missing messages, by using the ``--only-unused`` or ``--only-missing`` switches: .. code-block:: bash - $ php bin/console debug:translation en AcmeDemoBundle --only-unused - $ php bin/console debug:translation en AcmeDemoBundle --only-missing + $ php app/console debug:translation en AcmeDemoBundle --only-unused + $ php app/console debug:translation en AcmeDemoBundle --only-missing Summary ------- diff --git a/book/validation.rst b/book/validation.rst index e4b9d2c8579..d3082713234 100644 --- a/book/validation.rst +++ b/book/validation.rst @@ -103,6 +103,11 @@ following: Protected and private properties can also be validated, as well as "getter" methods (see :ref:`validator-constraint-targets`). +.. versionadded:: 2.7 + As of Symfony 2.7, XML and Yaml constraint files located in the + ``Resources/config/validation`` sub-directory of a bundle are loaded. Prior + to 2.7, only ``Resources/config/validation.yml`` (or ``.xml``) were loaded. + .. index:: single: Validation; Using the validator @@ -225,7 +230,7 @@ workflow looks like the following from inside a controller:: public function updateAction(Request $request) { $author = new Author(); - $form = $this->createForm(AuthorType::class, $author); + $form = $this->createForm(new AuthorType(), $author); $form->handleRequest($request); @@ -877,8 +882,12 @@ the class name or the string ``Default``. To tell the validator to use a specific group, pass one or more group names as the third argument to the ``validate()`` method:: + // If you're using the new 2.5 validation API (you probably are!) $errors = $validator->validate($author, null, array('registration')); + // If you're using the old 2.4 validation API, pass the group names as the second argument + // $errors = $validator->validate($author, array('registration')); + If no groups are specified, all constraints that belong to the group ``Default`` will be applied. @@ -1239,11 +1248,20 @@ it looks like this:: $emailConstraint->message = 'Invalid email address'; // use the validator to validate the value + // If you're using the new 2.5 validation API (you probably are!) $errorList = $this->get('validator')->validate( $email, $emailConstraint ); + // If you're using the old 2.4 validation API + /* + $errorList = $this->get('validator')->validateValue( + $email, + $emailConstraint + ); + */ + if (0 === count($errorList)) { // ... this IS a valid email address, do something } else { diff --git a/changelog.rst b/changelog.rst index 129366565c0..ff4202fb450 100644 --- a/changelog.rst +++ b/changelog.rst @@ -19,7 +19,6 @@ March, 2016 New Documentation ~~~~~~~~~~~~~~~~~ -* `#6274 `_ Update Doctrine UTF8 docs (mcfedr) * `#6282 `_ [Form] fix ``choice_label`` values (HeahDude) * `#5894 `_ [WIP] Added an article to explain how to upgrade third-party bundles to Symfony 3 (javiereguiluz) * `#6273 `_ [PHPUnit bridge] Add documentation for the component (theofidry) @@ -28,28 +27,20 @@ New Documentation Fixed Documentation ~~~~~~~~~~~~~~~~~~~ -* `#6377 `_ Update "bootstrap.php.cache" to "autoload.php" (guilliamxavier) -* `#6368 `_ [cookbook] Made list of form types more consistent (AAstakhov) * `#6366 `_ Removed server:stop code block for 2.3 (theyoux) * `#6347 `_ Add a note about enabling DebugBundle to use VarDumper inside Symfony (martijn80, javiereguiluz) * `#6320 `_ Fixed typo in path (timhovius) * `#6334 `_ Fixed yaml configuration of app.exception_controller (AAstakhov) -* `#6322 `_ [DependencyInjection] fix autowiring docs (eXtreme) * `#6315 `_ Remove third parameter from createFormBuilder call (Hocdoc) -* `#6324 `_ Fixed UserCheckerInterface importing (VIs-a-vis) -* `#6326 `_ Missing svn:ignore (f-plante) Minor Documentation Changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~ * `#6404 `_ fixed a typo (RickieL) -* `#6409 `_ Update 'date' to DateType::class in form.rst (iltar) * `#6411 `_ Fixed a typo in configuration-block (VarunAgw) * `#6414 `_ stick to Sphinx 1.3.x for the moment (xabbuh) * `#6399 `_ Fixed wrong code examples for Isbn constraint (AAstakhov) * `#6397 `_ Fix typo in SwitchUserListener file name (luxifer) -* `#6390 `_ Reworded the example about $deep param (Oliboy50, javiereguiluz) -* `#6381 `_ [Form] [Cookbook] Correctly setup unit tests with dependencies (corphi) * `#6382 `_ unused use instructions (bshevchenko) * `#6365 `_ Removed the PR table example (this is now included by GitHub template) (javiereguiluz) * `#6363 `_ Removed info about reducing visibility for private (AAstakhov) @@ -67,7 +58,6 @@ Minor Documentation Changes * `#6345 `_ Remove link-local IPv6 address (snoek09) * `#6219 `_ Point that route parameters are also Request attributes (sfdumi) * `#6348 `_ [best practices] mostly typos (Talita Kocjan Zager) -* `#6350 `_ Fix reference to app folder (kainjow) * `#6275 `_ [quick tour] mostly typos (Talita Kocjan Zager) * `#6305 `_ Mention IvoryCKEditorBundle in the Symfony Forms doc (javiereguiluz) * `#6331 `_ Rename DunglasApiBundle to ApiPlatform (sroze) @@ -77,10 +67,8 @@ Minor Documentation Changes * `#6330 `_ [Form] reorder EntityType options (HeahDude) * `#6337 `_ Fix configuration.rst typo (gong023) * `#6295 `_ Update tools.rst (andrewtch) -* `#6323 `_ [DependencyInjection] Add Autowiring keyword (theofidry) * `#6325 `_ Minor error (ThomasLandauer) * `#6311 `_ Improved TwigExtension to show default values and optional arguments (javiereguiluz) -* `#6286 `_ [HttpFoundation] Fix typo for ParameterBag getters - 3.0 (rendler-denis) * `#6267 `_ [Form] fix 'data_class' option in EntityType (HeahDude) * `#6281 `_ Change isValid to isSubmitted. (mustafaaloko) @@ -93,21 +81,15 @@ New Documentation * `#6172 `_ move assets options from templating to assets section and add base_path documentation (snoek09) * `#6021 `_ mention routing from the database (dbu) -* `#6032 `_ [DependencyInjection] Autowiring doc (dunglas) * `#6233 `_ Document translation_domain for choice fields (merorafael, WouterJ) * `#5655 `_ Added doc about Homestead's Symfony integration (WouterJ) -* `#5886 `_ [2.8] Add "How to Use Multiple Guard Authenticators" cookbook documentation (mheki) * `#6072 `_ Add browserkit component documentation (yamiko, yamiko-ninja, robert Parker, javiereguiluz) * `#6243 `_ Add missing getBoolean() method (bocharsky-bw) * `#6231 `_ Use hash_equals instead of StringUtils::equals (WouterJ) -* `#5530 `_ [Cookbook, Security] Added user_checkers.rst (iltar) -* `#5920 `_ Document automatic registration of extension compiler passes (WouterJ) * `#5724 `_ Describe configuration behaviour with multiple mailers (xelan) * `#6077 `_ fixes #5971 (vincentaubert) -* `#5483 `_ [FrameworkBundle] Name converter of Serializer (dunglas) * `#6156 `_ [reference] [form] [options] fix #6153 (HeahDude) * `#6104 `_ Fix #6103 (zsturgess) -* `#6058 `_ Update Testing Form Types article for 2.8 refactorings (WouterJ) * `#5856 `_ Reworded the "How to use Gmail" cookbook article (javiereguiluz) * `#6230 `_ Add annotation to glossary (rebased) (DerStoffel) * `#5642 `_ Documented label_format option (WouterJ) @@ -115,49 +97,38 @@ New Documentation Fixed Documentation ~~~~~~~~~~~~~~~~~~~ -* `#6292 `_ Fix setting permission for var subdirectories (voda) * `#5995 `_ Update dev_environment.rst (gonzalovilaseca) * `#6240 `_ [#6224] some tweaks (xabbuh) * `#5513 `_ [load_balancer_reverse_proxy ] Always use 127.0.0.1 as a trusted proxy (ruudk) -* `#6081 `_ [cookbook New project] Fix symfony version and initial add (bigs21) * `#6124 `_ [cookbook] Add annotations block and fix regex (peterkokot) Minor Documentation Changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~ * `#6308 `_ fix literal syntax (xabbuh) -* `#6299 `_ Removed True and False constraints from reference (edefimov) -* `#6298 `_ Update dependency_injection.rst because it has an error. (joserprieto) -* `#6263 `_ [Cookbook][Debugging] reflect behavior changes in cache generation (xabbuh) * `#6251 `_ To use annotations, files must be removed (pbowyer) * `#6288 `_ Update factories.rst (velikanov) * `#6278 `_ [HttpFoundation] Fix typo for ParameterBag getters (rendler-denis) * `#6280 `_ Fix syntax of Company class example (cakper) * `#6284 `_ [Book] [Routing] Fix third param true to UrlGeneratorInterface::ABSOLUTE_URI (eriwin) * `#6269 `_ [Cookbook][Bundles]fix yaml syntax (mhor) -* `#6277 `_ remove dot in front of colon (xabbuh) * `#6255 `_ [Cookbook][Doctrine] some tweaks to the Doctrine registration article (xabbuh) * `#6229 `_ Rewrite EventDispatcher introduction (WouterJ) * `#6260 `_ add missing options `choice_value`, `choice_name` and `choice_attr` to `EntityType` (HeahDude) * `#6262 `_ [Form] reorder options in choice types references (HeahDude) * `#6256 `_ Fixed code example (twifty) -* `#6257 `_ [Components][Form] remove outdated caution (xabbuh) -* `#6253 `_ [Security] Include guard firewall configuration sample. (calinpristavu) * `#6250 `_ [Cookbook][Console] remove note about memory spool handling on CLI (xabbuh) * `#6249 `_ [Cookbook][Serializer] fix wording (xabbuh) -* `#6242 `_ Removed all 2.x versionadded directives (WouterJ) * `#6246 `_ removed duplicate lines (seferov) * `#6222 `_ Updated "Learn more from the Cookbook" section (sfdumi) * `#6245 `_ [Cookbook][Console] change API doc class name (xabbuh) * `#6223 `_ Improveme the apache/mod_php configuration example (gnat42) * `#6234 `_ File System Security Issue in Custom Auth Article (finished) (mattjanssen, WouterJ) * `#4773 `_ [Cookbook] Make registration_form follow best practices (xelaris) -* `#6090 `_ Reworded the article about profiler storage (xavierleune, javiereguiluz) * `#5630 `_ Add a caution about logout when using http-basic authenticated firewall (rmed19) * `#6215 `_ Added a caution about failing cache warmers (javiereguiluz) * `#6239 `_ Remove app_dev as build-in server is used (rmed19, WouterJ) * `#6241 `_ [ExpressionLanguage] Add caution about backslash handling (zerustech, WouterJ) -* `#6235 `_ #6232 update forms as services section (backbone87) * `#6236 `_ fix some minor typos (xabbuh) * `#6237 `_ use literals for external class names (xabbuh) * `#6206 `_ add separate placeholder examples for birthday, datetime and time type (snoek09) @@ -166,16 +137,10 @@ Minor Documentation Changes * `#5958 `_ Update security.rst (mpaquet) * `#6092 `_ Updated information about testing code coverage. (roga) * `#6051 `_ Mention HautelookAliceBundle in best practices (theofidry, WouterJ) -* `#6044 `_ Added note about the hash_equals polyfill (WouterJ) -* `#6213 `_ Update form_collections.rst (insekticid) * `#6220 `_ [book] fixes typo about redirect status codes in the controller chapter. (hhamon) * `#6227 `_ Update testing.rst (dvapelnik) -* `#6228 `_ removed unnecessary exception from repository (gondo) * `#6212 `_ Typo in default session save_path (DerekRoth) * `#6208 `_ Replace references of PSR-0 with PSR-4 (opdavies) -* `#6170 `_ change translation getMessages() to getCatalogue() (snoek09) -* `#6211 `_ Remove 2.3.\* from composer snippets in the form component doc (Nicofuma) -* `#6225 `_ [Reference][Forms] add versionadded directive for range type (xabbuh) * `#6190 `_ Fix redundant command line sample (sylozof) @@ -187,8 +152,6 @@ New Documentation * `#6174 `_ Missing reference docs for kernel.finish_request event (acrobat) * `#6184 `_ added Javier as a merger for the WebProfiler bundle (fabpot) -* `#6136 `_ Update directory permissions to make var/ writable (andrerom) -* `#5600 `_ [DependencyInjection] Documented the ability of define the service decoration priority (dosten) * `#5303 `_ [WIP] 4373 - document security events (kevintweber) * `#6023 `_ clarify the routing component documentation a bit (dbu) * `#6091 `_ Added an example for info() method (javiereguiluz) @@ -198,55 +161,37 @@ Fixed Documentation * `#6193 `_ Added the missing namespace in example of a subscriber class (raulconti) * `#6152 `_ csrf_token_generator and csrf_token_id documentation (Raistlfiren, Aaron Valandra, xabbuh) -* `#6115 `_ [Form] Fix syntax error in code snippet (valisj) Minor Documentation Changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* `#6199 `_ fix types (garak) * `#6207 `_ revert form login CSRF changes on wrong branch (xabbuh) * `#6191 `_ Document the invalidate_session option (javiereguiluz) -* `#6204 `_ Expected: semicolon (cn007b) * `#6141 `_ Docs do not match functionality (Loupax) * `#6192 `_ fix MongoDB shell syntax highlighting (xabbuh) * `#6147 `_ Update templating.rst - Asset absolute url fix (gbalcewicz) * `#6187 `_ Typofix for "Defining and Processing Configuration Values" (kix) -* `#6182 `_ Latest demo has no bin folder (Jace25) * `#6183 `_ use valid XML in code block (xabbuh) * `#6180 `_ use single quotes for YAML strings (snoek09) * `#6070 `_ Typo in When Things Get More Advanced (BallisticPain) * `#6119 `_ Remove phrase "in order" (micheal) * `#6160 `_ remove versionadded for unmaintained versions (xabbuh) * `#6161 `_ [Contributing][Documentation] replace EOL with EOM (xabbuh) -* `#6166 `_ Fix by_reference deprecated FormType::class (nemo-) * `#6162 `_ [Reference] add missing version number (xabbuh) * `#6163 `_ Remove excessive pluses (aivus) -* `#6082 `_ change app/check.php for 3.0 (nanocom) -* `#6149 `_ Reference to session + Corrected sample code char (sfdumi) -* `#6130 `_ [Security][Guard] Completed start method signature (jeremyFreeAgent) -* `#6080 `_ Removed doc about getting original parameter value from ParameterBag (edefimov) * `#6158 `_ Update override_dir_structure.rst (denniskoenigComparon) * `#6122 `_ Added missing mandatory parameter (yceruto) -* `#6108 `_ [Form] remove the getName() function as it is deprecated (aybbou) * `#6100 `_ [Cookbook][Security] add back updateUserSecurityIdentity() hint (xabbuh) -* `#6129 `_ Added new links to the Symfony screencast series at KnpU (javiereguiluz) * `#6138 `_ Correction needed (pfleu) -* `#6139 `_ Update the doc to change a deprecated use case (ChristopheBoucaut) * `#6133 `_ fixed the component name (fabpot) * `#6127 `_ escape namespace backslashes in class role (xabbuh) * `#5818 `_ document old way of checking validity of CSRF token (snoek09) * `#6062 `_ Update HTTP method requirement example (WouterJ) -* `#6120 `_ fix README requirements link (garak) * `#6109 `_ add link to Monolog configuration (snoek09) -* `#6121 `_ [MicroKernel] Fixed the display of a code block (jeremyFreeAgent) * `#6096 `_ [Contributing] update year in license (xabbuh) * `#6114 `_ make method protected (OskarStark) * `#6111 `_ Fixed a typo in the choice_label code example (ferdynator) -* `#6110 `_ [Security][Guard] Fixed a typo (jeremyFreeAgent) -* `#6105 `_ Removed deprecated methods from VoterInterface (edefimov) -* `#6106 `_ Remove repetition in text (dominikhajduk) * `#6102 `_ promoted xabbuh as merger on the Yaml component (fabpot) -* `#6014 `_ [2.8][Form] entry_type option: replace "in favor" misuses (ogizanagi) * `#6013 `_ [2.7][Form] placeholder option: replace "in favor" misuses (ogizanagi) @@ -259,18 +204,13 @@ New Documentation * `#5906 `_ Added documentation for choice_translation_domain option (peterrehm) * `#6017 `_ Documented the Symfony Console Styles (javiereguiluz) * `#5811 `_ Conversion from mysql to PDO (iqbalmalik89) -* `#5966 `_ Remove deprecated StringUtils from WSSE custom auth provider (pimpreneil) * `#5962 `_ Simplify code example in "Adding custom extensions" section (snoek09) -* `#5977 `_ RequestStack parameter is required since 3.0 (leunggamciu) * `#6022 `_ clarify custom route loader documentation (dbu) * `#5994 `_ Updated the release process for Symfony 3.x and future releases (javiereguiluz) -* `#5954 `_ Fix #5236 [2.8][Translation] specify additional translation loading paths (Pierre Maraitre, Balamung) -* `#5948 `_ Update 3.0 docs accordingly to min PHP version requirement (ogizanagi) Fixed Documentation ~~~~~~~~~~~~~~~~~~~ -* `#6086 `_ Update form_customization.rst (vudaltsov) * `#6063 `_ minor #5829 Fix broken composer command (JHGitty) * `#5904 `_ Update php_soap_extension.rst (xDaizu) * `#5819 `_ Remove AppBundle (roukmoute) @@ -281,7 +221,6 @@ Minor Documentation Changes * `#6043 `_ Mention commiting only bower.json (krike, WouterJ) * `#5848 `_ Added hints to spool config section (martinczerwi) -* `#5586 `_ [2.8] Remove 2.6 versionaddeds as version reached eom (WouterJ) * `#6042 `_ some tweaks to unit testing form types (xabbuh) * `#6059 `_ Add best practice about the Form type namespace (WouterJ) * `#6068 `_ Remove references to API tagging (dunglas) @@ -290,13 +229,10 @@ Minor Documentation Changes * `#6094 `_ [Form] Added a missing php opening tag (dev-symfony-void) * `#5840 `_ [Contributing] [Standards] Add note about ``trigger_error()`` and deprecation messages (phansys) * `#6050 `_ Lots of minor fixes & applying best practices to form cookbook doc (ThomasLandauer, WouterJ) -* `#5993 `_ [Cookbook] [Security] Use UserLoaderInterface instead of UserProviderInterface (ogizanagi) -* `#6071 `_ Fix syntax (WouterJ) * `#5570 `_ Quick review of 'create framework' tutorial (WouterJ) * `#5445 `_ Reworded the explanation about the kernel.event_listener tag (javiereguiluz) * `#6054 `_ Remove 2.8 branch from patch documentation (Triiistan) * `#6057 `_ Fix PHP code for registering service (WouterJ) -* `#6066 `_ Update location of ``app/check.php`` to ``bin/symfony_requirements`` (Kevinrob) * `#6067 `_ improve phrasing (greg0ire) * `#6063 `_ minor #5829 Fix broken composer command (JHGitty) * `#6041 `_ Fixed misspelling of human in glossary.rst YAML (Wasserschlange) @@ -310,9 +246,6 @@ Minor Documentation Changes * `#6006 `_ [Book] use AppBundle examples and follow best practices (xabbuh) * `#6016 `_ Corrected the line references for the basic controller example (theTeddyBear) * `#5446 `_ [Contributing] [Standards] Added note about phpdoc_separation (phansys) -* `#6027 `_ Update guard-authentication.rst (rvanginneken) -* `#6025 `_ Update guard-authentication.rst (rvanginneken) -* `#6038 `_ Fix #6037 (zsturgess) * `#5820 `_ Fixed an issue with command option shortcuts (javiereguiluz) * `#6033 `_ Fix Typo (Shine-neko) * `#6011 `_ Fixed formatting issues (javiereguiluz) @@ -320,13 +253,11 @@ Minor Documentation Changes * `#6009 `_ Fix missing constant usage for generating urls (Tobion) * `#5965 `_ Removing php opening tags (Deamon) * `#6003 `_ #5999 fix files names (vincentaubert) -* `#6004 `_ Fix for small typo (djoos) * `#5996 `_ Clarify example for SUBMIT form event (bkosborne) * `#6000 `_ Update registration_form.rst (afurculita) * `#5989 `_ Fix words according context (richardpq) * `#5992 `_ More use single quotes for YAML strings (snoek09) * `#5957 `_ mark deep option as deprecated (snoek09) -* `#5940 `_ [Cookbook][ServiceContainer] move filename comment to the top of the code block (xabbuh) * `#5943 `_ Add tip for when returning ``null`` from ``createToken()`` (jeroenseegers) * `#5956 `_ Update security.rst (mpaquet) * `#5959 `_ Fix #5912 Ambiguity on Access Decision Manager's Strategy (Pierre Maraitre) @@ -334,10 +265,7 @@ Minor Documentation Changes * `#5979 `_ [Book] Do not extend the base controller before introducing it (ogizanagi) * `#5970 `_ Remove isSubmitted call (DanielSiepmann) * `#5972 `_ Add isSubmitted call (DanielSiepmann) -* `#5964 `_ Missing n in Column (joshuataylor) * `#5961 `_ update from_flat_php_to_symfony2.rst (thao-witkam) -* `#5924 `_ Removed note about removed content (WouterJ) -* `#5938 `_ Add proper use of the password type (themccallister) November, 2015 @@ -346,24 +274,9 @@ November, 2015 New Documentation ~~~~~~~~~~~~~~~~~ -* `#5917 `_ [3.0][Cookbook] Use the 3.0 directory structure (WouterJ) -* `#5916 `_ [3.0][Best Practices][Quick Tour] Use the 3.0 directory structure (WouterJ) -* `#5913 `_ [3.0][Book] Use the 3.0 directory structure (WouterJ) -* `#5907 `_ Updating some places to use the new CustomUserMessageAuthenticationException (weaverryan) -* `#5922 `_ Added minimal cookbook article about the shared flag (WouterJ) -* `#5908 `_ Voter update (weaverryan) -* `#5909 `_ More 2.8 form updates (weaverryan) -* `#5927 `_ Use path() and url() PHP templating helpers (WouterJ) -* `#5926 `_ Update voter section of best practices (WouterJ) -* `#5921 `_ [2.8] Document some Security changes (WouterJ) -* `#5834 `_ Updated form aliases to FQCNs for forms in book and component (hiddewie) -* `#5265 `_ Documentation for the new Guard authentication style (weaverryan) -* `#5899 `_ Adding the MicroKernel article (weaverryan) * `#5893 `_ Added a note about the use of _format query parameter (javiereguiluz) -* `#5891 `_ Removed the comments about the is_granted() issues in non-secure pages (javiereguiluz) * `#5876 `_ Symfony 2.7 Form choice option update (aivus, althaus, weaverryan) * `#5861 `_ Updated Table Console helper for spanning cols and rows (hiddewie) -* `#5835 `_ Updated CssSelector code example to use the new Converter (hiddewie) * `#5816 `_ Merge branches (nicolas-grekas, snoek09, WouterJ, xabbuh) * `#5804 `_ Added documentation for dnsMessage option (BenjaminPaap) * `#5774 `_ Show a more real example in data collectors doc (WouterJ) @@ -394,7 +307,6 @@ Minor Documentation Changes * `#5897 `_ Fixed some wrong line number references in doctrine.rst (DigNative) * `#5895 `_ Update debug_formatter.rst (strannik-06) * `#5883 `_ Book: Update Service Container Documentation (zanderbaldwin) -* `#5868 `_ [2.8] Make screenshots with the new profiler/web dev toolbar design (WouterJ) * `#5862 `_ Fixes done automatically by the docbot (WouterJ) * `#5851 `_ updated sentence (OskarStark) * `#5870 `_ Update securing_services.rst (aruku) @@ -406,7 +318,6 @@ Minor Documentation Changes * `#5813 `_ use constants to choose generated URL type (xabbuh) * `#5808 `_ Reworded the explanation about flash messages (javiereguiluz) * `#5809 `_ Minor fix (javiereguiluz) -* `#5807 `_ Minor rewordings for the "deprecated" service option (javiereguiluz) * `#5805 `_ Mentioned the BETA and RC support for the Symfony Installer (javiereguiluz) * `#5781 `_ Added annotations example to Linking to Pages examples (carlos-granados) * `#5780 `_ Clarify when we are talking about PHP and Twig (carlos-granados) @@ -428,15 +339,10 @@ New Documentation * `#5345 `_ Adding information about empty files sent using BinaryFileResponse. (kherge) * `#5214 `_ [WIP] Reworking most of the registration form: (weaverryan) -* `#5051 `_ Rename CollectionType entry options (WouterJ) * `#5677 `_ replacing deprecated usage of True, False, Null validators in docs (Tim Stamp) * `#5314 `_ Documented the useAttributeAsKey() method (javiereguiluz) * `#5377 `_ Added a cookbook section about event subscribers (beni0888, javiereguiluz) -* `#5623 `_ [Validator] added BIC validator (mvhirsch) -* `#5689 `_ [DI] Add some documentation for the deprecation feature (Taluu) * `#5592 `_ Updated the article about data collectors (javiereguiluz) -* `#5745 `_ [Translation] Ability to format a message catalogue without actually writing it. (aitboudad) -* `#5702 `_ Added a reference to the Foundation form theme (totophe) Fixed Documentation ~~~~~~~~~~~~~~~~~~~ @@ -452,7 +358,6 @@ Minor Documentation Changes * `#5812 `_ Remove duplicate and confusing info about testing error pages (carlos-granados) * `#5821 `_ Minor fixes in the HttpFoundation introduction article (javiereguiluz) * `#5822 `_ Fixed a syntax issue (javiereguiluz) -* `#5817 `_ fix version for `entry_options` and `entry_type` (craue) * `#5796 `_ Fix for #5783 (BenjaminPaap) * `#5810 `_ Fixed a typo (javiereguiluz) * `#5784 `_ Add fe80::1 (j-d) @@ -466,17 +371,14 @@ Minor Documentation Changes * `#5664 `_ Info about implicit session start (ThomasLandauer) * `#5744 `_ translations have been removed from symfony.com (xabbuh) * `#5771 `_ Remove not existing response constant (amansilla) -* `#5761 `_ [DX] [Security] Renamed key to secret (SongoQ) * `#5766 `_ Fixed two typos (ThomasLandauer) * `#5733 `_ [Components][OptionsResolver] adding type hint to normalizer callback (xabbuh) -* `#5561 `_ Change default value of cookie_httponly (jderusse) * `#5678 `_ Update HttpFoundation note after recent changes in routing component (senkal) * `#5643 `_ Document how to customize the prototype (daFish, WouterJ) * `#5584 `_ Add DebugBundle config reference (WouterJ) * `#5753 `_ configureOptions(...) : protected => public (lucascherifi) * `#5750 `_ fix YAML syntax highlighting (xabbuh) * `#5749 `_ complete Swiftmailer XML examples (xabbuh) -* `#5730 `_ Remove documentation of deprecated console shell (Tobion) * `#5726 `_ Document the support of Mintty for colors (stof) * `#5708 `_ Added caution to call createView after handleRequest (WouterJ) * `#5640 `_ Update controller.rst clarifying automatic deletion for flash messages (miguelvilata) @@ -568,7 +470,6 @@ Minor Documentation Changes * `#5553 `_ Fix all broken links/permanent redirects/removed anchors (WouterJ) * `#5650 `_ [RFR] fixing typo and removing duplicated lines in Config component doc (salahm) * `#5635 `_ Fix minor problems in book/page_creation.rst (fabschurt) -* `#5579 `_ [3.0] Remove mentions of Symfony1 (WouterJ) * `#5647 `_ don't ignore the _exts directory anymore (xabbuh) * `#5587 `_ [2.6] Don't use deprecated features (WouterJ) * `#5637 `_ Add QueryBuilder vs DQL section (bocharsky-bw) @@ -602,16 +503,13 @@ July, 2015 New Documentation ~~~~~~~~~~~~~~~~~ -* `#5374 `_ Remove deprecated parameters (norkunas) * `#5533 `_ Replace Capifony with Capistrano/symfony (mojzis) * `#5543 `_ Add deprecation notice to "choice_list" option of ChoiceType (XitasoChris) -* `#5521 `_ [Cookbook][WebServer] #5504 add a tip for the --force option (vincentaubert) * `#5516 `_ Added a note about session data size in PdoSessionHandler (javiereguiluz) * `#5499 `_ The "property" option of DoctrineType was deprecated. (XWB) * `#5491 `_ added composer info (OskarStark) * `#5478 `_ Add cookbook article for using MongoDB to store session data (stevenmusumeche) * `#5472 `_ Added a tip about hashing the result of nextBytes() (javiereguiluz) -* `#5458 `_ HTML5 range documentation (harikt) * `#5453 `_ Cleanup security voters cookbook recipes (WouterJ) * `#5444 `_ Documented the "auto_alias" feature (javiereguiluz) * `#5201 `_ [Book][Routing] Add example about how to match multiple methods (xelaris) @@ -640,7 +538,6 @@ Minor Documentation Changes * `#5580 `_ Additional User check in voter class (weaverryan) * `#5573 `_ fix YAML syntax highlighting (xabbuh) * `#5564 `_ Improve and simplify the contributing instructions about tests (javiereguiluz) -* `#5498 `_ [WIP] Added caution notes about the deprecation of container scopes (javiereguiluz) * `#5550 `_ [docbot] Reviewed some component chapters (WouterJ) * `#5556 `_ Fix typo Esi in part create framework (nicolasdewez) * `#5568 `_ [Create Framework] Fix extract calls (replaces #5522) (kenjis) @@ -693,7 +590,6 @@ New Documentation ~~~~~~~~~~~~~~~~~ * `#5423 `_ [Security] add & update doc entries on AbstractVoter implementation (Inoryy, javiereguiluz) -* `#5409 `_ [Reference] document new Doctrine APC cache service (xabbuh) * `#5401 `_ Added some more docs about the remember me feature (WouterJ) * `#5384 `_ Added information about the new date handling in the comparison constraints and Range (webmozart, javiereguiluz) * `#5382 `_ Added support for standard Forwarded header (tony-co, javiereguiluz) @@ -701,7 +597,6 @@ New Documentation * `#5332 `_ [Serializer] ObjectNormalizer, object_to_populate doc. Minor enhancements. (dunglas) * `#5335 `_ [Serializer] Updated the cookbook. (dunglas) * `#5313 `_ Documented the overridden form options (javiereguiluz) -* `#5360 `_ [Serializer] Array Denormalization (derrabus) * `#5307 `_ Update data_transformers.rst (zebba) * `#5186 `_ Added a new article about using/installing unstable Symfony versions (javiereguiluz) * `#5166 `_ Proposed a new article about using pure PHP libraries with Assetic (javiereguiluz) @@ -717,7 +612,6 @@ New Documentation * `#5355 `_ Added a mention to the Symfony Demo application (javiereguiluz) * `#5331 `_ [PSR-7] Bridge documentation (dunglas) * `#5373 `_ Added mentions to some popular (and useful) Symfony bundles (javiereguiluz) -* `#4354 `_ [WCM] Added depreciation note for the cascade_validation constraint (peterrehm) Fixed Documentation ~~~~~~~~~~~~~~~~~~~ @@ -764,7 +658,6 @@ Minor Documentation Changes * `#5381 `_ remove Yoda condition (greg0ire) * `#5452 `_ [#5388] change echo and print in examples (snoek09) * `#5451 `_ [#5388] change echo and print in examples (snoek09) -* `#3782 `_ [Form] Deprecate read_only option (snoob) * `#5432 `_ removed squashing stuff. fixes #5368 (OskarStark) * `#5383 `_ Reword a paragraph about service configurations (richardudovich) * `#5389 `_ Updates to security.rst (HexTitan) @@ -1038,7 +931,6 @@ Minor Documentation Changes - `3be0081 `_ #4976 Improved sentence (edsonmedina) - `a444220 `_ #4885 Fix typos (ifdattic) - `482502d `_ #4793 [Contributing] Several tweaks (xelaris) -- `a2395ef `_ #5054 [Changelog] fix changelog syntax (xabbuh) - `6b66f03 `_ #5003 Updated the generic Deployment article (javiereguiluz) - `39a1487 `_ #4999 Fixed semantic error (beni0888) @@ -1079,6 +971,7 @@ Minor Documentation Changes - `1726054 `_ #4500 Link to standard edition (harikt) - `91ff6f8 `_ #4329 ensure consistency with the note (greg0ire) - `f4ab4b6 `_ #5002 Revert very bad merge (WouterJ) +- `e747392 `_ Revert "#4977 Unnecessary comma (edsonmedina)" - `e5dbd49 `_ #4977 Unnecessary comma (edsonmedina) - `ed80100 `_ #4977 Unnecessary comma (edsonmedina) - `5d44987 `_ #4991 Fixed typo and tweaked syntax. (cdvrooman) diff --git a/components/asset/index.rst b/components/asset/index.rst deleted file mode 100644 index 14d04b7eb6f..00000000000 --- a/components/asset/index.rst +++ /dev/null @@ -1,7 +0,0 @@ -Asset -===== - -.. toctree:: - :maxdepth: 2 - - introduction diff --git a/components/asset/introduction.rst b/components/asset/introduction.rst deleted file mode 100644 index 9c72f9342d5..00000000000 --- a/components/asset/introduction.rst +++ /dev/null @@ -1,324 +0,0 @@ -.. index:: - single: Asset - single: Components; Asset - -The Asset Component -=================== - - The Asset component manages URL generation and versioning of web assets such - as CSS stylesheets, JavaScript files and image files. - -In the past, it was common for web applications to hardcode URLs of web assets. -For example: - -.. code-block:: html - - - - - - - -This practice is no longer recommended unless the web application is extremely -simple. Hardcoding URLs can be a disadvantage because: - -* **Templates get verbose**: you have to write the full path for each - asset. When using the Asset component, you can group assets in packages to - avoid repeating the common part of their path; -* **Versioning is difficult**: it has to be custom managed for each - application. Adding a version (e.g. ``main.css?v=5``) to the asset URLs - is essential for some applications because it allows you to control how - the assets are cached. The Asset component allows you to define different - versioning strategies for each package; -* **Moving assets location** is cumbersome and error-prone: it requires you to - carefully update the URLs of all assets included in all templates. The Asset - component allows to move assets effortlessly just by changing the base path - value associated with the package of assets; -* **It's nearly impossible to use multiple CDNs**: this technique requires - you to change the URL of the asset randomly for each request. The Asset component - provides out-of-the-box support for any number of multiple CDNs, both regular - (``http://``) and secure (``https://``). - -Installation ------------- - -You can install the component in two different ways: - -* :doc:`Install it via Composer ` (``symfony/asset`` on `Packagist`_); -* Use the official Git repository (https://github.com/symfony/asset). - -Usage ------ - -Asset Packages -~~~~~~~~~~~~~~ - -The Asset component manages assets through packages. A package groups all the -assets which share the same properties: versioning strategy, base path, CDN hosts, -etc. In the following basic example, a package is created to manage assets without -any versioning:: - - use Symfony\Component\Asset\Package; - use Symfony\Component\Asset\VersionStrategy\EmptyVersionStrategy; - - $package = new Package(new EmptyVersionStrategy()); - - echo $package->getUrl('/image.png'); - // result: /image.png - -Packages implement :class:`Symfony\\Component\\Asset\\PackageInterface`, -which defines the following two methods: - -:method:`Symfony\\Component\\Asset\\PackageInterface::getVersion` - Returns the asset version for an asset. - -:method:`Symfony\\Component\\Asset\\PackageInterface::getUrl` - Returns an absolute or root-relative public path. - -With a package, you can: - -A) :ref:`version the assets `; -B) set a :ref:`common base path ` (e.g. ``/css``) - for the assets; -C) :ref:`configure a CDN ` for the assets - -.. _component-assets-versioning: - -Versioned Assets -~~~~~~~~~~~~~~~~ - -One of the main features of the Asset component is the ability to manage -the versioning of the application's assets. Asset versions are commonly used -to control how these assets are cached. - -Instead of relying on a simple version mechanism, the Asset component allows -you to define advanced versioning strategies via PHP classes. The two built-in -strategies are the :class:`Symfony\\Component\\Asset\\VersionStrategy\\EmptyVersionStrategy`, -which doesn't add any version to the asset and :class:`Symfony\\Component\\Asset\\VersionStrategy\\StaticVersionStrategy`, -which allows you to set the version with a format string. - -In this example, the ``StaticVersionStrategy`` is used to append the ``v1`` -suffix to any asset path:: - - use Symfony\Component\Asset\Package; - use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy; - - $package = new Package(new StaticVersionStrategy('v1')); - - echo $package->getUrl('/image.png'); - // result: /image.png?v1 - -In case you want to modify the version format, pass a sprintf-compatible format -string as the second argument of the ``StaticVersionStrategy`` constructor:: - - // put the 'version' word before the version value - $package = new Package(new StaticVersionStrategy('v1', '%s?version=%s')); - - echo $package->getUrl('/image.png'); - // result: /image.png?version=v1 - - // put the asset version before its path - $package = new Package(new StaticVersionStrategy('v1', '%2$s/%1$s')); - - echo $package->getUrl('/image.png'); - // result: /v1/image.png - -Custom Version Strategies -......................... - -Use the :class:`Symfony\\Component\\Asset\\VersionStrategy\\VersionStrategyInterface` -to define your own versioning strategy. For example, your application may need -to append the current date to all its web assets in order to bust the cache -every day:: - - use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface; - - class DateVersionStrategy implements VersionStrategyInterface - { - private $version; - - public function __construct() - { - $this->version = date('Ymd'); - } - - public function getVersion($path) - { - return $this->version; - } - - public function applyVersion($path) - { - return sprintf('%s?v=%s', $path, $this->getVersion($path)); - } - } - -.. _component-assets-path-package: - -Grouped Assets -~~~~~~~~~~~~~~ - -Often, many assets live under a common path (e.g. ``/static/images``). If -that's your case, replace the default :class:`Symfony\\Component\\Asset\\Package` -class with :class:`Symfony\\Component\\Asset\\PathPackage` to avoid repeating -that path over and over again:: - - use Symfony\Component\Asset\PathPackage; - // ... - - $package = new PathPackage('/static/images', new StaticVersionStrategy('v1')); - - echo $package->getUrl('/logo.png'); - // result: /static/images/logo.png?v1 - -Request Context Aware Assets -............................ - -If you are also using the :doc:`HttpFoundation ` -component in your project (for instance, in a Symfony application), the ``PathPackage`` -class can take into account the context of the current request:: - - use Symfony\Component\Asset\PathPackage; - use Symfony\Component\Asset\Context\RequestStackContext; - // ... - - $package = new PathPackage( - '/static/images', - new StaticVersionStrategy('v1'), - new RequestStackContext($requestStack) - ); - - echo $package->getUrl('/logo.png'); - // result: /somewhere/static/images/logo.png?v1 - -Now that the request context is set, the ``PathPackage`` will prepend the -current request base URL. So, for example, if your entire site is hosted under -the ``/somewhere`` directory of your web server root directory and the configured -base path is ``/static/images``, all paths will be prefixed with -``/somewhere/static/images``. - -.. _component-assets-cdn: - -Absolute Assets and CDNs -~~~~~~~~~~~~~~~~~~~~~~~~ - -Applications that host their assets on different domains and CDNs (*Content -Delivery Networks*) should use the :class:`Symfony\\Component\\Asset\\UrlPackage` -class to generate absolute URLs for their assets:: - - use Symfony\Component\Asset\UrlPackage; - // ... - - $package = new UrlPackage( - 'http://static.example.com/images/', - new StaticVersionStrategy('v1') - ); - - echo $package->getUrl('/logo.png'); - // result: http://static.example.com/images/logo.png?v1 - -You can also pass a schema-agnostic URL:: - - use Symfony\Component\Asset\UrlPackage; - // ... - - $package = new UrlPackage( - '//static.example.com/images/', - new StaticVersionStrategy('v1') - ); - - echo $package->getUrl('/logo.png'); - // result: //static.example.com/images/logo.png?v1 - -This is useful because assets will automatically be requested via HTTPS if -a visitor is viewing your site in https. Just make sure that your CDN host -supports https. - -In case you serve assets from more than one domain to improve application -performance, pass an array of URLs as the first argument to the ``UrlPackage`` -constructor:: - - use Symfony\Component\Asset\UrlPackage; - // ... - - $urls = array( - '//static1.example.com/images/', - '//static2.example.com/images/', - ); - $package = new UrlPackage($urls, new StaticVersionStrategy('v1')); - - echo $package->getUrl('/logo.png'); - // result: http://static1.example.com/images/logo.png?v1 - echo $package->getUrl('/icon.png'); - // result: http://static2.example.com/images/icon.png?v1 - -For each asset, one of the URLs will be randomly used. But, the selection -is deterministic, meaning that each asset will be always served by the same -domain. This behavior simplifies the management of HTTP cache. - -Request Context Aware Assets -............................ - -Similarly to application-relative assets, absolute assets can also take into -account the context of the current request. In this case, only the request -scheme is considered, in order to select the appropriate base URL (HTTPs or -protocol-relative URLs for HTTPs requests, any base URL for HTTP requests):: - - use Symfony\Component\Asset\UrlPackage; - use Symfony\Component\Asset\Context\RequestStackContext; - // ... - - $package = new UrlPackage( - array('http://example.com/', 'https://example.com/'), - new StaticVersionStrategy('v1'), - new RequestStackContext($requestStack) - ); - - echo $package->getUrl('/logo.png'); - // assuming the RequestStackContext says that we are on a secure host - // result: https://example.com/logo.png?v1 - -Named Packages -~~~~~~~~~~~~~~ - -Applications that manage lots of different assets may need to group them in -packages with the same versioning strategy and base path. The Asset component -includes a :class:`Symfony\\Component\\Asset\\Packages` class to simplify -management of several packages. - -In the following example, all packages use the same versioning strategy, but -they all have different base paths:: - - use Symfony\Component\Asset\Package; - use Symfony\Component\Asset\PathPackage; - use Symfony\Component\Asset\UrlPackage; - use Symfony\Component\Asset\Packages; - // ... - - $versionStrategy = new StaticVersionStrategy('v1'); - - $defaultPackage = new Package($versionStrategy); - - $namedPackages = array( - 'img' => new UrlPackage('http://img.example.com/', $versionStrategy), - 'doc' => new PathPackage('/somewhere/deep/for/documents', $versionStrategy), - ); - - $packages = new Packages($defaultPackage, $namedPackages) - -The ``Packages`` class allows to define a default package, which will be applied -to assets that don't define the name of package to use. In addition, this -application defines a package named ``img`` to serve images from an external -domain and a ``doc`` package to avoid repeating long paths when linking to a -document inside a template:: - - echo $packages->getUrl('/main.css'); - // result: /main.css?v1 - - echo $packages->getUrl('/logo.png', 'img'); - // result: http://img.example.com/logo.png?v1 - - echo $packages->getUrl('/resume.pdf', 'doc'); - // result: /somewhere/deep/for/documents/resume.pdf?v1 - -.. _Packagist: https://packagist.org/packages/symfony/asset diff --git a/components/class_loader/cache_class_loader.rst b/components/class_loader/cache_class_loader.rst index ff7aaba0885..46622eb4e3d 100644 --- a/components/class_loader/cache_class_loader.rst +++ b/components/class_loader/cache_class_loader.rst @@ -26,6 +26,9 @@ for a class. ApcClassLoader -------------- +.. versionadded:: 2.1 + The ``ApcClassLoader`` class was introduced in Symfony 2.1. + ``ApcClassLoader`` wraps an existing class loader and caches calls to its ``findFile()`` method using `APC`_:: @@ -46,6 +49,9 @@ ApcClassLoader XcacheClassLoader ----------------- +.. versionadded:: 2.1 + The ``XcacheClassLoader`` class was introduced 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 2d0e64978d1..9e477795c10 100644 --- a/components/class_loader/class_loader.rst +++ b/components/class_loader/class_loader.rst @@ -4,6 +4,9 @@ The PSR-0 Class Loader ====================== +.. versionadded:: 2.1 + The ``ClassLoader`` class was introduced 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. @@ -12,7 +15,8 @@ to load all of your project's classes. You can use both the ``ApcClassLoader`` and the ``XcacheClassLoader`` to :doc:`cache ` a ``ClassLoader`` - instance. + instance or the ``DebugClassLoader`` to :doc:`debug ` + it. Usage ----- diff --git a/components/class_loader/debug_class_loader.rst b/components/class_loader/debug_class_loader.rst index 06dfce69716..d41afe9d277 100644 --- a/components/class_loader/debug_class_loader.rst +++ b/components/class_loader/debug_class_loader.rst @@ -4,5 +4,5 @@ Debugging a Class Loader .. caution:: The ``DebugClassLoader`` from the ClassLoader component was deprecated - in Symfony 2.5 and removed in Symfony 3.0. Use the + in Symfony 2.5 and will be removed in Symfony 3.0. Use the :doc:`DebugClassLoader provided by the Debug component `. diff --git a/components/class_loader/index.rst b/components/class_loader/index.rst index 5215b57291d..864bf77d734 100644 --- a/components/class_loader/index.rst +++ b/components/class_loader/index.rst @@ -6,12 +6,7 @@ ClassLoader introduction class_loader - psr4_class_loader map_class_loader cache_class_loader - class_map_generator - -.. toctree:: - :hidden: - debug_class_loader + class_map_generator diff --git a/components/class_loader/introduction.rst b/components/class_loader/introduction.rst index 0c9ae90402b..e5e3f581f56 100644 --- a/components/class_loader/introduction.rst +++ b/components/class_loader/introduction.rst @@ -12,26 +12,21 @@ Usage Whenever you reference a class that has not been required or included yet, PHP uses the `autoloading mechanism`_ to delegate the loading of a file -defining the class. Symfony provides three autoloaders, which are able to +defining the class. Symfony provides two autoloaders, which are able to load your classes: * :doc:`/components/class_loader/class_loader`: loads classes that follow the `PSR-0`_ class naming standard; -* :doc:`/components/class_loader/psr4_class_loader`: loads classes that follow - the `PSR-4` class naming standard; - * :doc:`/components/class_loader/map_class_loader`: loads classes using a static map from class name to file path. -Additionally, the Symfony ClassLoader component ships with a wrapper class -which makes it possible -:doc:`to cache the results of a class loader `. +Additionally, the Symfony ClassLoader component ships with a set of wrapper +classes which can be used to add additional functionality on top of existing +autoloaders: -When using the :doc:`Debug component `, you -can also use a special :doc:`DebugClassLoader ` -that eases debugging by throwing more helpful exceptions when a class could -not be found by a class loader. +* :doc:`/components/class_loader/cache_class_loader` +* :doc:`/components/class_loader/debug_class_loader` Installation ------------ diff --git a/components/class_loader/psr4_class_loader.rst b/components/class_loader/psr4_class_loader.rst deleted file mode 100644 index b593e174027..00000000000 --- a/components/class_loader/psr4_class_loader.rst +++ /dev/null @@ -1,63 +0,0 @@ -.. index:: - single: ClassLoader; PSR-4 Class Loader - -The PSR-4 Class Loader -====================== - -Libraries that follow the `PSR-4`_ standard can be loaded with the ``Psr4ClassLoader``. - -.. note:: - - If you manage your dependencies via Composer, you get a PSR-4 compatible - autoloader out of the box. Use this loader in environments where Composer - is not available. - -.. tip:: - - All Symfony components follow PSR-4. - -Usage ------ - -The following example demonstrates how you can use the -:class:`Symfony\\Component\\ClassLoader\\Psr4ClassLoader` autoloader to use -Symfony's Yaml component. Imagine, you downloaded both the ClassLoader and -Yaml component as ZIP packages and unpacked them to a ``libs`` directory. -The directory structure will look like this: - -.. code-block:: text - - libs/ - ClassLoader/ - Psr4ClassLoader.php - ... - Yaml/ - Yaml.php - ... - config.yml - demo.php - -In ``demo.php`` you are going to parse the ``config.yml`` file. To do that, you -first need to configure the ``Psr4ClassLoader``: - -.. code-block:: php - - use Symfony\Component\ClassLoader\Psr4ClassLoader; - use Symfony\Component\Yaml\Yaml; - - require __DIR__.'/lib/ClassLoader/Psr4ClassLoader.php'; - - $loader = new Psr4ClassLoader(); - $loader->addPrefix('Symfony\\Component\\Yaml\\', __DIR__.'/lib/Yaml'); - $loader->register(); - - $data = Yaml::parse(file_get_contents(__DIR__.'/config.yml')); - -First of all, the class loader is loaded manually using a ``require`` -statement, since there is no autoload mechanism yet. With the -:method:`Symfony\\Component\\ClassLoader\\Psr4ClassLoader::addPrefix` call, you -tell the class loader where to look for classes with the -``Symfony\Component\Yaml\`` namespace prefix. After registering the autoloader, -the Yaml component is ready to be used. - -.. _PSR-4: http://www.php-fig.org/psr/psr-4/ diff --git a/components/config/definition.rst b/components/config/definition.rst index cb799da44d0..b2a714d5cdc 100644 --- a/components/config/definition.rst +++ b/components/config/definition.rst @@ -446,6 +446,10 @@ and in XML: +.. versionadded:: 2.6 + Since Symfony 2.6, the info will also be added to the exception message + when an invalid type is given. + Optional Sections ----------------- diff --git a/components/console/changing_default_command.rst b/components/console/changing_default_command.rst deleted file mode 100644 index adbf31a4ae3..00000000000 --- a/components/console/changing_default_command.rst +++ /dev/null @@ -1,63 +0,0 @@ -.. index:: - single: Console; Changing the Default Command - -Changing the Default Command -============================ - -The Console component will always run the ``ListCommand`` when no command name is -passed. In order to change the default command you just need to pass the command -name to the ``setDefaultCommand`` method:: - - namespace Acme\Console\Command; - - use Symfony\Component\Console\Command\Command; - use Symfony\Component\Console\Input\InputInterface; - use Symfony\Component\Console\Output\OutputInterface; - - class HelloWorldCommand extends Command - { - protected function configure() - { - $this->setName('hello:world') - ->setDescription('Outputs \'Hello World\''); - } - - protected function execute(InputInterface $input, OutputInterface $output) - { - $output->writeln('Hello World'); - } - } - -Executing the application and changing the default Command:: - - // application.php - - use Acme\Console\Command\HelloWorldCommand; - use Symfony\Component\Console\Application; - - $command = new HelloWorldCommand(); - $application = new Application(); - $application->add($command); - $application->setDefaultCommand($command->getName()); - $application->run(); - -Test the new default console command by running the following: - -.. code-block:: bash - - $ php application.php - -This will print the following to the command line: - -.. code-block:: text - - Hello World - -.. tip:: - - This feature has a limitation: you cannot use it with any Command arguments. - -Learn More! ------------ - -* :doc:`/components/console/single_command_tool` diff --git a/components/console/events.rst b/components/console/events.rst index 9405635ebeb..e5b51c910a1 100644 --- a/components/console/events.rst +++ b/components/console/events.rst @@ -4,6 +4,9 @@ Using Events ============ +.. versionadded:: 2.3 + Console events were introduced 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:: @@ -56,6 +59,9 @@ dispatched. Listeners receive a Disable Commands inside Listeners ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. versionadded:: 2.6 + Disabling commands inside listeners was introduced in Symfony 2.6. + Using the :method:`Symfony\\Component\\Console\\Event\\ConsoleCommandEvent::disableCommand` method, you can disable a command inside a listener. The application diff --git a/components/console/helpers/debug_formatter.rst b/components/console/helpers/debug_formatter.rst index d48b6a9e060..b5af8bb9782 100644 --- a/components/console/helpers/debug_formatter.rst +++ b/components/console/helpers/debug_formatter.rst @@ -4,6 +4,9 @@ Debug Formatter Helper ====================== +.. versionadded:: 2.6 + The Debug Formatter helper was introduced in Symfony 2.6. + The :class:`Symfony\\Component\\Console\\Helper\\DebugFormatterHelper` provides functions to output debug information when running an external program, for instance a process or HTTP request. For example, if you used it to output diff --git a/components/console/helpers/dialoghelper.rst b/components/console/helpers/dialoghelper.rst index 8618ffcba17..09af2971d65 100644 --- a/components/console/helpers/dialoghelper.rst +++ b/components/console/helpers/dialoghelper.rst @@ -6,7 +6,286 @@ Dialog Helper .. caution:: - The Dialog Helper was deprecated in Symfony 2.5 and removed in + The Dialog Helper was deprecated in Symfony 2.5 and will be removed in Symfony 3.0. You should now use the :doc:`Question Helper ` instead, which is simpler to use. + +The :class:`Symfony\\Component\\Console\\Helper\\DialogHelper` provides +functions to ask the user for more information. It is included in the default +helper set, which you can get by calling +:method:`Symfony\\Component\\Console\\Command\\Command::getHelperSet`:: + + $dialog = $this->getHelper('dialog'); + +All the methods inside the Dialog Helper have an +:class:`Symfony\\Component\\Console\\Output\\OutputInterface` as the first +argument, the question as the second argument and the default value as the last +argument. + +Asking the User for Confirmation +-------------------------------- + +Suppose you want to confirm an action before actually executing it. Add +the following to your command:: + + // ... + if (!$dialog->askConfirmation( + $output, + 'Continue with this action?', + false + )) { + return; + } + +In this case, the user will be asked "Continue with this action?", and will +return ``true`` if the user answers with ``y`` or ``false`` if the user answers +with ``n``. The third argument to +:method:`Symfony\\Component\\Console\\Helper\\DialogHelper::askConfirmation` +is the default value to return if the user doesn't enter any input. Any other +input will ask the same question again. + +Asking the User for Information +------------------------------- + +You can also ask question with more than a simple yes/no answer. For instance, +if you want to know a bundle name, you can add this to your command:: + + // ... + $bundle = $dialog->ask( + $output, + 'Please enter the name of the bundle', + 'AcmeDemoBundle' + ); + +The user will be asked "Please enter the name of the bundle". They can type +some name which will be returned by the +:method:`Symfony\\Component\\Console\\Helper\\DialogHelper::ask` method. +If they leave it empty, the default value (AcmeDemoBundle here) is returned. + +Autocompletion +~~~~~~~~~~~~~~ + +You can also specify an array of potential answers for a given question. These +will be autocompleted as the user types:: + + $dialog = $this->getHelper('dialog'); + $bundleNames = array('AcmeDemoBundle', 'AcmeBlogBundle', 'AcmeStoreBundle'); + $name = $dialog->ask( + $output, + 'Please enter the name of a bundle', + 'FooBundle', + $bundleNames + ); + +Hiding the User's Response +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can also ask a question and hide the response. This is particularly +convenient for passwords:: + + $dialog = $this->getHelper('dialog'); + $password = $dialog->askHiddenResponse( + $output, + 'What is the database password?', + false + ); + +.. caution:: + + When you ask for a hidden response, Symfony will use either a binary, change + stty mode or use another trick to hide the response. If none is available, + it will fallback and allow the response to be visible unless you pass ``false`` + as the third argument like in the example above. In this case, a ``RuntimeException`` + would be thrown. + +Validating the Answer +--------------------- + +You can even validate the answer. For instance, in the last example you asked +for the bundle name. Following the Symfony naming conventions, it should +be suffixed with ``Bundle``. You can validate that by using the +:method:`Symfony\\Component\\Console\\Helper\\DialogHelper::askAndValidate` +method:: + + // ... + $bundle = $dialog->askAndValidate( + $output, + 'Please enter the name of the bundle', + function ($answer) { + if ('Bundle' !== substr($answer, -6)) { + throw new \RuntimeException( + 'The name of the bundle should be suffixed with \'Bundle\'' + ); + } + + return $answer; + }, + false, + 'AcmeDemoBundle' + ); + +This methods has 2 new arguments, the full signature is:: + + askAndValidate( + OutputInterface $output, + string|array $question, + callback $validator, + integer $attempts = false, + string $default = null, + array $autocomplete = null + ) + +The ``$validator`` is a callback which handles the validation. It should +throw an exception if there is something wrong. The exception message is displayed +in the console, so it is a good practice to put some useful information in it. The callback +function should also return the value of the user's input if the validation was successful. + +You can set the max number of times to ask in the ``$attempts`` argument. +If you reach this max number it will use the default value. +Using ``false`` means the amount of attempts is infinite. +The user will be asked as long as they provide an invalid answer and will only +be able to proceed if their input is valid. + +Validating a Hidden Response +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can also ask and validate a hidden response:: + + $dialog = $this->getHelper('dialog'); + + $validator = function ($value) { + if ('' === trim($value)) { + throw new \Exception('The password can not be empty'); + } + + return $value; + }; + + $password = $dialog->askHiddenResponseAndValidate( + $output, + 'Please enter your password', + $validator, + 20, + false + ); + +If you want to allow the response to be visible if it cannot be hidden for +some reason, pass true as the fifth argument. + +Let the User Choose from a List of Answers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you have a predefined set of answers the user can choose from, you +could use the ``ask`` method described above or, to make sure the user +provided a correct answer, the ``askAndValidate`` method. Both have +the disadvantage that you need to handle incorrect values yourself. + +Instead, you can use the +:method:`Symfony\\Component\\Console\\Helper\\DialogHelper::select` +method, which makes sure that the user can only enter a valid string +from a predefined list:: + + $dialog = $this->getHelper('dialog'); + $colors = array('red', 'blue', 'yellow'); + + $color = $dialog->select( + $output, + 'Please select your favorite color (default to red)', + $colors, + 0 + ); + $output->writeln('You have just selected: ' . $colors[$color]); + + // ... do something with the color + +The option which should be selected by default is provided with the fourth +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 they enter a valid string +or the maximum attempts is reached (which you can define in the fifth +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 introduced 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 +------------------------------------- + +If you want to write a unit test for a command which expects some kind of input +from the command line, you need to overwrite the HelperSet used by the command:: + + use Symfony\Component\Console\Application; + use Symfony\Component\Console\Helper\DialogHelper; + use Symfony\Component\Console\Helper\HelperSet; + use Symfony\Component\Console\Tester\CommandTester; + + // ... + public function testExecute() + { + // ... + $application = new Application(); + $application->add(new MyCommand()); + $command = $application->find('my:command:name'); + $commandTester = new CommandTester($command); + + $dialog = $command->getHelper('dialog'); + $dialog->setInputStream($this->getInputStream("Test\n")); + // Equals to a user inputting "Test" and hitting ENTER + // If you need to enter a confirmation, "yes\n" will work + + $commandTester->execute(array('command' => $command->getName())); + + // $this->assertRegExp('/.../', $commandTester->getDisplay()); + } + + protected function getInputStream($input) + { + $stream = fopen('php://memory', 'r+', false); + fputs($stream, $input); + rewind($stream); + + return $stream; + } + +By setting the input stream of the ``DialogHelper``, you imitate what the +console would do internally with all user input through the cli. This way +you can test any user interaction (even complex ones) by passing an appropriate +input stream. + +.. seealso:: + + You find more information about testing commands in the console component + docs about :ref:`testing console commands `. diff --git a/components/console/helpers/index.rst b/components/console/helpers/index.rst index bf51dc40c92..1c95bc47057 100644 --- a/components/console/helpers/index.rst +++ b/components/console/helpers/index.rst @@ -9,13 +9,8 @@ The Console Helpers dialoghelper formatterhelper - processhelper - progressbar progresshelper - questionhelper - table tablehelper - debug_formatter The Console component 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 68e1e722a87..d0913db4033 100644 --- a/components/console/helpers/map.rst.inc +++ b/components/console/helpers/map.rst.inc @@ -1,6 +1,9 @@ +* :doc:`/components/console/helpers/dialoghelper` (deprecated as of 2.5) * :doc:`/components/console/helpers/formatterhelper` * :doc:`/components/console/helpers/processhelper` * :doc:`/components/console/helpers/progressbar` +* :doc:`/components/console/helpers/progresshelper` (deprecated as of 2.5) * :doc:`/components/console/helpers/questionhelper` * :doc:`/components/console/helpers/table` -* :doc:`/components/console/helpers/debug_formatter` +* :doc:`/components/console/helpers/tablehelper` (deprecated as of 2.5) +* :doc:`/components/console/helpers/debug_formatter` (new in 2.6) diff --git a/components/console/helpers/processhelper.rst b/components/console/helpers/processhelper.rst index 6a4f7c6f6b5..5494ca0137f 100644 --- a/components/console/helpers/processhelper.rst +++ b/components/console/helpers/processhelper.rst @@ -4,6 +4,9 @@ Process Helper ============== +.. versionadded:: 2.6 + The Process Helper was introduced in Symfony 2.6. + The Process Helper shows processes as they're running and reports useful information about process status. diff --git a/components/console/helpers/progressbar.rst b/components/console/helpers/progressbar.rst index 0e73aa91231..3c97a53ec49 100644 --- a/components/console/helpers/progressbar.rst +++ b/components/console/helpers/progressbar.rst @@ -40,6 +40,14 @@ Instead of advancing the bar by a number of steps (with the you can also set the current progress by calling the :method:`Symfony\\Component\\Console\\Helper\\ProgressBar::setProgress` method. +.. versionadded:: 2.6 + The ``setProgress()`` method was called ``setCurrent()`` prior to Symfony 2.6. + +.. caution:: + + Prior to version 2.6, the progress bar only works if your platform + supports ANSI codes; on other platforms, no output is generated. + .. tip:: If your platform doesn't support ANSI codes, updates to the progress @@ -49,6 +57,9 @@ you can also set the current progress by calling the accordingly. By default, when using a ``max``, the redraw frequency is set to *10%* of your ``max``. + .. versionadded:: 2.6 + The ``setRedrawFrequency()`` method was introduced in Symfony 2.6. + If you don't know the number of steps in advance, just omit the steps argument when creating the :class:`Symfony\\Component\\Console\\Helper\\ProgressBar` instance:: @@ -296,6 +307,9 @@ that displays the number of remaining steps:: } ); +.. versionadded:: 2.6 + The ``getProgress()`` method was called ``getStep()`` prior to Symfony 2.6. + Custom Messages ~~~~~~~~~~~~~~~ diff --git a/components/console/helpers/progresshelper.rst b/components/console/helpers/progresshelper.rst index aec5c9b62ea..7d858d21691 100644 --- a/components/console/helpers/progresshelper.rst +++ b/components/console/helpers/progresshelper.rst @@ -4,9 +4,91 @@ Progress Helper =============== +.. versionadded:: 2.3 + The ``setCurrent`` method was introduced in Symfony 2.3. + .. caution:: - The Progress Helper was deprecated in Symfony 2.5 and removed in Symfony - 3.0. You should now use the + The Progress Helper was deprecated in Symfony 2.5 and will be removed in + Symfony 3.0. You should now use the :doc:`Progress Bar ` instead which is more powerful. + +When executing longer-running commands, it may be helpful to show progress +information, which updates as your command runs: + +.. image:: /images/components/console/progress.png + +To display progress details, use the :class:`Symfony\\Component\\Console\\Helper\\ProgressHelper`, +pass it a total number of units, and advance the progress as your command executes:: + + $progress = $this->getHelper('progress'); + + $progress->start($output, 50); + $i = 0; + while ($i++ < 50) { + // ... do some work + + // advances the progress bar 1 unit + $progress->advance(); + } + + $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 +information (e.g. 10/50):: + + $progress->setFormat(ProgressHelper::FORMAT_QUIET); + $progress->setFormat(ProgressHelper::FORMAT_NORMAL); + $progress->setFormat(ProgressHelper::FORMAT_VERBOSE); + $progress->setFormat(ProgressHelper::FORMAT_QUIET_NOMAX); + // the default value + $progress->setFormat(ProgressHelper::FORMAT_NORMAL_NOMAX); + $progress->setFormat(ProgressHelper::FORMAT_VERBOSE_NOMAX); + +You can also control the different characters and the width used for the +progress bar:: + + // the finished part of the bar + $progress->setBarCharacter('='); + // the unfinished part of the bar + $progress->setEmptyBarCharacter(' '); + $progress->setProgressCharacter('|'); + $progress->setBarWidth(50); + +To see other available options, check the API documentation for +:class:`Symfony\\Component\\Console\\Helper\\ProgressHelper`. + +.. caution:: + + For performance reasons, be careful if you set the total number of steps + to a high number. For example, if you're iterating over a large number of + items, consider setting the redraw frequency to a higher value by calling + :method:`Symfony\\Component\\Console\\Helper\\ProgressHelper::setRedrawFrequency`, + so it updates on only some iterations:: + + $progress->start($output, 50000); + + // updates every 100 iterations + $progress->setRedrawFrequency(100); + + $i = 0; + while ($i++ < 50000) { + // ... do some work + + $progress->advance(); + } diff --git a/components/console/helpers/questionhelper.rst b/components/console/helpers/questionhelper.rst index ca799d4c40c..6ca82baa5b7 100644 --- a/components/console/helpers/questionhelper.rst +++ b/components/console/helpers/questionhelper.rst @@ -65,6 +65,10 @@ the second argument is not provided, ``true`` is assumed. The regex defaults to ``/^y/i``. + .. versionadded:: 2.7 + The regex argument was introduced in Symfony 2.7. Before, only answers + starting with ``y`` were considered as "yes". + Asking the User for Information ------------------------------- diff --git a/components/console/helpers/table.rst b/components/console/helpers/table.rst index 5dc4e827bb3..2c37d379a8e 100644 --- a/components/console/helpers/table.rst +++ b/components/console/helpers/table.rst @@ -147,6 +147,9 @@ Here is a full list of things you can customize: Spanning Multiple Columns and Rows ---------------------------------- +.. versionadded:: 2.7 + Spanning multiple columns and rows was introduced in Symfony 2.7. + To make a table cell that spans multiple columns you can use a :class:`Symfony\\Component\\Console\\Helper\\TableCell`:: use Symfony\Component\Console\Helper\Table; diff --git a/components/console/helpers/tablehelper.rst b/components/console/helpers/tablehelper.rst index f0f88a7b57c..0e508b4d4d6 100644 --- a/components/console/helpers/tablehelper.rst +++ b/components/console/helpers/tablehelper.rst @@ -4,9 +4,61 @@ Table Helper ============ +.. versionadded:: 2.3 + The ``table`` helper was introduced in Symfony 2.3. + .. caution:: - The Table Helper was deprecated in Symfony 2.5 and removed in + The Table Helper was deprecated in Symfony 2.5 and will be removed in Symfony 3.0. You should now use the :doc:`Table ` class instead which is more powerful. + +When building a console application it may be useful to display tabular data: + +.. image:: /images/components/console/table.png + +To display a table, use the :class:`Symfony\\Component\\Console\\Helper\\TableHelper`, +set headers, rows and render:: + + $table = $this->getHelper('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 three preconfigured table layouts: + +* ``TableHelper::LAYOUT_DEFAULT`` + +* ``TableHelper::LAYOUT_BORDERLESS`` + +* ``TableHelper::LAYOUT_COMPACT`` + +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 1ae77d50566..b46548de647 100644 --- a/components/console/index.rst +++ b/components/console/index.rst @@ -6,9 +6,7 @@ Console introduction usage - changing_default_command single_command_tool console_arguments events - logger helpers/index diff --git a/components/console/introduction.rst b/components/console/introduction.rst index 0dfcda479ac..629aaa31cd0 100644 --- a/components/console/introduction.rst +++ b/components/console/introduction.rst @@ -195,11 +195,13 @@ You can also set these colors and options inside the tagname:: // bold text on a yellow background $output->writeln('foo'); -.. _verbosity-levels: - Verbosity Levels ~~~~~~~~~~~~~~~~ +.. versionadded:: 2.3 + The ``VERBOSITY_VERY_VERBOSE`` and ``VERBOSITY_DEBUG`` constants were introduced + in version 2.3 + The console has five verbosity levels. These are defined in the :class:`Symfony\\Component\\Console\\Output\\OutputInterface`: @@ -225,43 +227,10 @@ level. For example:: $output->writeln(...); } -There are also more semantic methods you can use to test for each of the -verbosity levels:: - - if ($output->isQuiet()) { - // ... - } - - if ($output->isVerbose()) { - // ... - } - - if ($output->isVeryVerbose()) { - // ... - } - - if ($output->isDebug()) { - // ... - } - -.. note:: - - These semantic methods are defined in the ``OutputInterface`` starting from - Symfony 3.0. In previous Symfony versions they are defined in the different - implementations of the interface (e.g. :class:`Symfony\\Component\\Console\\Output\\Output`) - in order to keep backwards compatibility. - When the quiet level is used, all output is suppressed as the default :method:`Symfony\\Component\\Console\\Output\\Output::write` method returns without actually printing. -.. tip:: - - The MonologBridge provides a :class:`Symfony\\Bridge\\Monolog\\Handler\\ConsoleHandler` - class that allows you to display messages on the console. This is cleaner - than wrapping your output calls in conditions. For an example use in - the Symfony Framework, see :doc:`/cookbook/logging/monolog_console`. - Using Command Arguments ----------------------- @@ -431,10 +400,10 @@ Console Helpers The console component also contains a set of "helpers" - different small tools capable of helping you with different tasks: -* :doc:`/components/console/helpers/questionhelper`: interactively ask the user for information +* :doc:`/components/console/helpers/dialoghelper`: interactively ask the user for information * :doc:`/components/console/helpers/formatterhelper`: customize the output colorization -* :doc:`/components/console/helpers/progressbar`: shows a progress bar -* :doc:`/components/console/helpers/table`: displays tabular data as a table +* :doc:`/components/console/helpers/progresshelper`: shows a progress bar +* :doc:`/components/console/helpers/tablehelper`: displays tabular data as a table .. _component-console-testing-commands: @@ -572,7 +541,6 @@ Learn More! * :doc:`/components/console/usage` * :doc:`/components/console/single_command_tool` -* :doc:`/components/console/changing_default_command` * :doc:`/components/console/events` * :doc:`/components/console/console_arguments` diff --git a/components/console/logger.rst b/components/console/logger.rst deleted file mode 100644 index 8a713189b05..00000000000 --- a/components/console/logger.rst +++ /dev/null @@ -1,106 +0,0 @@ -.. index:: - single: Console; Logger - -Using the Logger -================ - -The Console component comes with a standalone logger complying with the -`PSR-3`_ standard. Depending on the verbosity setting, log messages will -be sent to the :class:`Symfony\\Component\\Console\\Output\\OutputInterface` -instance passed as a parameter to the constructor. - -The logger does not have any external dependency except ``php-fig/log``. -This is useful for console applications and commands needing a lightweight -PSR-3 compliant logger:: - - namespace Acme; - - use Psr\Log\LoggerInterface; - - class MyDependency - { - private $logger; - - public function __construct(LoggerInterface $logger) - { - $this->logger = $logger; - } - - public function doStuff() - { - $this->logger->info('I love Tony Vairelles\' hairdresser.'); - } - } - -You can rely on the logger to use this dependency inside a command:: - - namespace Acme\Console\Command; - - use Acme\MyDependency; - use Symfony\Component\Console\Command\Command; - use Symfony\Component\Console\Input\InputInterface; - use Symfony\Component\Console\Output\OutputInterface; - use Symfony\Component\Console\Logger\ConsoleLogger; - - class MyCommand extends Command - { - protected function configure() - { - $this - ->setName('my:command') - ->setDescription( - 'Use an external dependency requiring a PSR-3 logger' - ) - ; - } - - protected function execute(InputInterface $input, OutputInterface $output) - { - $logger = new ConsoleLogger($output); - - $myDependency = new MyDependency($logger); - $myDependency->doStuff(); - } - } - -The dependency will use the instance of -:class:`Symfony\\Component\\Console\\Logger\\ConsoleLogger` as logger. -Log messages emitted will be displayed on the console output. - -Verbosity ---------- - -Depending on the verbosity level that the command is run, messages may or -may not be sent to the :class:`Symfony\\Component\\Console\\Output\\OutputInterface` -instance. - -By default, the console logger behaves like the -:doc:`Monolog's Console Handler `. -The association between the log level and the verbosity can be configured -through the second parameter of the :class:`Symfony\\Component\\Console\\ConsoleLogger` -constructor:: - - use Psr\Log\LogLevel; - // ... - - $verbosityLevelMap = array( - LogLevel::NOTICE => OutputInterface::VERBOSITY_NORMAL, - LogLevel::INFO => OutputInterface::VERBOSITY_NORMAL, - ); - $logger = new ConsoleLogger($output, $verbosityLevelMap); - -Color ------ - -The logger outputs the log messages formatted with a color reflecting their -level. This behavior is configurable through the third parameter of the -constructor:: - - // ... - $formatLevelMap = array( - LogLevel::CRITICAL => ConsoleLogger::INFO, - LogLevel::DEBUG => ConsoleLogger::ERROR, - ); - $logger = new ConsoleLogger($output, array(), $formatLevelMap); - -.. _PSR-3: http://www.php-fig.org/psr/psr-3/ diff --git a/components/css_selector.rst b/components/css_selector.rst index 588582fb371..3935f3c85ee 100644 --- a/components/css_selector.rst +++ b/components/css_selector.rst @@ -47,12 +47,11 @@ The CssSelector Component ~~~~~~~~~~~~~~~~~~~~~~~~~ The component's only goal is to convert CSS selectors to their XPath -equivalents, using :method:`Symfony\\Component\\CssSelector\\CssSelectorConverter::toXPath`:: +equivalents:: - use Symfony\Component\CssSelector\CssSelectorConverter; + use Symfony\Component\CssSelector\CssSelector; - $converter = new CssSelectorConverter(); - var_dump($converter->toXPath('div.item > h4 > a')); + var_dump(CssSelector::toXPath('div.item > h4 > a')); This gives the following output: diff --git a/components/debug/introduction.rst b/components/debug.rst similarity index 86% rename from components/debug/introduction.rst rename to components/debug.rst index 1042e9e504c..cec6b52f08f 100644 --- a/components/debug/introduction.rst +++ b/components/debug.rst @@ -7,6 +7,10 @@ The Debug Component The Debug component provides tools to ease debugging PHP code. +.. versionadded:: 2.3 + The Debug component was introduced in Symfony 2.3. Previously, the classes + were located in the HttpKernel component. + Installation ------------ @@ -28,8 +32,9 @@ Enabling them all is as easy as it can get:: Debug::enable(); The :method:`Symfony\\Component\\Debug\\Debug::enable` method registers an -error handler, an exception handler and -:doc:`a special class loader `. +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. diff --git a/components/debug/class_loader.rst b/components/debug/class_loader.rst deleted file mode 100644 index ff906101ed1..00000000000 --- a/components/debug/class_loader.rst +++ /dev/null @@ -1,18 +0,0 @@ -.. index:: - single: Class Loader; DebugClassLoader - single: Debug; DebugClassLoader - -Debugging a Class Loader -======================== - -The :class:`Symfony\\Component\\Debug\\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 -with a ``DebugClassLoader`` wrapper. - -Using the ``DebugClassLoader`` is as easy as calling its static -:method:`Symfony\\Component\\Debug\\DebugClassLoader::enable` method:: - - use Symfony\Component\Debug\DebugClassLoader; - - DebugClassLoader::enable(); diff --git a/components/debug/index.rst b/components/debug/index.rst deleted file mode 100644 index 6797789cb1b..00000000000 --- a/components/debug/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -Debug -===== - -.. toctree:: - :maxdepth: 2 - - introduction - class_loader diff --git a/components/dependency_injection/advanced.rst b/components/dependency_injection/advanced.rst index 73b8554c41c..0f693dfe917 100644 --- a/components/dependency_injection/advanced.rst +++ b/components/dependency_injection/advanced.rst @@ -218,138 +218,3 @@ You can change the inner service name if you want to: ->addArgument(new Reference('bar.wooz')) ->setPublic(false) ->setDecoratedService('foo', 'bar.wooz'); - -If you want to apply more than one decorator to a service, you can control their -order by configuring the priority of decoration, this can be any integer number -(decorators with higher priorities will be applied first). - -.. configuration-block:: - - .. code-block:: yaml - - foo: - class: Foo - - bar: - class: Bar - public: false - decorates: foo - decoration_priority: 5 - arguments: ['@bar.inner'] - - baz: - class: Baz - public: false - decorates: foo - decoration_priority: 1 - arguments: ['@baz.inner'] - - .. code-block:: xml - - - - - - - - - - - - - - - - - - - .. code-block:: php - - use Symfony\Component\DependencyInjection\Reference; - - $container->register('foo', 'Foo') - - $container->register('bar', 'Bar') - ->addArgument(new Reference('bar.inner')) - ->setPublic(false) - ->setDecoratedService('foo', null, 5); - - $container->register('baz', 'Baz') - ->addArgument(new Reference('baz.inner')) - ->setPublic(false) - ->setDecoratedService('foo', null, 1); - -The generated code will be the following: - -.. code-block:: php - - $this->services['foo'] = new Baz(new Bar(new Foo()))); - -Deprecating Services --------------------- - -Once you have decided to deprecate the use of a service (because it is outdated -or you decided not to maintain it anymore), you can deprecate its definition: - -.. configuration-block:: - - .. code-block:: yaml - - acme.my_service: - class: ... - deprecated: The "%service_id%" service is deprecated since 2.8 and will be removed in 3.0. - - .. code-block:: xml - - - - - - - The "%service_id%" service is deprecated since 2.8 and will be removed in 3.0. - - - - - .. code-block:: php - - $container - ->register('acme.my_service', '...') - ->setDeprecated( - true, - 'The "%service_id%" service is deprecated since 2.8 and will be removed in 3.0.' - ) - ; - -Now, every time this service is used, a deprecation warning is triggered, -advising you to stop or to change your uses of that service. - -The message is actually a message template, which replaces occurrences of the -``%service_id%`` placeholder by the service's id. You **must** have at least one -occurrence of the ``%service_id%`` placeholder in your template. - -.. note:: - - The deprecation message is optional. If not set, Symfony will show this default - message: ``The "%service_id%" service is deprecated. You should stop using it, - as it will soon be removed.``. - -.. tip:: - - It is strongly recommended that you define a custom message because the - default one is too generic. A good message informs when this service was - deprecated, until when it will be maintained and the alternative services - to use (if any). - -For service decorators (see above), if the definition does not modify the -deprecated status, it will inherit the status from the definition that is -decorated. - -.. caution:: - - The ability to "un-deprecate" a service is possible only when declaring the - definition in PHP. diff --git a/components/dependency_injection/autowiring.rst b/components/dependency_injection/autowiring.rst deleted file mode 100644 index ad781a2609d..00000000000 --- a/components/dependency_injection/autowiring.rst +++ /dev/null @@ -1,405 +0,0 @@ -.. index:: - single: DependencyInjection; Autowiring - -Defining Services Dependencies Automatically (Autowiring) -========================================================= - -.. versionadded:: 2.8 - Support for autowiring services was introduced in Symfony 2.8. - -Autowiring allows to register services in the container with minimal configuration. -It automatically resolves the service dependencies based on the constructor's -typehint which is useful in the field of `Rapid Application Development`_, -when designing prototypes in early stages of large projects. It makes it easy -to register a service graph and eases refactoring. - -Imagine you're building an API to publish statuses on a Twitter feed, obfuscated -with `ROT13`_ (a special case of the Caesar cipher). - -Start by creating a ROT13 transformer class:: - - // src/AppBundle/Rot13Transformer.php - namespace AppBundle; - - class Rot13Transformer - { - public function transform($value) - { - return str_rot13($value); - } - } - -And now a Twitter client using this transformer:: - - // src/AppBundle/TwitterClient.php - namespace AppBundle; - - class TwitterClient - { - private $transformer; - - public function __construct(Rot13Transformer $transformer) - { - $this->transformer = $transformer; - } - - public function tweet($user, $key, $status) - { - $transformedStatus = $this->transformer->transform($status); - - // ... connect to Twitter and send the encoded status - } - } - -The DependencyInjection component will be able to automatically register -the dependencies of this ``TwitterClient`` class when the ``twitter_client`` -service is marked as autowired: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/services.yml - services: - twitter_client: - class: 'AppBundle\TwitterClient' - autowire: true - - .. code-block:: xml - - - - - - - - - - - .. code-block:: php - - use Symfony\Component\DependencyInjection\Definition; - - // ... - $definition = new Definition('AppBundle\TwitterClient'); - $definition->setAutowired(true); - - $container->setDefinition('twitter_client', $definition); - -The autowiring subsystem will detect the dependencies of the ``TwitterClient`` -class by parsing its constructor. For instance it will find here an instance of -a ``Rot13Transformer`` as dependency. If an existing service definition (and only -one – see below) is of the required type, this service will be injected. If it's -not the case (like in this example), the subsystem is smart enough to automatically -register a private service for the ``Rot13Transformer`` class and set it as first -argument of the ``twitter_client`` service. Again, it can work only if there is one -class of the given type. If there are several classes of the same type, you must -use an explicit service definition or register a default implementation. - -As you can see, the autowiring feature drastically reduces the amount of configuration -required to define a service. No more arguments section! It also makes it easy -to change the dependencies of the ``TwitterClient`` class: just add or remove typehinted -arguments in the constructor and you are done. There is no need anymore to search -and edit related service definitions. - -Here is a typical controller using the ``twitter_client`` service:: - - // src/AppBundle/Controller/DefaultController.php - namespace AppBundle\Controller; - - use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; - use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; - use Symfony\Bundle\FrameworkBundle\Controller\Controller; - use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\HttpFoundation\Response; - use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; - - class DefaultController extends Controller - { - /** - * @Route("/tweet") - * @Method("POST") - */ - public function tweetAction(Request $request) - { - $user = $request->request->get('user'); - $key = $request->request->get('key'); - $status = $request->request->get('status'); - - if (!$user || !$key || !$status) { - throw new BadRequestHttpException(); - } - - $this->get('twitter_client')->tweet($user, $key, $status); - - return new Response('OK'); - } - } - -You can give the API a try using ``curl``: - -.. code-block:: bash - - $ curl -d "user=kevin&key=ABCD&status=Hello" http://localhost:8000/tweet - -It should return ``OK``. - -Working with Interfaces ------------------------ - -You might also find yourself using abstractions instead of implementations (especially -in grown applications) as it allows to easily replace some dependencies without -modifying the class depending of them. - -To follow this best practice, constructor arguments must be typehinted with interfaces -and not concrete classes. It allows to replace easily the current implementation -if necessary. It also allows to use other transformers. - -Let's introduce a ``TransformerInterface``:: - - // src/AppBundle/TransformerInterface.php - namespace AppBundle; - - interface TransformerInterface - { - public function transform($value); - } - -Then edit ``Rot13Transformer`` to make it implementing the new interface:: - - // ... - - class Rot13Transformer implements TransformerInterface - - // ... - - -And update ``TwitterClient`` to depend of this new interface:: - - class TwitterClient - { - // ... - - public function __construct(TransformerInterface $transformer) - { - // ... - } - - // ... - } - -Finally the service definition must be updated because, obviously, the autowiring -subsystem isn't able to find itself the interface implementation to register: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/services.yml - services: - rot13_transformer: - class: 'AppBundle\Rot13Transformer' - - twitter_client: - class: 'AppBundle\TwitterClient' - autowire: true - - .. code-block:: xml - - - - - - - - - - - - .. code-block:: php - - use Symfony\Component\DependencyInjection\Definition; - - // ... - $definition1 = new Definition('AppBundle\Rot13Transformer'); - $container->setDefinition('rot13_transformer', $definition1); - - $definition2 = new Definition('AppBundle\TwitterClient'); - $definition2->setAutowired(true); - $container->setDefinition('twitter_client', $definition2); - -The autowiring subsystem detects that the ``rot13_transformer`` service implements -the ``TransformerInterface`` and injects it automatically. Even when using -interfaces (and you should), building the service graph and refactoring the project -is easier than with standard definitions. - -Dealing with Multiple Implementations of the Same Type ------------------------------------------------------- - -Last but not least, the autowiring feature allows to specify the default implementation -of a given type. Let's introduce a new implementation of the ``TransformerInterface`` -returning the result of the ROT13 transformation uppercased:: - - // src/AppBundle/UppercaseRot13Transformer.php - namespace AppBundle; - - class UppercaseTransformer implements TransformerInterface - { - private $transformer; - - public function __construct(TransformerInterface $transformer) - { - $this->transformer = $transformer; - } - - public function transform($value) - { - return strtoupper($this->transformer->transform($value)); - } - } - -This class is intended to decorate the any transformer and return its value uppercased. - -We can now refactor the controller to add another endpoint leveraging this new -transformer:: - - // src/AppBundle/Controller/DefaultController.php - namespace AppBundle\Controller; - - use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; - use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; - use Symfony\Bundle\FrameworkBundle\Controller\Controller; - use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\HttpFoundation\Response; - use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; - - class DefaultController extends Controller - { - /** - * @Route("/tweet") - * @Method("POST") - */ - public function tweetAction(Request $request) - { - return $this->tweet($request, 'twitter_client'); - } - - /** - * @Route("/tweet-uppercase") - * @Method("POST") - */ - public function tweetUppercaseAction(Request $request) - { - return $this->tweet($request, 'uppercase_twitter_client'); - } - - private function tweet(Request $request, $service) - { - $user = $request->request->get('user'); - $key = $request->request->get('key'); - $status = $request->request->get('status'); - - if (!$user || !$key || !$status) { - throw new BadRequestHttpException(); - } - - $this->get($service)->tweet($user, $key, $status); - - return new Response('OK'); - } - } - -The last step is to update service definitions to register this new implementation -and a Twitter client using it: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/services.yml - services: - rot13_transformer: - class: AppBundle\Rot13Transformer - autowiring_types: AppBundle\TransformerInterface - - twitter_client: - class: AppBundle\TwitterClient - autowire: true - - uppercase_rot13_transformer: - class: AppBundle\UppercaseRot13Transformer - autowire: true - - uppercase_twitter_client: - class: AppBundle\TwitterClient - arguments: ['@uppercase_rot13_transformer'] - - .. code-block:: xml - - - - - - - - AppBundle\TransformerInterface - - - - - - - - - - .. code-block:: php - - use Symfony\Component\DependencyInjection\Reference; - use Symfony\Component\DependencyInjection\Definition; - - // ... - $definition1 = new Definition('AppBundle\Rot13Transformer'); - $definition1->setAutowiringTypes(array('AppBundle\TransformerInterface')); - $container->setDefinition('rot13_transformer', $definition1); - - $definition2 = new Definition('AppBundle\TwitterClient'); - $definition2->setAutowired(true); - $container->setDefinition('twitter_client', $definition2); - - $definition3 = new Definition('AppBundle\UppercaseRot13Transformer'); - $definition3->setAutowired(true); - $container->setDefinition('uppercase_rot13_transformer', $definition3); - - $definition4 = new Definition('AppBundle\TwitterClient'); - $definition4->addArgument(new Reference('uppercase_rot13_transformer')); - $container->setDefinition('uppercase_twitter_client', $definition4); - -This deserves some explanations. You now have two services implementing the -``TransformerInterface``. The autowiring subsystem cannot guess which one -to use which leads to errors like this: - -.. code-block:: text - - [Symfony\Component\DependencyInjection\Exception\RuntimeException] - Unable to autowire argument of type "AppBundle\TransformerInterface" for the service "twitter_client". - -Fortunately, the ``autowiring_types`` key is here to specify which implementation -to use by default. This key can take a list of types if necessary. - -Thanks to this setting, the ``rot13_transformer`` service is automatically injected -as an argument of the ``uppercase_rot13_transformer`` and ``twitter_client`` services. For -the ``uppercase_twitter_client``, we use a standard service definition to inject -the specific ``uppercase_rot13_transformer`` service. - -As for other RAD features such as the FrameworkBundle controller or annotations, -keep in mind to not use autowiring in public bundles nor in large projects with -complex maintenance needs. - -.. _Rapid Application Development: https://en.wikipedia.org/wiki/Rapid_application_development -.. _ROT13: https://en.wikipedia.org/wiki/ROT13 diff --git a/components/dependency_injection/compilation.rst b/components/dependency_injection/compilation.rst index d821857a475..d3ccfd13a4c 100644 --- a/components/dependency_injection/compilation.rst +++ b/components/dependency_injection/compilation.rst @@ -306,89 +306,46 @@ For more details, see :doc:`/cookbook/bundles/prepend_extension`, which is specific to the Symfony Framework, but contains more details about this feature. -.. _creating-a-compiler-pass: -.. _components-di-compiler-pass: +Creating a Compiler Pass +------------------------ -Execute Code During Compilation -------------------------------- - -You can also execute custom code during compilation by writing your own -compiler pass. By implementing +You can also create and register your own compiler passes with the container. +To create a compiler pass it needs to implement the :class:`Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface` -in your extension, the added ``process()`` method will be called during -compilation:: +interface. The compiler pass gives you an opportunity to manipulate the +service definitions that have been compiled. This can be very powerful, +but is not something needed in everyday use. + +The compiler pass must have the ``process`` method which is passed the container +being compiled:: - // ... use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; + use Symfony\Component\DependencyInjection\ContainerBuilder; - class AcmeDemoExtension implements ExtensionInterface, CompilerPassInterface + class CustomCompilerPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { - // ... do something during the compilation + // ... } - - // ... } -As ``process()`` is called *after* all extensions are loaded, it allows you to -edit service definitions of other extensions as well as retrieving information -about service definitions. - The container's parameters and definitions can be manipulated using the -methods described in :doc:`/components/dependency_injection/definitions`. - -.. note:: - - Please note that the ``process()`` method in the extension class is - called during the optimization step. You can read - :ref:`the next section ` if you - need to edit the container during another step. - -.. note:: - - As a rule, only work with services definition in a compiler pass and do not - create service instances. In practice, this means using the methods - ``has()``, ``findDefinition()``, ``getDefinition()``, ``setDefinition()``, - etc. instead of ``get()``, ``set()``, etc. - -.. tip:: - - Make sure your compiler pass does not require services to exist. Abort the - method call if some required service is not available. - -A common use-case of compiler passes is to search for all service definitions -that have a certain tag in order to process dynamically plug each into some -other service. See the section on :ref:`service tags ` -for an example. +methods described in the :doc:`/components/dependency_injection/definitions`. +One common thing to do in a compiler pass is to search for all services +that have a certain tag in order to process them in some way or dynamically +plug each into some other service. -.. _components-di-separate-compiler-passes: +Registering a Compiler Pass +--------------------------- -Creating Separate Compiler Passes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Sometimes, you need to do more than one thing during compliation, want to use -compiler passes without an extension or you need to execute some code at -another step in the compilation process. In these cases, you can create a new -class implementing the ``CompilerPassInterface``:: - - use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; - use Symfony\Component\DependencyInjection\ContainerBuilder; - - class CustomPass implements CompilerPassInterface - { - public function process(ContainerBuilder $container) - { - // ... do something during the compilation - } - } - -You then need to register your custom pass with the container:: +You need to register your custom pass with the container. Its process method +will then be called when the container is compiled:: use Symfony\Component\DependencyInjection\ContainerBuilder; $container = new ContainerBuilder(); - $container->addCompilerPass(new CustomPass()); + $container->addCompilerPass(new CustomCompilerPass); .. note:: @@ -397,16 +354,17 @@ You then need to register your custom pass with the container:: more details. Controlling the Pass Ordering -............................. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The default compiler passes are grouped into optimization passes and removal passes. The optimization passes run first and include tasks such as resolving references within the definitions. The removal passes perform tasks such -as removing private aliases and unused services. When registering compiler -passes using ``addCompilerPass()``, you can configure when your compiler pass -is run. By default, they are run before the optimization passes. +as removing private aliases and unused services. You can choose where in +the order any custom passes you add are run. By default they will be run +before the optimization passes. -You can use the following constants to determine when your pass is executed: +You can use the following constants as the second argument when registering +a pass with the container to control where it goes in the order: * ``PassConfig::TYPE_BEFORE_OPTIMIZATION`` * ``PassConfig::TYPE_OPTIMIZE`` @@ -415,11 +373,14 @@ You can use the following constants to determine when your pass is executed: * ``PassConfig::TYPE_AFTER_REMOVING`` For example, to run your custom pass after the default removal passes have -been run, use:: +been run:: - // ... + use Symfony\Component\DependencyInjection\ContainerBuilder; + use Symfony\Component\DependencyInjection\Compiler\PassConfig; + + $container = new ContainerBuilder(); $container->addCompilerPass( - new CustomPass(), + new CustomCompilerPass, PassConfig::TYPE_AFTER_REMOVING ); diff --git a/components/dependency_injection/factories.rst b/components/dependency_injection/factories.rst index e97fc0f4aa6..a5a37cf1c49 100644 --- a/components/dependency_injection/factories.rst +++ b/components/dependency_injection/factories.rst @@ -12,6 +12,11 @@ For this situation, you can use a factory to create the object and tell the service container to call a method on the factory rather than directly instantiating the class. +.. versionadded:: 2.6 + The new :method:`Symfony\\Component\\DependencyInjection\\Definition::setFactory` + method was introduced in Symfony 2.6. Refer to older versions for the + syntax for factories prior to 2.6. + Suppose you have a factory that configures and returns a new ``NewsletterManager`` object:: @@ -28,8 +33,8 @@ object:: } To make the ``NewsletterManager`` object available as a service, you can -configure the service container to use the -``NewsletterManagerFactory::createNewsletterManager()`` factory method: +configure the service container to use the ``NewsletterManagerFactory`` +factory class: .. configuration-block:: @@ -37,8 +42,9 @@ configure the service container to use the services: newsletter_manager: - class: NewsletterManager - factory: [NewsletterManagerFactory, createNewsletterManager] + class: NewsletterManager + factory_class: NewsletterManagerFactory + factory_method: createNewsletterManager .. code-block:: xml @@ -48,9 +54,11 @@ configure the service container to use the xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - - - + @@ -60,7 +68,8 @@ configure the service container to use the // ... $definition = new Definition('NewsletterManager'); - $definition->setFactory(array('NewsletterManagerFactory', 'createNewsletterManager')); + $definition->setFactoryClass('NewsletterManagerFactory'); + $definition->setFactoryMethod('createNewsletterManager'); $container->setDefinition('newsletter_manager', $definition); @@ -72,21 +81,23 @@ configure the service container to use the the configured class name may be used by compiler passes and therefore should be set to a sensible value. -Now, the method will be called statically. If the factory class itself should -be instantiated and the resulting object's method called, configure the factory -itself as a service. In this case, the method (e.g. get) should be changed to -be non-static. +When you specify the class to use for the factory (via ``factory_class``) +the method will be called statically. If the factory itself should be instantiated +and the resulting object's method called, configure the factory itself +as a service. In this case, the method (e.g. ``createNewsletterManager``) +should be changed to be non-static: .. configuration-block:: .. code-block:: yaml services: - newsletter_manager.factory: - class: NewsletterManagerFactory + newsletter_manager_factory: + class: NewsletterManagerFactory newsletter_manager: - class: NewsletterManager - factory: ["@newsletter_manager.factory", createNewsletterManager] + class: NewsletterManager + factory_service: newsletter_manager_factory + factory_method: createNewsletterManager .. code-block:: xml @@ -96,28 +107,36 @@ be non-static. xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - + - - - + .. code-block:: php - use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Definition; - // ... - $container->register('newsletter_manager.factory', 'NewsletterManagerFactory'); - - $newsletterManager = new Definition(); - $newsletterManager->setFactory(array( - new Reference('newsletter_manager.factory'), - 'createNewsletterManager' + $container->setDefinition('newsletter_manager_factory', new Definition( + 'NewsletterManager' )); - $container->setDefinition('newsletter_manager', $newsletterManager); + $container->setDefinition('newsletter_manager', new Definition( + 'NewsletterManagerFactory' + ))->setFactoryService( + 'newsletter_manager_factory' + )->setFactoryMethod( + 'createNewsletterManager' + ); + +.. note:: + + The factory service is specified by its id name and not a reference + to the service itself. So, you do not need to use the ``@`` syntax for + this in YAML configurations. Passing Arguments to the Factory Method --------------------------------------- @@ -131,12 +150,12 @@ method in the previous example takes the ``templating`` service as an argument: .. code-block:: yaml services: - newsletter_manager.factory: - class: NewsletterManagerFactory - + newsletter_manager_factory: + class: NewsletterManagerFactory newsletter_manager: - class: NewsletterManager - factory: ["@newsletter_manager.factory", createNewsletterManager] + class: NewsletterManager + factory_service: newsletter_manager_factory + factory_method: createNewsletterManager arguments: - '@templating' @@ -148,29 +167,32 @@ method in the previous example takes the ``templating`` service as an argument: xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - + - - - + + + .. code-block:: php - use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Definition; // ... - $container->register('newsletter_manager.factory', 'NewsletterManagerFactory'); - - $newsletterManager = new Definition( + $container->setDefinition('newsletter_manager_factory', new Definition( + 'NewsletterManagerFactory' + )); + $container->setDefinition('newsletter_manager', new Definition( 'NewsletterManager', array(new Reference('templating')) - ); - $newsletterManager->setFactory(array( - new Reference('newsletter_manager.factory'), + ))->setFactoryService( + 'newsletter_manager_factory' + )->setFactoryMethod( 'createNewsletterManager' - )); - $container->setDefinition('newsletter_manager', $newsletterManager); + ); diff --git a/components/dependency_injection/index.rst b/components/dependency_injection/index.rst index bc6ec0daf73..313f29af3f4 100644 --- a/components/dependency_injection/index.rst +++ b/components/dependency_injection/index.rst @@ -8,7 +8,6 @@ DependencyInjection types parameters definitions - autowiring synthetic_services compilation tags diff --git a/components/dependency_injection/lazy_services.rst b/components/dependency_injection/lazy_services.rst index 21c78075888..38f0968631f 100644 --- a/components/dependency_injection/lazy_services.rst +++ b/components/dependency_injection/lazy_services.rst @@ -4,6 +4,9 @@ Lazy Services ============= +.. versionadded:: 2.3 + Lazy services were introduced in Symfony 2.3. + Why Lazy Services? ------------------ @@ -27,7 +30,7 @@ the `ProxyManager bridge`_: .. code-block:: bash - $ composer require symfony/proxy-manager-bridge + $ composer require symfony/proxy-manager-bridge:~2.3 .. note:: diff --git a/components/dependency_injection/parentservices.rst b/components/dependency_injection/parentservices.rst index b153db59f8b..aa1ec8622d8 100644 --- a/components/dependency_injection/parentservices.rst +++ b/components/dependency_injection/parentservices.rst @@ -277,7 +277,8 @@ called when the child services are instantiated. .. caution:: - The ``abstract`` and ``tags`` attributes are always taken from the child service. + The ``scope``, ``abstract`` and ``tags`` attributes are always taken + from the child service. The parent service is abstract as it should not be directly retrieved from the container or passed into another service. It exists merely as a "template" diff --git a/components/dependency_injection/tags.rst b/components/dependency_injection/tags.rst index 2cb5713401a..c92cebaf3f8 100644 --- a/components/dependency_injection/tags.rst +++ b/components/dependency_injection/tags.rst @@ -117,14 +117,11 @@ Notice that each was given a tag named ``acme_mailer.transport``. This is the custom tag that you'll use in your compiler pass. The compiler pass is what makes this tag "mean" something. -.. _components-di-compiler-pass-tags: -.. _create-a-compilerpass: +Create a ``CompilerPass`` +------------------------- -Create a Compiler Pass ----------------------- - -You can now use a :ref:`compiler pass ` to ask the -container for any services with the ``acme_mailer.transport`` tag:: +Your compiler pass can now ask the container for any services with the +custom tag:: use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; @@ -157,7 +154,7 @@ container for any services with the ``acme_mailer.transport`` tag:: The ``process()`` method checks for the existence of the ``acme_mailer.transport_chain`` service, then looks for all services tagged ``acme_mailer.transport``. It adds to the definition of the ``acme_mailer.transport_chain`` service a -call to ``addTransport()`` for each ``acme_mailer.transport`` service it has +call to ``addTransport()`` for each "acme_mailer.transport" service it has found. The first argument of each of these calls will be the mailer transport service itself. @@ -178,13 +175,6 @@ run when the container is compiled:: framework. See :doc:`/cookbook/service_container/compiler_passes` for more details. -.. tip:: - - When implementing the ``CompilerPassInterface`` in a service extension, you - do not need to register it. See the - :ref:`components documentation ` for more - information. - Adding Additional Attributes on Tags ------------------------------------ @@ -306,3 +296,4 @@ The double loop may be confusing. This is because a service can have more than one tag. You tag a service twice or more with the ``acme_mailer.transport`` tag. The second foreach loop iterates over the ``acme_mailer.transport`` tags set for the current service and gives you the attributes. + diff --git a/components/dom_crawler.rst b/components/dom_crawler.rst index d4cc5d79d7f..f9a3fe030f3 100644 --- a/components/dom_crawler.rst +++ b/components/dom_crawler.rst @@ -190,6 +190,10 @@ Get all the child or parent nodes:: Accessing Node Values ~~~~~~~~~~~~~~~~~~~~~ +.. versionadded:: 2.6 + The :method:`Symfony\\Component\\DomCrawler\\Crawler::nodeName` + method was introduced in Symfony 2.6. + Access the node name (HTML tag name) of the first node of the current selection (eg. "p" or "div"):: // will return the node name (HTML tag name) of the first child element under @@ -223,6 +227,11 @@ Call an anonymous function on each node of the list:: return $node->text(); }); +.. versionadded:: 2.3 + 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 node (as a Crawler) and the position as arguments. The result is an array of values returned by the anonymous function calls. @@ -289,6 +298,8 @@ and :phpclass:`DOMNode` objects: $html = $crawler->html(); + The ``html`` method is new in Symfony 2.3. + Links ~~~~~ diff --git a/components/event_dispatcher/immutable_dispatcher.rst b/components/event_dispatcher/immutable_dispatcher.rst index da757aeacce..7df2aecf282 100644 --- a/components/event_dispatcher/immutable_dispatcher.rst +++ b/components/event_dispatcher/immutable_dispatcher.rst @@ -4,6 +4,9 @@ The Immutable Event Dispatcher ============================== +.. versionadded:: 2.1 + This feature was introduced 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 823cd54a8ed..9311ad9dc75 100644 --- a/components/event_dispatcher/introduction.rst +++ b/components/event_dispatcher/introduction.rst @@ -194,14 +194,14 @@ determine which instance is passed. and the :doc:`DependencyInjection component `, you can use the - :class:`Symfony\\Component\\EventDispatcher\\DependencyInjection\\RegisterListenersPass` - to tag services as event listeners:: + :class:`Symfony\\Component\\HttpKernel\\DependencyInjection\\RegisterListenersPass` + from the HttpKernel component to tag services as event listeners:: use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\Reference; - use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass; + use Symfony\Component\HttpKernel\DependencyInjection\RegisterListenersPass; $containerBuilder = new ContainerBuilder(new ParameterBag()); $containerBuilder->addCompilerPass(new RegisterListenersPass()); @@ -439,11 +439,11 @@ method which returns a boolean value:: EventDispatcher Aware Events and Listeners ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``EventDispatcher`` always passes the dispatched event, the event's -name and a reference to itself to the listeners. This can be used in some -advanced usages of the ``EventDispatcher`` like dispatching other events -in listeners, event chaining or even lazy loading of more listeners into -the dispatcher object as shown in the following examples. +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`` +object's :method:`Symfony\\Component\\EventDispatcher\\Event::getDispatcher` +method. This can lead to some advanced applications of the ``EventDispatcher`` including dispatching other events inside listeners, chaining events or even @@ -487,15 +487,20 @@ and so on. Event Name Introspection ~~~~~~~~~~~~~~~~~~~~~~~~ -The ``EventDispatcher`` instance, as well as the name of the event that -is dispatched, are passed as arguments to the listener:: +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 +to event listeners via the :method:`Symfony\\Component\\EventDispatcher\\Event::getName` +method. + +The event name, (as with any other data in a custom event object) can be +used as part of the listener's processing logic:: use Symfony\Component\EventDispatcher\Event; - use Symfony\Component\EventDispatcher\EventDispatcherInterface; class Foo { - public function myEventListener(Event $event, $eventName, EventDispatcherInterface $dispatcher) + public function myEventListener(Event $event) { // ... do something with the event name } diff --git a/components/event_dispatcher/traceable_dispatcher.rst b/components/event_dispatcher/traceable_dispatcher.rst index f76b70ae938..70fad87bb03 100644 --- a/components/event_dispatcher/traceable_dispatcher.rst +++ b/components/event_dispatcher/traceable_dispatcher.rst @@ -5,13 +5,13 @@ The Traceable Event Dispatcher ============================== -The :class:`Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcher` +The :class:`Symfony\\Component\\HttpKernel\\Debug\\TraceableEventDispatcher` is an event dispatcher that wraps any other event dispatcher and can then be used to determine which event listeners have been called by the dispatcher. Pass the event dispatcher to be wrapped and an instance of the :class:`Symfony\\Component\\Stopwatch\\Stopwatch` to its constructor:: - use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher; + use Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher; use Symfony\Component\Stopwatch\Stopwatch; // the event dispatcher to debug diff --git a/components/expression_language/caching.rst b/components/expression_language/caching.rst deleted file mode 100644 index b06176a0375..00000000000 --- a/components/expression_language/caching.rst +++ /dev/null @@ -1,74 +0,0 @@ -.. index:: - single: Caching; ExpressionLanguage - -Caching Expressions Using Parser Caches -======================================= - -The ExpressionLanguage component already provides a -:method:`Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage::compile` -method to be able to cache the expressions in plain PHP. But internally, the -component also caches the parsed expressions, so duplicated expressions can be -compiled/evaluated quicker. - -The Workflow ------------- - -Both :method:`Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage::evaluate` -and ``compile()`` need to do some things before each can provide the return -values. For ``evaluate()``, this overhead is even bigger. - -Both methods need to tokenize and parse the expression. This is done by the -:method:`Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage::parse` -method. It returns a :class:`Symfony\\Component\\ExpressionLanguage\\ParsedExpression`. -Now, the ``compile()`` method just returns the string conversion of this object. -The ``evaluate()`` method needs to loop through the "nodes" (pieces of an -expression saved in the ``ParsedExpression``) and evaluate them on the fly. - -To save time, the ``ExpressionLanguage`` caches the ``ParsedExpression`` so -it can skip the tokenize and parse steps with duplicate expressions. -The caching is done by a -:class:`Symfony\\Component\\ExpressionLanguage\\ParserCache\\ParserCacheInterface` -instance (by default, it uses an -:class:`Symfony\\Component\\ExpressionLanguage\\ParserCache\\ArrayParserCache`). -You can customize this by creating a custom ``ParserCache`` and injecting this -in the object using the constructor:: - - use Symfony\Component\ExpressionLanguage\ExpressionLanguage; - use Acme\ExpressionLanguage\ParserCache\MyDatabaseParserCache; - - $cache = new MyDatabaseParserCache(...); - $language = new ExpressionLanguage($cache); - -.. note:: - - The `DoctrineBridge`_ provides a Parser Cache implementation using the - `doctrine cache library`_, which gives you caching for all sorts of cache - strategies, like Apc, Filesystem and Memcached. - -Using Parsed and Serialized Expressions ---------------------------------------- - -Both ``evaluate()`` and ``compile()`` can handle ``ParsedExpression`` and -``SerializedParsedExpression``:: - - // ... - - // the parse() method returns a ParsedExpression - $expression = $language->parse('1 + 4', array()); - - var_dump($language->evaluate($expression)); // prints 5 - -.. code-block:: php - - use Symfony\Component\ExpressionLanguage\SerializedParsedExpression; - // ... - - $expression = new SerializedParsedExpression( - '1 + 4', - serialize($language->parse('1 + 4', array())->getNodes()) - ); - - var_dump($language->evaluate($expression)); // prints 5 - -.. _DoctrineBridge: https://github.com/symfony/doctrine-bridge -.. _`doctrine cache library`: http://docs.doctrine-project.org/projects/doctrine-common/en/latest/reference/caching.html diff --git a/components/expression_language/extending.rst b/components/expression_language/extending.rst index eeb9963c6c6..fa90165014d 100644 --- a/components/expression_language/extending.rst +++ b/components/expression_language/extending.rst @@ -56,6 +56,9 @@ evaluating or the "names" if compiling). Using Expression Providers -------------------------- +.. versionadded:: 2.6 + Expression providers were introduced in Symfony 2.6. + When you use the ``ExpressionLanguage`` class in your library, you often want to add custom functions. To do so, you can create a new expression provider by creating a class that implements diff --git a/components/expression_language/index.rst b/components/expression_language/index.rst deleted file mode 100644 index e2bfed27824..00000000000 --- a/components/expression_language/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -ExpressionLanguage -================== - -.. toctree:: - :maxdepth: 2 - - introduction - syntax - extending - caching diff --git a/components/expression_language/introduction.rst b/components/expression_language/introduction.rst deleted file mode 100644 index 98b4402f7c7..00000000000 --- a/components/expression_language/introduction.rst +++ /dev/null @@ -1,115 +0,0 @@ -.. index:: - single: Expressions - Single: Components; Expression Language - -The ExpressionLanguage Component -================================ - - The ExpressionLanguage component provides an engine that can compile and - evaluate expressions. An expression is a one-liner that returns a value - (mostly, but not limited to, Booleans). - -Installation ------------- - -You can install the component in 2 different ways: - -* :doc:`Install it via Composer ` (``symfony/expression-language`` on `Packagist`_); -* Use the official Git repository (https://github.com/symfony/expression-language). - -How can the Expression Engine Help Me? --------------------------------------- - -The purpose of the component is to allow users to use expressions inside -configuration for more complex logic. For some examples, the Symfony2 Framework -uses expressions in security, for validation rules and in route matching. - -Besides using the component in the framework itself, the ExpressionLanguage -component is a perfect candidate for the foundation of a *business rule engine*. -The idea is to let the webmaster of a website configure things in a dynamic -way without using PHP and without introducing security problems: - -.. _component-expression-language-examples: - -.. code-block:: text - - # Get the special price if - user.getGroup() in ['good_customers', 'collaborator'] - - # Promote article to the homepage when - article.commentCount > 100 and article.category not in ["misc"] - - # Send an alert when - product.stock < 15 - -Expressions can be seen as a very restricted PHP sandbox and are immune to -external injections as you must explicitly declare which variables are available -in an expression. - -Usage ------ - -The ExpressionLanguage component can compile and evaluate expressions. -Expressions are one-liners that often return a Boolean, which can be used -by the code executing the expression in an ``if`` statement. A simple example -of an expression is ``1 + 2``. You can also use more complicated expressions, -such as ``someArray[3].someMethod('bar')``. - -The component provides 2 ways to work with expressions: - -* **evaluation**: the expression is evaluated without being compiled to PHP; -* **compile**: the expression is compiled to PHP, so it can be cached and - evaluated. - -The main class of the component is -:class:`Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage`:: - - use Symfony\Component\ExpressionLanguage\ExpressionLanguage; - - $language = new ExpressionLanguage(); - - var_dump($language->evaluate('1 + 2')); // displays 3 - - var_dump($language->compile('1 + 2')); // displays (1 + 2) - -Expression Syntax ------------------ - -See :doc:`/components/expression_language/syntax` to learn the syntax of the -ExpressionLanguage component. - -Passing in Variables --------------------- - -You can also pass variables into the expression, which can be of any valid -PHP type (including objects):: - - use Symfony\Component\ExpressionLanguage\ExpressionLanguage; - - $language = new ExpressionLanguage(); - - class Apple - { - public $variety; - } - - $apple = new Apple(); - $apple->variety = 'Honeycrisp'; - - var_dump($language->evaluate( - 'fruit.variety', - array( - 'fruit' => $apple, - ) - )); - -This will print "Honeycrisp". For more information, see the :doc:`/components/expression_language/syntax` -entry, especially :ref:`component-expression-objects` and :ref:`component-expression-arrays`. - -Caching -------- - -The component provides some different caching strategies, read more about them -in :doc:`/components/expression_language/caching`. - -.. _Packagist: https://packagist.org/packages/symfony/expression-language diff --git a/components/expression_language/syntax.rst b/components/expression_language/syntax.rst deleted file mode 100644 index c3140ace7a2..00000000000 --- a/components/expression_language/syntax.rst +++ /dev/null @@ -1,310 +0,0 @@ -.. index:: - single: Syntax; ExpressionLanguage - -The Expression Syntax -===================== - -The ExpressionLanguage component uses a specific syntax which is based on the -expression syntax of Twig. In this document, you can find all supported -syntaxes. - -Supported Literals ------------------- - -The component supports: - -* **strings** - single and double quotes (e.g. ``'hello'``) -* **numbers** - e.g. ``103`` -* **arrays** - using JSON-like notation (e.g. ``[1, 2]``) -* **hashes** - using JSON-like notation (e.g. ``{ foo: 'bar' }``) -* **booleans** - ``true`` and ``false`` -* **null** - ``null`` - -.. caution:: - - A backslash (``\``) must be escaped by 4 backslashes (``\\\\``) in a string - and 8 backslashes (``\\\\\\\\``) in a regex:: - - echo $language->evaluate('"\\\\"'); // prints \ - $language->evaluate('"a\\\\b" matches "/^a\\\\\\\\b$/"'); // returns true - - Control characters (e.g. ``\n``) in expressions are replaced with - whitespace. To avoid this, escape the sequence with a single backslash - (e.g. ``\\n``). - -.. _component-expression-objects: - -Working with Objects --------------------- - -When passing objects into an expression, you can use different syntaxes to -access properties and call methods on the object. - -Accessing Public Properties -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Public properties on objects can be accessed by using the ``.`` syntax, similar -to JavaScript:: - - class Apple - { - public $variety; - } - - $apple = new Apple(); - $apple->variety = 'Honeycrisp'; - - var_dump($language->evaluate( - 'fruit.variety', - array( - 'fruit' => $apple, - ) - )); - -This will print out ``Honeycrisp``. - -Calling Methods -~~~~~~~~~~~~~~~ - -The ``.`` syntax can also be used to call methods on an object, similar to -JavaScript:: - - class Robot - { - public function sayHi($times) - { - $greetings = array(); - for ($i = 0; $i < $times; $i++) { - $greetings[] = 'Hi'; - } - - return implode(' ', $greetings).'!'; - } - } - - $robot = new Robot(); - - var_dump($language->evaluate( - 'robot.sayHi(3)', - array( - 'robot' => $robot, - ) - )); - -This will print out ``Hi Hi Hi!``. - -.. _component-expression-functions: - -Working with Functions ----------------------- - -You can also use registered functions in the expression by using the same -syntax as PHP and JavaScript. The ExpressionLanguage component comes with one -function by default: ``constant()``, which will return the value of the PHP -constant:: - - define('DB_USER', 'root'); - - var_dump($language->evaluate( - 'constant("DB_USER")' - )); - -This will print out ``root``. - -.. tip:: - - To read how to register your own functions to use in an expression, see - ":doc:`/components/expression_language/extending`". - -.. _component-expression-arrays: - -Working with Arrays -------------------- - -If you pass an array into an expression, use the ``[]`` syntax to access -array keys, similar to JavaScript:: - - $data = array('life' => 10, 'universe' => 10, 'everything' => 22); - - var_dump($language->evaluate( - 'data["life"] + data["universe"] + data["everything"]', - array( - 'data' => $data, - ) - )); - -This will print out ``42``. - -Supported Operators -------------------- - -The component comes with a lot of operators: - -Arithmetic Operators -~~~~~~~~~~~~~~~~~~~~ - -* ``+`` (addition) -* ``-`` (subtraction) -* ``*`` (multiplication) -* ``/`` (division) -* ``%`` (modulus) -* ``**`` (pow) - -For example:: - - var_dump($language->evaluate( - 'life + universe + everything', - array( - 'life' => 10, - 'universe' => 10, - 'everything' => 22, - ) - )); - -This will print out ``42``. - -Bitwise Operators -~~~~~~~~~~~~~~~~~ - -* ``&`` (and) -* ``|`` (or) -* ``^`` (xor) - -Comparison Operators -~~~~~~~~~~~~~~~~~~~~ - -* ``==`` (equal) -* ``===`` (identical) -* ``!=`` (not equal) -* ``!==`` (not identical) -* ``<`` (less than) -* ``>`` (greater than) -* ``<=`` (less than or equal to) -* ``>=`` (greater than or equal to) -* ``matches`` (regex match) - -.. tip:: - - To test if a string does *not* match a regex, use the logical ``not`` - operator in combination with the ``matches`` operator:: - - $language->evaluate('not ("foo" matches "/bar/")'); // returns true - - You must use parenthesis because the unary operator ``not`` has precedence - over the binary operator ``matches``. - -Examples:: - - $ret1 = $language->evaluate( - 'life == everything', - array( - 'life' => 10, - 'universe' => 10, - 'everything' => 22, - ) - ); - - $ret2 = $language->evaluate( - 'life > everything', - array( - 'life' => 10, - 'universe' => 10, - 'everything' => 22, - ) - ); - -Both variables would be set to ``false``. - -Logical Operators -~~~~~~~~~~~~~~~~~ - -* ``not`` or ``!`` -* ``and`` or ``&&`` -* ``or`` or ``||`` - -For example:: - - $ret = $language->evaluate( - 'life < universe or life < everything', - array( - 'life' => 10, - 'universe' => 10, - 'everything' => 22, - ) - ); - -This ``$ret`` variable will be set to ``true``. - -String Operators -~~~~~~~~~~~~~~~~ - -* ``~`` (concatenation) - -For example:: - - var_dump($language->evaluate( - 'firstName~" "~lastName', - array( - 'firstName' => 'Arthur', - 'lastName' => 'Dent', - ) - )); - -This would print out ``Arthur Dent``. - -Array Operators -~~~~~~~~~~~~~~~ - -* ``in`` (contain) -* ``not in`` (does not contain) - -For example:: - - class User - { - public $group; - } - - $user = new User(); - $user->group = 'human_resources'; - - $inGroup = $language->evaluate( - 'user.group in ["human_resources", "marketing"]', - array( - 'user' => $user, - ) - ); - -The ``$inGroup`` would evaluate to ``true``. - -Numeric Operators -~~~~~~~~~~~~~~~~~ - -* ``..`` (range) - -For example:: - - class User - { - public $age; - } - - $user = new User(); - $user->age = 34; - - $language->evaluate( - 'user.age in 18..45', - array( - 'user' => $user, - ) - ); - -This will evaluate to ``true``, because ``user.age`` is in the range from -``18`` to ``45``. - -Ternary Operators -~~~~~~~~~~~~~~~~~ - -* ``foo ? 'yes' : 'no'`` -* ``foo ?: 'no'`` (equal to ``foo ? foo : 'no'``) -* ``foo ? 'yes'`` (equal to ``foo ? 'yes' : ''``) diff --git a/components/filesystem/introduction.rst b/components/filesystem.rst similarity index 97% rename from components/filesystem/introduction.rst rename to components/filesystem.rst index 53cbced419e..eab50f7e6cd 100644 --- a/components/filesystem/introduction.rst +++ b/components/filesystem.rst @@ -6,6 +6,10 @@ The Filesystem Component The Filesystem component provides basic utilities for the filesystem. +.. tip:: + + The lock handler feature was introduced in symfony 2.6. + :doc:`See the documentation for more information `. Installation ------------ @@ -235,6 +239,9 @@ isAbsolutePath dumpFile ~~~~~~~~ +.. versionadded:: 2.3 + The ``dumpFile()`` was introduced in Symfony 2.3. + :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. diff --git a/components/filesystem/index.rst b/components/filesystem/index.rst deleted file mode 100644 index e643f5a90f4..00000000000 --- a/components/filesystem/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -Filesystem -========== - -.. toctree:: - :maxdepth: 2 - - introduction - lock_handler diff --git a/components/filesystem/lock_handler.rst b/components/filesystem/lock_handler.rst index 90efe6b1033..5d442e79547 100644 --- a/components/filesystem/lock_handler.rst +++ b/components/filesystem/lock_handler.rst @@ -1,6 +1,9 @@ LockHandler =========== +.. versionadded:: 2.6 + The lock handler feature was introduced in Symfony 2.6 + What is a Lock? --------------- diff --git a/components/finder.rst b/components/finder.rst index 2a12460031a..e8c70b3aabc 100644 --- a/components/finder.rst +++ b/components/finder.rst @@ -84,6 +84,9 @@ Search in several locations by chaining calls to $finder->files()->in(__DIR__)->in('/elsewhere'); +.. versionadded:: 2.2 + Wildcard support was introduced in version 2.2. + Use wildcard characters to search in the directories matching a pattern:: $finder->in('src/Symfony/*/*/Resources'); @@ -95,6 +98,10 @@ Exclude directories from matching with the $finder->in(__DIR__)->exclude('ruby'); +.. versionadded:: 2.3 + The :method:`Symfony\\Component\\Finder\\Finder::ignoreUnreadableDirs` + method was introduced in Symfony 2.3. + It's also possible to ignore directories that you don't have permission to read:: $finder->ignoreUnreadableDirs()->in(__DIR__); @@ -199,6 +206,9 @@ The ``notContains()`` method excludes files containing given pattern:: Path ~~~~ +.. versionadded:: 2.2 + The ``path()`` and ``notPath()`` methods were introduced in Symfony 2.2. + Restrict files and directories by path with the :method:`Symfony\\Component\\Finder\\Finder::path` method:: diff --git a/components/form/form_events.rst b/components/form/form_events.rst index 188d72c8460..d024cbdc3ea 100644 --- a/components/form/form_events.rst +++ b/components/form/form_events.rst @@ -257,6 +257,19 @@ Name ``FormEvents`` Constant Event's Data ``form.post_bind`` ``FormEvents::POST_SUBMIT`` View data ====================== ============================= =============== +.. versionadded:: 2.3 + Before Symfony 2.3, ``FormEvents::PRE_SUBMIT``, ``FormEvents::SUBMIT`` + and ``FormEvents::POST_SUBMIT`` were called ``FormEvents::PRE_BIND``, + ``FormEvents::BIND`` and ``FormEvents::POST_BIND``. + +.. caution:: + + The ``FormEvents::PRE_BIND``, ``FormEvents::BIND`` and + ``FormEvents::POST_BIND`` constants will be removed in version 3.0 of + Symfony. + The event names still keep their original values, so make sure you use the + ``FormEvents`` constants in your code for forward compatibility. + Event Listeners ~~~~~~~~~~~~~~~ @@ -268,13 +281,10 @@ Creating and binding an event listener to the form is very easy:: use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; - use Symfony\Component\Form\Extension\Core\Type\TextType; - use Symfony\Component\Form\Extension\Core\Type\CheckboxType; - use Symfony\Component\Form\Extension\Core\Type\EmailType; $form = $formFactory->createBuilder() - ->add('username', TextType::class) - ->add('show_email', CheckboxType::class) + ->add('username', 'text') + ->add('show_email', 'checkbox') ->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) { $user = $event->getData(); $form = $event->getForm(); @@ -287,7 +297,7 @@ Creating and binding an event listener to the form is very easy:: // If the data was submitted previously, the additional value that is // included in the request variables needs to be removed. if (true === $user['show_email']) { - $form->add('email', EmailType::class); + $form->add('email', 'email'); } else { unset($user['email']); $event->setData($user); @@ -300,17 +310,14 @@ Creating and binding an event listener to the form is very easy:: When you have created a form type class, you can use one of its methods as a callback for better readability:: - use Symfony\Component\Form\Extension\Core\Type\TextType; - use Symfony\Component\Form\Extension\Core\Type\CheckboxType; - // ... class SubscriptionType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->add('username', TextType::class); - $builder->add('show_email', CheckboxType::class); + $builder->add('username', 'text'); + $builder->add('show_email', 'checkbox'); $builder->addEventListener( FormEvents::PRE_SET_DATA, array($this, 'onPreSetData') @@ -337,7 +344,6 @@ Event subscribers have different uses: use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; - use Symfony\Component\Form\Extension\Core\Type\EmailType; class AddEmailFieldListener implements EventSubscriberInterface { @@ -357,7 +363,7 @@ Event subscribers have different uses: // Check whether the user from the initial data has chosen to // display his email or not. if (true === $user->isShowEmail()) { - $form->add('email', EmailType::class); + $form->add('email', 'email'); } } @@ -374,7 +380,7 @@ Event subscribers have different uses: // If the data was submitted previously, the additional value that // is included in the request variables needs to be removed. if (true === $user['show_email']) { - $form->add('email', EmailType::class); + $form->add('email', 'email'); } else { unset($user['email']); $event->setData($user); @@ -384,14 +390,11 @@ Event subscribers have different uses: To register the event subscriber, use the addEventSubscriber() method:: - use Symfony\Component\Form\Extension\Core\Type\TextType; - use Symfony\Component\Form\Extension\Core\Type\CheckboxType; - // ... $form = $formFactory->createBuilder() - ->add('username', TextType::class) - ->add('show_email', CheckboxType::class) + ->add('username', 'text') + ->add('show_email', 'checkbox') ->addEventSubscriber(new AddEmailFieldListener()) ->getForm(); diff --git a/components/form/introduction.rst b/components/form/introduction.rst index 6ff900cddfa..2b0aab979f1 100644 --- a/components/form/introduction.rst +++ b/components/form/introduction.rst @@ -68,6 +68,9 @@ factory. Request Handling ~~~~~~~~~~~~~~~~ +.. versionadded:: 2.3 + The ``handleRequest()`` method was introduced in Symfony 2.3. + To process form data, you'll need to call the :method:`Symfony\\Component\\Form\\Form::handleRequest` method:: @@ -110,45 +113,45 @@ CSRF Protection ~~~~~~~~~~~~~~~ Protection against CSRF attacks is built into the Form component, but you need -to explicitly enable it or replace it with a custom solution. If you want to -use the built-in support, require the Security CSRF component by executing -``composer require symfony/security-csrf``. - -The following snippet adds CSRF protection to the form factory:: +to explicitly enable it or replace it with a custom solution. The following +snippet adds CSRF protection to the form factory:: use Symfony\Component\Form\Forms; + use Symfony\Component\Form\Extension\Csrf\CsrfExtension; + use Symfony\Component\Form\Extension\Csrf\CsrfProvider\SessionCsrfProvider; use Symfony\Component\HttpFoundation\Session\Session; - use Symfony\Component\Security\Extension\Csrf\CsrfExtension; - use Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage; - use Symfony\Component\Security\Csrf\TokenGenerator\UriSafeTokenGenerator; - use Symfony\Component\Security\Csrf\CsrfTokenManager; + + // generate a CSRF secret from somewhere + $csrfSecret = ''; // create a Session object from the HttpFoundation component $session = new Session(); - $csrfGenerator = new UriSafeTokenGenerator(); - $csrfStorage = new SessionTokenStorage($session); - $csrfManager = new CsrfTokenManager($csrfGenerator, $csrfStorage); + $csrfProvider = new SessionCsrfProvider($session, $csrfSecret); $formFactory = Forms::createFormFactoryBuilder() // ... - ->addExtension(new CsrfExtension($csrfStorage)) + ->addExtension(new CsrfExtension($csrfProvider)) ->getFormFactory(); +To secure your application against CSRF attacks, you need to define a CSRF +secret. Generate a random string with at least 32 characters, insert it in the +above snippet and make sure that nobody except your web server can access +the secret. + Internally, this extension will automatically add a hidden field to every -form (called ``_token`` by default) whose value is automatically generated by -the CSRF generator and validated when binding the form. +form (called ``_token`` by default) whose value is automatically generated +and validated when binding the form. .. tip:: If you're not using the HttpFoundation component, you can use - :class:`Symfony\\Component\\Security\\Csrf\\TokenStorage\\NativeSessionTokenStorage` + :class:`Symfony\\Component\\Form\\Extension\\Csrf\\CsrfProvider\\DefaultCsrfProvider` instead, which relies on PHP's native session handling:: - use Symfony\Component\Security\Csrf\TokenStorage\NativeSessionTokenStorage; + use Symfony\Component\Form\Extension\Csrf\CsrfProvider\DefaultCsrfProvider; - $csrfStorage = new NativeSessionTokenStorage(); - // ... + $csrfProvider = new DefaultCsrfProvider($csrfSecret); Twig Templating ~~~~~~~~~~~~~~~ @@ -160,14 +163,14 @@ component offers a rich integration. To use the integration, you'll need the ``TwigBridge``, which provides integration between Twig and several Symfony components. If you're using Composer, you -could install the latest 3.x version by adding the following ``require`` +could install the latest 2.3 version by adding the following ``require`` line to your ``composer.json`` file: .. code-block:: json { "require": { - "symfony/twig-bridge": "~3.0" + "symfony/twig-bridge": "2.3.*" } } @@ -240,15 +243,15 @@ via your own Twig extension. To use the built-in integration, be sure that your project has Symfony's Translation and :doc:`Config ` components -installed. If you're using Composer, you could get the latest 3.x version +installed. If you're using Composer, you could get the latest 2.3 version of each of these by adding the following to your ``composer.json`` file: .. code-block:: json { "require": { - "symfony/translation": "~3.0", - "symfony/config": "~3.0" + "symfony/translation": "2.3.*", + "symfony/config": "2.3.*" } } @@ -292,13 +295,13 @@ array or object) and pass it through your own validation system. To use the integration with Symfony's Validator component, first make sure it's installed in your application. If you're using Composer and want to -install the latest 3.x version, add this to your ``composer.json``: +install the latest 2.3 version, add this to your ``composer.json``: .. code-block:: json { "require": { - "symfony/validator": "~3.0" + "symfony/validator": "2.3.*" } } @@ -315,8 +318,9 @@ Your integration with the Validation component will look something like this:: use Symfony\Component\Validator\Validation; $vendorDir = realpath(__DIR__.'/../vendor'); - $vendorFormDir = $vendorDir.'/symfony/form'; - $vendorValidatorDir = $vendorDir.'/symfony/validator'; + $vendorFormDir = $vendorDir.'/symfony/form/Symfony/Component/Form'; + $vendorValidatorDir = + $vendorDir.'/symfony/validator/Symfony/Component/Validator'; // create the validator - details will vary $validator = Validation::createValidator(); @@ -387,14 +391,9 @@ is created from the form factory. .. code-block:: php-standalone - use Symfony\Component\Form\Extension\Core\Type\TextType; - use Symfony\Component\Form\Extension\Core\Type\DateType; - - // ... - $form = $formFactory->createBuilder() - ->add('task', TextType::class) - ->add('dueDate', DateType::class) + ->add('task', 'text') + ->add('dueDate', 'date') ->getForm(); var_dump($twig->render('new.html.twig', array( @@ -408,8 +407,6 @@ is created from the form factory. use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\Form\Extension\Core\Type\TextType; - use Symfony\Component\Form\Extension\Core\Type\DateType; class DefaultController extends Controller { @@ -417,10 +414,9 @@ is created from the form factory. { // createFormBuilder is a shortcut to get the "form factory" // and then call "createBuilder()" on it - $form = $this->createFormBuilder() - ->add('task', TextType::class) - ->add('dueDate', DateType::class) + ->add('task', 'text') + ->add('dueDate', 'date') ->getForm(); return $this->render('AcmeTaskBundle:Default:new.html.twig', array( @@ -431,8 +427,8 @@ is created from the form factory. As you can see, creating a form is like writing a recipe: you call ``add`` for each new field you want to create. The first argument to ``add`` is the -name of your field, and the second is the fully qualified class name. The Form -component comes with a lot of :doc:`built-in types `. +name of your field, and the second is the field "type". The Form component +comes with a lot of :doc:`built-in types `. Now that you've built your form, learn how to :ref:`render ` it and :ref:`process the form submission `. @@ -448,35 +444,24 @@ builder: .. code-block:: php-standalone - use Symfony\Component\Form\Extension\Core\Type\FormType; - use Symfony\Component\Form\Extension\Core\Type\TextType; - use Symfony\Component\Form\Extension\Core\Type\DateType; - - // ... - $defaults = array( 'dueDate' => new \DateTime('tomorrow'), ); - $form = $formFactory->createBuilder(FormType::class, $defaults) - ->add('task', TextType::class) - ->add('dueDate', DateType::class) + $form = $formFactory->createBuilder('form', $defaults) + ->add('task', 'text') + ->add('dueDate', 'date') ->getForm(); .. code-block:: php-symfony - use Symfony\Component\Form\Extension\Core\Type\TextType; - use Symfony\Component\Form\Extension\Core\Type\DateType; - - // ... - $defaults = array( 'dueDate' => new \DateTime('tomorrow'), ); $form = $this->createFormBuilder($defaults) - ->add('task', TextType::class) - ->add('dueDate', DateType::class) + ->add('task', 'text') + ->add('dueDate', 'date') ->getForm(); .. tip:: @@ -515,6 +500,10 @@ to do that in the ":ref:`form-rendering-template`" section. Changing a Form's Method and Action ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. versionadded:: 2.3 + The ability to configure the form method and action was introduced in + Symfony 2.3. + By default, a form is submitted to the same URI that rendered the form with an HTTP POST request. This behavior can be changed using the :ref:`form-option-action` and :ref:`form-option-method` options (the ``method`` option is also used @@ -524,11 +513,7 @@ by ``handleRequest()`` to determine whether a form has been submitted): .. code-block:: php-standalone - use Symfony\Component\Form\Extension\Core\Type\FormType; - - // ... - - $formBuilder = $formFactory->createBuilder(FormType::class, null, array( + $formBuilder = $formFactory->createBuilder('form', null, array( 'action' => '/search', 'method' => 'GET', )); @@ -537,8 +522,6 @@ by ``handleRequest()`` to determine whether a form has been submitted): .. code-block:: php-symfony - use Symfony\Component\Form\Extension\Core\Type\FormType; - // ... public function searchAction() @@ -565,14 +548,10 @@ method: use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RedirectResponse; - use Symfony\Component\Form\Extension\Core\Type\TextType; - use Symfony\Component\Form\Extension\Core\Type\DateType; - - // ... $form = $formFactory->createBuilder() - ->add('task', TextType::class) - ->add('dueDate', DateType::class) + ->add('task', 'text') + ->add('dueDate', 'date') ->getForm(); $request = Request::createFromGlobals(); @@ -594,16 +573,13 @@ method: .. code-block:: php-symfony - use Symfony\Component\Form\Extension\Core\Type\TextType; - use Symfony\Component\Form\Extension\Core\Type\DateType; - // ... public function newAction(Request $request) { $form = $this->createFormBuilder() - ->add('task', TextType::class) - ->add('dueDate', DateType::class) + ->add('task', 'text') + ->add('dueDate', 'date') ->getForm(); $form->handleRequest($request); @@ -613,7 +589,7 @@ method: // ... perform some action, such as saving the data to the database - return $this->redirectToRoute('task_success'); + return $this->redirect($this->generateUrl('task_success')); } // ... @@ -648,14 +624,12 @@ option when building each field: use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\Type; - use Symfony\Component\Form\Extension\Core\Type\TextType; - use Symfony\Component\Form\Extension\Core\Type\DateType; $form = $formFactory->createBuilder() - ->add('task', TextType::class, array( + ->add('task', 'text', array( 'constraints' => new NotBlank(), )) - ->add('dueDate', DateType::class, array( + ->add('dueDate', 'date', array( 'constraints' => array( new NotBlank(), new Type('\DateTime'), @@ -667,14 +641,12 @@ option when building each field: use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\Type; - use Symfony\Component\Form\Extension\Core\Type\TextType; - use Symfony\Component\Form\Extension\Core\Type\DateType; $form = $this->createFormBuilder() - ->add('task', TextType::class, array( + ->add('task', 'text', array( 'constraints' => new NotBlank(), )) - ->add('dueDate', DateType::class, array( + ->add('dueDate', 'date', array( 'constraints' => array( new NotBlank(), new Type('\DateTime'), @@ -694,27 +666,41 @@ Accessing Form Errors ~~~~~~~~~~~~~~~~~~~~~ You can use the :method:`Symfony\\Component\\Form\\FormInterface::getErrors` -method to access the list of errors. It returns a -:class:`Symfony\\Component\\Form\\FormErrorIterator` instance:: +method to access the list of errors. Each element is a :class:`Symfony\\Component\\Form\\FormError` +object:: $form = ...; // ... - // a FormErrorIterator instance, but only errors attached to this + // an array of FormError objects, but only errors attached to this // form level (e.g. "global errors) $errors = $form->getErrors(); - // a FormErrorIterator instance, but only errors attached to the + // an array of FormError objects, but only errors attached to the // "firstName" field $errors = $form['firstName']->getErrors(); - // a FormErrorIterator instance in a flattened structure - // use getOrigin() to determine the form causing the error - $errors = $form->getErrors(true); + // a string representation of all errors of the whole form tree + $errors = $form->getErrorsAsString(); + +.. note:: + + If you enable the :ref:`error_bubbling ` + option on a field, calling ``getErrors()`` on the parent form will include + errors from that field. However, there is no way to determine which field + an error was originally attached to. + +.. tip:: + + In older Symfony versions, ``getErrors()`` returned an array. To use the + errors the same way in Symfony 2.5 or newer, you have to pass them to + PHP's :phpfunction:`iterator_to_array` function:: + + $errorsAsArray = iterator_to_array($form->getErrors()); - // a FormErrorIterator instance representing the form tree structure - $errors = $form->getErrors(true, false); + This is useful, for example, if you want to use PHP's ``array_`` function + on the form errors. .. _Packagist: https://packagist.org/packages/symfony/form .. _Twig: http://twig.sensiolabs.org diff --git a/components/form/type_guesser.rst b/components/form/type_guesser.rst index 78fa338a814..13a64400118 100644 --- a/components/form/type_guesser.rst +++ b/components/form/type_guesser.rst @@ -32,9 +32,11 @@ This interface requires 4 methods: tries to guess the value of the :ref:`required ` option; * :method:`Symfony\\Component\\Form\\FormTypeGuesserInterface::guessMaxLength` - - tries to guess the value of the ``maxlength`` input attribute; + tries to guess the value of the :ref:`max_length ` + option; * :method:`Symfony\\Component\\Form\\FormTypeGuesserInterface::guessPattern` - - tries to guess the value of the ``pattern`` input attribute. + tries to guess the value of the :ref:`pattern ` + option. Start by creating the class and these methods. Next, you'll learn how to fill each on. @@ -89,10 +91,6 @@ With this knowledge, you can easily implement the ``guessType`` method of the use Symfony\Component\Form\Guess\Guess; use Symfony\Component\Form\Guess\TypeGuess; - use Symfony\Component\Form\Extension\Core\Type\TextType; - use Symfony\Component\Form\Extension\Core\Type\IntegerType; - use Symfony\Component\Form\Extension\Core\Type\NumberType; - use Symfony\Component\Form\Extension\Core\Type\CheckboxType; class PHPDocTypeGuesser implements FormTypeGuesserInterface { @@ -109,25 +107,25 @@ With this knowledge, you can easily implement the ``guessType`` method of the case 'string': // there is a high confidence that the type is text when // @var string is used - return new TypeGuess(TextType::class, array(), Guess::HIGH_CONFIDENCE); + return new TypeGuess('text', array(), Guess::HIGH_CONFIDENCE); case 'int': case 'integer': // integers can also be the id of an entity or a checkbox (0 or 1) - return new TypeGuess(IntegerType::class, array(), Guess::MEDIUM_CONFIDENCE); + return new TypeGuess('integer', array(), Guess::MEDIUM_CONFIDENCE); case 'float': case 'double': case 'real': - return new TypeGuess(NumberType::class, array(), Guess::MEDIUM_CONFIDENCE); + return new TypeGuess('number', array(), Guess::MEDIUM_CONFIDENCE); case 'boolean': case 'bool': - return new TypeGuess(CheckboxType::class, array(), Guess::HIGH_CONFIDENCE); + return new TypeGuess('checkbox', array(), Guess::HIGH_CONFIDENCE); default: // there is a very low confidence that this one is correct - return new TypeGuess(TextType::class, array(), Guess::LOW_CONFIDENCE); + return new TypeGuess('text', array(), Guess::LOW_CONFIDENCE); } } diff --git a/components/http_foundation/introduction.rst b/components/http_foundation/introduction.rst index 6f6c6ccc5eb..2cbae21727c 100644 --- a/components/http_foundation/introduction.rst +++ b/components/http_foundation/introduction.rst @@ -125,12 +125,6 @@ has some methods to filter the input values: :method:`Symfony\\Component\\HttpFoundation\\ParameterBag::getAlnum` Returns the alphabetic characters and digits of the parameter value; -:method:`Symfony\\Component\\HttpFoundation\\ParameterBag::getBoolean` - Returns the parameter value converted to boolean; - - .. versionadded:: 2.6 - The ``getBoolean()`` method was introduced in Symfony 2.6. - :method:`Symfony\\Component\\HttpFoundation\\ParameterBag::getDigits` Returns the digits of the parameter value; @@ -140,35 +134,39 @@ has some methods to filter the input values: :method:`Symfony\\Component\\HttpFoundation\\ParameterBag::filter` Filters the parameter by using the PHP :phpfunction:`filter_var` function. -All getters take up to two arguments: the first one is the parameter name +All getters take up to three arguments: the first one is the parameter name and the second one is the default value to return if the parameter does not exist:: // the query string is '?foo=bar' $request->query->get('foo'); - // returns 'bar' + // returns bar $request->query->get('bar'); // returns null - $request->query->get('bar', 'baz'); - // returns 'baz' + $request->query->get('bar', 'bar'); + // returns 'bar' When PHP imports the request query, it handles request parameters like ``foo[bar]=bar`` in a special way as it creates an array. So you can get the -``foo`` parameter and you will get back an array with a ``bar`` element:: +``foo`` parameter and you will get back an array with a ``bar`` element. But +sometimes, you might want to get the value for the "original" parameter name: +``foo[bar]``. This is possible with all the ``ParameterBag`` getters like +:method:`Symfony\\Component\\HttpFoundation\\Request::get` via the third +argument:: - // the query string is '?foo[bar]=baz' + // the query string is '?foo[bar]=bar' $request->query->get('foo'); - // returns array('bar' => 'baz') + // returns array('bar' => 'bar') $request->query->get('foo[bar]'); // returns null - $request->query->get('foo')['bar']; - // returns 'baz' + $request->query->get('foo[bar]', null, true); + // returns 'bar' .. _component-foundation-attributes: @@ -254,8 +252,9 @@ by using the following methods: :method:`Symfony\\Component\\HttpFoundation\\Request::getCharsets` Returns the list of accepted charsets ordered by descending quality. -:method:`Symfony\\Component\\HttpFoundation\\Request::getEncodings` - Returns the list of accepted encodings ordered by descending quality. +.. versionadded:: 2.2 + The :class:`Symfony\\Component\\HttpFoundation\\AcceptHeader` class was + introduced in Symfony 2.2. If you need to get full access to parsed data from ``Accept``, ``Accept-Language``, ``Accept-Charset`` or ``Accept-Encoding``, you can use @@ -282,38 +281,6 @@ request information. Have a look at :class:`the Request API ` for more information about them. -Overriding the Request -~~~~~~~~~~~~~~~~~~~~~~ - -The ``Request`` class should not be overridden as it is a data object that -represents an HTTP message. But when moving from a legacy system, adding -methods or changing some default behavior might help. In that case, register a -PHP callable that is able to create an instance of your ``Request`` class:: - - use Symfony\Component\HttpFoundation\Request; - - Request::setFactory(function ( - array $query = array(), - array $request = array(), - array $attributes = array(), - array $cookies = array(), - array $files = array(), - array $server = array(), - $content = null - ) { - return SpecialRequest::create( - $query, - $request, - $attributes, - $cookies, - $files, - $server, - $content - ); - }); - - $request = Request::createFromGlobals(); - .. _component-http-foundation-response: Response @@ -328,7 +295,7 @@ code, and an array of HTTP headers:: $response = new Response( 'Content', - Response::HTTP_OK, + 200, array('content-type' => 'text/html') ); @@ -339,7 +306,7 @@ This information can also be manipulated after the Response object creation:: // the headers public attribute is a ResponseHeaderBag $response->headers->set('Content-Type', 'text/plain'); - $response->setStatusCode(Response::HTTP_NOT_FOUND); + $response->setStatusCode(404); When setting the ``Content-Type`` of the Response, you can set the charset, but it is better to set it via the @@ -486,6 +453,10 @@ abstracts the hard work behind a simple API:: $response->headers->set('Content-Disposition', $d); +.. versionadded:: 2.2 + The :class:`Symfony\\Component\\HttpFoundation\\BinaryFileResponse` + class was introduced in Symfony 2.2. + Alternatively, if you are serving a static file, you can use a :class:`Symfony\\Component\\HttpFoundation\\BinaryFileResponse`:: @@ -512,6 +483,9 @@ or change its ``Content-Disposition``:: 'filename.txt' ); +.. versionadded:: 2.6 + The ``deleteFileAfterSend()`` method was introduced in Symfony 2.6. + It is possible to delete the file after the request is sent with the :method:`Symfony\\Component\\HttpFoundation\\BinaryFileResponse::deleteFileAfterSend` method. Please note that this will not work when the ``X-Sendfile`` header is set. diff --git a/components/http_foundation/trusting_proxies.rst b/components/http_foundation/trusting_proxies.rst index a8c0193668d..fbe9b30cdee 100644 --- a/components/http_foundation/trusting_proxies.rst +++ b/components/http_foundation/trusting_proxies.rst @@ -19,6 +19,10 @@ Since HTTP headers can be spoofed, Symfony does *not* trust these proxy headers by default. If you are behind a proxy, you should manually whitelist your proxy. +.. versionadded:: 2.3 + CIDR notation support was introduced in Symfony 2.3, so you can whitelist whole + subnets (e.g. ``10.0.0.0/8``, ``fc00::/7``). + .. code-block:: php use Symfony\Component\HttpFoundation\Request; diff --git a/components/http_kernel/introduction.rst b/components/http_kernel/introduction.rst index fd4682a9a53..1a808980b5e 100644 --- a/components/http_kernel/introduction.rst +++ b/components/http_kernel/introduction.rst @@ -592,17 +592,16 @@ each event has their own event object: .. _component-http-kernel-event-table: -===================== ================================ =================================================================================== -Name ``KernelEvents`` Constant Argument passed to the listener -===================== ================================ =================================================================================== -kernel.request ``KernelEvents::REQUEST`` :class:`Symfony\\Component\\HttpKernel\\Event\\GetResponseEvent` -kernel.controller ``KernelEvents::CONTROLLER`` :class:`Symfony\\Component\\HttpKernel\\Event\\FilterControllerEvent` -kernel.view ``KernelEvents::VIEW`` :class:`Symfony\\Component\\HttpKernel\\Event\\GetResponseForControllerResultEvent` -kernel.response ``KernelEvents::RESPONSE`` :class:`Symfony\\Component\\HttpKernel\\Event\\FilterResponseEvent` -kernel.finish_request ``KernelEvents::FINISH_REQUEST`` :class:`Symfony\\Component\\HttpKernel\\Event\\FinishRequestEvent` -kernel.terminate ``KernelEvents::TERMINATE`` :class:`Symfony\\Component\\HttpKernel\\Event\\PostResponseEvent` -kernel.exception ``KernelEvents::EXCEPTION`` :class:`Symfony\\Component\\HttpKernel\\Event\\GetResponseForExceptionEvent` -===================== ================================ =================================================================================== +================= ============================ =================================================================================== +Name ``KernelEvents`` Constant Argument Passed to the Listener +================= ============================ =================================================================================== +kernel.request ``KernelEvents::REQUEST`` :class:`Symfony\\Component\\HttpKernel\\Event\\GetResponseEvent` +kernel.controller ``KernelEvents::CONTROLLER`` :class:`Symfony\\Component\\HttpKernel\\Event\\FilterControllerEvent` +kernel.view ``KernelEvents::VIEW`` :class:`Symfony\\Component\\HttpKernel\\Event\\GetResponseForControllerResultEvent` +kernel.response ``KernelEvents::RESPONSE`` :class:`Symfony\\Component\\HttpKernel\\Event\\FilterResponseEvent` +kernel.terminate ``KernelEvents::TERMINATE`` :class:`Symfony\\Component\\HttpKernel\\Event\\PostResponseEvent` +kernel.exception ``KernelEvents::EXCEPTION`` :class:`Symfony\\Component\\HttpKernel\\Event\\GetResponseForExceptionEvent` +================= ============================ =================================================================================== .. _http-kernel-working-example: @@ -616,7 +615,6 @@ However, the HttpKernel component comes with some built-in listeners and a built-in ControllerResolver that can be used to create a working example:: use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernel; use Symfony\Component\EventDispatcher\EventDispatcher; @@ -642,7 +640,7 @@ a built-in ControllerResolver that can be used to create a working example:: $matcher = new UrlMatcher($routes, new RequestContext()); $dispatcher = new EventDispatcher(); - $dispatcher->addSubscriber(new RouterListener($matcher, new RequestStack())); + $dispatcher->addSubscriber(new RouterListener($matcher)); $resolver = new ControllerResolver(); $kernel = new HttpKernel($dispatcher, $resolver); @@ -687,8 +685,8 @@ This creates another full request-response cycle where this new ``Request`` is transformed into a ``Response``. The only difference internally is that some listeners (e.g. security) may only act upon the master request. Each listener is passed some sub-class of :class:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent`, -whose :method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::isMasterRequest` -can be used to check if the current request is a "master" or "sub" request. +whose :method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::getRequestType` +can be used to figure out if the current request is a "master" or "sub" request. For example, a listener that only needs to act on the master request may look like this:: @@ -698,7 +696,7 @@ look like this:: public function onKernelRequest(GetResponseEvent $event) { - if (!$event->isMasterRequest()) { + if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { return; } diff --git a/components/index.rst b/components/index.rst index 43aa14e5e40..780b33b2c9e 100644 --- a/components/index.rst +++ b/components/index.rst @@ -5,25 +5,22 @@ The Components :hidden: using_components - asset/index browser_kit/index class_loader/index config/index console/index css_selector - debug/index + debug dependency_injection/index dom_crawler event_dispatcher/index - expression_language/index - filesystem/index + filesystem finder form/index http_foundation/index http_kernel/index intl options_resolver - phpunit_bridge process property_access/index routing/index @@ -32,7 +29,6 @@ The Components stopwatch templating/index translation/index - var_dumper/index yaml/index .. include:: /components/map.rst.inc diff --git a/components/intl.rst b/components/intl.rst index d7282cf0d14..b8047db0cd0 100644 --- a/components/intl.rst +++ b/components/intl.rst @@ -8,6 +8,10 @@ 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 introduced 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 @@ -56,6 +60,87 @@ code:: $loader->registerPrefixFallback('/path/to/Icu/Resources/stubs'); } +.. sidebar:: ICU and Deployment Problems + + .. note:: + + These deployment problems only affect the following Symfony versions: + 2.3.0 to 2.3.20 versions, any 2.4.x version and 2.5.0 to 2.5.5 versions. + + 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, Symfony 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 4.0 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 ``composer update`` on the development machine, version + 1.2.* of the Icu component will be installed. But after deploying the + application, ``composer install`` will fail with the following error: + + .. code-block:: bash + + $ composer 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 ``composer update`` instead of + ``composer 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 ``composer 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 ------------------------------------ diff --git a/components/map.rst.inc b/components/map.rst.inc index deb5d6b84c8..b69b347373f 100644 --- a/components/map.rst.inc +++ b/components/map.rst.inc @@ -1,20 +1,16 @@ * :doc:`/components/using_components` -* :doc:`/components/asset/index` - - * :doc:`/components/asset/introduction` - * :doc:`/components/browser_kit/index` - + * :doc:`/components/browser_kit/introduction` * :doc:`/components/class_loader/index` * :doc:`/components/class_loader/introduction` * :doc:`/components/class_loader/class_loader` - * :doc:`/components/class_loader/psr4_class_loader` * :doc:`/components/class_loader/map_class_loader` * :doc:`/components/class_loader/cache_class_loader` + * :doc:`/components/class_loader/debug_class_loader` * :doc:`/components/class_loader/class_map_generator` * :doc:`/components/config/index` @@ -29,20 +25,17 @@ * :doc:`/components/console/introduction` * :doc:`/components/console/usage` * :doc:`/components/console/single_command_tool` - * :doc:`/components/console/changing_default_command` * :doc:`/components/console/console_arguments` * :doc:`/components/console/events` - * :doc:`/components/console/logger` * :doc:`/components/console/helpers/index` * **CssSelector** * :doc:`/components/css_selector` -* :doc:`/components/debug/index` +* **Debug** - * :doc:`/components/debug/introduction` - * :doc:`/components/debug/class_loader` + * :doc:`/components/debug` * :doc:`/components/dependency_injection/index` @@ -50,7 +43,6 @@ * :doc:`/components/dependency_injection/types` * :doc:`/components/dependency_injection/parameters` * :doc:`/components/dependency_injection/definitions` - * :doc:`/components/dependency_injection/autowiring` * :doc:`/components/dependency_injection/synthetic_services` * :doc:`/components/dependency_injection/compilation` * :doc:`/components/dependency_injection/tags` @@ -73,17 +65,9 @@ * :doc:`/components/event_dispatcher/immutable_dispatcher` * :doc:`/components/event_dispatcher/traceable_dispatcher` -* :doc:`/components/expression_language/index` - - * :doc:`/components/expression_language/introduction` - * :doc:`/components/expression_language/syntax` - * :doc:`/components/expression_language/extending` - * :doc:`/components/expression_language/caching` - -* :doc:`/components/filesystem/index` +* **Filesystem** - * :doc:`/components/filesystem/introduction` - * :doc:`/components/filesystem/lock_handler` + * :doc:`/components/filesystem` * **Finder** @@ -116,10 +100,6 @@ * :doc:`/components/options_resolver` -* **PHPUnitBridge** - - * :doc:`/components/phpunit_bridge` - * **Process** * :doc:`/components/process` @@ -159,11 +139,6 @@ * :doc:`/components/translation/usage` * :doc:`/components/translation/custom_formats` -* :doc:`/components/var_dumper/index` - - * :doc:`/components/var_dumper/introduction` - * :doc:`/components/var_dumper/advanced` - * :doc:`/components/yaml/index` * :doc:`/components/yaml/introduction` diff --git a/components/options_resolver.rst b/components/options_resolver.rst index 4c0bb039e55..436d54e5109 100644 --- a/components/options_resolver.rst +++ b/components/options_resolver.rst @@ -22,6 +22,11 @@ You can install the component in 2 different ways: Notes on Previous Versions -------------------------- +.. versionadded:: 2.6 + This documentation was written for Symfony 2.6 and later. If you use an older + version, please `read the Symfony 2.5 documentation`_. For a list of changes, + see the `CHANGELOG`_. + Usage ----- @@ -217,6 +222,10 @@ For example, to make the ``host`` option required, you can do:: } } +.. versionadded:: 2.6 + As of Symfony 2.6, ``setRequired()`` accepts both an array of options or a + single option. Prior to 2.6, you could only pass arrays. + If you omit a required option, a :class:`Symfony\\Component\\OptionsResolver\\Exception\\MissingOptionsException` will be thrown:: @@ -241,6 +250,11 @@ one required option:: } } +.. versionadded:: 2.6 + The methods :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::isRequired` + and :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::getRequiredOptions` + were introduced in Symfony 2.6. + Use :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::isRequired` to find out if an option is required. You can use :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::getRequiredOptions` to @@ -261,6 +275,11 @@ retrieve the names of all required options:: } } +.. versionadded:: 2.6 + The methods :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::isMissing` + and :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::getMissingOptions` + were introduced in Symfony 2.6. + If you want to check whether a required option is still missing from the default options, you can use :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::isMissing`. The difference between this and :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::isRequired` @@ -343,6 +362,11 @@ is thrown:: In sub-classes, you can use :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::addAllowedTypes` to add additional allowed types without erasing the ones already set. +.. versionadded:: 2.6 + Before Symfony 2.6, ``setAllowedTypes()`` and ``addAllowedTypes()`` expected + the values to be given as an array mapping option names to allowed types: + ``$resolver->setAllowedTypes(array('port' => array('null', 'int')));`` + Value Validation ~~~~~~~~~~~~~~~~ @@ -389,6 +413,11 @@ returns ``true`` for acceptable values and ``false`` for invalid values:: In sub-classes, you can use :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::addAllowedValues` to add additional allowed values without erasing the ones already set. +.. versionadded:: 2.6 + Before Symfony 2.6, ``setAllowedValues()`` and ``addAllowedValues()`` expected + the values to be given as an array mapping option names to allowed values: + ``$resolver->setAllowedValues(array('transport' => array('sendmail', 'mail', 'smtp')));`` + Option Normalization ~~~~~~~~~~~~~~~~~~~~ @@ -419,6 +448,11 @@ option. You can configure a normalizer by calling } } +.. versionadded:: 2.6 + The method :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setNormalizer` + was introduced in Symfony 2.6. Before, you had to use + :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setNormalizers`. + The normalizer receives the actual ``$value`` and returns the normalized form. You see that the closure also takes an ``$options`` parameter. This is useful if you need to use other options during normalization:: @@ -553,6 +587,11 @@ comes from the default:: } } +.. versionadded:: 2.6 + The method :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setDefined` + was introduced in Symfony 2.6. Before, you had to use + :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setOptional`. + You can use :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setDefined` to define an option without setting a default value. Then the option will only be included in the resolved options if it was actually passed to @@ -604,6 +643,11 @@ options in one go:: } } +.. versionadded:: 2.6 + The method :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::isDefined` + and :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::getDefinedOptions` + were introduced in Symfony 2.6. + The methods :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::isDefined` and :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::getDefinedOptions` let you find out which options are defined:: @@ -690,3 +734,4 @@ options in your code. .. _Packagist: https://packagist.org/packages/symfony/options-resolver .. _Form component: http://symfony.com/doc/current/components/form/introduction.html .. _CHANGELOG: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/OptionsResolver/CHANGELOG.md#260 +.. _`read the Symfony 2.5 documentation`: http://symfony.com/doc/2.5/components/options_resolver.html diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst deleted file mode 100644 index ae5e7b4da33..00000000000 --- a/components/phpunit_bridge.rst +++ /dev/null @@ -1,246 +0,0 @@ -.. index:: - single: PHPUnitBridge - single: Components; PHPUnitBridge - -The PHPUnit Bridge -================== - - The PHPUnit Bridge provides utilities to report legacy tests and usage of - deprecated code and a helper for time-sensitive tests. - -It comes with the following features: - -* Forces the tests to use a consistent locale (``C``); - -* Auto-register ``class_exists`` to load Doctrine annotations (when used); - -* It displays the whole list of deprecated features used in the application; - -* Displays the stack trace of a deprecation on-demand; - -* Provides a ``ClockMock`` helper class for time-sensitive tests. - -.. versionadded:: 2.7 - The PHPUnit Bridge was introduced in Symfony 2.7. It is however possible to - install the bridge in any Symfony application (even 2.3). - -Installation ------------- - -You can install the component in 2 different ways: - -* :doc:`Install it via Composer ` - (``symfony/phpunit-bridge`` on `Packagist`_); as a dev dependency; - -* Use the official Git repository (https://github.com/symfony/phpunit-bridge). - -.. include:: /components/require_autoload.rst.inc - -Usage ------ - -Once the component installed, it automatically registers a -`PHPUnit event listener`_ which in turn registers a `PHP error handler`_ -called :class:`Symfony\\Bridge\\PhpUnit\\DeprecationErrorHandler`. After -running your PHPUnit tests, you will get a report similar to this one: - -.. image:: /images/components/phpunit_bridge/report.png - -The summary includes: - -**Unsilenced** - Reports deprecation notices that were triggered without the recommended - `@-silencing operator`_. - -**Legacy** - Deprecation notices denote tests that explicitly test some legacy features. - -**Remaining/Other** - Deprecation notices are all other (non-legacy) notices, grouped by message, - test class and method. - -Trigger Deprecation Notices ---------------------------- - -Deprecation notices can be triggered by using:: - - @trigger_error('Your deprecation message', E_USER_DEPRECATED); - -Without the `@-silencing operator`_, users would need to opt-out from deprecation -notices. Silencing by default swaps this behavior and allows users to opt-in -when they are ready to cope with them (by adding a custom error handler like the -one provided by this bridge). When not silenced, deprecation notices will appear -in the **Unsilenced** section of the deprecation report. - -Mark Tests as Legacy --------------------- - -There are four ways to mark a test as legacy: - -* (**Recommended**) Add the ``@group legacy`` annotation to its class or method; - -* Make its class name start with the ``Legacy`` prefix; - -* Make its method name start with ``testLegacy`` instead of ``test``; - -* Make its data provider start with ``provideLegacy`` or ``getLegacy``. - -Configuration -------------- - -In case you need to inspect the stack trace of a particular deprecation -triggered by your unit tests, you can set the ``SYMFONY_DEPRECATIONS_HELPER`` -`environment variable`_ to a regular expression that matches this deprecation's -message, enclosed with ``/``. For example, with: - -.. code-block:: xml - - - - - - - - - - - - -PHPUnit_ will stop your test suite once a deprecation notice is triggered whose -message contains the ``"foobar"`` string. - -Making Tests Fail ------------------ - -By default, any non-legacy-tagged or any non-`@-silenced`_ deprecation notices will -make tests fail. Alternatively, setting ``SYMFONY_DEPRECATIONS_HELPER`` to an -arbitrary value (ex: ``320``) will make the tests fails only if a higher number -of deprecation notices is reached (``0`` is the default value). You can also set -the value ``"weak"`` which will make the bridge ignore any deprecation notices. -This is useful to projects that must use deprecated interfaces for backward -compatibility reasons. - -Time-sensitive Tests --------------------- - -Use Case -~~~~~~~~ - -If you have this kind of time-related tests:: - - use Symfony\Component\Stopwatch\Stopwatch; - - class MyTest extends \PHPUnit_Framework_TestCase - { - public function testSomething() - { - $stopwatch = new Stopwatch(); - - $stopwatch->start(); - sleep(10); - $duration = $stopwatch->stop(); - - $this->assertEquals(10, $duration); - } - } - -You used the :doc:`Symfony Stopwatch Component ` to -calculate the duration time of your process, here 10 seconds. However, depending -on the load of the server your the processes running on your local machine, the -``$duration`` could for example be `10.000023s` instead of `10s`. - -This kind of tests are called transient tests: they are failing randomly -depending on spurious and external circumstances. They are often cause trouble -when using public continuous integration services like `Travis CI`_. - -Clock Mocking -~~~~~~~~~~~~~ - -The :class:`Symfony\\Bridge\\PhpUnit\\ClockMock` class provided by this bridge -allows you to mock the PHP's built-in time functions ``time()``, -``microtime()``, ``sleep()`` and ``usleep()``. - -To use the ``ClockMock`` class in your test, you can: - -* (**Recommended**) Add the ``@group time-sensitive`` annotation to its class or - method; - -* Register it manually by calling ``ClockMock::register(__CLASS__)`` and - ``ClockMock::withClockMock(true)`` before the test and - ``ClockMock::withClockMock(false)`` after the test. - -As a result, the following is guarenteed to work and is no longer a transient -test:: - - use Symfony\Component\Stopwatch\Stopwatch; - - /** - * @group time-sensitive - */ - class MyTest extends \PHPUnit_Framework_TestCase - { - public function testSomething() - { - $stopwatch = new Stopwatch(); - - $stopwatch->start(); - sleep(10); - $duration = $stopwatch->stop(); - - $this->assertEquals(10, $duration); - } - } - -And that's all! - -.. tip:: - - An added bonus of using the ``ClockMock`` class is that time passes - instantly. Using PHP's ``sleep(10)`` will make your test wait for 10 - actual seconds (more or less). In contrast, the ``ClockMock`` class - advances the internal clock the given number of seconds without actually - waiting that time, so your test will execute 10 seconds faster. - -Troubleshooting -~~~~~~~~~~~~~~~ - -The ``@group time-sensitive`` works "by convention" and assumes that the -namespace of the tested class can be obtained just by removing the ``\Tests\`` -part from the test namespace. I.e. that if the your test case fully-qualified -class name (FQCN) is ``App\Tests\Watch\DummyWatchTest``, it assumes the tested -class FQCN is ``App\Watch\DummyWatch``. - -If this convention doesn't work for your application, you can also configure -the mocked namespaces in the ``phpunit.xml`` file, as done for example in the -:doc:`HttpKernel Component `: - -.. code-block:: xml - - - - - - - - - - - Symfony\Component\HttpFoundation - - - - - - -.. _PHPUnit: https://phpunit.de -.. _`PHPUnit event listener`: https://phpunit.de/manual/current/en/extending-phpunit.html#extending-phpunit.PHPUnit_Framework_TestListener -.. _`PHP error handler`: http://php.net/manual/en/book.errorfunc.php -.. _`environment variable`: https://phpunit.de/manual/current/en/appendixes.configuration.html#appendixes.configuration.php-ini-constants-variables -.. _Packagist: https://packagist.org/packages/symfony/phpunit-bridge -.. _`@-silencing operator`: http://php.net/manual/en/language.operators.errorcontrol.php -.. _`@-silenced`: http://php.net/manual/en/language.operators.errorcontrol.php -.. _`Travis CI`: https://travis-ci.com/ diff --git a/components/process.rst b/components/process.rst index aaa732d053c..c848fcc07bc 100644 --- a/components/process.rst +++ b/components/process.rst @@ -24,50 +24,30 @@ The :class:`Symfony\\Component\\Process\\Process` class allows you to execute a command in a sub-process:: use Symfony\Component\Process\Process; - use Symfony\Component\Process\Exception\ProcessFailedException; $process = new Process('ls -lsa'); $process->run(); // executes after the command finishes if (!$process->isSuccessful()) { - throw new ProcessFailedException($process); + throw new \RuntimeException($process->getErrorOutput()); } - echo $process->getOutput(); + print $process->getOutput(); The component takes care of the subtle differences between the different platforms when executing the command. +.. versionadded:: 2.2 + The ``getIncrementalOutput()`` and ``getIncrementalErrorOutput()`` methods + were introduced in Symfony 2.2. + The ``getOutput()`` method always returns the whole content of the standard output of the command and ``getErrorOutput()`` the content of the error output. Alternatively, the :method:`Symfony\\Component\\Process\\Process::getIncrementalOutput` and :method:`Symfony\\Component\\Process\\Process::getIncrementalErrorOutput` methods returns the new outputs since the last call. -The :method:`Symfony\\Component\\Process\\Process::clearOutput` method clears -the contents of the output and -:method:`Symfony\\Component\\Process\\Process::clearErrorOutput` clears -the contents of the error output. - -The ``mustRun()`` method is identical to ``run()``, except that it will throw -a :class:`Symfony\\Component\\Process\\Exception\\ProcessFailedException` -if the process couldn't be executed successfully (i.e. the process exited -with a non-zero code):: - - use Symfony\Component\Process\Exception\ProcessFailedException; - use Symfony\Component\Process\Process; - - $process = new Process('ls -lsa'); - - try { - $process->mustRun(); - - echo $process->getOutput(); - } catch (ProcessFailedException $e) { - echo $e->getMessage(); - } - Getting real-time Process Output -------------------------------- @@ -87,6 +67,9 @@ anonymous function to the } }); +.. versionadded:: 2.1 + The non-blocking feature was introduced in 2.1. + Running Processes Asynchronously -------------------------------- @@ -131,6 +114,9 @@ are done doing other stuff:: Stopping a Process ------------------ +.. versionadded:: 2.3 + The ``signal`` parameter of the ``stop`` method was introduced 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 two arguments: a timeout and a signal. Once the timeout is reached, the signal @@ -167,6 +153,10 @@ 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 introduced in Symfony 2.3. + In case you are building a binary driver, you can use the :method:`Symfony\\Component\\Process\\ProcessBuilder::setPrefix` method to prefix all the generated process commands. @@ -223,25 +213,12 @@ check regularly:: .. _reference-process-signal: -Process Idle Timeout --------------------- - -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 introduced in Symfony 2.3. + When running a program asynchronously, you can send it POSIX signals with the :method:`Symfony\\Component\\Process\\Process::signal` method:: @@ -265,6 +242,9 @@ When running a program asynchronously, you can send it POSIX signals with the Process Pid ----------- +.. versionadded:: 2.3 + The ``getPid`` method was introduced in Symfony 2.3. + You can access the `pid`_ of a running process with the :method:`Symfony\\Component\\Process\\Process::getPid` method. @@ -283,29 +263,6 @@ You can access the `pid`_ of a running process with the you may have to prefix your commands with `exec`_. Please read `Symfony Issue#5759`_ to understand why this is happening. -Disabling Output ----------------- - -As standard output and error output are always fetched from the underlying process, -it might be convenient to disable output in some cases to save memory. -Use :method:`Symfony\\Component\\Process\\Process::disableOutput` and -:method:`Symfony\\Component\\Process\\Process::enableOutput` to toggle this feature:: - - use Symfony\Component\Process\Process; - - $process = new Process('/usr/bin/php worker.php'); - $process->disableOutput(); - $process->run(); - -.. caution:: - - You can not enable or disable the output while the process is running. - - If you disable the output, you cannot access ``getOutput``, - ``getIncrementalOutput``, ``getErrorOutput`` or ``getIncrementalErrorOutput``. - Moreover, you could not pass a callback to the ``start``, ``run`` or ``mustRun`` - methods or use ``setIdleTimeout``. - .. _`Symfony Issue#5759`: https://github.com/symfony/symfony/issues/5759 .. _`PHP Bug#39992`: https://bugs.php.net/bug.php?id=39992 .. _`exec`: https://en.wikipedia.org/wiki/Exec_(operating_system) diff --git a/components/property_access/introduction.rst b/components/property_access/introduction.rst index 041f7543b89..ae8e6a66e4f 100644 --- a/components/property_access/introduction.rst +++ b/components/property_access/introduction.rst @@ -8,6 +8,10 @@ The PropertyAccess Component The PropertyAccess component provides function to read and write from/to an object or array using a simple string notation. +.. versionadded:: 2.2 + The PropertyAccess component was introduced in Symfony 2.2. Previously, + the ``PropertyPath`` class was located in the Form component. + Installation ------------ @@ -31,6 +35,10 @@ default configuration:: $accessor = PropertyAccess::createPropertyAccessor(); +.. versionadded:: 2.3 + The :method:`Symfony\\Component\\PropertyAccess\\PropertyAccess::createPropertyAccessor` + method was introduced in Symfony 2.3. Previously, it was called ``getPropertyAccessor()``. + Reading from Arrays ------------------- @@ -173,8 +181,6 @@ The ``getValue`` method can also use the magic ``__get`` method:: var_dump($accessor->getValue($person, 'Wouter')); // array(...) -.. _components-property-access-magic-call: - Magic ``__call()`` Method ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -211,6 +217,9 @@ enable this feature by using :class:`Symfony\\Component\\PropertyAccess\\Propert var_dump($accessor->getValue($person, 'wouter')); // array(...) +.. versionadded:: 2.3 + The use of magic ``__call()`` method was introduced in Symfony 2.3. + .. caution:: The ``__call`` feature is disabled by default, you can enable it by calling @@ -306,32 +315,6 @@ see `Enable other Features`_. var_dump($person->getWouter()); // array(...) -Checking Property Paths ------------------------ - -When you want to check whether -:method:`PropertyAccessor::getValue` -can safely be called without actually calling that method, you can use -:method:`PropertyAccessor::isReadable` -instead:: - - $person = new Person(); - - if ($accessor->isReadable($person, 'firstName')) { - // ... - } - -The same is possible for :method:`PropertyAccessor::setValue`: -Call the -:method:`PropertyAccessor::isWritable` -method to find out whether a property path can be updated:: - - $person = new Person(); - - if ($accessor->isWritable($person, 'firstName')) { - // ... - } - Mixing Objects and Arrays ------------------------- diff --git a/components/routing/hostname_pattern.rst b/components/routing/hostname_pattern.rst index 4c49199fcaa..0b2f5392be6 100644 --- a/components/routing/hostname_pattern.rst +++ b/components/routing/hostname_pattern.rst @@ -4,6 +4,9 @@ How to Match a Route Based on the Host ====================================== +.. versionadded:: 2.2 + Host matching support was introduced in Symfony 2.2 + You can also match on the HTTP *host* of the incoming request. .. configuration-block:: diff --git a/components/routing/introduction.rst b/components/routing/introduction.rst index 350585e0547..409ed76b19a 100644 --- a/components/routing/introduction.rst +++ b/components/routing/introduction.rst @@ -98,6 +98,9 @@ A full route definition can contain up to seven parts: #. An array of methods. These enforce a certain HTTP request method (``HEAD``, ``GET``, ``POST``, ...). +.. versionadded:: 2.2 + Host matching support was introduced in Symfony 2.2 + Take the following route, which combines several of these ideas:: $route = new Route( @@ -167,6 +170,7 @@ host to all routes of a subtree using methods provided by the $rootCollection->addCollection($subCollection); + Set the Request Parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/components/security/authentication.rst b/components/security/authentication.rst index 06fdc8faaeb..6532c4ed74e 100644 --- a/components/security/authentication.rst +++ b/components/security/authentication.rst @@ -4,17 +4,21 @@ Authentication ============== +.. versionadded:: 2.6 + The ``TokenStorageInterface`` was introduced in Symfony 2.6. Prior, you + had to use the ``getToken()`` method of the + :class:`Symfony\\Component\\Security\\Core\\SecurityContextInterface`. + When a request points to a secured area, and one of the listeners from the firewall map is able to extract the user's credentials from the current :class:`Symfony\\Component\\HttpFoundation\\Request` object, it should create a token, containing these credentials. The next thing the listener should do is ask the authentication manager to validate the given token, and return an *authenticated* token if the supplied credentials were found to be valid. -The listener should then store the authenticated token using -:class:`the token storage `:: +The listener should then store the authenticated token in the security context:: use Symfony\Component\Security\Http\Firewall\ListenerInterface; - use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; + use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; @@ -22,9 +26,9 @@ The listener should then store the authenticated token using class SomeAuthenticationListener implements ListenerInterface { /** - * @var TokenStorageInterface + * @var SecurityContextInterface */ - private $tokenStorage; + private $securityContext; /** * @var AuthenticationManagerInterface @@ -55,7 +59,7 @@ The listener should then store the authenticated token using ->authenticationManager ->authenticate($unauthenticatedToken); - $this->tokenStorage->setToken($authenticatedToken); + $this->securityContext->setToken($authenticatedToken); } } diff --git a/components/security/authorization.rst b/components/security/authorization.rst index 5f5287bd64c..5db01d6ef7a 100644 --- a/components/security/authorization.rst +++ b/components/security/authorization.rst @@ -7,8 +7,8 @@ Authorization When any of the authentication providers (see :ref:`authentication_providers`) has verified the still-unauthenticated token, an authenticated token will be returned. The authentication listener should set this token directly -in the :class:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorageInterface` -using its :method:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorageInterface::setToken` +in the :class:`Symfony\\Component\\Security\\Core\\SecurityContextInterface` +using its :method:`Symfony\\Component\\Security\\Core\\SecurityContextInterface::setToken` method. From then on, the user is authenticated, i.e. identified. Now, other parts @@ -29,6 +29,11 @@ An authorization decision will always be based on a few things: Any object for which access control needs to be checked, like an article or a comment object. +.. versionadded:: 2.6 + The ``TokenStorageInterface`` was introduced in Symfony 2.6. Prior, you + had to use the ``setToken()`` method of the + :class:`Symfony\\Component\\Security\\Core\\SecurityContextInterface`. + .. _components-security-access-decision-manager: Access Decision Manager @@ -85,6 +90,13 @@ of :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterf which means they have to implement a few methods which allows the decision manager to use them: +``supportsAttribute($attribute)`` + will be used to check if the voter knows how to handle the given attribute; + +``supportsClass($class)`` + will be used to check if the voter is able to grant or deny access for + an object of the given class; + ``vote(TokenInterface $token, $object, array $attributes)`` this method will do the actual voting and return a value equal to one of the class constants of :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface`, @@ -220,25 +232,24 @@ are required for the current user to get access to the application:: $authenticationManager ); -Authorization Checker -~~~~~~~~~~~~~~~~~~~~~ +Security Context +~~~~~~~~~~~~~~~~ The access decision manager is also available to other parts of the application -via the :method:`Symfony\\Component\\Security\\Core\\Authorization\\AuthorizationChecker::isGranted` -method of the :class:`Symfony\\Component\\Security\\Core\\Authorization\\AuthorizationChecker`. +via the :method:`Symfony\\Component\\Security\\Core\\SecurityContext::isGranted` +method of the :class:`Symfony\\Component\\Security\\Core\\SecurityContext`. A call to this method will directly delegate the question to the access decision manager:: - use Symfony\Component\Security\Core\Authorization\AuthorizationChecker; + use Symfony\Component\Security\SecurityContext; use Symfony\Component\Security\Core\Exception\AccessDeniedException; - $authorizationChecker = new AuthorizationChecker( - $tokenStorage, + $securityContext = new SecurityContext( $authenticationManager, $accessDecisionManager ); - if (!$authorizationChecker->isGranted('ROLE_ADMIN')) { + if (!$securityContext->isGranted('ROLE_ADMIN')) { throw new AccessDeniedException(); } diff --git a/components/security/firewall.rst b/components/security/firewall.rst index c3fe82f4c49..e67d59212de 100644 --- a/components/security/firewall.rst +++ b/components/security/firewall.rst @@ -1,39 +1,40 @@ .. index:: single: Security, Firewall -The Firewall and Authorization -============================== +The Firewall and Security Context +================================= -Central to the Security component is authorization. This is handled by an instance -of :class:`Symfony\\Component\\Security\\Core\\Authorization\\AuthorizationCheckerInterface`. -When all steps in the process of authenticating the user have been taken successfully, -you can ask the authorization checker if the authenticated user has access to a +Central to the Security component is the security context, which is an instance +of :class:`Symfony\\Component\\Security\\Core\\SecurityContextInterface`. When all +steps in the process of authenticating the user have been taken successfully, +you can ask the security context if the authenticated user has access to a certain action or resource of the application:: - use Symfony\Component\Security\Core\Authorization\AuthorizationChecker; + use Symfony\Component\Security\Core\SecurityContext; use Symfony\Component\Security\Core\Exception\AccessDeniedException; - // instance of Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface - $tokenStorage = ...; - // instance of Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface $authenticationManager = ...; // instance of Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface $accessDecisionManager = ...; - $authorizationChecker = new AuthorizationChecker( - $tokenStorage, + $securityContext = new SecurityContext( $authenticationManager, $accessDecisionManager ); // ... authenticate the user - if (!$authorizationChecker->isGranted('ROLE_ADMIN')) { + if (!$securityContext->isGranted('ROLE_ADMIN')) { throw new AccessDeniedException(); } +.. versionadded:: 2.6 + As of Symfony 2.6, the :class:`Symfony\\Component\\Security\\Core\\SecurityContext` class was split + in the :class:`Symfony\\Component\\Security\\Core\\Authorization\\AuthorizationChecker` and + :class:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorage` classes. + .. note:: Read the dedicated sections to learn more about :doc:`/components/security/authentication` @@ -119,7 +120,7 @@ which will eventually result in an "HTTP/1.1 403: Access Denied" response. Entry Points ~~~~~~~~~~~~ -When the user is not authenticated at all (i.e. when the token storage +When the user is not authenticated at all (i.e. when the security context has no token yet), the firewall's entry point will be called to "start" the authentication process. An entry point should implement :class:`Symfony\\Component\\Security\\Http\\EntryPoint\\AuthenticationEntryPointInterface`, diff --git a/components/security/introduction.rst b/components/security/introduction.rst index 57957f6516a..96ac494470b 100644 --- a/components/security/introduction.rst +++ b/components/security/introduction.rst @@ -21,23 +21,6 @@ You can install the component in 2 different ways: .. include:: /components/require_autoload.rst.inc -The Security component is divided into four smaller sub-components which can be -used separately: - -``symfony/security-core`` - It provides all the common security features, from authentication to - authorization and from encoding passwords to loading users. - -``symfony/security-http`` - It integrates the core sub-component with the HTTP protocol to handle HTTP - requests and responses. - -``symfony/security-csrf`` - It provides protection against `CSRF attacks`_. - -``symfony/security-acl`` - It provides a fine grained permissions mechanism based on Access Control Lists. - Sections -------- @@ -47,4 +30,3 @@ Sections * :doc:`/components/security/secure_tools` .. _Packagist: https://packagist.org/packages/symfony/security -.. _`CSRF attacks`: https://en.wikipedia.org/wiki/Cross-site_request_forgery diff --git a/components/security/secure_tools.rst b/components/security/secure_tools.rst index 16a2c5256f8..a7060c26597 100644 --- a/components/security/secure_tools.rst +++ b/components/security/secure_tools.rst @@ -1,5 +1,5 @@ -Securely Generating Random Values -================================= +Securely Comparing Strings and Generating Random Values +======================================================= The Symfony Security component comes with a collection of nice utilities related to security. These utilities are used by Symfony, but you should diff --git a/components/serializer.rst b/components/serializer.rst index be53706a54e..9daf8c4c26c 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -178,6 +178,10 @@ This is a common need when working with an ORM. Attributes Groups ----------------- +.. versionadded:: 2.7 + The support of serialization and deserialization groups was introduced + in Symfony 2.7. + Sometimes, you want to serialize different sets of attributes from your entities. Groups are a handy way to achieve this need. @@ -316,6 +320,14 @@ Ignoring Attributes Using attribute groups instead of the :method:`Symfony\\Component\\Serializer\\Normalizer\\AbstractNormalizer::setIgnoredAttributes` method is considered best practice. +.. versionadded:: 2.3 + The :method:`Symfony\\Component\\Serializer\\Normalizer\\AbstractNormalizer::setIgnoredAttributes` + method was introduced in Symfony 2.3. + +.. versionadded:: 2.7 + Prior to Symfony 2.7, attributes were only ignored while serializing. Since Symfony + 2.7, they are ignored when deserializing too. + As an option, there's a way to ignore attributes from the origin object. To remove those attributes use the :method:`Symfony\\Component\\Serializer\\Normalizer\\AbstractNormalizer::setIgnoredAttributes` @@ -332,11 +344,13 @@ method on the normalizer definition:: $serializer = new Serializer(array($normalizer), array($encoder)); $serializer->serialize($person, 'json'); // Output: {"name":"foo","sportsman":false} -.. _component-serializer-converting-property-names-when-serializing-and-deserializing: - Converting Property Names when Serializing and Deserializing ------------------------------------------------------------ +.. versionadded:: 2.7 + The :class:`Symfony\\Component\\Serializer\\NameConverter\\NameConverterInterface` + interface was introduced in Symfony 2.7. + Sometimes serialized attributes must be named differently than properties or getter/setter methods of PHP classes. @@ -402,6 +416,10 @@ and :class:`Symfony\\Component\\Serializer\\Normalizer\\PropertyNormalizer`:: CamelCase to snake_case ~~~~~~~~~~~~~~~~~~~~~~~ +.. versionadded:: 2.7 + The :class:`Symfony\\Component\\Serializer\\NameConverter\\CamelCaseToSnakeCaseNameConverter` + interface was introduced in Symfony 2.7. + In many formats, it's common to use underscores to separate words (also known as snake_case). However, PSR-1 specifies that the preferred style for PHP properties and methods is CamelCase. @@ -511,9 +529,21 @@ There are several types of normalizers available: Objects are normalized to a map of property names to property values. +.. versionadded:: 2.6 + The :class:`Symfony\\Component\\Serializer\\Normalizer\\PropertyNormalizer` + class was introduced in Symfony 2.6. + +.. versionadded:: 2.7 + The :class:`Symfony\\Component\\Serializer\\Normalizer\\ObjectNormalizer` + class was introduced in Symfony 2.7. + Handling Circular References ---------------------------- +.. versionadded:: 2.6 + Handling of circular references was introduced in Symfony 2.6. In previous + versions of Symfony, circular references led to infinite loops. + Circular references are common when dealing with entity relations:: class Organization @@ -602,50 +632,6 @@ having unique identifiers:: var_dump($serializer->serialize($org, 'json')); // {"name":"Les-Tilleuls.coop","members":[{"name":"K\u00e9vin", organization: "Les-Tilleuls.coop"}]} -Handling Arrays ---------------- - -The Serializer component is capable of handling arrays of objects as well. -Serializing arrays works just like serializing a single object:: - - use Acme\Person; - - $person1 = new Person(); - $person1->setName('foo'); - $person1->setAge(99); - $person1->setSportsman(false); - - $person2 = new Person(); - $person2->setName('bar'); - $person2->setAge(33); - $person2->setSportsman(true); - - $persons = array($person1, $person2); - $data = $serializer->serialize($persons, 'json'); - - // $data contains [{"name":"foo","age":99,"sportsman":false},{"name":"bar","age":33,"sportsman":true}] - -If you want to deserialize such a structure, you need to add the -:class:`Symfony\\Component\\Serializer\\Normalizer\\ArrayDenormalizer` -to the set of normalizers. By appending ``[]`` to the type parameter of the -:method:`Symfony\\Component\\Serializer\\Serializer::deserialize` method, -you indicate that you're expecting an array instead of a single object. - -.. code-block:: php - - use Symfony\Component\Serializer\Encoder\JsonEncoder; - use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; - use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer; - use Symfony\Component\Serializer\Serializer; - - $serializer = new Serializer( - array(new GetSetMethodNormalizer(), new ArrayDenormalizer()), - array(new JsonEncoder()) - ); - - $data = ...; // The serialized data from the previous example - $persons = $serializer->deserialize($data, 'Acme\Person[]', 'json'); - .. seealso:: A popular alternative to the Symfony Serializer Component is the third-party diff --git a/components/stopwatch.rst b/components/stopwatch.rst index d2791f5bbb5..49b0876a6a5 100644 --- a/components/stopwatch.rst +++ b/components/stopwatch.rst @@ -7,6 +7,11 @@ The Stopwatch Component The Stopwatch component provides a way to profile code. +.. versionadded:: 2.2 + The Stopwatch component was introduced in Symfony 2.2. Previously, the + ``Stopwatch`` class was located in the HttpKernel component (and was introduced + in Symfony 2.1). + Installation ------------ @@ -34,12 +39,9 @@ microtime by yourself. Instead, use the simple $event = $stopwatch->stop('eventName'); The :class:`Symfony\\Component\\Stopwatch\\StopwatchEvent` object can be retrieved -from the :method:`Symfony\\Component\\Stopwatch\\Stopwatch::start`, -:method:`Symfony\\Component\\Stopwatch\\Stopwatch::stop`, -:method:`Symfony\\Component\\Stopwatch\\Stopwatch::lap` and -:method:`Symfony\\Component\\Stopwatch\\Stopwatch::getEvent` methods. -The latter should be used when you need to retrieve the duration of an event -while it is still running. +from the :method:`Symfony\\Component\\Stopwatch\\Stopwatch::start`, +:method:`Symfony\\Component\\Stopwatch\\Stopwatch::stop` and +:method:`Symfony\\Component\\Stopwatch\\Stopwatch::lap` methods. You can also provide a category name to an event:: diff --git a/components/templating/helpers/assetshelper.rst b/components/templating/helpers/assetshelper.rst index 837b94255bc..d369214f8b2 100644 --- a/components/templating/helpers/assetshelper.rst +++ b/components/templating/helpers/assetshelper.rst @@ -47,20 +47,6 @@ You can also specify a URL to use in the second parameter of the constructor:: Now URLs are rendered like ``http://cdn.example.com/images/logo.png``. -You can also use the third argument of the helper to force an absolute URL: - -.. code-block:: html+php - - - - -.. note:: - - If you already set a URL in the constructor, using the third argument of - ``getUrl`` will not affect the generated URL. - Versioning ---------- @@ -77,16 +63,6 @@ is used in :phpfunction:`sprintf`. The first argument is the path and the second is the version. For instance, ``%s?v=%s`` will be rendered as ``/images/logo.png?v=328rad75``. -You can also generate a versioned URL on an asset-by-asset basis using the -fourth argument of the helper: - -.. code-block:: html+php - - - - Multiple Packages ----------------- diff --git a/components/translation/custom_formats.rst b/components/translation/custom_formats.rst index d5d9ddcd446..14c6e65c8b0 100644 --- a/components/translation/custom_formats.rst +++ b/components/translation/custom_formats.rst @@ -85,7 +85,7 @@ will save a few lines:: class MyFormatDumper extends FileDumper { - public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = array()) + protected function format(MessageCatalogue $messages, $domain = 'messages') { $output = ''; @@ -102,14 +102,7 @@ will save a few lines:: } } -.. sidebar:: Format a message catalogue - - In some cases, you want to send the dump contents as a response instead of - writing them in files. To do this, you can use the ``formatCatalogue`` - method. In this case, you must pass the domain argument, which determines - the list of messages that should be dumped. - -The :method:`Symfony\\Component\\Translation\\Dumper\\FileDumper::formatCatalogue` +The :method:`Symfony\\Component\\Translation\\Dumper\\FileDumper::format` method creates the output string, that will be used by the :method:`Symfony\\Component\\Translation\\Dumper\\FileDumper::dump` method of the FileDumper class to create the file. The dumper can be used like any other @@ -123,3 +116,4 @@ YAML file are dumped into a text file with the custom format:: $dumper = new MyFormatDumper(); $dumper->dump($catalogue, array('path' => __DIR__.'/dumps')); + diff --git a/components/translation/introduction.rst b/components/translation/introduction.rst index 228597182b6..035d904be30 100644 --- a/components/translation/introduction.rst +++ b/components/translation/introduction.rst @@ -64,8 +64,7 @@ The Translation component uses Loader classes to load catalogs. You can load multiple resources for the same locale, which will then be combined into one catalog. -The component comes with some default Loaders and you can create your own -Loader too. The default loaders are: +The component comes with some default loaders: * :class:`Symfony\\Component\\Translation\\Loader\\ArrayLoader` - to load catalogs from PHP arrays. @@ -87,11 +86,14 @@ Loader too. The default loaders are: catalogs from QT XML files. * :class:`Symfony\\Component\\Translation\\Loader\\XliffFileLoader` - to load catalogs from Xliff files. -* :class:`Symfony\\Component\\Translation\\Loader\\JsonFileLoader` - to load - catalogs from JSON files. * :class:`Symfony\\Component\\Translation\\Loader\\YamlFileLoader` - to load catalogs from Yaml files (requires the :doc:`Yaml component`). +.. versionadded:: 2.1 + The ``IcuDatFileLoader``, ``IcuResFileLoader``, ``IniFileLoader``, + ``MoFileLoader``, ``PoFileLoader`` and ``QtFileLoader`` were introduced + in Symfony 2.1. + All file loaders require the :doc:`Config component `. You can also :doc:`create your own Loader `, diff --git a/components/translation/usage.rst b/components/translation/usage.rst index 00887e5bb12..dae457f2f2a 100644 --- a/components/translation/usage.rst +++ b/components/translation/usage.rst @@ -378,11 +378,7 @@ In case you want to use the same translation catalogue outside your application (e.g. use translation on the client side), it's possible to fetch raw translation messages. Just specify the required locale:: - $catalogue = $translator->getCatalogue('fr_FR'); - $messages = $catalogue->all(); - while ($catalogue = $catalogue->getFallbackCatalogue()) { - $messages = array_replace_recursive($catalogue->all(), $messages); - } + $messages = $translator->getMessages('fr_FR'); The ``$messages`` variable will have the following structure:: diff --git a/components/var_dumper/advanced.rst b/components/var_dumper/advanced.rst deleted file mode 100644 index ccc0308cad7..00000000000 --- a/components/var_dumper/advanced.rst +++ /dev/null @@ -1,242 +0,0 @@ -.. index:: - single: VarDumper - single: Components; VarDumper - -Advanced Usage of the VarDumper Component -========================================= - -The ``dump()`` function is just a thin wrapper and a more convenient way to call -:method:`VarDumper::dump() `. -You can change the behavior of this function by calling -:method:`VarDumper::setHandler($callable) `. -Calls to ``dump()`` will then be forwarded to ``$callable``. - -By adding a handler, you can customize the `Cloners`_, `Dumpers`_ and `Casters`_ -as explained below. A simple implementation of a handler function might look -like this:: - - use Symfony\Component\VarDumper\VarDumper; - use Symfony\Component\VarDumper\Cloner\VarCloner; - use Symfony\Component\VarDumper\Dumper\CliDumper; - use Symfony\Component\VarDumper\Dumper\HtmlDumper; - - VarDumper::setHandler(function ($var) { - $cloner = new VarCloner(); - $dumper = 'cli' === PHP_SAPI ? new CliDumper() : new HtmlDumper(); - - $dumper->dump($cloner->cloneVar($var)); - }); - -Cloners -------- - -A cloner is used to create an intermediate representation of any PHP variable. -Its output is a :class:`Symfony\\Component\\VarDumper\\Cloner\\Data` -object that wraps this representation. - -You can create a :class:`Symfony\\Component\\VarDumper\\Cloner\\Data` -object this way:: - - use Symfony\Component\VarDumper\Cloner\VarCloner; - - $cloner = new VarCloner(); - $data = $cloner->cloneVar($myVar); - // this is commonly then passed to the dumper - // see the example at the top of this page - // $dumper->dump($data); - -A cloner also applies limits when creating the representation, so that the -corresponding Data object could represent only a subset of the cloned variable. -Before calling :method:`Symfony\\Component\\VarDumper\\Cloner\\VarCloner::cloneVar`, -you can configure these limits: - -:method:`Symfony\\Component\\VarDumper\\Cloner\\VarCloner::setMaxItems` - configures the maximum number of items that will be cloned - *past the first nesting level*. Items are counted using a breadth-first - algorithm so that lower level items have higher priority than deeply nested - items; - -:method:`Symfony\\Component\\VarDumper\\Cloner\\VarCloner::setMaxString` - configures the maximum number of characters that will be cloned before - cutting overlong strings; - -In both cases, specifying ``-1`` removes any limit. - -Before dumping it, you can further limit the resulting -:class:`Symfony\\Component\\VarDumper\\Cloner\\Data` object using the following methods: - -:method:`Symfony\\Component\\VarDumper\\Cloner\\Data::withMaxDepth` - Allows limiting dumps in the depth dimension. - -:method:`Symfony\\Component\\VarDumper\\Cloner\\Data::withMaxItemsPerDepth` - Limits the number of items per depth level. - -:method:`Symfony\\Component\\VarDumper\\Cloner\\Data::withRefHandles` - Allows removing internal objects' handles for sparser output (useful for tests). - -Unlike the previous limits on cloners that remove data on purpose, these can -be changed back and forth before dumping since they do not affect the -intermediate representation internally. - -.. note:: - - When no limit is applied, a :class:`Symfony\\Component\\VarDumper\\Cloner\\Data` - object is as accurate as the native :phpfunction:`serialize` function, - and thus could be for purposes beyond dumping for debugging. - -Dumpers -------- - -A dumper is responsible for outputting a string representation of a PHP variable, -using a :class:`Symfony\\Component\\VarDumper\\Cloner\\Data` object as input. -The destination and the formatting of this output vary with dumpers. - -This component comes with an :class:`Symfony\\Component\\VarDumper\\Dumper\\HtmlDumper` -for HTML output and a :class:`Symfony\\Component\\VarDumper\\Dumper\\CliDumper` -for optionally colored command line output. - -For example, if you want to dump some ``$variable``, just do:: - - use Symfony\Component\VarDumper\Cloner\VarCloner; - use Symfony\Component\VarDumper\Dumper\CliDumper; - - $cloner = new VarCloner(); - $dumper = new CliDumper(); - - $dumper->dump($cloner->cloneVar($variable)); - -By using the first argument of the constructor, you can select the output -stream where the dump will be written. By default, the ``CliDumper`` writes -on ``php://stdout`` and the ``HtmlDumper`` on ``php://output``. But any PHP -stream (resource or URL) is acceptable. - -Instead of a stream destination, you can also pass it a ``callable`` that -will be called repeatedly for each line generated by a dumper. This -callable can be configured using the first argument of a dumper's constructor, -but also using the -:method:`Symfony\\Component\\VarDumper\\Dumper\\AbstractDumper::setOutput` -method or the second argument of the -:method:`Symfony\\Component\\VarDumper\\Dumper\\AbstractDumper::dump` method. - -For example, to get a dump as a string in a variable, you can do:: - - use Symfony\Component\VarDumper\Cloner\VarCloner; - use Symfony\Component\VarDumper\Dumper\CliDumper; - - $cloner = new VarCloner(); - $dumper = new CliDumper(); - $output = ''; - - $dumper->dump( - $cloner->cloneVar($variable), - function ($line, $depth) use (&$output) { - // A negative depth means "end of dump" - if ($depth >= 0) { - // Adds a two spaces indentation to the line - $output .= str_repeat(' ', $depth).$line."\n"; - } - } - ); - - // $output is now populated with the dump representation of $variable - -Another option for doing the same could be:: - - use Symfony\Component\VarDumper\Cloner\VarCloner; - use Symfony\Component\VarDumper\Dumper\CliDumper; - - $cloner = new VarCloner(); - $dumper = new CliDumper(); - $output = fopen('php://memory', 'r+b'); - - $dumper->dump($cloner->cloneVar($variable), $output); - $output = stream_get_contents($output, -1, 0); - - // $output is now populated with the dump representation of $variable - -Dumpers implement the :class:`Symfony\\Component\\VarDumper\\Dumper\\DataDumperInterface` -interface that specifies the -:method:`dump(Data $data) ` -method. They also typically implement the -:class:`Symfony\\Component\\VarDumper\\Cloner\\DumperInterface` that frees -them from re-implementing the logic required to walk through a -:class:`Symfony\\Component\\VarDumper\\Cloner\\Data` object's internal structure. - -Casters -------- - -Objects and resources nested in a PHP variable are "cast" to arrays in the -intermediate :class:`Symfony\\Component\\VarDumper\\Cloner\\Data` -representation. You can tweak the array representation for each object/resource -by hooking a Caster into this process. The component already includes many -casters for base PHP classes and other common classes. - -If you want to build your own Caster, you can register one before cloning -a PHP variable. Casters are registered using either a Cloner's constructor -or its ``addCasters()`` method:: - - use Symfony\Component\VarDumper\Cloner\VarCloner; - - $myCasters = array(...); - $cloner = new VarCloner($myCasters); - - // or - - $cloner->addCasters($myCasters); - -The provided ``$myCasters`` argument is an array that maps a class, -an interface or a resource type to a callable:: - - $myCasters = array( - 'FooClass' => $myFooClassCallableCaster, - ':bar resource' => $myBarResourceCallableCaster, - ); - -As you can notice, resource types are prefixed by a ``:`` to prevent -colliding with a class name. - -Because an object has one main class and potentially many parent classes -or interfaces, many casters can be applied to one object. In this case, -casters are called one after the other, starting from casters bound to the -interfaces, the parents classes and then the main class. Several casters -can also be registered for the same resource type/class/interface. -They are called in registration order. - -Casters are responsible for returning the properties of the object or resource -being cloned in an array. They are callables that accept four arguments: - -* the object or resource being casted, -* an array modelled for objects after PHP's native ``(array)`` cast operator, -* a :class:`Symfony\\Component\\VarDumper\\Cloner\\Stub` object - representing the main properties of the object (class, type, etc.), -* true/false when the caster is called nested in a structure or not. - -Here is a simple caster not doing anything:: - - function myCaster($object, $array, $stub, $isNested) - { - // ... populate/alter $array to your needs - - return $array; - } - -For objects, the ``$array`` parameter comes pre-populated using PHP's native -``(array)`` casting operator or with the return value of ``$object->__debugInfo()`` -if the magic method exists. Then, the return value of one Caster is given -as the array argument to the next Caster in the chain. - -When casting with the ``(array)`` operator, PHP prefixes protected properties -with a ``\0*\0`` and private ones with the class owning the property. For example, -``\0Foobar\0`` will be the prefix for all private properties of objects of -type Foobar. Casters follow this convention and add two more prefixes: ``\0~\0`` -is used for virtual properties and ``\0+\0`` for dynamic ones (runtime added -properties not in the class declaration). - -.. note:: - - Although you can, it is advised to not alter the state of an object - while casting it in a Caster. - -.. tip:: - - Before writing your own casters, you should check the existing ones. diff --git a/components/var_dumper/index.rst b/components/var_dumper/index.rst deleted file mode 100644 index 2c67f2aa53f..00000000000 --- a/components/var_dumper/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -VarDumper -========= - -.. toctree:: - :maxdepth: 2 - - introduction - advanced diff --git a/components/var_dumper/introduction.rst b/components/var_dumper/introduction.rst index 3d162b7d328..0e2b0adbf94 100644 --- a/components/var_dumper/introduction.rst +++ b/components/var_dumper/introduction.rst @@ -9,6 +9,9 @@ The VarDumper Component arbitrary PHP variable. Built on top, it provides a better ``dump()`` function that you can use instead of :phpfunction:`var_dump`. +.. versionadded:: 2.6 + The VarDumper component was introduced in Symfony 2.6. + Installation ------------ @@ -81,7 +84,7 @@ DebugBundle and Twig Integration The DebugBundle allows greater integration of the component into the Symfony full-stack framework. It is enabled by default in the *dev* and *test* -environment of the Symfony Standard Edition. +environment of the standard edition since version 2.6. Since generating (even debug) output in the controller or in the model of your application may just break it by e.g. sending HTTP headers or @@ -108,6 +111,10 @@ option. Read more about this and other options in Using the VarDumper Component in your PHPUnit Test Suite -------------------------------------------------------- +.. versionadded:: 2.7 + The :class:`Symfony\\Component\\VarDumper\\Test\\VarDumperTestTrait` was + introduced in Symfony 2.7. + The VarDumper component provides :class:`a trait ` that can help writing some of your tests for PHPUnit. @@ -143,6 +150,11 @@ Example:: } } +.. tip:: + + If you still use PHP 5.3, you can extend the + :class:`Symfony\\Component\\VarDumper\\Test\\VarDumperTestClass` instead. + Dump Examples and Output ------------------------ diff --git a/components/yaml/introduction.rst b/components/yaml/introduction.rst index c4104e01e40..adb0d0956e6 100644 --- a/components/yaml/introduction.rst +++ b/components/yaml/introduction.rst @@ -135,9 +135,16 @@ It may also be convenient to use the $yaml = Yaml::parse(file_get_contents('/path/to/file.yml')); -The :method:`Symfony\\Component\\Yaml\\Yaml::parse` static method takes a YAML string. -Internally, it constructs a :class:`Symfony\\Component\\Yaml\\Parser` object and calls -the :method:`Symfony\\Component\\Yaml\\Parser::parse` method. +The :method:`Symfony\\Component\\Yaml\\Yaml::parse` static method takes a YAML +string or a file containing YAML. Internally, it calls the +:method:`Symfony\\Component\\Yaml\\Parser::parse` method, but enhances the +error if something goes wrong by adding the filename to the message. + +.. caution:: + + Because it is currently possible to pass a filename to this method, you + must validate the input first. Passing a filename is deprecated in + Symfony 2.2, and will be removed in Symfony 3.0. .. _components-yaml-dump: diff --git a/contributing/code/core_team.rst b/contributing/code/core_team.rst index 02734296d90..8e0a34f781b 100644 --- a/contributing/code/core_team.rst +++ b/contributing/code/core_team.rst @@ -58,8 +58,8 @@ Active Core Members * **Christophe Coevoet** (`stof`_) can merge into all components, bridges and bundles; - * **Kévin Dunglas** (`dunglas`_) can merge into the Serializer_ - component; + * **Kévin Dunglas** (`dunglas`_) can merge into the PropertyInfo_, + Serializer_ component; * **Abdellatif AitBoudad** (`aitboudad`_) can merge into the Translation_ component; diff --git a/contributing/code/patches.rst b/contributing/code/patches.rst index 0bcf49c97d1..4e4bdcad996 100644 --- a/contributing/code/patches.rst +++ b/contributing/code/patches.rst @@ -14,14 +14,14 @@ Before working on Symfony, setup a friendly environment with the following software: * Git; -* PHP version 5.5.9 or above; +* PHP version 5.3.9 or above; * `PHPUnit`_ 4.2 or above. .. caution:: - Before Symfony 2.7, the minimal PHP version was 5.3.3. Before Symfony 3.0, - minimal version was 5.3.9. Please keep this in mind, if you are working on a - bug fix for earlier versions of Symfony. + Before Symfony 2.7, the minimal PHP version was 5.3.3. Please keep + this in mind, if you are working on a bug fix for earlier versions + of Symfony. Configure Git ~~~~~~~~~~~~~ diff --git a/contributing/code/security.rst b/contributing/code/security.rst index baa1baf711f..a468aa0da3b 100644 --- a/contributing/code/security.rst +++ b/contributing/code/security.rst @@ -38,8 +38,6 @@ confirmed, the core-team works on a solution following these steps: #. Publish the post on the official Symfony `blog`_ (it must also be added to the "`Security Advisories`_" category); #. Update the security advisory list (see below). -#. Update the public `security advisories database`_ maintained by the - FriendsOfPHP organization and which is used by the ``security:check`` command. .. note:: @@ -95,11 +93,6 @@ of the downstream projects included in this process: Security Advisories ------------------- -.. tip:: - - You can check your Symfony application for known security vulnerabilities - using the ``security:check`` command. See :ref:`book-security-checking-vulnerabilities`. - This section indexes security vulnerabilities that were fixed in Symfony releases, starting from Symfony 1.0.0: @@ -138,4 +131,3 @@ releases, starting from Symfony 1.0.0: .. _Git repository: https://github.com/symfony/symfony .. _blog: https://symfony.com/blog/ .. _Security Advisories: https://symfony.com/blog/category/security-advisories -.. _`security advisories database`: https://github.com/FriendsOfPHP/security-advisories diff --git a/contributing/documentation/standards.rst b/contributing/documentation/standards.rst index 052110e59df..16f5eed12c7 100644 --- a/contributing/documentation/standards.rst +++ b/contributing/documentation/standards.rst @@ -57,9 +57,6 @@ Code Examples Unless the example requires a custom bundle, make sure to always use the ``AppBundle`` bundle to store your code; * Use ``Acme`` when the code requires a vendor name; -* Use ``example.com`` as the domain of sample URLs and ``example.org`` and - ``example.net`` when additional domains are required. All of these domains are - `reserved by the IANA`_. * To avoid horizontal scrolling on code blocks, we prefer to break a line correctly if it crosses the 85th character; * When you fold one or more lines of code, place ``...`` in a comment at the point @@ -177,7 +174,6 @@ In addition, documentation follows these rules: .. _`the Sphinx documentation`: http://sphinx-doc.org/rest.html#source-code .. _`Twig Coding Standards`: http://twig.sensiolabs.org/doc/coding_standards.html -.. _`reserved by the IANA`: http://tools.ietf.org/html/rfc2606#section-3 .. _`American English`: https://en.wikipedia.org/wiki/American_English .. _`American English Oxford Dictionary`: http://www.oxforddictionaries.com/definition/american_english/ .. _`headings and titles`: https://en.wikipedia.org/wiki/Letter_case#Headings_and_publication_titles diff --git a/cookbook/assetic/_standard_edition_warning.inc b/cookbook/assetic/_standard_edition_warning.inc deleted file mode 100644 index bab5c7ce994..00000000000 --- a/cookbook/assetic/_standard_edition_warning.inc +++ /dev/null @@ -1,5 +0,0 @@ -.. caution:: - - Starting from Symfony 2.8, Assetic is no longer included by default in the - Symfony Standard Edition. Refer to :doc:`this article ` - to learn how to install and enable Assetic in your Symfony application. diff --git a/cookbook/assetic/apply_to_option.rst b/cookbook/assetic/apply_to_option.rst index 376420b464a..8f5776c7fe0 100644 --- a/cookbook/assetic/apply_to_option.rst +++ b/cookbook/assetic/apply_to_option.rst @@ -4,8 +4,6 @@ How to Apply an Assetic Filter to a specific File Extension =========================================================== -.. include:: /cookbook/assetic/_standard_edition_warning.inc - Assetic filters can be applied to individual files, groups of files or even, as you'll see here, files that have a specific extension. To show you how to handle each option, suppose that you want to use Assetic's CoffeeScript diff --git a/cookbook/assetic/asset_management.rst b/cookbook/assetic/asset_management.rst index f8c018bb0a1..9cd09d3f11c 100644 --- a/cookbook/assetic/asset_management.rst +++ b/cookbook/assetic/asset_management.rst @@ -4,89 +4,6 @@ How to Use Assetic for Asset Management ======================================= -Installing and Enabling Assetic -------------------------------- - -Starting from Symfony 2.8, Assetic is no longer included by default in the -Symfony Standard Edition. Before using any of its features, install the -AsseticBundle executing this console command in your project: - -.. code-block:: bash - - $ composer require symfony/assetic-bundle - -Then, enable the bundle in the ``AppKernel.php`` file of your Symfony application:: - - // app/AppKernel.php - - // ... - class AppKernel extends Kernel - { - // ... - - public function registerBundles() - { - $bundles = array( - // ... - new Symfony\Bundle\AsseticBundle\AsseticBundle(), - ); - - // ... - } - } - -Finally, add the following minimal configuration to enable Assetic support in -your application: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - assetic: - debug: '%kernel.debug%' - use_controller: '%kernel.debug%' - filters: - cssrewrite: ~ - - # ... - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - // app/config/config.php - $container->loadFromExtension('assetic', array( - 'debug' => '%kernel.debug%', - 'use_controller' => '%kernel.debug%', - 'filters' => array( - 'cssrewrite' => null, - ), - // ... - )); - - // ... - -Introducing Assetic -------------------- - Assetic combines two major ideas: :ref:`assets ` and :ref:`filters `. The assets are files such as CSS, JavaScript and image files. The filters are things that can be applied to @@ -555,7 +472,7 @@ done from the template and is relative to the public document root: Symfony also contains a method for cache *busting*, where the final URL generated by Assetic contains a query parameter that can be incremented via configuration on each deployment. For more information, see the - :ref:`reference-framework-assets-version` configuration option. + :ref:`ref-framework-assets-version` configuration option. .. _cookbook-assetic-dumping: @@ -598,7 +515,7 @@ each time you deploy), you should run the following command: .. code-block:: bash - $ php bin/console assetic:dump --env=prod --no-debug + $ php app/console assetic:dump --env=prod --no-debug This will physically generate and write each file that you need (e.g. ``/js/abcd123.js``). If you update any of your assets, you'll need to run this again to regenerate @@ -650,7 +567,7 @@ need to dump them manually. To do so, run the following command: .. code-block:: bash - $ php bin/console assetic:dump + $ php app/console assetic:dump This physically writes all of the asset files you need for your ``dev`` environment. The big disadvantage is that you need to run this each time @@ -659,7 +576,7 @@ assets will be regenerated automatically *as they change*: .. code-block:: bash - $ php bin/console assetic:watch + $ php app/console assetic:watch The ``assetic:watch`` command was introduced in AsseticBundle 2.4. In prior versions, you had to use the ``--watch`` option of the ``assetic:dump`` diff --git a/cookbook/assetic/index.rst b/cookbook/assetic/index.rst index 7389c510d5c..c37efdc16ee 100644 --- a/cookbook/assetic/index.rst +++ b/cookbook/assetic/index.rst @@ -1,8 +1,6 @@ Assetic ======= -.. include:: /cookbook/assetic/_standard_edition_warning.inc - .. toctree:: :maxdepth: 2 diff --git a/cookbook/assetic/jpeg_optimize.rst b/cookbook/assetic/jpeg_optimize.rst index 49c3362c875..8d94266ae8e 100644 --- a/cookbook/assetic/jpeg_optimize.rst +++ b/cookbook/assetic/jpeg_optimize.rst @@ -4,8 +4,6 @@ How to Use Assetic for Image Optimization with Twig Functions ============================================================= -.. include:: /cookbook/assetic/_standard_edition_warning.inc - Among its many filters, Assetic has four filters which can be used for on-the-fly image optimization. This allows you to get the benefits of smaller file sizes without having to use an image editor to process each image. The results diff --git a/cookbook/assetic/php.rst b/cookbook/assetic/php.rst index 14176e1d84c..df07bbbc172 100644 --- a/cookbook/assetic/php.rst +++ b/cookbook/assetic/php.rst @@ -4,8 +4,6 @@ Combining, Compiling and Minimizing Web Assets with PHP Libraries ================================================================= -.. include:: /cookbook/assetic/_standard_edition_warning.inc - The official Symfony Best Practices recommend to use Assetic to :doc:`manage web assets `, unless you are comfortable with JavaScript-based front-end tools. @@ -33,8 +31,10 @@ directory and execute the following commands: .. code-block:: bash $ composer require leafo/scssphp - $ composer require patchwork/jsqueeze + $ composer require patchwork/jsqueeze:"~1.0" +It's very important to maintain the ``~1.0`` version constraint for the ``jsqueeze`` +dependency because the most recent stable version is not compatible with Assetic. Organizing your Web Asset Files ------------------------------- diff --git a/cookbook/assetic/uglifyjs.rst b/cookbook/assetic/uglifyjs.rst index 08f7e05fb6a..9e2b4735ae5 100644 --- a/cookbook/assetic/uglifyjs.rst +++ b/cookbook/assetic/uglifyjs.rst @@ -4,8 +4,6 @@ How to Minify CSS/JS Files (Using UglifyJS and UglifyCSS) ========================================================= -.. include:: /cookbook/assetic/_standard_edition_warning.inc - `UglifyJS`_ is a JavaScript parser/compressor/beautifier toolkit. It can be used to combine and minify JavaScript assets so that they require less HTTP requests and make your site load faster. `UglifyCSS`_ is a CSS compressor/beautifier diff --git a/cookbook/assetic/yuicompressor.rst b/cookbook/assetic/yuicompressor.rst index f2700034a04..8602215a0c0 100644 --- a/cookbook/assetic/yuicompressor.rst +++ b/cookbook/assetic/yuicompressor.rst @@ -10,8 +10,6 @@ How to Minify JavaScripts and Stylesheets with YUI Compressor **strongly advised to avoid using YUI utilities** unless strictly necessary. Read :doc:`/cookbook/assetic/uglifyjs` for a modern and up-to-date alternative. -.. include:: /cookbook/assetic/_standard_edition_warning.inc - Yahoo! provides an excellent utility for minifying JavaScripts and stylesheets so they travel over the wire faster, the `YUI Compressor`_. Thanks to Assetic, you can take advantage of this tool very easily. diff --git a/cookbook/bundles/best_practices.rst b/cookbook/bundles/best_practices.rst index 7f214270c14..266ee3b7066 100644 --- a/cookbook/bundles/best_practices.rst +++ b/cookbook/bundles/best_practices.rst @@ -413,6 +413,55 @@ The ``composer.json`` file should include at least the following metadata: In order to make it easier for developers to find your bundle, register it on `Packagist`_, the official repository for Composer packages. +Custom Validation Constraints +----------------------------- + +Starting with Symfony 2.5, a new Validation API was introduced. In fact, +there are 3 modes, which the user can configure in their project: + +* 2.4: the original 2.4 and earlier validation API; +* 2.5: the new 2.5 and later validation API; +* 2.5-BC: the new 2.5 API with a backwards-compatible layer so that the + 2.4 API still works. This is only available in PHP 5.3.9+. + +.. note:: + + Starting with Symfony 2.7, the support for the 2.4 API has been + dropped and the minimal PHP version required for Symfony was + increased to 5.3.9. If your bundles requires Symfony >=2.7, you + don't need to take care about the 2.4 API anymore. + +As a bundle author, you'll want to support *both* API's, since some users +may still be using the 2.4 API. Specifically, if your bundle adds a violation +directly to the :class:`Symfony\\Component\\Validator\\Context\\ExecutionContext` +(e.g. like in a custom validation constraint), you'll need to check for which +API is being used. The following code, would work for *all* users:: + + use Symfony\Component\Validator\ConstraintValidator; + use Symfony\Component\Validator\Constraint; + use Symfony\Component\Validator\Context\ExecutionContextInterface; + // ... + + class ContainsAlphanumericValidator extends ConstraintValidator + { + public function validate($value, Constraint $constraint) + { + if ($this->context instanceof ExecutionContextInterface) { + // the 2.5 API + $this->context->buildViolation($constraint->message) + ->setParameter('%string%', $value) + ->addViolation() + ; + } else { + // the 2.4 API + $this->context->addViolation( + $constraint->message, + array('%string%' => $value) + ); + } + } + } + Learn more from the Cookbook ---------------------------- diff --git a/cookbook/bundles/installation.rst b/cookbook/bundles/installation.rst index addd935980f..013ed4e4305 100644 --- a/cookbook/bundles/installation.rst +++ b/cookbook/bundles/installation.rst @@ -108,14 +108,14 @@ via the ``config:dump-reference`` command: .. code-block:: bash - $ bin/console config:dump-reference AsseticBundle + $ app/console config:dump-reference AsseticBundle Instead of the full bundle name, you can also pass the short name used as the root of the bundle's configuration: .. code-block:: bash - $ bin/console config:dump-reference assetic + $ app/console config:dump-reference assetic The output will look like this: diff --git a/cookbook/bundles/override.rst b/cookbook/bundles/override.rst index 775c62828ca..db60e778bba 100644 --- a/cookbook/bundles/override.rst +++ b/cookbook/bundles/override.rst @@ -105,16 +105,17 @@ associations. Learn more about this feature and its limitations in Forms ----- -Form types are referred to by their fully-qualified class name:: +In order to override a form type, it has to be registered as a service (meaning +it is tagged as ``form.type``). You can then override it as you would override any +service as explained in `Services & Configuration`_. This, of course, will only +work if the type is referred to by its alias rather than being instantiated, +e.g.:: - $builder->add('name', CustomType::class); + $builder->add('name', 'custom_type'); -This means that you cannot override this by creating a sub-class of ``CustomType`` -and registering it as a service and tagging it with ``form.type`` (you *could* -do this in earlier version). +rather than:: -Instead, you should use a "form type extension" to modify the existing form type. -For more information, see :doc:`/cookbook/form/create_form_type_extension`. + $builder->add('name', new CustomType()); .. _override-validation: diff --git a/cookbook/bundles/remove.rst b/cookbook/bundles/remove.rst index 9956704cdd2..3b9c3a28985 100644 --- a/cookbook/bundles/remove.rst +++ b/cookbook/bundles/remove.rst @@ -79,8 +79,7 @@ can remove the ``Acme`` directory as well. :method:`Symfony\\Component\\HttpKernel\\Bundle\\BundleInterface::getPath` method to get the path of the bundle:: - dump($this->container->get('kernel')->getBundle('AcmeDemoBundle')->getPath()); - die(); + var_dump($this->container->get('kernel')->getBundle('AcmeDemoBundle')->getPath()); 3.1 Remove Bundle Assets ~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/cookbook/configuration/apache_router.rst b/cookbook/configuration/apache_router.rst index 69c7ec14307..a8b4f8a7c33 100644 --- a/cookbook/configuration/apache_router.rst +++ b/cookbook/configuration/apache_router.rst @@ -19,7 +19,139 @@ handle routes directly, rather than using Symfony for this task. .. caution:: - Apache router was deprecated in Symfony 2.5 and removed in Symfony 3.0. - Since the PHP implementation of the Router was improved, performance gains - were no longer significant (while it's very hard to replicate the same - behavior). + Apache router was deprecated in Symfony 2.5 and will be removed in Symfony + 3.0. Since the PHP implementation of the Router was improved, performance + gains were no longer significant (while it's very hard to replicate the + same behavior). + +Change Router Configuration Parameters +-------------------------------------- + +To dump Apache routes you must first tweak some configuration parameters to tell +Symfony to use the ``ApacheUrlMatcher`` instead of the default one: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config_prod.yml + parameters: + router.options.matcher.cache_class: ~ # disable router cache + router.options.matcher_class: Symfony\Component\Routing\Matcher\ApacheUrlMatcher + + .. code-block:: xml + + + + null + + Symfony\Component\Routing\Matcher\ApacheUrlMatcher + + + + .. code-block:: php + + // app/config/config_prod.php + $container->setParameter('router.options.matcher.cache_class', null); // disable router cache + $container->setParameter( + 'router.options.matcher_class', + 'Symfony\Component\Routing\Matcher\ApacheUrlMatcher' + ); + +.. tip:: + + Note that :class:`Symfony\\Component\\Routing\\Matcher\\ApacheUrlMatcher` + extends :class:`Symfony\\Component\\Routing\\Matcher\\UrlMatcher` so even + if you don't regenerate the mod_rewrite rules, everything will work (because + at the end of ``ApacheUrlMatcher::match()`` a call to ``parent::match()`` + is done). + +Generating mod_rewrite Rules +---------------------------- + +To test that it's working, create a very basic route for the AppBundle: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/routing.yml + hello: + path: /hello/{name} + defaults: { _controller: AppBundle:Greet:hello } + + .. code-block:: xml + + + + AppBundle:Greet:hello + + + .. code-block:: php + + // app/config/routing.php + $collection->add('hello', new Route('/hello/{name}', array( + '_controller' => 'AppBundle:Greet:hello', + ))); + +Now generate the mod_rewrite rules: + +.. code-block:: bash + + $ php app/console router:dump-apache -e=prod --no-debug + +Which should roughly output the following: + +.. code-block:: apache + + # skip "real" requests + RewriteCond %{REQUEST_FILENAME} -f + RewriteRule .* - [QSA,L] + + # hello + RewriteCond %{REQUEST_URI} ^/hello/([^/]+?)$ + RewriteRule .* app.php [QSA,L,E=_ROUTING__route:hello,E=_ROUTING_name:%1,E=_ROUTING__controller:AppBundle\:Greet\:hello] + +You can now rewrite ``web/.htaccess`` to use the new rules, so with this example +it should look like this: + +.. code-block:: apache + + + RewriteEngine On + + # skip "real" requests + RewriteCond %{REQUEST_FILENAME} -f + RewriteRule .* - [QSA,L] + + # hello + RewriteCond %{REQUEST_URI} ^/hello/([^/]+?)$ + RewriteRule .* app.php [QSA,L,E=_ROUTING__route:hello,E=_ROUTING_name:%1,E=_ROUTING__controller:AppBundle\:Greet\:hello] + + +.. note:: + + The procedure above should be done each time you add/change a route if you + want to take full advantage of this setup. + +That's it! +You're now all set to use Apache routes. + +Additional Tweaks +----------------- + +To save some processing time, change occurrences of ``Request`` +to ``ApacheRequest`` in ``web/app.php``:: + + // web/app.php + + require_once __DIR__.'/../app/bootstrap.php.cache'; + require_once __DIR__.'/../app/AppKernel.php'; + // require_once __DIR__.'/../app/AppCache.php'; + + use Symfony\Component\HttpFoundation\ApacheRequest; + + $kernel = new AppKernel('prod', false); + $kernel->loadClassCache(); + // $kernel = new AppCache($kernel); + $kernel->handle(ApacheRequest::createFromGlobals())->send(); diff --git a/cookbook/configuration/configuration_organization.rst b/cookbook/configuration/configuration_organization.rst index d3a1fc85b2f..5473a4c06b1 100644 --- a/cookbook/configuration/configuration_organization.rst +++ b/cookbook/configuration/configuration_organization.rst @@ -34,9 +34,8 @@ default Symfony Standard Edition follow this structure: .. code-block:: text - your-project/ + / ├─ app/ - │ ├─ ... │ └─ config/ │ ├─ config.yml │ ├─ config_dev.yml @@ -47,7 +46,9 @@ default Symfony Standard Edition follow this structure: │ ├─ routing.yml │ ├─ routing_dev.yml │ └─ security.yml - ├─ ... + ├─ src/ + ├─ vendor/ + └─ web/ This default structure was chosen for its simplicity — one file per environment. But as any other Symfony feature, you can customize it to better suit your needs. @@ -64,9 +65,8 @@ name as the environment: .. code-block:: text - your-project/ + / ├─ app/ - │ ├─ ... │ └─ config/ │ ├─ common/ │ │ ├─ config.yml @@ -83,7 +83,9 @@ name as the environment: │ ├─ parameters.yml │ ├─ routing.yml │ └─ security.yml - ├─ ... + ├─ src/ + ├─ vendor/ + └─ web/ To make this work, change the code of the :method:`Symfony\\Component\\HttpKernel\\KernelInterface::registerContainerConfiguration` @@ -159,9 +161,8 @@ and several files to define all application services: .. code-block:: text - your-project/ + / ├─ app/ - │ ├─ ... │ └─ config/ │ ├─ bundles/ │ │ ├─ bundle1.yml @@ -181,7 +182,9 @@ and several files to define all application services: │ ├─ backend.yml │ ├─ ... │ └─ security.yml - ├─ ... + ├─ src/ + ├─ vendor/ + └─ web/ Again, change the code of the ``registerContainerConfiguration()`` method to make Symfony aware of the new file organization:: diff --git a/cookbook/configuration/environments.rst b/cookbook/configuration/environments.rst index a175e7397ea..57526912886 100644 --- a/cookbook/configuration/environments.rst +++ b/cookbook/configuration/environments.rst @@ -173,10 +173,10 @@ this code and changing the environment string. specifies if the application should run in "debug mode". Regardless of the environment, a Symfony application can be run with debug mode set to ``true`` or ``false``. This affects many things in the application, - such as displaying stacktraces on error pages or if cache files are + such as if 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. + 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 `. @@ -207,6 +207,10 @@ this code and changing the environment string. // ... )); + 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`. + Selecting the Environment for Console Commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -217,13 +221,13 @@ behavior: .. code-block:: bash # 'dev' environment and debug enabled - $ php bin/console command_name + $ php app/console command_name # 'prod' environment (debug is always disabled for 'prod') - $ php bin/console command_name --env=prod + $ php app/console command_name --env=prod # 'test' environment and debug disabled - $ php bin/console command_name --env=test --no-debug + $ php app/console command_name --env=test --no-debug In addition to the ``--env`` and ``--debug`` options, the behavior of Symfony commands can also be controlled with environment variables. The Symfony console @@ -338,13 +342,13 @@ Symfony takes advantage of caching in many ways: the application configuration, routing configuration, Twig templates and more are cached to PHP objects stored in files on the filesystem. -By default, these cached files are largely stored in the ``var/cache`` directory. +By default, these cached files are largely stored in the ``app/cache`` directory. However, each environment caches its own set of files: .. code-block:: text - your-project/ - ├─ var/ + / + ├─ app/ │ ├─ cache/ │ │ ├─ dev/ # cache directory for the *dev* environment │ │ └─ prod/ # cache directory for the *prod* environment @@ -353,7 +357,7 @@ However, each environment caches its own set of files: Sometimes, when debugging, it may be helpful to inspect a cached file to understand how something is working. When doing so, remember to look in the directory of the environment you're using (most commonly ``dev`` while -developing and debugging). While it can vary, the ``var/cache/dev`` directory +developing and debugging). While it can vary, the ``app/cache/dev`` directory includes the following: ``appDevDebugProjectContainer.php`` diff --git a/cookbook/configuration/front_controllers_and_kernel.rst b/cookbook/configuration/front_controllers_and_kernel.rst index 9bfe3be4e46..7e4fc4d1fd9 100644 --- a/cookbook/configuration/front_controllers_and_kernel.rst +++ b/cookbook/configuration/front_controllers_and_kernel.rst @@ -45,8 +45,8 @@ 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 `; -* Enabling (or skipping) the :doc:`ClassCache `; -* Enabling the :doc:`Debug Component `. +* Enabling (or skipping) the :doc:`ClassCache ` +* Enabling the :doc:`Debug component `. The front controller can be chosen by requesting URLs like: @@ -75,7 +75,7 @@ as the default one. access. For example, you don't want to make a debugging environment available to arbitrary users in your production environment. -Technically, the `bin/console`_ script used when running Symfony on the command +Technically, the `app/console`_ script used when running Symfony on the command line is also a front controller, only that is not used for web, but for command line requests. @@ -162,7 +162,7 @@ way of loading your configuration. .. _Symfony Standard Edition: https://github.com/symfony/symfony-standard .. _app.php: https://github.com/symfony/symfony-standard/blob/master/web/app.php .. _app_dev.php: https://github.com/symfony/symfony-standard/blob/master/web/app_dev.php -.. _bin/console: https://github.com/symfony/symfony-standard/blob/master/bin/console +.. _app/console: https://github.com/symfony/symfony-standard/blob/master/app/console .. _AppKernel: https://github.com/symfony/symfony-standard/blob/master/app/AppKernel.php .. _decorate: https://en.wikipedia.org/wiki/Decorator_pattern .. _RewriteRule shipped with the Symfony Standard Edition: https://github.com/symfony/symfony-standard/blob/master/web/.htaccess diff --git a/cookbook/configuration/index.rst b/cookbook/configuration/index.rst index 741fe5be4e4..11838c6fa38 100644 --- a/cookbook/configuration/index.rst +++ b/cookbook/configuration/index.rst @@ -5,7 +5,6 @@ Configuration :maxdepth: 2 environments - micro-kernel-trait override_dir_structure using_parameters_in_dic front_controllers_and_kernel diff --git a/cookbook/configuration/micro-kernel-trait.rst b/cookbook/configuration/micro-kernel-trait.rst deleted file mode 100644 index 65da709719f..00000000000 --- a/cookbook/configuration/micro-kernel-trait.rst +++ /dev/null @@ -1,321 +0,0 @@ -Building your own Framework with the MicroKernelTrait -===================================================== - -A :ref:`traditional Symfony app ` contains a sensible -directory structure, various configuration files and an ``AppKernel`` with several -bundles already-registered. This is a fully-featured app that's ready to go. - -But did you know, you can create a fully-functional Symfony application in as little -as one file? This is possible thanks to the new -:class:`Symfony\\Bundle\\FrameworkBundle\\Kernel\\MicroKernelTrait`. This allows -you to start with a tiny application, and then add features and structure as you -need to. - -A Single-File Symfony Application ---------------------------------- - -Start with a completely empty directory. Get ``symfony/symfony`` as a dependency -via Composer: - -.. code-block:: bash - - $ composer require symfony/symfony - -Next, create an ``index.php`` file that creates a kernel class and executes it:: - - use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; - use Symfony\Component\Config\Loader\LoaderInterface; - use Symfony\Component\DependencyInjection\ContainerBuilder; - use Symfony\Component\HttpFoundation\JsonResponse; - use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\HttpKernel\Kernel; - use Symfony\Component\Routing\RouteCollectionBuilder; - - // require Composer's autoloader - require __DIR__.'/vendor/autoload.php'; - - class AppKernel extends Kernel - { - use MicroKernelTrait; - - public function registerBundles() - { - return array( - new Symfony\Bundle\FrameworkBundle\FrameworkBundle() - ); - } - - protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader) - { - // PHP equivalent of config.yml - $c->loadFromExtension('framework', array( - 'secret' => 'S0ME_SECRET' - )); - } - - protected function configureRoutes(RouteCollectionBuilder $routes) - { - // kernel is a service that points to this class - // optional 3rd argument is the route name - $routes->add('/random/{limit}', 'kernel:randomAction'); - } - - public function randomAction($limit) - { - return new JsonResponse(array( - 'number' => rand(0, $limit) - )); - } - } - - $kernel = new AppKernel('dev', true); - $request = Request::createFromGlobals(); - $response = $kernel->handle($request); - $response->send(); - $kernel->terminate($request, $response); - -That's it! To test it, you can start the built-in web server: - -.. code-block:: bash - - $ php -S localhost:8000 - -Then see the JSON response in your browser: - -> http://localhost:8000/random/10 - -The Methods of a "Micro" Kernel -------------------------------- - -When you use the ``MicroKernelTrait``, your kernel needs to have exactly three methods -that define your bundles, your services and your routes: - -**registerBundles()** - This is the same ``registerBundles()`` that you see in a normal kernel. - -**configureContainer(ContainerBuilder $c, LoaderInterface $loader)** - This methods builds and configures the container. In practice, you will use - ``loadFromExtension`` to configure different bundles (this is the equivalent - of what you see in a normal ``config.yml`` file). You can also register services - directly in PHP or load external configuration files (shown below). - -**configureRoutes(RouteCollectionBuilder $routes)** - Your job in this method is to add routes to the application. The - ``RouteCollectionBuilder`` has methods that make adding routes in PHP more - fun. You can also load external routing files (shown below). - - -Advanced Example: Twig, Annotations and the Web Debug Toolbar -------------------------------------------------------------- - -The purpose of the ``MicroKernelTrait`` is *not* to have a single-file application. -Instead, its goal to give you the power to choose your bundles and structure. - -First, you'll probably want to put your PHP classes in an ``src/`` directory. Configure -your ``composer.json`` file to load from there: - -.. code-block:: json - - { - "require": { - "...": "..." - }, - "autoload": { - "psr-4": { - "": "src/" - } - } - } - -Now, suppose you want to use Twig and load routes via annotations. For annotation -routing, you need SensioFrameworkExtraBundle. This comes with a normal Symfony project. -But in this case, you need to download it: - -.. code-block:: bash - - $ composer require sensio/framework-extra-bundle - -Instead of putting *everything* in ``index.php``, create a new ``app/AppKernel.php`` -to hold the kernel. Now it looks like this:: - - // app/AppKernel.php - - use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; - use Symfony\Component\Config\Loader\LoaderInterface; - use Symfony\Component\DependencyInjection\ContainerBuilder; - use Symfony\Component\HttpKernel\Kernel; - use Symfony\Component\Routing\RouteCollectionBuilder; - use Doctrine\Common\Annotations\AnnotationRegistry; - - // require Composer's autoloader - $loader = require __DIR__.'/../vendor/autoload.php'; - // auto-load annotations - AnnotationRegistry::registerLoader(array($loader, 'loadClass')); - - class AppKernel extends Kernel - { - use MicroKernelTrait; - - public function registerBundles() - { - $bundles = array( - new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), - new Symfony\Bundle\TwigBundle\TwigBundle(), - new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle() - ); - - if ($this->getEnvironment() == 'dev') { - $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); - } - - return $bundles; - } - - protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader) - { - $loader->load(__DIR__.'/config/config.yml'); - - // configure WebProfilerBundle only if the bundle is enabled - if (isset($this->bundles['WebProfilerBundle'])) { - $c->loadFromExtension('web_profiler', array( - 'toolbar' => true, - 'intercept_redirects' => false, - )); - } - } - - protected function configureRoutes(RouteCollectionBuilder $routes) - { - // import the WebProfilerRoutes, only if the bundle is enabled - if (isset($this->bundles['WebProfilerBundle'])) { - $routes->mount('/_wdt', $routes->import('@WebProfilerBundle/Resources/config/routing/wdt.xml')); - $routes->mount('/_profiler', $routes->import('@WebProfilerBundle/Resources/config/routing/profiler.xml')); - } - - // load the annotation routes - $routes->mount( - '/', - $routes->import(__DIR__.'/../src/App/Controller/', 'annotation') - ); - } - } - -Unlike the previous kernel, this loads an external ``app/config/config.yml`` file, -because the configuration started to get bigger: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - framework: - secret: S0ME_SECRET - templating: - engines: ['twig'] - profiler: { only_exceptions: false } - - .. code-block:: xml - - - - - - - - twig - - - - - - .. code-block:: php - - // app/config/config.php - $container->loadFromExtension('framework', array( - 'secret' => 'S0ME_SECRET', - 'templating' => array( - 'engines' => array('twig'), - ), - 'profiler' => array( - 'only_exceptions' => false, - ), - )); - -This also loads annotation routes from an ``src/App/Controller/`` directory, which -has one file in it:: - - // src/App/Controller/MicroController.php - namespace App\Controller; - - use Symfony\Bundle\FrameworkBundle\Controller\Controller; - use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; - - class MicroController extends Controller - { - /** - * @Route("/random/{limit}") - */ - public function randomAction($limit) - { - $number = rand(0, $limit); - - return $this->render('micro/random.html.twig', array( - 'number' => $number - )); - } - } - -Template files should live in the ``Resources/views`` directory of whatever directory -your *kernel* lives in. Since ``AppKernel`` lives in ``app/``, this template lives -at ``app/Resources/views/micro/random.html.twig``. - -Finally, you need a front controller to boot and run the application. Create a -``web/index.php``:: - - // web/index.php - - use Symfony\Component\HttpFoundation\Request; - - require __DIR__.'/../app/AppKernel.php'; - - $kernel = new AppKernel('dev', true); - $request = Request::createFromGlobals(); - $response = $kernel->handle($request); - $response->send(); - $kernel->terminate($request, $response); - -That's it! This ``/random/10`` URL will work, Twig will render, and you'll even -get the web debug toolbar to show up at the bottom. The final structure looks like -this: - -.. code-block:: text - - your-project/ - ├─ app/ - | ├─ AppKernel.php - │ ├─ cache/ - │ ├─ config/ - │ ├─ logs/ - │ └─ Resources - | └─ views - | ├─ base.html.twig - | └─ micro - | └─ random.html.twig - ├─ src/ - │ └─ App - | └─ Controller - | └─ MicroController.php - ├─ vendor/ - │ └─ ... - ├─ web/ - | └─ index.php - ├─ composer.json - └─ composer.lock - -Hey, that looks a lot like a *traditional* Symfony application! You're right: the -``MicroKernelTrait`` *is* still Symfony: but you can control your structure and -features quite easily. diff --git a/cookbook/configuration/override_dir_structure.rst b/cookbook/configuration/override_dir_structure.rst index cb9d73286a5..6bcdcd46dd4 100644 --- a/cookbook/configuration/override_dir_structure.rst +++ b/cookbook/configuration/override_dir_structure.rst @@ -12,18 +12,12 @@ directory structure is: your-project/ ├─ app/ + │ ├─ cache/ │ ├─ config/ - │ └─ ... - ├─ bin/ + │ ├─ logs/ │ └─ ... ├─ src/ │ └─ ... - ├─ tests/ - │ └─ ... - ├─ var/ - │ ├─ cache/ - │ ├─ logs/ - │ └─ ... ├─ vendor/ │ └─ ... └─ web/ @@ -47,13 +41,13 @@ in the ``AppKernel`` class of your application:: public function getCacheDir() { - return dirname(__DIR__).'/var/'.$this->environment.'/cache'; + return $this->rootDir.'/'.$this->environment.'/cache'; } } -In this code, ``$this->environment`` is the current environment (i.e. ``dev``). -In this case you have changed the location of the cache directory to -``var/{environment}/cache``. +``$this->rootDir`` is the absolute path to the ``app`` directory and ``$this->environment`` +is the current environment (i.e. ``dev``). In this case you have changed +the location of the cache directory to ``app/{environment}/cache``. .. caution:: @@ -80,11 +74,11 @@ method:: public function getLogDir() { - return dirname(__DIR__).'/var/'.$this->environment.'/logs'; + return $this->rootDir.'/'.$this->environment.'/logs'; } } -Here you have changed the location of the directory to ``var/{environment}/logs``. +Here you have changed the location of the directory to ``app/{environment}/logs``. .. _override-web-dir: @@ -92,22 +86,23 @@ Override the ``web`` Directory ------------------------------ If you need to rename or move your ``web`` directory, the only thing you -need to guarantee is that the path to the ``var`` directory is still correct +need to guarantee is that the path to the ``app`` directory is still correct in your ``app.php`` and ``app_dev.php`` front controllers. If you simply renamed the directory, you're fine. But if you moved it in some way, you may need to modify these paths inside those files:: - require_once __DIR__.'/../path/to/app/autoload.php'; + require_once __DIR__.'/../Symfony/app/bootstrap.php.cache'; + require_once __DIR__.'/../Symfony/app/AppKernel.php'; -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 +.. code-block:: javascript { - "...": "...", + ... "extra": { - "...": "...", + ... "symfony-web-dir": "my_new_web_dir" } } @@ -168,8 +163,8 @@ You also need to change the ``extra.symfony-web-dir`` option in the .. code-block:: bash - $ php bin/console cache:clear --env=prod - $ php bin/console assetic:dump --env=prod --no-debug + $ php app/console cache:clear --env=prod + $ php app/console assetic:dump --env=prod --no-debug Override the ``vendor`` Directory --------------------------------- @@ -191,7 +186,6 @@ The change in the ``composer.json`` will look like this: Then, update the path to the ``autoload.php`` file in ``app/autoload.php``:: // app/autoload.php - // ... $loader = require '/some/dir/vendor/autoload.php'; diff --git a/cookbook/console/command_in_controller.rst b/cookbook/console/command_in_controller.rst index 1b4081c4e3d..6ba7c6807ad 100644 --- a/cookbook/console/command_in_controller.rst +++ b/cookbook/console/command_in_controller.rst @@ -30,7 +30,7 @@ Run this command from inside your controller via:: use Symfony\Bundle\FrameworkBundle\Console\Application; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\Console\Input\ArrayInput; - use Symfony\Component\Console\Output\BufferedOutput; + use Symfony\Component\Console\Output\StreamOutput; use Symfony\Component\HttpFoundation\Response; class SpoolController extends Controller @@ -46,12 +46,14 @@ Run this command from inside your controller via:: '--message-limit' => $messages, )); // You can use NullOutput() if you don't need the output - $output = new BufferedOutput(); + $output = new StreamOutput(tmpfile(), StreamOutput::VERBOSITY_NORMAL); $application->run($input, $output); // return the output, don't use if you used NullOutput() - $content = $output->fetch(); - + rewind($output->getStream()); + $content = stream_get_contents($output->getStream()); + fclose($output->getStream()); + // return new Response(""), if you used NullOutput() return new Response($content); } @@ -60,7 +62,7 @@ Run this command from inside your controller via:: Showing Colorized Command Output -------------------------------- -By telling the ``BufferedOutput`` it is decorated via the second parameter, +By telling the ``StreamOutput`` it is decorated via the third parameter, it will return the Ansi color-coded content. The `SensioLabs AnsiToHtml converter`_ can be used to convert this to colorful HTML. @@ -76,8 +78,8 @@ Now, use it in your controller:: namespace AppBundle\Controller; use SensioLabs\AnsiConverter\AnsiToHtmlConverter; - use Symfony\Component\Console\Output\BufferedOutput; use Symfony\Component\Console\Output\OutputInterface; + use Symfony\Component\Console\Output\StreamOutput; use Symfony\Component\HttpFoundation\Response; // ... @@ -86,15 +88,14 @@ Now, use it in your controller:: public function sendSpoolAction($messages = 10) { // ... - $output = new BufferedOutput( - OutputInterface::VERBOSITY_NORMAL, - true // true for decorated - ); + $output = new StreamOutput(tmpfile(), StreamOutput::VERBOSITY_NORMAL, true); // ... // return the output $converter = new AnsiToHtmlConverter(); - $content = $output->fetch(); + rewind($output->getStream()); + $content = stream_get_contents($output->getStream()); + fclose($output->getStream()); return new Response($converter->convert($content)); } diff --git a/cookbook/console/commands_as_services.rst b/cookbook/console/commands_as_services.rst deleted file mode 100644 index 1485fde9a4d..00000000000 --- a/cookbook/console/commands_as_services.rst +++ /dev/null @@ -1,184 +0,0 @@ -.. index:: - single: Console; Commands as Services - -How to Define Commands as Services -================================== - -By default, Symfony will take a look in the ``Command`` directory of each -bundle and automatically register your commands. If a command extends the -:class:`Symfony\\Bundle\\FrameworkBundle\\Command\\ContainerAwareCommand`, -Symfony will even inject the container. -While making life easier, this has some limitations: - -* Your command must live in the ``Command`` directory; -* There's no way to conditionally register your service based on the environment - or availability of some dependencies; -* You can't access the container in the ``configure()`` method (because - ``setContainer`` hasn't been called yet); -* You can't use the same class to create many commands (i.e. each with - different configuration). - -To solve these problems, you can register your command as a service and tag it -with ``console.command``: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - services: - app.command.my_command: - class: AppBundle\Command\MyCommand - tags: - - { name: console.command } - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - // app/config/config.php - $container - ->register( - 'app.command.my_command', - 'AppBundle\Command\MyCommand' - ) - ->addTag('console.command') - ; - -Using Dependencies and Parameters to Set Default Values for Options -------------------------------------------------------------------- - -Imagine you want to provide a default value for the ``name`` option. You could -pass one of the following as the 5th argument of ``addOption()``: - -* a hardcoded string; -* a container parameter (e.g. something from ``parameters.yml``); -* a value computed by a service (e.g. a repository). - -By extending ``ContainerAwareCommand``, only the first is possible, because you -can't access the container inside the ``configure()`` method. Instead, inject -any parameter or service you need into the constructor. For example, suppose you -store the default value in some ``%command.default_name%`` parameter:: - - // src/AppBundle/Command/GreetCommand.php - namespace AppBundle\Command; - - use Symfony\Component\Console\Command\Command; - use Symfony\Component\Console\Input\InputInterface; - use Symfony\Component\Console\Input\InputOption; - use Symfony\Component\Console\Output\OutputInterface; - - class GreetCommand extends Command - { - protected $defaultName; - - public function __construct($defaultName) - { - $this->defaultName = $defaultName; - - parent::__construct(); - } - - protected function configure() - { - // try to avoid work here (e.g. database query) - // this method is *always* called - see warning below - $defaultName = $this->defaultName; - - $this - ->setName('demo:greet') - ->setDescription('Greet someone') - ->addOption( - 'name', - '-n', - InputOption::VALUE_REQUIRED, - 'Who do you want to greet?', - $defaultName - ) - ; - } - - protected function execute(InputInterface $input, OutputInterface $output) - { - $name = $input->getOption('name'); - - $output->writeln($name); - } - } - -Now, just update the arguments of your service configuration like normal to -inject the ``command.default_name`` parameter: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - parameters: - command.default_name: Javier - - services: - app.command.my_command: - class: AppBundle\Command\MyCommand - arguments: ["%command.default_name%"] - tags: - - { name: console.command } - - .. code-block:: xml - - - - - - - Javier - - - - - %command.default_name% - - - - - - .. code-block:: php - - // app/config/config.php - $container->setParameter('command.default_name', 'Javier'); - - $container - ->register( - 'app.command.my_command', - 'AppBundle\Command\MyCommand', - ) - ->setArguments(array('%command.default_name%')) - ->addTag('console.command') - ; - -Great, you now have a dynamic default value! - -.. caution:: - - Be careful not to actually do any work in ``configure`` (e.g. make database - queries), as your code will be run, even if you're using the console to - execute a different command. diff --git a/cookbook/console/console_command.rst b/cookbook/console/console_command.rst index 8c88efb3622..7b4940623f0 100644 --- a/cookbook/console/console_command.rst +++ b/cookbook/console/console_command.rst @@ -68,7 +68,7 @@ This command will now automatically be available to run: .. code-block:: bash - $ php bin/console demo:greet Fabien + $ php app/console demo:greet Fabien .. _cookbook-console-dic: diff --git a/cookbook/console/index.rst b/cookbook/console/index.rst index 76a3014f5e3..77c289f7035 100644 --- a/cookbook/console/index.rst +++ b/cookbook/console/index.rst @@ -6,8 +6,6 @@ Console console_command usage - style command_in_controller request_context logging - commands_as_services diff --git a/cookbook/console/logging.rst b/cookbook/console/logging.rst index cd78c8a732c..90b7eb64f06 100644 --- a/cookbook/console/logging.rst +++ b/cookbook/console/logging.rst @@ -65,7 +65,7 @@ container and use it to do the logging:: } Depending on the environment in which you run your command (and your logging -setup), you should see the logged entries in ``var/logs/dev.log`` or ``var/logs/prod.log``. +setup), you should see the logged entries in ``app/logs/dev.log`` or ``app/logs/prod.log``. Enabling automatic Exceptions Logging ------------------------------------- @@ -73,6 +73,9 @@ Enabling automatic Exceptions Logging To get your console application to automatically log uncaught exceptions for all of your commands, you can use :doc:`console events`. +.. versionadded:: 2.3 + Console events were introduced in Symfony 2.3. + First configure a listener for console exception events in the service container: .. configuration-block:: diff --git a/cookbook/console/request_context.rst b/cookbook/console/request_context.rst index ff90b182ede..a10d8b2df3c 100644 --- a/cookbook/console/request_context.rst +++ b/cookbook/console/request_context.rst @@ -16,13 +16,16 @@ what URL it should use when generating URLs. There are two ways of configuring the request context: at the application level and per Command. -Configuring the Request Context Globally +Configuring the Request Context globally ---------------------------------------- +.. versionadded:: 2.2 + The ``base_url`` parameter was introduced in Symfony 2.2. + To configure the Request Context - which is used by the URL Generator - you can redefine the parameters it uses as default values to change the default host -(localhost) and scheme (http). You can also configure the base path if Symfony -is not running in the root directory. +(localhost) and scheme (http). Starting with Symfony 2.2 you can also configure +the base path if Symfony is not running in the root directory. Note that this does not impact URLs generated via normal web requests, since those will override the defaults. diff --git a/cookbook/console/style.rst b/cookbook/console/style.rst index f2a1d6b6ce7..97ac2886de9 100644 --- a/cookbook/console/style.rst +++ b/cookbook/console/style.rst @@ -4,6 +4,9 @@ How to Style a Console Command ============================== +.. versionadded:: 2.7 + Symfony Styles for console commands were introduced in Symfony 2.7. + One of the most boring tasks when creating console commands is to deal with the styling of the command's input and output. Displaying titles and tables or asking questions to the user involves a lot of repetitive code. diff --git a/cookbook/console/usage.rst b/cookbook/console/usage.rst index 8bdd134913e..6275f760aa0 100644 --- a/cookbook/console/usage.rst +++ b/cookbook/console/usage.rst @@ -17,13 +17,13 @@ clear and warm the ``prod`` cache you need to run: .. code-block:: bash - $ php bin/console cache:clear --env=prod + $ php app/console cache:clear --env=prod or the equivalent: .. code-block:: bash - $ php bin/console cache:clear -e prod + $ php app/console cache:clear -e prod In addition to changing the environment, you can also choose to disable debug mode. This can be useful where you want to run commands in the ``dev`` environment @@ -31,4 +31,35 @@ but avoid the performance hit of collecting debug data: .. code-block:: bash - $ php bin/console list --no-debug + $ php app/console list --no-debug + +There is an interactive shell which allows you to enter commands without having to +specify ``php app/console`` each time, which is useful if you need to run several +commands. To enter the shell run: + +.. code-block:: bash + + $ php app/console --shell + $ php app/console -s + +You can now just run commands with the command name: + +.. code-block:: bash + + Symfony > list + +When using the shell you can choose to run each command in a separate process: + +.. code-block:: bash + + $ php app/console --shell --process-isolation + $ php app/console -s --process-isolation + +When you do this, the output will not be colorized and interactivity is not +supported so you will need to pass all command parameters explicitly. + +.. note:: + + Unless you are using isolated processes, clearing the cache in the shell + will not have an effect on subsequent commands you run. This is because + the original cached files are still being used. diff --git a/cookbook/controller/error_pages.rst b/cookbook/controller/error_pages.rst index 193b64c417a..5ae2fdcfbe5 100644 --- a/cookbook/controller/error_pages.rst +++ b/cookbook/controller/error_pages.rst @@ -96,7 +96,7 @@ To override the 404 error template for HTML pages, create a new

    Page not found

    {# example security usage, see below #} - {% if is_granted('IS_AUTHENTICATED_FULLY') %} + {% if app.user and is_granted('IS_AUTHENTICATED_FULLY') %} {# ... #} {% endif %} @@ -124,6 +124,24 @@ store the HTTP status code and message respectively. for the standard HTML exception page or ``exception.json.twig`` for the JSON exception page. +Avoiding Exceptions when Using Security Functions in Error Templates +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +One of the common pitfalls when designing custom error pages is to use the +``is_granted()`` function in the error template (or in any parent template +inherited by the error template). If you do that, you'll see an exception thrown +by Symfony. + +The cause of this problem is that routing is done before security. If a 404 error +occurs, the security layer isn't loaded and thus, the ``is_granted()`` function +is undefined. The solution is to add the following check before using this function: + +.. code-block:: twig + + {% if app.user and is_granted('...') %} + {# ... #} + {% endif %} + .. _testing-error-pages: Testing Error Pages during Development @@ -136,6 +154,10 @@ what it looks like and debug it? Fortunately, the default ``ExceptionController`` allows you to preview your *error* pages during development. +.. versionadded:: 2.6 + This feature was introduced in Symfony 2.6. Before, the third-party + `WebfactoryExceptionsBundle`_ could be used for the same purpose. + To use this feature, you need to have a definition in your ``routing_dev.yml`` file like so: diff --git a/cookbook/controller/service.rst b/cookbook/controller/service.rst index 44ee81ab9f6..05c812df270 100644 --- a/cookbook/controller/service.rst +++ b/cookbook/controller/service.rst @@ -127,6 +127,9 @@ the route ``_controller`` value: If your controller implements the ``__invoke()`` method, you can simply refer to the service id (``app.hello_controller``). + .. versionadded:: 2.6 + Support for ``__invoke()`` was introduced in Symfony 2.6. + Alternatives to base Controller Methods --------------------------------------- diff --git a/cookbook/controller/upload_file.rst b/cookbook/controller/upload_file.rst index 74bc77d8503..065b4bbaf0a 100644 --- a/cookbook/controller/upload_file.rst +++ b/cookbook/controller/upload_file.rst @@ -57,7 +57,6 @@ Then, add a new ``brochure`` field to the form that manages the ``Product`` enti use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; - use Symfony\Component\Form\Extension\Core\Type\FileType; class ProductType extends AbstractType { @@ -65,7 +64,7 @@ Then, add a new ``brochure`` field to the form that manages the ``Product`` enti { $builder // ... - ->add('brochure', FileType::class, array('label' => 'Brochure (PDF file)')) + ->add('brochure', 'file', array('label' => 'Brochure (PDF file)')) // ... ; } @@ -76,6 +75,11 @@ Then, add a new ``brochure`` field to the form that manages the ``Product`` enti 'data_class' => 'AppBundle\Entity\Product', )); } + + public function getName() + { + return 'product'; + } } Now, update the template that renders the form to display the new ``brochure`` @@ -112,7 +116,7 @@ Finally, you need to update the code of the controller that handles the form:: public function newAction(Request $request) { $product = new Product(); - $form = $this->createForm(ProductType::class, $product); + $form = $this->createForm(new ProductType(), $product); $form->handleRequest($request); if ($form->isValid()) { diff --git a/cookbook/debugging.rst b/cookbook/debugging.rst index d56c36f3656..98fae25bad8 100644 --- a/cookbook/debugging.rst +++ b/cookbook/debugging.rst @@ -21,32 +21,31 @@ Disabling the Bootstrap File and Class Caching And to make the production environment as fast as possible, Symfony creates big PHP files in your cache containing the aggregation of PHP classes your -project needs for every request. However, this behavior can confuse your debugger, -because the same class can be located in two different places: the original class -file and the big file which aggregates lots of classes. - -This recipe shows you how you can tweak this caching mechanism to make it friendlier -when you need to debug code that involves Symfony classes. +project needs for every request. However, this behavior can confuse your IDE +or your debugger. This recipe shows you how you can tweak this caching +mechanism to make it friendlier when you need to debug code that involves +Symfony classes. The ``app_dev.php`` front controller reads as follows by default:: // ... - $loader = require __DIR__.'/../app/autoload.php'; - Debug::enable(); + $loader = require_once __DIR__.'/../app/bootstrap.php.cache'; + require_once __DIR__.'/../app/AppKernel.php'; $kernel = new AppKernel('dev', true); $kernel->loadClassCache(); $request = Request::createFromGlobals(); - // ... -To make your debugger happier, disable the loading of all PHP class caches -by removing the call to ``loadClassCache()``:: +To make your debugger happier, disable all PHP class caches by removing the +call to ``loadClassCache()`` and by replacing the require statements like +below:: // ... + // $loader = require_once __DIR__.'/../app/bootstrap.php.cache'; $loader = require_once __DIR__.'/../app/autoload.php'; - Debug::enable(); + require_once __DIR__.'/../app/AppKernel.php'; $kernel = new AppKernel('dev', true); // $kernel->loadClassCache(); @@ -58,5 +57,7 @@ by removing the call to ``loadClassCache()``:: session. Some IDEs do not like the fact that some classes are stored in different -locations. To avoid problems, you can tell your IDE to ignore the PHP cache -file. +locations. To avoid problems, you can either tell your IDE to ignore the PHP +cache files, or you can change the extension used by Symfony for these files:: + + $kernel->loadClassCache('classes', '.php.cache'); diff --git a/cookbook/deployment/azure-website.rst b/cookbook/deployment/azure-website.rst index 54c6175b55f..e24ed31409e 100644 --- a/cookbook/deployment/azure-website.rst +++ b/cookbook/deployment/azure-website.rst @@ -96,8 +96,8 @@ and how to properly configure PHP for a production environment. Configuring the latest PHP Runtime ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Even though Symfony only requires PHP 5.5.9 to run, it's always recommended -to use the most recent PHP version whenever possible. Earlier versions are no longer +Even though Symfony only requires PHP 5.3.9 to run, it's always recommended +to use the most recent PHP version whenever possible. PHP 5.3 is no longer supported by the PHP core team, but you can update it easily in Azure. To update your PHP version on Azure, go to the **Configure** tab of the control @@ -259,13 +259,13 @@ directory with at least the following contents: .. code-block:: text - /var/bootstrap.php.cache - /var/cache/* + /app/bootstrap.php.cache + /app/cache/* /app/config/parameters.yml - /var/logs/* - !var/cache/.gitkeep - !var/logs/.gitkeep - /var/SymfonyRequirements.php + /app/logs/* + !app/cache/.gitkeep + !app/logs/.gitkeep + /app/SymfonyRequirements.php /build/ /vendor/ /bin/ @@ -388,7 +388,7 @@ MySQL database. .. code-block:: bash - $ php bin/console doctrine:schema:update --force + $ php app/console doctrine:schema:update --force This command builds the tables and indexes for your MySQL database. If your Symfony application is more complex than a basic Symfony Standard Edition, you diff --git a/cookbook/deployment/heroku.rst b/cookbook/deployment/heroku.rst index f1330f8f80e..b07ae033ad7 100644 --- a/cookbook/deployment/heroku.rst +++ b/cookbook/deployment/heroku.rst @@ -275,7 +275,7 @@ This is also very useful to build assets on the production system, e.g. with Ass { "scripts": { "compile": [ - "bin/console assetic:dump" + "app/console assetic:dump" ] } } diff --git a/cookbook/deployment/platformsh.rst b/cookbook/deployment/platformsh.rst index 2f0857f5af1..d257c8df4c2 100644 --- a/cookbook/deployment/platformsh.rst +++ b/cookbook/deployment/platformsh.rst @@ -62,16 +62,16 @@ Platform.sh how to deploy your application (read more about # The mounts that will be performed when the package is deployed. mounts: - '/var/cache': 'shared:files/cache' - '/var/logs': 'shared:files/logs' + '/app/cache': 'shared:files/cache' + '/app/logs': 'shared:files/logs' # The hooks that will be performed when the package is deployed. hooks: build: | rm web/app_dev.php - bin/console --env=prod assetic:dump --no-debug + app/console --env=prod assetic:dump --no-debug deploy: | - bin/console --env=prod cache:clear + app/console --env=prod cache:clear For best practices, you should also add a ``.platform`` folder at the root of your Git repository which contains the following files: diff --git a/cookbook/deployment/tools.rst b/cookbook/deployment/tools.rst index c76d1fe70fd..40379502eaf 100644 --- a/cookbook/deployment/tools.rst +++ b/cookbook/deployment/tools.rst @@ -115,7 +115,7 @@ Check if your server meets the requirements by running: .. code-block:: bash - $ php bin/symfony_requirements + $ php app/check.php B) Configure your ``app/config/parameters.yml`` File ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -154,7 +154,7 @@ Make sure you clear (and warm-up) your Symfony cache: .. code-block:: bash - $ php bin/console cache:clear --env=prod --no-debug + $ php app/console cache:clear --env=prod --no-debug E) Dump your Assetic Assets ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -163,7 +163,7 @@ If you're using Assetic, you'll also want to dump your assets: .. code-block:: bash - $ php bin/console assetic:dump --env=prod --no-debug + $ php app/console assetic:dump --env=prod --no-debug F) Other Things! ~~~~~~~~~~~~~~~~ diff --git a/cookbook/doctrine/console.rst b/cookbook/doctrine/console.rst index 11459a3b2d5..0cfb7befca0 100644 --- a/cookbook/doctrine/console.rst +++ b/cookbook/doctrine/console.rst @@ -11,7 +11,7 @@ command: .. code-block:: bash - $ php bin/console list doctrine + $ php app/console list doctrine A list of available commands will print out. You can find out more information about any of these commands (or any Symfony command) by running the ``help`` @@ -20,7 +20,7 @@ task, run: .. code-block:: bash - $ php bin/console help doctrine:database:create + $ php app/console help doctrine:database:create Some notable or interesting tasks include: @@ -30,7 +30,7 @@ Some notable or interesting tasks include: .. code-block:: bash - $ php bin/console doctrine:ensure-production-settings --env=prod + $ php app/console doctrine:ensure-production-settings --env=prod * ``doctrine:mapping:import`` - allows Doctrine to introspect an existing database and create mapping information. For more information, see diff --git a/cookbook/doctrine/event_listeners_subscribers.rst b/cookbook/doctrine/event_listeners_subscribers.rst index 64c8d79ab9a..bda41b7c212 100644 --- a/cookbook/doctrine/event_listeners_subscribers.rst +++ b/cookbook/doctrine/event_listeners_subscribers.rst @@ -156,12 +156,6 @@ specific type of entity (e.g. a ``Product`` entity but not a ``BlogPost`` entity), you should check for the entity's class type in your method (as shown above). -.. tip:: - - In Doctrine 2.4, a feature called Entity Listeners was introduced. - It is a lifecycle listener class used for an entity. You can read - about it in `the Doctrine Documentation`_. - Creating the Subscriber Class ----------------------------- @@ -219,4 +213,3 @@ interface and have an event method for each event it subscribes to:: For a full reference, see chapter `The Event System`_ in the Doctrine documentation. .. _`The Event System`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html -.. _`the Doctrine Documentation`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#entity-listeners diff --git a/cookbook/doctrine/file_uploads.rst b/cookbook/doctrine/file_uploads.rst index 2615a1a8f2b..4e086ed699e 100644 --- a/cookbook/doctrine/file_uploads.rst +++ b/cookbook/doctrine/file_uploads.rst @@ -14,7 +14,7 @@ How to Handle File Uploads with Doctrine Handling file uploads with Doctrine entities is no different than handling any other file upload. In other words, you're free to move the file in your controller after handling a form submission. For examples of how to do this, -see the :doc:`FileType reference ` page. +see the :doc:`file type reference ` page. If you choose to, you can also integrate the file upload into your entity lifecycle (i.e. creation, update and removal). In this case, as your entity @@ -98,7 +98,7 @@ file. .. tip:: If you have not done so already, you should probably read the - :doc:`FileType ` documentation first to + :doc:`file ` type documentation first to understand how the basic upload process works. .. note:: @@ -258,7 +258,7 @@ The following controller shows you how to handle the entire process:: $em->persist($document); $em->flush(); - return $this->redirectToRoute(...); + return $this->redirect($this->generateUrl(...)); } return array('form' => $form->createView()); @@ -281,7 +281,7 @@ in a moment to handle the file upload:: $em->persist($document); $em->flush(); - return $this->redirectToRoute(...); + return $this->redirect(...); } The ``upload()`` method will take advantage of the :class:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile` @@ -446,7 +446,7 @@ call to ``$document->upload()`` should be removed from the controller:: $em->persist($document); $em->flush(); - return $this->redirectToRoute(...); + return $this->redirect(...); } .. note:: diff --git a/cookbook/doctrine/mapping_model_classes.rst b/cookbook/doctrine/mapping_model_classes.rst index da5943dc915..61fb4d56e23 100644 --- a/cookbook/doctrine/mapping_model_classes.rst +++ b/cookbook/doctrine/mapping_model_classes.rst @@ -14,10 +14,36 @@ register the mappings for your model classes. 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. + just to get the auto mapping, use the compiler pass. + +.. versionadded:: 2.3 + The base mapping compiler pass was introduced in Symfony 2.3. The Doctrine bundles + support it from DoctrineBundle >= 1.3.0, 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``. + + +.. versionadded:: 2.3 + The base mapping compiler pass was introduced in Symfony 2.3. The Doctrine bundles + support it from DoctrineBundle >= 1.3.0, MongoDBBundle >= 3.0.0, + PHPCRBundle >= 1.0.0 and the (unversioned) CouchDBBundle supports the + compiler pass since the `CouchDB Mapping Compiler Pass pull request`_ + was merged. + +.. versionadded:: 2.6 + Support for defining namespace aliases was introduced in Symfony 2.6. + It is safe to define the aliases with older versions of Symfony as + the aliases are the last argument to ``createXmlMappingDriver`` and + are ignored by PHP if that argument doesn't exist. In your bundle class, write the following code to register the compiler pass. -This one is written for the CmfRoutingBundle, so parts of it will need to +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; @@ -25,7 +51,7 @@ be adapted for your case:: use Doctrine\Bundle\CouchDBBundle\DependencyInjection\Compiler\DoctrineCouchDBMappingsPass; use Doctrine\Bundle\PHPCRBundle\DependencyInjection\Compiler\DoctrinePhpcrMappingsPass; - class CmfRoutingBundle extends Bundle + class FOSUserBundle extends Bundle { public function build(ContainerBuilder $container) { @@ -34,7 +60,7 @@ be adapted for your case:: $modelDir = realpath(__DIR__.'/Resources/config/doctrine/model'); $mappings = array( - $modelDir => 'Symfony\Cmf\RoutingBundle\Model', + $modelDir => 'FOS\UserBundle\Model', ); $ormCompilerClass = 'Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass'; @@ -42,9 +68,8 @@ be adapted for your case:: $container->addCompilerPass( DoctrineOrmMappingsPass::createXmlMappingDriver( $mappings, - array('cmf_routing.model_manager_name'), - 'cmf_routing.backend_type_orm', - array('CmfRoutingBundle' => 'Symfony\Cmf\RoutingBundle\Model') + array('fos_user.model_manager_name'), + 'fos_user.backend_type_orm' )); } @@ -53,9 +78,8 @@ be adapted for your case:: $container->addCompilerPass( DoctrineMongoDBMappingsPass::createXmlMappingDriver( $mappings, - array('cmf_routing.model_manager_name'), - 'cmf_routing.backend_type_mongodb', - array('CmfRoutingBundle' => 'Symfony\Cmf\RoutingBundle\Model') + array('fos_user.model_manager_name'), + 'fos_user.backend_type_mongodb' )); } @@ -64,9 +88,8 @@ be adapted for your case:: $container->addCompilerPass( DoctrineCouchDBMappingsPass::createXmlMappingDriver( $mappings, - array('cmf_routing.model_manager_name'), - 'cmf_routing.backend_type_couchdb', - array('CmfRoutingBundle' => 'Symfony\Cmf\RoutingBundle\Model') + array('fos_user.model_manager_name'), + 'fos_user.backend_type_couchdb' )); } @@ -75,9 +98,8 @@ be adapted for your case:: $container->addCompilerPass( DoctrinePhpcrMappingsPass::createXmlMappingDriver( $mappings, - array('cmf_routing.model_manager_name'), - 'cmf_routing.backend_type_phpcr', - array('CmfRoutingBundle' => 'Symfony\Cmf\RoutingBundle\Model') + array('fos_user.model_manager_name'), + 'fos_user.backend_type_phpcr' )); } } @@ -90,20 +112,17 @@ 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 example above, the CmfRoutingBundle - stores the manager name that's being used under the ``cmf_routing.model_manager_name`` +* 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 +* 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; -* A map/hash of aliases to namespace. This should be the same convention used - by Doctrine auto-mapping. In the example above, this allows the user to call - ``$om->getRepository('CmfRoutingBundle:Route')``. + bundle is only used with one type of Doctrine. .. note:: @@ -114,7 +133,7 @@ Annotations, XML, Yaml, PHP and StaticPHP. The arguments are: 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 taken from the + with the ``DefaultFileLocator`` like this. This code is simply taken from the ``DoctrineOrmMappingsPass`` and adapted to use the ``DefaultFileLocator`` instead of the ``SymfonyFileLocator``:: @@ -132,9 +151,6 @@ Annotations, XML, Yaml, PHP and StaticPHP. The arguments are: ); } - Note that you do not need to provide a namespace alias unless your users are - expected to ask Doctrine for the base classes. - 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 @@ -143,3 +159,4 @@ Annotations, XML, Yaml, PHP and StaticPHP. The arguments are: 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/multiple_entity_managers.rst b/cookbook/doctrine/multiple_entity_managers.rst index aeab0576eff..7bcb18b2861 100644 --- a/cookbook/doctrine/multiple_entity_managers.rst +++ b/cookbook/doctrine/multiple_entity_managers.rst @@ -165,20 +165,20 @@ When working with multiple connections to create your databases: .. code-block:: bash # Play only with "default" connection - $ php bin/console doctrine:database:create + $ php app/console doctrine:database:create # Play only with "customer" connection - $ php bin/console doctrine:database:create --connection=customer + $ php app/console doctrine:database:create --connection=customer When working with multiple entity managers to update your schema: .. code-block:: bash # Play only with "default" mappings - $ php bin/console doctrine:schema:update --force + $ php app/console doctrine:schema:update --force # Play only with "customer" mappings - $ php bin/console doctrine:schema:update --force --em=customer + $ php app/console doctrine:schema:update --force --em=customer If you *do* omit the entity manager's name when asking for it, the default entity manager (i.e. ``default``) is returned:: diff --git a/cookbook/doctrine/pdo_session_storage.rst b/cookbook/doctrine/pdo_session_storage.rst index 0e2c923d5d9..b9d8f4fcf82 100644 --- a/cookbook/doctrine/pdo_session_storage.rst +++ b/cookbook/doctrine/pdo_session_storage.rst @@ -4,6 +4,12 @@ How to Use PdoSessionHandler to Store Sessions in the Database ============================================================== +.. caution:: + + There was a backwards-compatibility break in Symfony 2.6: the database + schema changed slightly. See :ref:`Symfony 2.6 Changes ` + for details. + The default Symfony session storage writes the session information to files. Most medium to large websites use a database to store the session values instead of files, because databases are easier to use and scale in a @@ -13,6 +19,13 @@ Symfony has a built-in solution for database session storage called :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\PdoSessionHandler`. To use it, you just need to change some parameters in the main configuration file: +.. versionadded:: 2.1 + In Symfony 2.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 Symfony 2.1 you should configure ``handler_id`` not ``storage_id`` like in Symfony 2.0. + Below, you'll notice that ``%session.storage.options%`` is not used anymore. + .. configuration-block:: .. code-block:: yaml @@ -23,13 +36,26 @@ To use it, you just need to change some parameters in the main configuration fil # ... handler_id: session.handler.pdo + parameters: + pdo.db_options: + db_table: session + db_id_col: session_id + db_data_col: session_value + db_time_col: session_time + services: + pdo: + class: PDO + arguments: + dsn: "mysql:dbname=mydatabase" + user: myuser + password: mypassword + calls: + - [setAttribute, [3, 2]] # \PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION + session.handler.pdo: class: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler - public: false - arguments: - - 'mysql:dbname=mydatabase' - - { db_username: myuser, db_password: mypassword } + arguments: ['@pdo', '%pdo.db_options%'] .. code-block:: xml @@ -38,13 +64,29 @@ To use it, you just need to change some parameters in the main configuration fil + + + session + session_id + session_value + session_time + + + - - mysql:dbname=mydatabase - - myuser - mypassword - + + mysql:dbname=mydatabase + myuser + mypassword + + PDO::ATTR_ERRMODE + PDO::ERRMODE_EXCEPTION + + + + + + %pdo.db_options% @@ -62,77 +104,44 @@ To use it, you just need to change some parameters in the main configuration fil ), )); - $storageDefinition = new Definition('Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler', array( - 'mysql:dbname=mydatabase', - array('db_username' => 'myuser', 'db_password' => 'mypassword') + $container->setParameter('pdo.db_options', array( + 'db_table' => 'session', + 'db_id_col' => 'session_id', + 'db_data_col' => 'session_value', + 'db_time_col' => 'session_time', )); - $container->setDefinition('session.handler.pdo', $storageDefinition); - -Configuring the Table and Column Names --------------------------------------- - -This will expect a ``sessions`` table with a number of different columns. -The table name, and all of the column names, can be configured by passing -a second array argument to ``PdoSessionHandler``: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - services: - # ... - session.handler.pdo: - class: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler - public: false - arguments: - - 'mysql:dbname=mydatabase' - - { db_table: sessions, db_username: myuser, db_password: mypassword } - - .. code-block:: xml - - - - mysql:dbname=mydatabase - - sessions - myuser - mypassword - - - - - .. code-block:: php - - // app/config/config.php - - use Symfony\Component\DependencyInjection\Definition; - // ... + $pdoDefinition = new Definition('PDO', array( + 'mysql:dbname=mydatabase', + 'myuser', + 'mypassword', + )); + $pdoDefinition->addMethodCall('setAttribute', array(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION)); + $container->setDefinition('pdo', $pdoDefinition); $storageDefinition = new Definition('Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler', array( - 'mysql:dbname=mydatabase', - array('db_table' => 'sessions', 'db_username' => 'myuser', 'db_password' => 'mypassword') + new Reference('pdo'), + '%pdo.db_options%', )); $container->setDefinition('session.handler.pdo', $storageDefinition); -These are parameters that you must configure: +.. versionadded:: 2.6 + The ``db_lifetime_col`` was introduced in Symfony 2.6. Prior to 2.6, + this column did not exist. -``db_table`` (default ``sessions``): - The name of the session table in your database; - -``db_id_col`` (default ``sess_id``): - The name of the id column in your session table (VARCHAR(128)); +These are parameters that you must configure: -``db_data_col`` (default ``sess_data``): - The name of the value column in your session table (BLOB); +``db_table`` + The name of the session table in your database. -``db_time_col`` (default ``sess_time``): - The name of the time column in your session table (INTEGER); +``db_id_col`` + The name of the id column in your session table (``VARCHAR(255)`` or larger). -``db_lifetime_col`` (default ``sess_lifetime``): - The name of the lifetime column in your session table (INTEGER). +``db_data_col`` + The name of the value column in your session table (``TEXT`` or ``CLOB``). +``db_time_col``: + The name of the time column in your session table (``INTEGER``). Sharing your Database Connection Information -------------------------------------------- @@ -150,28 +159,27 @@ of your project's data, you can use the connection settings from the .. code-block:: yaml services: - session.handler.pdo: - class: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler - public: false + pdo: + class: PDO arguments: - 'mysql:host=%database_host%;port=%database_port%;dbname=%database_name%' - - { db_username: '%database_user%', db_password: '%database_password%' } + - '%database_user%' + - '%database_password%' .. code-block:: xml - + mysql:host=%database_host%;port=%database_port%;dbname=%database_name% - - %database_user% - %database_password% - + %database_user% + %database_password% .. code-block:: php - $storageDefinition = new Definition('Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler', array( + $pdoDefinition = new Definition('PDO', array( 'mysql:host=%database_host%;port=%database_port%;dbname=%database_name%', - array('db_username' => '%database_user%', 'db_password' => '%database_password%') + '%database_user%', + '%database_password%', )); .. _example-sql-statements: @@ -183,35 +191,46 @@ Before storing sessions in the database, you must create the table that stores the information. The following sections contain some examples of the SQL statements you may use for your specific database engine. +.. _pdo-session-handle-26-changes: + +.. sidebar:: Schema Changes needed when Upgrading to Symfony 2.6 + + If you use the ``PdoSessionHandler`` prior to Symfony 2.6 and upgrade, you'll + need to make a few changes to your session table: + + * A new session lifetime (``sess_lifetime`` by default) integer column + needs to be added; + * The data column (``sess_data`` by default) needs to be changed to a + BLOB type. + + Check the SQL statements below for more details. + + To keep the old (2.5 and earlier) functionality, change your class name + to use ``LegacyPdoSessionHandler`` instead of ``PdoSessionHandler`` (the + legacy class was added in Symfony 2.6.2). + MySQL ~~~~~ .. code-block:: sql - CREATE TABLE `sessions` ( - `sess_id` VARBINARY(128) NOT NULL PRIMARY KEY, - `sess_data` BLOB NOT NULL, - `sess_time` INTEGER UNSIGNED NOT NULL, - `sess_lifetime` MEDIUMINT NOT NULL - ) COLLATE utf8_bin, ENGINE = InnoDB; - -.. note:: - - A ``BLOB`` column type can only store up to 64 kb. If the data stored in - a user's session exceeds this, an exception may be thrown or their session - will be silently reset. Consider using a ``MEDIUMBLOB`` if you need more - space. + CREATE TABLE `session` ( + `session_id` varchar(255) NOT NULL, + `session_value` text NOT NULL, + `session_time` int(11) NOT NULL, + PRIMARY KEY (`session_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; PostgreSQL ~~~~~~~~~~ .. code-block:: sql - CREATE TABLE sessions ( - sess_id VARCHAR(128) NOT NULL PRIMARY KEY, - sess_data BYTEA NOT NULL, - sess_time INTEGER NOT NULL, - sess_lifetime INTEGER NOT NULL + CREATE TABLE session ( + session_id character varying(255) NOT NULL, + session_value text NOT NULL, + session_time integer NOT NULL, + CONSTRAINT session_pkey PRIMARY KEY (session_id) ); Microsoft SQL Server @@ -219,13 +238,12 @@ Microsoft SQL Server .. code-block:: sql - CREATE TABLE [dbo].[sessions]( - [sess_id] [nvarchar](255) NOT NULL, - [sess_data] [ntext] NOT NULL, - [sess_time] [int] NOT NULL, - [sess_lifetime] [int] NOT NULL, + CREATE TABLE [dbo].[session]( + [session_id] [nvarchar](255) NOT NULL, + [session_value] [ntext] NOT NULL, + [session_time] [int] NOT NULL, PRIMARY KEY CLUSTERED( - [sess_id] ASC + [session_id] ASC ) WITH ( PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, diff --git a/cookbook/doctrine/registration_form.rst b/cookbook/doctrine/registration_form.rst index 00ce5b980fc..140f9f40aab 100644 --- a/cookbook/doctrine/registration_form.rst +++ b/cookbook/doctrine/registration_form.rst @@ -168,20 +168,16 @@ Next, create the form for the ``User`` entity:: use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; - use Symfony\Component\Form\Extension\Core\Type\EmailType; - use Symfony\Component\Form\Extension\Core\Type\TextType; - use Symfony\Component\Form\Extension\Core\Type\RepeatedType; - use Symfony\Component\Form\Extension\Core\Type\PasswordType; class UserType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('email', EmailType::class) - ->add('username', TextType::class) - ->add('plainPassword', RepeatedType::class, array( - 'type' => PasswordType::class, + ->add('email', 'email') + ->add('username', 'text') + ->add('plainPassword', 'repeated', array( + 'type' => 'password', 'first_options' => array('label' => 'Password'), 'second_options' => array('label' => 'Repeat Password'), ) @@ -194,6 +190,11 @@ Next, create the form for the ``User`` entity:: 'data_class' => 'AppBundle\Entity\User', )); } + + public function getName() + { + return 'user'; + } } There are just three fields: ``email``, ``username`` and ``plainPassword`` @@ -229,7 +230,7 @@ into the database:: { // 1) build the form $user = new User(); - $form = $this->createForm(UserType::class, $user); + $form = $this->createForm(new UserType(), $user); // 2) handle the submit (will only happen on POST) $form->handleRequest($request); @@ -378,7 +379,7 @@ your database schema using this command: .. code-block:: bash - $ php bin/console doctrine:schema:update --force + $ php app/console doctrine:schema:update --force That's it! Head to ``/register`` to try things out! @@ -424,17 +425,15 @@ To do this, add a ``termsAccepted`` field to your form, but set its // src/AppBundle/Form/UserType.php // ... use Symfony\Component\Validator\Constraints\IsTrue; - use Symfony\Component\Form\Extension\Core\Type\CheckboxType; - use Symfony\Component\Form\Extension\Core\Type\EmailType; class UserType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('email', EmailType::class); + ->add('email', 'email'); // ... - ->add('termsAccepted', CheckboxType::class, array( + ->add('termsAccepted', 'checkbox', array( 'mapped' => false, 'constraints' => new IsTrue(), )) diff --git a/cookbook/doctrine/reverse_engineering.rst b/cookbook/doctrine/reverse_engineering.rst index 355105f8103..b77d6609f92 100644 --- a/cookbook/doctrine/reverse_engineering.rst +++ b/cookbook/doctrine/reverse_engineering.rst @@ -59,7 +59,7 @@ table fields. .. code-block:: bash - $ php bin/console doctrine:mapping:import --force AcmeBlogBundle xml + $ php app/console doctrine:mapping:import --force AcmeBlogBundle xml This command line tool asks Doctrine to introspect the database and generate the XML metadata files under the ``src/Acme/BlogBundle/Resources/config/doctrine`` @@ -92,8 +92,8 @@ entity classes by executing the following two commands. .. code-block:: bash - $ php bin/console doctrine:mapping:convert annotation ./src - $ php bin/console doctrine:generate:entities AcmeBlogBundle + $ php app/console doctrine:mapping:convert annotation ./src + $ php app/console doctrine:generate:entities AcmeBlogBundle The first command generates entity classes with annotation mappings. But if you want to use YAML or XML mapping instead of annotations, you should diff --git a/cookbook/email/email.rst b/cookbook/email/email.rst index c2f51cc786b..3f648f4c43b 100644 --- a/cookbook/email/email.rst +++ b/cookbook/email/email.rst @@ -125,21 +125,12 @@ an email is pretty straightforward:: } To keep things decoupled, the email body has been stored in a template and -rendered with the ``renderView()`` method. The ``registration.html.twig`` -template might look something like this: +rendered with the ``renderView()`` method. -.. code-block:: html+jinja - - {# app/Resources/views/Emails/registration.html.twig #} -

    You did it! You registered!

    - - {# example, assuming you have a route named "login" #} - To login, go to: .... - - Thanks! - - {# Makes an absolute URL to the /images/logo.png file #} - +.. versionadded:: 2.7 + The ``absolute_url()`` function was introduced in Symfony 2.7. Prior + to 2.7, the ``asset()`` function has an argument to enable returning + an absolute URL. The ``$message`` object supports many more options, such as including attachments, adding HTML content, and much more. Fortunately, Swift Mailer covers the topic diff --git a/cookbook/email/spool.rst b/cookbook/email/spool.rst index 8c3f63c6b75..923c2b8afe0 100644 --- a/cookbook/email/spool.rst +++ b/cookbook/email/spool.rst @@ -124,19 +124,19 @@ There is a console command to send the messages in the spool: .. code-block:: bash - $ php bin/console swiftmailer:spool:send --env=prod + $ php app/console swiftmailer:spool:send --env=prod It has an option to limit the number of messages to be sent: .. code-block:: bash - $ php bin/console swiftmailer:spool:send --message-limit=10 --env=prod + $ php app/console swiftmailer:spool:send --message-limit=10 --env=prod You can also set the time limit in seconds: .. code-block:: bash - $ php bin/console swiftmailer:spool:send --time-limit=10 --env=prod + $ php app/console swiftmailer:spool:send --time-limit=10 --env=prod Of course you will not want to run this manually in reality. Instead, the console command should be triggered by a cron job or scheduled task and run diff --git a/cookbook/email/testing.rst b/cookbook/email/testing.rst index 6ab1e522e7e..270f7506895 100644 --- a/cookbook/email/testing.rst +++ b/cookbook/email/testing.rst @@ -33,9 +33,7 @@ Start with an easy controller action that sends an email:: In your functional test, use the ``swiftmailer`` collector on the profiler to get information about the messages sent on the previous request:: - // tests/AppBundle/Controller/MailControllerTest.php - namespace Tests\AppBundle\Controller; - + // src/AppBundle/Tests/Controller/MailControllerTest.php use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class MailControllerTest extends WebTestCase diff --git a/cookbook/event_dispatcher/before_after_filters.rst b/cookbook/event_dispatcher/before_after_filters.rst index fff97e4b04b..2ae36f8a0de 100644 --- a/cookbook/event_dispatcher/before_after_filters.rst +++ b/cookbook/event_dispatcher/before_after_filters.rst @@ -8,10 +8,10 @@ It is quite common in web application development to need some logic to be executed just before or just after your controller actions acting as filters or hooks. -Some web frameworks define methods like ``preExecute()`` and ``postExecute()``, -but there is no such thing in Symfony. The good news is that there is a much -better way to interfere with the Request -> Response process using the -:doc:`EventDispatcher component `. +In symfony1, this was achieved with the preExecute and postExecute methods. +Most major frameworks have similar methods but there is no such thing in Symfony. +The good news is that there is a much better way to interfere with the +Request -> Response process using the :doc:`EventDispatcher component `. Token Validation Example ------------------------ diff --git a/cookbook/event_dispatcher/event_listener.rst b/cookbook/event_dispatcher/event_listener.rst index a1351b62604..20286209a26 100644 --- a/cookbook/event_dispatcher/event_listener.rst +++ b/cookbook/event_dispatcher/event_listener.rst @@ -264,16 +264,19 @@ there are some minor advantages for each of them: Debugging Event Listeners ------------------------- +.. versionadded:: 2.6 + The ``debug:event-dispatcher`` command was introduced in Symfony 2.6. + You can find out what listeners are registered in the event dispatcher using the console. To show all events and their listeners, run: .. code-block:: bash - $ php bin/console debug:event-dispatcher + $ php app/console debug:event-dispatcher You can get registered listeners for a particular event by specifying its name: .. code-block:: bash - $ php bin/console debug:event-dispatcher kernel.exception + $ php app/console debug:event-dispatcher kernel.exception diff --git a/cookbook/expression/expressions.rst b/cookbook/expression/expressions.rst index 8e162c988ad..73e43745bb8 100644 --- a/cookbook/expression/expressions.rst +++ b/cookbook/expression/expressions.rst @@ -4,9 +4,9 @@ How to use Expressions in Security, Routing, Services, and Validation ===================================================================== -Symfony comes with a powerful -:doc:`ExpressionLanguage ` -component. It allows you to add highly customized logic inside configuration. +In Symfony 2.4, a powerful :doc:`ExpressionLanguage ` +component was added to Symfony. This allows us to add highly customized +logic inside configuration. The Symfony Framework leverages expressions out of the box in the following ways: diff --git a/cookbook/expression/index.rst b/cookbook/expression/index.rst deleted file mode 100644 index 909ecc72224..00000000000 --- a/cookbook/expression/index.rst +++ /dev/null @@ -1,7 +0,0 @@ -Expressions -=========== - -.. toctree:: - :maxdepth: 2 - - expressions diff --git a/cookbook/form/create_custom_field_type.rst b/cookbook/form/create_custom_field_type.rst index e6c3ed08ee2..884bc345269 100644 --- a/cookbook/form/create_custom_field_type.rst +++ b/cookbook/form/create_custom_field_type.rst @@ -25,7 +25,6 @@ for form fields, which is ``\Form\Type``. Make sure the field extend use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\OptionsResolver; - use Symfony\Component\Form\Extension\Core\Type\ChoiceType; class GenderType extends AbstractType { @@ -41,7 +40,12 @@ for form fields, which is ``\Form\Type``. Make sure the field extend public function getParent() { - return ChoiceType::class; + return 'choice'; + } + + public function getName() + { + return 'app_gender'; } } @@ -51,7 +55,7 @@ for form fields, which is ``\Form\Type``. Make sure the field extend is just a convention. Here, the return value of the ``getParent`` function indicates that you're -extending the ``ChoiceType`` field. This means that, by default, you inherit +extending the ``choice`` field type. This means that, by default, you inherit all of the logic and rendering of that field type. To see some of the logic, check out the `ChoiceType`_ class. There are three methods that are particularly important: @@ -68,6 +72,10 @@ important: set) the ``multiple`` attribute on the ``select`` field. See `Creating a Template for the Field`_ for more details. +.. versionadded:: 2.7 + The ``configureOptions()`` method was introduced in Symfony 2.7. Previously, + the method was called ``setDefaultOptions()``. + ``configureOptions()`` This defines options for your form type that can be used in ``buildForm()`` and ``buildView()``. There are a lot of @@ -81,6 +89,10 @@ important: Also, if you need to modify the "view" of any of your child types from your parent type, use the ``finishView()`` method. +The ``getName()`` method returns an identifier which should be unique in +your application. This is used in various places, such as when customizing +how your form type will be rendered. + The goal of this field was to extend the choice type to enable selection of a gender. This is achieved by fixing the ``choices`` to a list of possible genders. @@ -88,19 +100,13 @@ genders. Creating a Template for the Field --------------------------------- -Each field type is rendered by a template fragment, which is determined in part by -the class name of your type. For more information, see +Each field type is rendered by a template fragment, which is determined in +part by the value of your ``getName()`` method. For more information, see :ref:`cookbook-form-customization-form-themes`. -.. note:: - - The first part of the prefix (e.g. ``gender``) comes from the class name - (``GenderType`` -> ``gender``). This can be controlled by overriding ``getBlockPrefix()`` - in ``GenderType``. - -In this case, since the parent field is ``ChoiceType``, you don't *need* to do -any work as the custom field type will automatically be rendered like a ``ChoiceType``. -But for the sake of this example, suppose that when your field is "expanded" +In this case, since the parent field is ``choice``, you don't *need* to do +any work as the custom field type will automatically be rendered like a ``choice`` +type. But for the sake of this example, suppose that when your field is "expanded" (i.e. radio buttons or checkboxes, instead of a select field), you want to always render it in a ``ul`` element. In your form theme template (see above link for details), create a ``gender_widget`` block to handle this: @@ -148,7 +154,7 @@ link for details), create a ``gender_widget`` block to handle this: .. note:: Make sure the correct widget prefix is used. In this example the name should - be ``gender_widget`` (see :ref:`cookbook-form-customization-form-themes`). + be ``gender_widget``, according to the value returned by ``getName``. Further, the main config file should point to the custom form template so that it's used when rendering all forms. @@ -235,22 +241,25 @@ new instance of the type in one of your forms:: use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; - use AppBundle\Form\Type\GenderType; class AuthorType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->add('gender_code', GenderType::class, array( + $builder->add('gender_code', new GenderType(), array( 'placeholder' => 'Choose a gender', )); } } -But this only works because the ``GenderType`` is very simple. What if +But this only works because the ``GenderType()`` is very simple. What if the gender codes were stored in configuration or in a database? The next section explains how more complex field types solve this problem. +.. versionadded:: 2.6 + The ``placeholder`` option was introduced in Symfony 2.6 and replaces + ``empty_value``, which is available prior to 2.6. + .. _form-cookbook-form-field-service: Creating your Field Type as a Service @@ -302,14 +311,14 @@ the ``genders`` parameter value as the first argument to its to-be-created arguments: - '%genders%' tags: - - { name: form.type } + - { name: form.type, alias: app_gender } .. code-block:: xml %genders% - + .. code-block:: php @@ -322,7 +331,9 @@ the ``genders`` parameter value as the first argument to its to-be-created 'AppBundle\Form\Type\GenderType', array('%genders%') )) - ->addTag('form.type') + ->addTag('form.type', array( + 'alias' => 'app_gender', + )) ; .. tip:: @@ -330,8 +341,10 @@ the ``genders`` parameter value as the first argument to its to-be-created Make sure the services file is being imported. See :ref:`service-container-imports-directive` for details. -First, add a ``__construct`` method to ``GenderType``, which receives the gender -configuration:: +Be sure that the ``alias`` attribute of the tag corresponds with the value +returned by the ``getName`` method defined earlier. You'll see the importance +of this in a moment when you use the custom field type. But first, add a ``__construct`` +method to ``GenderType``, which receives the gender configuration:: // src/AppBundle/Form/Type/GenderType.php namespace AppBundle\Form\Type; @@ -361,28 +374,28 @@ configuration:: } Great! The ``GenderType`` is now fueled by the configuration parameters and -registered as a service. Because you used the ``form.type`` alias in its configuration, -your service will be used instead of creating a *new* ``GenderType``. In other words, -your controller *does not need to change*, it still looks like this:: +registered as a service. Additionally, because you used the ``form.type`` alias in its +configuration, using the field is now much easier:: // src/AppBundle/Form/Type/AuthorType.php namespace AppBundle\Form\Type; - use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; - use AppBundle\Form\Type\GenderType; + + // ... class AuthorType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->add('gender_code', GenderType::class, array( + $builder->add('gender_code', 'gender', array( 'placeholder' => 'Choose a gender', )); } } -Have fun! +Notice that instead of instantiating a new instance, you can just refer to +it by the alias used in your service configuration, ``gender``. Have fun! .. _`ChoiceType`: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php .. _`FieldType`: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Form/Extension/Core/Type/FieldType.php diff --git a/cookbook/form/create_form_type_extension.rst b/cookbook/form/create_form_type_extension.rst index 7ad80384c0b..e8cd7187497 100644 --- a/cookbook/form/create_form_type_extension.rst +++ b/cookbook/form/create_form_type_extension.rst @@ -15,7 +15,7 @@ extensions come in. Form type extensions have 2 main use-cases: #. You want to add a **specific feature to a single type** (such - as adding a "download" feature to the ``FileType`` field type); + as adding a "download" feature to the "file" field type); #. You want to add a **generic feature to several types** (such as adding a "help" text to every "input text"-like type). @@ -51,7 +51,6 @@ class. In most cases, it's easier to extend the abstract class:: namespace AppBundle\Form\Extension; use Symfony\Component\Form\AbstractTypeExtension; - use Symfony\Component\Form\Extension\Core\Type\FileType; class ImageTypeExtension extends AbstractTypeExtension { @@ -62,7 +61,7 @@ class. In most cases, it's easier to extend the abstract class:: */ public function getExtendedType() { - return FileType::class; + return 'file'; } } @@ -73,8 +72,8 @@ by your extension. .. tip:: The value you return in the ``getExtendedType`` method corresponds - to the fully qualified class name of the form type class you wish to - extend. + to the value returned by the ``getName`` method in the form type class + you wish to extend. In addition to the ``getExtendedType`` function, you will probably want to override one of the following methods: @@ -106,14 +105,14 @@ tag: app.image_type_extension: class: AppBundle\Form\Extension\ImageTypeExtension tags: - - { name: form.type_extension, extended_type: Symfony\Component\Form\Extension\Core\Type\FileType } + - { name: form.type_extension, alias: file } .. code-block:: xml - + .. code-block:: php @@ -123,11 +122,11 @@ tag: 'app.image_type_extension', 'AppBundle\Form\Extension\ImageTypeExtension' ) - ->addTag('form.type_extension', array('extended_type' => 'Symfony\Component\Form\Extension\Core\Type\FileType')); + ->addTag('form.type_extension', array('alias' => 'file')); -The ``extended_type`` key of the tag is the type of field that this extension should -be applied to. In your case, as you want to extend the ``Symfony\Component\Form\Extension\Core\Type\FileType`` -field type, you will use that as the ``extended_type``. +The ``alias`` key of the tag is the type of field that this extension should +be applied to. In your case, as you want to extend the ``file`` field type, +you will use ``file`` as an alias. Adding the extension Business Logic ----------------------------------- @@ -176,14 +175,14 @@ database):: } Your form type extension class will need to do two things in order to extend -the ``FileType::class`` form type: +the ``file`` form type: #. Override the ``configureOptions`` method in order to add an ``image_path`` option; #. Override the ``buildForm`` and ``buildView`` methods in order to pass the image URL to the view. -The logic is the following: when adding a form field of type ``FileType::class``, +The logic is the following: when adding a form field of type ``file``, you will be able to specify a new option: ``image_path``. This option will tell the file field how to get the actual image URL in order to display it in the view:: @@ -196,7 +195,6 @@ it in the view:: use Symfony\Component\Form\FormInterface; use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\OptionsResolver\OptionsResolver; - use Symfony\Component\Form\Extension\Core\Type\FileType; class ImageTypeExtension extends AbstractTypeExtension { @@ -207,7 +205,7 @@ it in the view:: */ public function getExtendedType() { - return FileType::class; + return 'file'; } /** @@ -293,7 +291,7 @@ Specifically, you need to override the ``file_widget`` block: Using the Form Type Extension ----------------------------- -From now on, when adding a field of type ``FileType::class`` in your form, you can +From now on, when adding a field of type ``file`` in your form, you can specify an ``image_path`` option that will be used to display an image next to the file field. For example:: @@ -302,16 +300,19 @@ next to the file field. For example:: use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; - use Symfony\Component\Form\Extension\Core\Type\TextType; - use Symfony\Component\Form\Extension\Core\Type\FileType; class MediaType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('name', TextType::class) - ->add('file', FileType::class, array('image_path' => 'webPath')); + ->add('name', 'text') + ->add('file', 'file', array('image_path' => 'webPath')); + } + + public function getName() + { + return 'app_media'; } } @@ -323,13 +324,13 @@ Generic Form Type Extensions You can modify several form types at once by specifying their common parent (:doc:`/reference/forms/types`). For example, several form types natively -available in Symfony inherit from the ``TextType`` form type (such as ``EmailType``, -``SearchType``, ``UrlType``, etc.). A form type extension applying to ``TextType`` -(i.e. whose ``getExtendedType`` method returns ``TextType::class``) would apply -to all of these form types. +available in Symfony inherit from the ``text`` form type (such as ``email``, +``search``, ``url``, etc.). A form type extension applying to ``text`` +(i.e. whose ``getExtendedType`` method returns ``text``) would apply to all of +these form types. In the same way, since **most** form types natively available in Symfony inherit -from the ``FormType`` form type, a form type extension applying to ``FormType`` -would apply to all of these. A notable exception are the ``ButtonType`` form -types. Also keep in mind that a custom form type which extends neither the -``FormType`` nor the ``ButtonType`` type could always be created. +from the ``form`` form type, a form type extension applying to ``form`` would +apply to all of these. A notable exception are the ``button`` form types. Also +keep in mind that a custom form type which extends neither the ``form`` nor +the ``button`` type could always be created. diff --git a/cookbook/form/data_transformers.rst b/cookbook/form/data_transformers.rst index 680758ddd6d..689d5b55a1d 100644 --- a/cookbook/form/data_transformers.rst +++ b/cookbook/form/data_transformers.rst @@ -6,7 +6,7 @@ How to Use Data Transformers Data transformers are used to translate the data for a field into a format that can be displayed in a form (and back on submit). They're already used internally for -many field types. For example, the :doc:`DateType ` field +many field types. For example, the :doc:`date field type ` can be rendered as a ``yyyy-MM-dd``-formatted input textbox. Internally, a data transformer converts the starting ``DateTime`` value of the field into the ``yyyy-MM-dd`` string to render the form, and then back into a ``DateTime`` object on submit. @@ -26,14 +26,13 @@ Suppose you have a Task form with a description ``textarea`` type:: use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; - use Symfony\Component\Form\Extension\Core\Type\TextareaType; // ... class TaskType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->add('description', TextareaType::class); + $builder->add('description', 'textarea'); } public function configureOptions(OptionsResolver $resolver) @@ -63,14 +62,13 @@ class:: use Symfony\Component\Form\CallbackTransformer; use Symfony\Component\Form\FormBuilderInterface; - use Symfony\Component\Form\Extension\Core\Type\TextareaType; // ... class TaskType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->add('description', TextareaType::class); + $builder->add('description', 'textarea'); $builder->get('description') ->addModelTransformer(new CallbackTransformer( @@ -106,10 +104,8 @@ in your code. You can also add the transformer, right when adding the field by changing the format slightly:: - use Symfony\Component\Form\Extension\Core\Type\TextareaType; - $builder->add( - $builder->create('description', TextareaType::class) + $builder->create('description', 'textarea') ->addModelTransformer(...) ); @@ -127,17 +123,14 @@ Start by setting up the text field like normal:: // src/AppBundle/Form/TaskType.php namespace AppBundle\Form\Type; - use Symfony\Component\Form\Extension\Core\Type\TextareaType; - use Symfony\Component\Form\Extension\Core\Type\TextType; - // ... class TaskType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('description', TextareaType::class) - ->add('issue', TextType::class) + ->add('description', 'textarea') + ->add('issue', 'text') ; } @@ -254,15 +247,13 @@ Next, you need to instantiate the ``IssueToNumberTransformer`` class from inside of the entity manager (because ``IssueToNumberTransformer`` needs this). No problem! Just add a ``__construct()`` function to ``TaskType`` and force this -to be passed in by registering ``TaskType`` as a service:: +to be passed in. Then, you can easily create and add the transformer:: // src/AppBundle/Form/TaskType.php namespace AppBundle\Form\Type; use AppBundle\Form\DataTransformer\IssueToNumberTransformer; use Doctrine\Common\Persistence\ObjectManager; - use Symfony\Component\Form\Extension\Core\Type\TextareaType; - use Symfony\Component\Form\Extension\Core\Type\TextType; // ... class TaskType extends AbstractType @@ -277,8 +268,8 @@ to be passed in by registering ``TaskType`` as a service:: public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('description', TextareaType::class) - ->add('issue', TextType::class, array( + ->add('description', 'textarea') + ->add('issue', 'text', array( // validation message if the data transformer fails 'invalid_message' => 'That is not a valid issue number', )); @@ -292,63 +283,19 @@ to be passed in by registering ``TaskType`` as a service:: // ... } -Define the form type as a service in your configuration files. - -.. configuration-block:: - - .. code-block:: yaml - - # src/AppBundle/Resources/config/services.yml - services: - app.form.type.task: - class: AppBundle\Form\Type\TaskType - arguments: ["@doctrine.orm.entity_manager"] - tags: - - { name: form.type } - - .. code-block:: xml - - - - - - - - - - - - - - .. code-block:: php - - // src/AppBundle/Resources/config/services.php - use AppBundle\Form\Type\TaskType; - - $definition = new Definition(TaskType::class, array( - new Reference('doctrine.orm.entity_manager'), - )); - $container - ->setDefinition( - 'app.form.type.task', - $definition - ) - ->addTag('form.type') - ; -.. tip:: - - For more information about defining form types as services, read - :ref:`register your form type as a service `. - -Now, you can easily use your ``TaskType``:: +Now, when you create your ``TaskType``, you'll need to pass in the entity manager:: // e.g. in a controller somewhere - $form = $this->createForm(TaskType::class, $task); + $manager = $this->getDoctrine()->getManager(); + $form = $this->createForm(new TaskType($manager), $task); // ... +.. note:: + + To make this step easier (especially if ``TaskType`` is embedded into other + form type classes), you might choose to :ref:`register your form type as a service `. + 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 submission, the Form component will pass a real @@ -365,7 +312,7 @@ its error message can be controlled with the ``invalid_message`` field option. // THIS IS WRONG - TRANSFORMER WILL BE APPLIED TO THE ENTIRE FORM // see above example for correct code - $builder->add('issue', TextType::class) + $builder->add('issue', 'text') ->addModelTransformer($transformer); .. _using-transformers-in-a-custom-field-type: @@ -413,7 +360,12 @@ First, create the custom field type class:: public function getParent() { - return TextType::class; + return 'text'; + } + + public function getName() + { + return 'issue_selector'; } } @@ -433,7 +385,7 @@ it's recognized as a custom field type: class: AppBundle\Form\IssueSelectorType arguments: ['@doctrine.orm.entity_manager'] tags: - - { name: form.type } + - { name: form.type, alias: issue_selector } .. code-block:: xml @@ -449,7 +401,7 @@ it's recognized as a custom field type: - + @@ -469,7 +421,9 @@ it's recognized as a custom field type: new Reference('doctrine.orm.entity_manager'), ) ) - ->addTag('form.type') + ->addTag('form.type', array( + 'alias' => 'issue_selector', + )) ; Now, whenever you need to use your special ``issue_selector`` field type, @@ -479,7 +433,6 @@ it's quite easy:: namespace AppBundle\Form\Type; use AppBundle\Form\DataTransformer\IssueToNumberTransformer; - use Symfony\Component\Form\Extension\Core\Type\TextareaType; // ... class TaskType extends AbstractType @@ -487,8 +440,8 @@ it's quite easy:: public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('description', TextareaType::class) - ->add('issue', IssueSelectorType::class) + ->add('description', 'textarea') + ->add('issue', 'issue_selector') ; } diff --git a/cookbook/form/direct_submit.rst b/cookbook/form/direct_submit.rst index f2f2b665ced..57440d527b4 100644 --- a/cookbook/form/direct_submit.rst +++ b/cookbook/form/direct_submit.rst @@ -4,6 +4,10 @@ How to Use the submit() Function to Handle Form Submissions =========================================================== +.. versionadded:: 2.3 + The :method:`Symfony\\Component\\Form\\FormInterface::handleRequest` + method was introduced in Symfony 2.3. + With the ``handleRequest()`` method, it is really easy to handle form submissions:: @@ -38,6 +42,9 @@ 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` @@ -83,3 +90,44 @@ method, pass the submitted data directly to submitted fields. To achieve this, you may pass an optional second boolean parameter to ``submit()``. Passing ``false`` will remove any missing fields within the form object. Otherwise, the mising fields will be set to ``null``. + +.. _cookbook-form-submit-request: + +Passing a Request to Form::submit() (Deprecated) +------------------------------------------------ + +.. versionadded:: 2.3 + 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->redirectToRoute('task_success'); + } + } + + return $this->render('AppBundle: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 15b77e804a2..bc6022ec772 100644 --- a/cookbook/form/dynamic_form_modification.rst +++ b/cookbook/form/dynamic_form_modification.rst @@ -57,6 +57,11 @@ a bare form class looks like:: 'data_class' => 'AppBundle\Entity\Product' )); } + + public function getName() + { + return 'product'; + } } .. note:: @@ -123,7 +128,7 @@ the event listener might look like the following:: // If no data is passed to the form, the data is "null". // This should be considered a new "Product" if (!$product || null === $product->getId()) { - $form->add('name', TextType::class); + $form->add('name', 'text'); } }); } @@ -173,7 +178,6 @@ class:: use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Component\EventDispatcher\EventSubscriberInterface; - use Symfony\Component\Form\Extension\Core\Type\TextType; class AddNameFieldSubscriber implements EventSubscriberInterface { @@ -190,7 +194,7 @@ class:: $form = $event->getForm(); if (!$product || null === $product->getId()) { - $form->add('name', TextType::class); + $form->add('name', 'text'); } } } @@ -220,21 +224,24 @@ Using an event listener, your form might look like this:: use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\FormEvent; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; - use Symfony\Component\Form\Extension\Core\Type\TextType; - use Symfony\Component\Form\Extension\Core\Type\TextareaType; class FriendMessageFormType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('subject', TextType::class) - ->add('body', TextareaType::class) + ->add('subject', 'text') + ->add('body', 'textarea') ; $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { // ... add a choice list of friends of the current application user }); } + + public function getName() + { + return 'app_friend_message'; + } } The problem is now to get the current user and create a choice field that @@ -270,10 +277,6 @@ and fill in the listener logic:: use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Doctrine\ORM\EntityRepository; - use Symfony\Component\Form\Extension\Core\Type\TextType; - use Symfony\Component\Form\Extension\Core\Type\TextareaType; - use Symfony\Bridge\Doctrine\Form\Type\EntityType; - // ... class FriendMessageFormType extends AbstractType @@ -288,8 +291,8 @@ and fill in the listener logic:: public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('subject', TextType::class) - ->add('body', TextareaType::class) + ->add('subject', 'text') + ->add('body', 'textarea') ; // grab the user, do a quick sanity check that one exists @@ -320,7 +323,7 @@ and fill in the listener logic:: // create the field, this is similar the $builder->add() // field name, field type, data, options - $form->add('friend', EntityType::class, $formOptions); + $form->add('friend', 'entity', $formOptions); } ); } @@ -328,16 +331,52 @@ and fill in the listener logic:: // ... } +.. versionadded:: 2.6 + The :class:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorageInterface` was + introduced in Symfony 2.6. Prior, you had to use the ``getToken()`` method of + :class:`Symfony\\Component\\Security\\Core\\SecurityContextInterface`. + .. note:: The ``multiple`` and ``expanded`` form options will default to false - because the type of the friend field is ``EntityType::class``. + because the type of the friend field is ``entity``. Using the Form ~~~~~~~~~~~~~~ -Our form is now ready to use. But first, because it has a ``__construct()`` method, -you need to register it as a service and tag it with :ref:`form.type `: +Our form is now ready to use and there are two possible ways to use it inside +of a controller: + +a) create it manually and remember to pass the token storage to it; + +or + +b) define it as a service. + +a) Creating the Form manually +............................. + +This is very simple, and is probably the better approach unless you're using +your new form type in many places or embedding it into other forms:: + + class FriendMessageController extends Controller + { + public function newAction(Request $request) + { + $tokenStorage = $this->container->get('security.token_storage'); + $form = $this->createForm( + new FriendMessageFormType($tokenStorage) + ); + + // ... + } + } + +b) Defining the Form as a Service +................................. + +To define your form as a service, just create a normal service and then tag +it with :ref:`dic-tags-form-type`. .. configuration-block:: @@ -349,7 +388,7 @@ you need to register it as a service and tag it with :ref:`form.type - + @@ -370,10 +409,15 @@ you need to register it as a service and tag it with :ref:`form.type addTag('form.type'); + $definition->addTag('form.type', array('alias' => 'app_friend_message')); $container->setDefinition('app.form.friend_message', $definition); +If you wish to create it from within a service that has access to the form factory, +you then use:: + + $form = $formFactory->create('friend_message'); + In a controller that extends the :class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller` class, you can simply call:: @@ -383,7 +427,7 @@ class, you can simply call:: { public function newAction(Request $request) { - $form = $this->createForm(FriendMessageFormType::class); + $form = $this->createForm('app_friend_message'); // ... } @@ -394,7 +438,7 @@ You can also easily embed the form type into another form:: // inside some other "form type" class public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->add('message', FriendMessageFormType::class); + $builder->add('message', 'app_friend_message'); } .. _cookbook-form-events-submitted-data: @@ -420,7 +464,6 @@ sport like this:: use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; - use Symfony\Bridge\Doctrine\Form\Type\EntityType; // ... class SportMeetupType extends AbstractType @@ -428,7 +471,7 @@ sport like this:: public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('sport', EntityType::class, array( + ->add('sport', 'entity', array( 'class' => 'AppBundle:Sport', 'placeholder' => '', )) @@ -445,7 +488,7 @@ sport like this:: $sport = $data->getSport(); $positions = null === $sport ? array() : $sport->getAvailablePositions(); - $form->add('position', EntityType::class, array( + $form->add('position', 'entity', array( 'class' => 'AppBundle:Position', 'placeholder' => '', 'choices' => $positions, @@ -457,6 +500,10 @@ sport like this:: // ... } +.. versionadded:: 2.6 + The ``placeholder`` option was introduced in Symfony 2.6 and replaces + ``empty_value``, which is available prior to 2.6. + When you're building this form to display to the user for the first time, then this example works perfectly. @@ -472,6 +519,10 @@ On a form, we can usually listen to the following events: * ``SUBMIT`` * ``POST_SUBMIT`` +.. versionadded:: 2.3 + The events ``PRE_SUBMIT``, ``SUBMIT`` and ``POST_SUBMIT`` were introduced + in Symfony 2.3. Before, they were named ``PRE_BIND``, ``BIND`` and ``POST_BIND``. + 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 @@ -484,7 +535,6 @@ The type would now look like:: // ... use Symfony\Component\Form\FormInterface; - use Symfony\Bridge\Doctrine\Form\Type\EntityType; use AppBundle\Entity\Sport; class SportMeetupType extends AbstractType @@ -492,7 +542,7 @@ The type would now look like:: public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('sport', EntityType::class, array( + ->add('sport', 'entity', array( 'class' => 'AppBundle:Sport', 'placeholder' => '', )); @@ -501,7 +551,7 @@ The type would now look like:: $formModifier = function (FormInterface $form, Sport $sport = null) { $positions = null === $sport ? array() : $sport->getAvailablePositions(); - $form->add('position', EntityType::class, array( + $form->add('position', 'entity', array( 'class' => 'AppBundle:Position', 'placeholder' => '', 'choices' => $positions, @@ -558,7 +608,7 @@ your application. Assume that you have a sport meetup creation controller:: public function createAction(Request $request) { $meetup = new SportMeetup(); - $form = $this->createForm(SportMeetupType::class, $meetup); + $form = $this->createForm(new SportMeetupType(), $meetup); $form->handleRequest($request); if ($form->isValid()) { // ... save the meetup, redirect etc. diff --git a/cookbook/form/form_collections.rst b/cookbook/form/form_collections.rst index b7cea09bba0..88226e4c3b3 100644 --- a/cookbook/form/form_collections.rst +++ b/cookbook/form/form_collections.rst @@ -99,6 +99,11 @@ Then, create a form class so that a ``Tag`` object can be modified by the user:: 'data_class' => 'AppBundle\Entity\Tag', )); } + + public function getName() + { + return 'tag'; + } } With this, you have enough to render a tag form by itself. But since the end @@ -106,7 +111,7 @@ goal is to allow the tags of a ``Task`` to be modified right inside the task form itself, create a form for the ``Task`` class. Notice that you embed a collection of ``TagType`` forms using the -:doc:`CollectionType ` field:: +:doc:`collection ` field type:: // src/AppBundle/Form/Type/TaskType.php namespace AppBundle\Form\Type; @@ -114,7 +119,6 @@ Notice that you embed a collection of ``TagType`` forms using the use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; - use Symfony\Component\Form\Extension\Core\Type\CollectionType; class TaskType extends AbstractType { @@ -122,9 +126,7 @@ Notice that you embed a collection of ``TagType`` forms using the { $builder->add('description'); - $builder->add('tags', CollectionType::class, array( - 'entry_type' => TagType::class - )); + $builder->add('tags', 'collection', array('type' => new TagType())); } public function configureOptions(OptionsResolver $resolver) @@ -133,9 +135,14 @@ Notice that you embed a collection of ``TagType`` forms using the 'data_class' => 'AppBundle\Entity\Task', )); } + + public function getName() + { + return 'task'; + } } -In your controller, you'll create a new form from the ``TaskType``:: +In your controller, you'll now initialize a new instance of ``TaskType``:: // src/AppBundle/Controller/TaskController.php namespace AppBundle\Controller; @@ -162,7 +169,7 @@ In your controller, you'll create a new form from the ``TaskType``:: $task->getTags()->add($tag2); // end dummy code - $form = $this->createForm(TaskType::class, $task); + $form = $this->createForm(new TaskType(), $task); $form->handleRequest($request); @@ -277,8 +284,8 @@ add the ``allow_add`` option to your collection field:: { $builder->add('description'); - $builder->add('tags', CollectionType::class, array( - 'entry_type' => TagType::class, + $builder->add('tags', 'collection', array( + 'type' => new TagType(), 'allow_add' => true, )); } @@ -446,7 +453,7 @@ Next, add a ``by_reference`` option to the ``tags`` field and set it to ``false` { // ... - $builder->add('tags', CollectionType::class, array( + $builder->add('tags', 'collection', array( // ... 'by_reference' => false, )); @@ -562,7 +569,7 @@ you will learn about next!). .. _cookbook-form-collections-remove: Allowing Tags to be Removed ---------------------------- +---------------------------- The next step is to allow the deletion of a particular item in the collection. The solution is similar to allowing tags to be added. @@ -576,7 +583,7 @@ Start by adding the ``allow_delete`` option in the form Type:: { // ... - $builder->add('tags', CollectionType::class, array( + $builder->add('tags', 'collection', array( // ... 'allow_delete' => true, )); @@ -689,7 +696,7 @@ the relationship between the removed ``Tag`` and ``Task`` object. $originalTags->add($tag); } - $editForm = $this->createForm(TaskType::class, $task); + $editForm = $this->createForm(new TaskType(), $task); $editForm->handleRequest($request); diff --git a/cookbook/form/form_customization.rst b/cookbook/form/form_customization.rst index 7f4de2a0721..e5ab6035a29 100644 --- a/cookbook/form/form_customization.rst +++ b/cookbook/form/form_customization.rst @@ -101,7 +101,7 @@ rendering a form. In other words, if you want to customize one portion of how a form is rendered, you'll import a *theme* which contains a customization of the appropriate form fragments. -Symfony comes with some **built-in form themes** that define each and every +Symfony comes with four **built-in form themes** that define each and every fragment needed to render every part of a form: * `form_div_layout.html.twig`_, wraps each form field inside a ``
    `` element. @@ -113,9 +113,6 @@ fragment needed to render every part of a form: * `bootstrap_3_horizontal_layout.html.twig`_, it's similar to the previous theme, but the CSS classes applied are the ones used to display the forms horizontally (i.e. the label and the widget in the same row). -* `foundation_5_layout.html.twig`_, wraps each form field inside a ``
    `` element - with the appropriate CSS classes to apply the default `Foundation CSS framework`_ - styles. .. caution:: @@ -211,9 +208,6 @@ this folder. In this example, the customized fragment name is ``integer_widget`` because you want to override the HTML ``widget`` for all ``integer`` field types. If you need to customize ``textarea`` fields, you would customize ``textarea_widget``. - - The ``integer`` part comes from the class name: ``IntegerType`` becomes ``integer``, - based on a standard. As you can see, the fragment name is a combination of the field type and which part of the field is being rendered (e.g. ``widget``, ``label``, @@ -711,13 +705,12 @@ field whose *id* is ``product_name`` (and name is ``product[name]``). form type:: use Symfony\Component\Form\FormBuilderInterface; - use Symfony\Component\Form\Extension\Core\Type\TextType; public function buildForm(FormBuilderInterface $builder, array $options) { // ... - $builder->add('name', TextType::class, array( + $builder->add('name', 'text', array( 'block_name' => 'custom_name', )); } @@ -1147,5 +1140,3 @@ more details about this concept in Twig, see :ref:`twig-reference-form-variables .. _`bootstrap_3_layout.html.twig`: https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig .. _`bootstrap_3_horizontal_layout.html.twig`: https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_horizontal_layout.html.twig .. _`Bootstrap 3 CSS framework`: http://getbootstrap.com/ -.. _`foundation_5_layout.html.twig`: https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig -.. _`Foundation CSS framework`: http://foundation.zurb.com/ diff --git a/cookbook/form/inherit_data_option.rst b/cookbook/form/inherit_data_option.rst index 4f0ff9a6839..7429baae325 100644 --- a/cookbook/form/inherit_data_option.rst +++ b/cookbook/form/inherit_data_option.rst @@ -4,6 +4,10 @@ How to Reduce Code Duplication with "inherit_data" ================================================== +.. versionadded:: 2.3 + This ``inherit_data`` option was introduced in Symfony 2.3. Before, it + was known as ``virtual``. + 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``:: @@ -48,15 +52,14 @@ Start with building two forms for these entities, ``CompanyType`` and ``Customer use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; - use Symfony\Component\Form\Extension\Core\Type\TextType; class CompanyType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('name', TextType::class) - ->add('website', TextType::class); + ->add('name', 'text') + ->add('website', 'text'); } } @@ -67,15 +70,14 @@ Start with building two forms for these entities, ``CompanyType`` and ``Customer use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\AbstractType; - use Symfony\Component\Form\Extension\Core\Type\TextType; class CustomerType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('firstName', TextType::class) - ->add('lastName', TextType::class); + ->add('firstName', 'text') + ->add('lastName', 'text'); } } @@ -89,18 +91,16 @@ for that:: use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; - use Symfony\Component\Form\Extension\Core\Type\TextareaType; - use Symfony\Component\Form\Extension\Core\Type\TextType; class LocationType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('address', TextareaType::class) - ->add('zipcode', TextType::class) - ->add('city', TextType::class) - ->add('country', TextType::class); + ->add('address', 'textarea') + ->add('zipcode', 'text') + ->add('city', 'text') + ->add('country', 'text'); } public function configureOptions(OptionsResolver $resolver) @@ -109,6 +109,11 @@ for that:: 'inherit_data' => true )); } + + public function getName() + { + return 'location'; + } } The location form has an interesting option set, namely ``inherit_data``. This @@ -130,7 +135,7 @@ Finally, make this work by adding the location form to your two original forms:: { // ... - $builder->add('foo', LocationType::class, array( + $builder->add('foo', new LocationType(), array( 'data_class' => 'AppBundle\Entity\Company' )); } @@ -142,7 +147,7 @@ Finally, make this work by adding the location form to your two original forms:: { // ... - $builder->add('bar', LocationType::class, array( + $builder->add('bar', new LocationType(), array( 'data_class' => 'AppBundle\Entity\Customer' )); } diff --git a/cookbook/form/unit_testing.rst b/cookbook/form/unit_testing.rst index 1fe851f293b..6ab99830165 100644 --- a/cookbook/form/unit_testing.rst +++ b/cookbook/form/unit_testing.rst @@ -20,6 +20,11 @@ There is already a class that you can benefit from for simple FormTypes 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. +.. 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``. + .. note:: Depending on the way you installed your Symfony or Symfony Form component @@ -31,8 +36,8 @@ The Basics The simplest ``TypeTestCase`` implementation looks like the following:: - // tests/AppBundle/Form/Type/TestedTypeTest.php - namespace Tests\AppBundle\Form\Type; + // src/AppBundle/Tests/Form/Type/TestedTypeTest.php + namespace AppBundle\Tests\Form\Type; use AppBundle\Form\Type\TestedType; use AppBundle\Model\TestObject; @@ -47,7 +52,8 @@ The simplest ``TypeTestCase`` implementation looks like the following:: 'test2' => 'test2', ); - $form = $this->factory->create(TestedType::class); + $type = new TestedType(); + $form = $this->factory->create($type); $object = TestObject::fromArray($formData); @@ -72,7 +78,8 @@ First you verify if the ``FormType`` compiles. This includes basic class inheritance, the ``buildForm`` function and options resolution. This should be the first test you write:: - $form = $this->factory->create(TestedType::class); + $type = new TestedType(); + $form = $this->factory->create($type); This test checks that none of your data transformers used by the form failed. The :method:`Symfony\\Component\\Form\\FormInterface::isSynchronized` @@ -102,57 +109,55 @@ widgets you want to display are available in the children property:: $this->assertArrayHasKey($key, $children); } -Testings Types from the Service Container ------------------------------------------ +Adding a Type your Form Depends on +---------------------------------- + +Your form may depend on other types that are defined as services. It +might look like this:: + + // src/AppBundle/Form/Type/TestedType.php -Your form may be used as a service, as it depends on other services (e.g. the -Doctrine entity manager). In these cases, using the above code won't work, as -the Form component just instantiates the form type without passing any -arguments to the constructor. + // ... the buildForm method + $builder->add('app_test_child_type'); -To solve this, you have to mock the injected dependencies, instantiate your own -form type and use the :class:`Symfony\\Component\\Form\\PreloadedExtension` to -make sure the ``FormRegistry`` uses the created instance:: +To create your form correctly, you need to make the type available to the +form factory in your test. The easiest way is to register it manually +before creating the parent form using the ``PreloadedExtension`` class:: - // tests/AppBundle/Form/Type/TestedTypeTests.php - namespace Tests\AppBundle\Form\Type; + // src/AppBundle/Tests/Form/Type/TestedTypeTests.php + namespace AppBundle\Tests\Form\Type; + use AppBundle\Form\Type\TestedType; + use AppBundle\Model\TestObject; + use Symfony\Component\Form\Test\TypeTestCase; use Symfony\Component\Form\PreloadedExtension; - // ... class TestedTypeTest extends TypeTestCase { - private $entityManager; - - protected function setUp() - { - // mock any dependencies - $this->entityManager = $this->getMock('Doctrine\Common\Persistence\ObjectManager'); - - parent::setUp(); - } - protected function getExtensions() { - // create a type instance with the mocked dependencies - $type = new TestedType($this->entityManager); + $childType = new TestChildType(); - return array( - // register the type instances with the PreloadedExtension - new PreloadedExtension(array($type), array()), - ); + return array(new PreloadedExtension(array( + $childType->getName() => $childType, + ), array())); } public function testSubmitValidData() { - // Instead of creating a new instance, the one created in - // getExtensions() will be used. - $form = $this->factory->create(TestedType::class); + $type = new TestedType(); + $form = $this->factory->create($type); // ... your test } } +.. caution:: + + Make sure the child type you add is well tested. Otherwise you may + be getting errors that are not related to the form you are currently + testing but to its children. + Adding Custom Extensions ------------------------ @@ -165,28 +170,26 @@ will be raised if you try to test a class that depends on other extensions. The :method:`Symfony\\Component\\Form\\Test\\TypeTestCase::getExtensions` method allows you to return a list of extensions to register:: - // tests/AppBundle/Form/Type/TestedTypeTests.php - namespace Tests\AppBundle\Form\Type; + // src/AppBundle/Tests/Form/Type/TestedTypeTests.php + namespace AppBundle\Tests\Form\Type; - // ... + use AppBundle\Form\Type\TestedType; + use AppBundle\Model\TestObject; use Symfony\Component\Form\Extension\Validator\ValidatorExtension; + use Symfony\Component\Form\Forms; + use Symfony\Component\Form\FormBuilder; + use Symfony\Component\Form\Test\TypeTestCase; use Symfony\Component\Validator\ConstraintViolationList; class TestedTypeTest extends TypeTestCase { - private $validator; - protected function getExtensions() { - $this->validator = $this->getMock( - 'Symfony\Component\Validator\Validator\ValidatorInterface' - ); - $this->validator - ->method('validate') - ->will($this->returnValue(new ConstraintViolationList())); + $validator = $this->getMock('\Symfony\Component\Validator\Validator\ValidatorInterface'); + $validator->method('validate')->will($this->returnValue(new ConstraintViolationList())); return array( - new ValidatorExtension($this->validator), + new ValidatorExtension($validator), ); } @@ -199,8 +202,8 @@ Testing against Different Sets of Data If you are not familiar yet with PHPUnit's `data providers`_, this might be a good opportunity to use them:: - // tests/AppBundle/Form/Type/TestedTypeTests.php - namespace Tests\AppBundle\Form\Type; + // src/AppBundle/Tests/Form/Type/TestedTypeTests.php + namespace AppBundle\Tests\Form\Type; use AppBundle\Form\Type\TestedType; use AppBundle\Model\TestObject; @@ -208,6 +211,7 @@ a good opportunity to use them:: class TestedTypeTest extends TypeTestCase { + /** * @dataProvider getValidTestData */ diff --git a/cookbook/form/use_empty_data.rst b/cookbook/form/use_empty_data.rst index 79026a573f0..7bbe95b633a 100644 --- a/cookbook/form/use_empty_data.rst +++ b/cookbook/form/use_empty_data.rst @@ -15,11 +15,11 @@ your form. For example:: // $blog is passed in as the data, so the empty_data // option is not needed - $form = $this->createForm(BlogType::class, $blog); + $form = $this->createForm(new BlogType(), $blog); // no data is passed in, so empty_data is // used to get the "starting data" - $form = $this->createForm(BlogType::class); + $form = $this->createForm(new BlogType()); } By default, ``empty_data`` is set to ``null``. Or, if you have specified @@ -41,7 +41,7 @@ that constructor with no arguments:: // ... use Symfony\Component\Form\AbstractType; use AppBundle\Entity\Blog; - use Symfony\Component\OptionsResolver\OptionsResolver; + use Symfony\Component\OptionsResolver\OptionsResolverInterface; class BlogType extends AbstractType { @@ -53,7 +53,7 @@ that constructor with no arguments:: } // ... - public function configureOptions(OptionsResolver $resolver) + public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( 'empty_data' => new Blog($this->someDependency), @@ -61,14 +61,10 @@ that constructor with no arguments:: } } -You can instantiate your class however you want. In this example, you pass -some dependency into the ``BlogType`` then use that to instantiate the ``Blog`` class. -The point is, you can set ``empty_data`` to the exact "new" object that you want to use. - -.. tip:: - - In order to pass arguments to the ``BlogType`` constructor, you'll need to - :ref:`register it as a service and tag with form.type `. +You can instantiate your class however you want. In this example, we pass +some dependency into the ``BlogType`` when we instantiate it, then use that +to instantiate the ``Blog`` class. The point is, you can set ``empty_data`` +to the exact "new" object that you want to use. Option 2: Provide a Closure --------------------------- @@ -78,11 +74,11 @@ if it is needed. The closure must accept a ``FormInterface`` instance as the first argument:: - use Symfony\Component\OptionsResolver\OptionsResolver; + use Symfony\Component\OptionsResolver\OptionsResolverInterface; use Symfony\Component\Form\FormInterface; // ... - public function configureOptions(OptionsResolver $resolver) + public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( 'empty_data' => function (FormInterface $form) { diff --git a/cookbook/form/use_virtuals_forms.rst b/cookbook/form/use_virtuals_forms.rst index b6f75063795..0de48e6ecb7 100644 --- a/cookbook/form/use_virtuals_forms.rst +++ b/cookbook/form/use_virtuals_forms.rst @@ -1,8 +1,5 @@ How to Use the virtual Form Field Option ======================================== -.. caution:: - - 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`". +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 ba0f13c6fc1..5d5a2797c3f 100644 --- a/cookbook/index.rst +++ b/cookbook/index.rst @@ -16,7 +16,6 @@ The Cookbook doctrine/index email/index event_dispatcher/index - expression/index form/index frontend/index install/index @@ -29,6 +28,7 @@ The Cookbook service_container/index session/index psr7 + symfony1 templating/index testing/index upgrade/index diff --git a/cookbook/logging/channels_handlers.rst b/cookbook/logging/channels_handlers.rst index 58ad102a7c7..870c342c585 100644 --- a/cookbook/logging/channels_handlers.rst +++ b/cookbook/logging/channels_handlers.rst @@ -125,7 +125,8 @@ specified. Configure Additional Channels without Tagged Services ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can also configure additional channels without the need to tag your services: +With MonologBundle 2.4 you can configure additional channels without the +need to tag your services: .. configuration-block:: diff --git a/cookbook/logging/index.rst b/cookbook/logging/index.rst index 2570b3d5627..dda7d7cafdd 100644 --- a/cookbook/logging/index.rst +++ b/cookbook/logging/index.rst @@ -6,6 +6,5 @@ Logging monolog monolog_email - monolog_console monolog_regex_based_excludes channels_handlers diff --git a/cookbook/logging/monolog.rst b/cookbook/logging/monolog.rst index f08f934e3e2..376bf5affba 100644 --- a/cookbook/logging/monolog.rst +++ b/cookbook/logging/monolog.rst @@ -23,7 +23,8 @@ your controller:: } The ``logger`` service has different methods for different logging levels. -See LoggerInterface_ for details on which methods are available. +See :class:`Symfony\\Component\\HttpKernel\\Log\\LoggerInterface` for details +on which methods are available. Handlers and Channels: Writing Logs to different Locations ---------------------------------------------------------- @@ -39,8 +40,8 @@ to write the logs (the handlers can be shared). the logger will log to. The basic handler is the ``StreamHandler`` which writes logs in a stream -(by default in the ``var/logs/prod.log`` in the prod environment and -``var/logs/dev.log`` in the dev environment). +(by default in the ``app/logs/prod.log`` in the prod environment and +``app/logs/dev.log`` in the dev environment). Monolog comes also with a powerful built-in handler for the logging in prod environment: ``FingersCrossedHandler``. It allows you to store the @@ -538,6 +539,5 @@ the ``monolog.processor`` tag: ->addArgument(new Reference('session')) ->addTag('monolog.processor', array('method' => 'processRecord', 'channel' => 'main')); -.. _Monolog: https://github.com/Seldaek/monolog -.. _LoggerInterface: https://github.com/php-fig/log/blob/master/Psr/Log/LoggerInterface.php +.. _`Monolog`: https://github.com/Seldaek/monolog .. _`logrotate`: https://fedorahosted.org/logrotate/ diff --git a/cookbook/logging/monolog_console.rst b/cookbook/logging/monolog_console.rst index 22b2144f2f4..f3cddb9a890 100644 --- a/cookbook/logging/monolog_console.rst +++ b/cookbook/logging/monolog_console.rst @@ -58,7 +58,8 @@ the console. If they are displayed, they are timestamped and colored appropriate Additionally, error logs are written to the error output (php://stderr). There is no need to conditionally handle the verbosity settings anymore. -The Monolog console handler is enabled in the Monolog configuration. +The Monolog console handler is enabled in the Monolog configuration. This is +the default in Symfony Standard Edition 2.4 too. .. configuration-block:: diff --git a/cookbook/logging/monolog_email.rst b/cookbook/logging/monolog_email.rst index 3d2bed7d1e7..f23f0510cc6 100644 --- a/cookbook/logging/monolog_email.rst +++ b/cookbook/logging/monolog_email.rst @@ -139,6 +139,14 @@ to and from addresses and the subject. You can combine these handlers with other handlers so that the errors still get logged on the server as well as the emails being sent: +.. caution:: + + The default spool setting for swiftmailer is set to ``memory``, which + means that emails are sent at the very end of the request. However, this + does not work with buffered logs at the moment. In order to enable emailing + logs per the example below, you must comment out the ``spool: { type: memory }`` + line in the ``config.yml`` file. + .. configuration-block:: .. code-block:: yaml diff --git a/cookbook/logging/monolog_regex_based_excludes.rst b/cookbook/logging/monolog_regex_based_excludes.rst index 1c9b000a59f..f7f02d51131 100644 --- a/cookbook/logging/monolog_regex_based_excludes.rst +++ b/cookbook/logging/monolog_regex_based_excludes.rst @@ -6,6 +6,11 @@ How to Configure Monolog to Exclude 404 Errors from the Log =========================================================== +.. versionadded:: 2.3 + This feature was introduced to the MonologBundle in version 2.4. This + version is compatible with Symfony 2.3, but only MonologBundle 2.3 is + installed by default. To use this feature, upgrade your bundle manually. + Sometimes your logs become flooded with unwanted 404 HTTP errors, for example, when an attacker scans your app for some well-known application paths (e.g. `/phpmyadmin`). When using a ``fingers_crossed`` handler, you can exclude diff --git a/cookbook/map.rst.inc b/cookbook/map.rst.inc index dac8ec5c77d..65276f9a4a5 100644 --- a/cookbook/map.rst.inc +++ b/cookbook/map.rst.inc @@ -30,7 +30,6 @@ * :doc:`/cookbook/configuration/index` * :doc:`/cookbook/configuration/environments` - * :doc:`/cookbook/configuration/micro-kernel-trait` * :doc:`/cookbook/configuration/override_dir_structure` * :doc:`/cookbook/configuration/using_parameters_in_dic` * :doc:`/cookbook/configuration/front_controllers_and_kernel` @@ -165,7 +164,6 @@ * :doc:`/cookbook/security/form_login_setup` * :doc:`/cookbook/security/entity_provider` - * :doc:`/cookbook/security/guard-authentication` * :doc:`/cookbook/security/remember_me` * :doc:`/cookbook/security/impersonating_user` * :doc:`/cookbook/security/form_login` @@ -178,10 +176,8 @@ * :doc:`/cookbook/security/csrf_in_login_form` * :doc:`/cookbook/security/named_encoders` * :doc:`/cookbook/security/multiple_user_providers` - * :doc:`/cookbook/security/multiple_guard_authenticators` * :doc:`/cookbook/security/firewall_restriction` * :doc:`/cookbook/security/host_restriction` - * :doc:`/cookbook/security/user_checkers` * :doc:`Security Authorization (Denying Access) ` @@ -198,7 +194,7 @@ * :doc:`/cookbook/service_container/index` - * :doc:`/cookbook/service_container/shared` + * :doc:`/cookbook/service_container/scopes` * :doc:`/cookbook/service_container/compiler_passes` * (Event Dispatcher) :doc:`/cookbook/event_dispatcher/event_listener` @@ -218,6 +214,10 @@ * :doc:`/cookbook/psr7` +* **symfony1** + + * :doc:`/cookbook/symfony1` + * :doc:`/cookbook/templating/index` * :doc:`/cookbook/templating/global_variables` diff --git a/cookbook/profiler/matchers.rst b/cookbook/profiler/matchers.rst index 600883cc41d..a7ff6bb4e6f 100644 --- a/cookbook/profiler/matchers.rst +++ b/cookbook/profiler/matchers.rst @@ -83,25 +83,30 @@ matcher:: // src/AppBundle/Profiler/SuperAdminMatcher.php namespace AppBundle\Profiler; - use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; + use Symfony\Component\Security\Core\SecurityContext; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestMatcherInterface; class SuperAdminMatcher implements RequestMatcherInterface { - protected $authorizationChecker; + protected $securityContext; - public function __construct(AuthorizationCheckerInterface $authorizationChecker) + public function __construct(SecurityContext $securityContext) { - $this->authorizationChecker = $authorizationChecker; + $this->securityContext = $securityContext; } public function matches(Request $request) { - return $this->authorizationChecker->isGranted('ROLE_SUPER_ADMIN'); + return $this->securityContext->isGranted('ROLE_SUPER_ADMIN'); } } +.. versionadded:: 2.6 + The :class:`Symfony\\Component\\Security\\Core\\Authorization\\AuthorizationCheckerInterface` was + introduced in Symfony 2.6. Prior, you had to use the ``isGranted`` method of + :class:`Symfony\\Component\\Security\\Core\\SecurityContextInterface`. + Then, configure a new service and set it as ``private`` because the application won't use it directly: @@ -113,16 +118,16 @@ won't use it directly: services: app.super_admin_matcher: class: AppBundle\Profiler\SuperAdminMatcher - arguments: ['@security.authorization_checker'] + arguments: ['@security.context'] public: false .. code-block:: xml - - + .. code-block:: php @@ -133,12 +138,16 @@ won't use it directly: $definition = new Definition( 'AppBundle\Profiler\SuperAdminMatcher', - array(new Reference('security.authorization_checker')) + array(new Reference('security.context')) ); $definition->setPublic(false); $container->setDefinition('app.super_admin_matcher', $definition); +.. versionadded:: 2.6 + The ``security.authorization_checker`` service was introduced in Symfony 2.6. Prior + to Symfony 2.6, you had to use the ``isGranted()`` method of the ``security.context`` service. + Once the service is registered, the only thing left to do is configure the profiler to use this service as the matcher: diff --git a/cookbook/profiler/profiling_data.rst b/cookbook/profiler/profiling_data.rst index bb87bbf8cd7..761dae943e6 100644 --- a/cookbook/profiler/profiling_data.rst +++ b/cookbook/profiler/profiling_data.rst @@ -53,10 +53,10 @@ one where the information was generated, use the ``profiler:export`` and .. code-block:: bash # on the production machine - $ php bin/console profiler:export > profile.data + $ php app/console profiler:export > profile.data # on the development machine - $ php bin/console profiler:import /path/to/profile.data + $ php app/console profiler:import /path/to/profile.data # you can also pipe from the STDIN - $ cat /path/to/profile.data | php bin/console profiler:import + $ cat /path/to/profile.data | php app/console profiler:import diff --git a/cookbook/profiler/storage.rst b/cookbook/profiler/storage.rst index f0a330f2da6..37463ae6fee 100644 --- a/cookbook/profiler/storage.rst +++ b/cookbook/profiler/storage.rst @@ -4,13 +4,10 @@ Switching the Profiler Storage ============================== -In Symfony versions prior to 3.0, profiles could be stored in files, databases, -services like Redis and Memcache, etc. Starting from Symfony 3.0, the only storage -mechanism with built-in support is the filesystem. - -By default the profile stores the collected data in the ``%kernel.cache_dir%/profiler/`` -directory. If you want to use another location to store the profiles, define the -``dsn`` option of the ``framework.profiler``: +By default the profile stores the collected data in files in the ``%kernel.cache_dir%/profiler/`` directory. +You can control the storage being used through the ``dsn``, ``username``, +``password`` and ``lifetime`` options. For example, the following configuration +uses MySQL as the storage for the profiler with a lifetime of one hour: .. configuration-block:: @@ -19,7 +16,10 @@ directory. If you want to use another location to store the profiles, define the # app/config/config.yml framework: profiler: - dsn: 'file:/tmp/symfony/profiler' + dsn: 'mysql:host=localhost;dbname=%database_name%' + username: '%database_user%' + password: '%database_password%' + lifetime: 3600 .. code-block:: xml @@ -34,7 +34,12 @@ directory. If you want to use another location to store the profiles, define the http://symfony.com/schema/dic/symfony/symfony-1.0.xsd" > - + @@ -45,10 +50,20 @@ directory. If you want to use another location to store the profiles, define the // ... $container->loadFromExtension('framework', array( 'profiler' => array( - 'dsn' => 'file:/tmp/symfony/profiler', + 'dsn' => 'mysql:host=localhost;dbname=%database_name%', + 'username' => '%database_user', + 'password' => '%database_password%', + 'lifetime' => 3600, ), )); -You can also create your own profile storage service implementing the -:class:``Symfony\Component\HttpKernel\Profiler\ProfilerStorageInterface`` and -overriding the ``profiler.storage`` service. +The :doc:`HttpKernel component ` currently +supports the following profiler storage drivers: + +* file +* sqlite +* mysql +* mongodb +* memcache +* memcached +* redis diff --git a/cookbook/request/load_balancer_reverse_proxy.rst b/cookbook/request/load_balancer_reverse_proxy.rst index f5e2c9f4196..343c9c35fa8 100644 --- a/cookbook/request/load_balancer_reverse_proxy.rst +++ b/cookbook/request/load_balancer_reverse_proxy.rst @@ -13,6 +13,9 @@ will now be the IP address of your reverse proxy), the user's true IP will be stored in a standard ``Forwarded: for="..."`` header or a non standard ``X-Forwarded-For`` header. +.. versionadded:: 2.7 + ``Forwarded`` header support was introduced in Symfony 2.7. + If you don't configure Symfony to look for these headers, you'll get incorrect information about the client's IP address, whether or not the client is connecting via HTTPS, the client's port and the hostname being requested. diff --git a/cookbook/request/mime_type.rst b/cookbook/request/mime_type.rst index 269156654c3..a16d8c15844 100644 --- a/cookbook/request/mime_type.rst +++ b/cookbook/request/mime_type.rst @@ -15,104 +15,81 @@ object. Internally, Symfony contains a map of the most common formats (e.g. easily be added. This document will show how you can add the ``jsonp`` format and corresponding MIME type. -Configure your New Format -------------------------- +Create a ``kernel.request`` Listener +------------------------------------- + +The key to defining a new MIME type is to create a class that will "listen" to +the ``kernel.request`` event dispatched by the Symfony kernel. The +``kernel.request`` event is dispatched early in Symfony's request handling +process and allows you to modify the request object. + +Create the following class, replacing the path with a path to a bundle in your +project:: -The FrameworkBundle registers a subscriber that will add formats to incoming requests. + // src/AppBundle/EventListener/RequestListener.php + namespace AppBundle\EventListener; -All you have to do is to configure the ``jsonp`` format: + use Symfony\Component\HttpKernel\HttpKernelInterface; + use Symfony\Component\HttpKernel\Event\GetResponseEvent; + + class RequestListener + { + public function onKernelRequest(GetResponseEvent $event) + { + $event->getRequest()->setFormat('jsonp', 'application/javascript'); + } + } + +Registering your Listener +------------------------- + +As with any other listener, you need to add it in one of your configuration +files and register it as a listener by adding the ``kernel.event_listener`` tag: .. configuration-block:: .. code-block:: yaml - # app/config/config.yml - framework: - request: - formats: - jsonp: 'application/javascript' + # app/config/services.yml + services: + app.listener.request: + class: AppBundle\EventListener\RequestListener + tags: + - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest } .. code-block:: xml - - - + + - - - - application/javascript - - - + xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> + + + + + .. code-block:: php - // app/config/config.php - $container->loadFromExtension('framework', array( - 'request' => array( - 'formats' => array( - 'jsonp' => 'application/javascript', - ), - ), + # app/config/services.php + $definition = new Definition('AppBundle\EventListener\RequestListener'); + $definition->addTag('kernel.event_listener', array( + 'event' => 'kernel.request', + 'method' => 'onKernelRequest', )); + $container->setDefinition('app.listener.request', $definition); + +At this point, the ``app.listener.request`` service has been +configured and will be notified when the Symfony kernel dispatches the +``kernel.request`` event. .. tip:: - You can also associate multiple mime types to a format, but please note that - the preferred one must be the first as it will be used as the content type: - - .. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - framework: - request: - formats: - csv: ['text/csv', 'text/plain'] - - .. code-block:: xml - - - - - - - - - text/csv - text/plain - - - - - - .. code-block:: php - - // app/config/config.php - $container->loadFromExtension('framework', array( - 'request' => array( - 'formats' => array( - 'jsonp' => array( - 'text/csv', - 'text/plain', - ), - ), - ), - )); + You can also register the listener in a configuration extension class (see + :ref:`service-container-extension-configuration` for more information). diff --git a/cookbook/routing/method_parameters.rst b/cookbook/routing/method_parameters.rst index 5151f3eafe9..be270240dd2 100644 --- a/cookbook/routing/method_parameters.rst +++ b/cookbook/routing/method_parameters.rst @@ -74,17 +74,19 @@ delete it by matching on GET, PUT and DELETE. Faking the Method with ``_method`` ---------------------------------- -Unfortunately, life isn't quite this simple, since most browsers do not support -sending PUT and DELETE requests via the ``method`` attribute in an HTML form. -Fortunately, Symfony 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, Symfony will 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. - .. note:: - This feature can be disabled using the - :ref:`configuration-framework-http_method_override` option. + 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 via the `method` attribute in an HTML form. Fortunately, +Symfony 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, Symfony +will 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/security/_ircmaxwell_password-compat.rst.inc b/cookbook/security/_ircmaxwell_password-compat.rst.inc new file mode 100644 index 00000000000..b8f0f1d021d --- /dev/null +++ b/cookbook/security/_ircmaxwell_password-compat.rst.inc @@ -0,0 +1,8 @@ +.. caution:: + + If you're using PHP 5.4 or lower, you'll need to install the ``ircmaxell/password-compat`` + library via Composer in order to be able to use the ``bcrypt`` encoder: + + .. code-block:: bash + + $ composer require ircmaxell/password-compat "~1.0" diff --git a/cookbook/security/_supportsToken.rst.inc b/cookbook/security/_supportsToken.rst.inc deleted file mode 100644 index aede5833cfb..00000000000 --- a/cookbook/security/_supportsToken.rst.inc +++ /dev/null @@ -1,10 +0,0 @@ -After Symfony calls ``createToken()``, it will then call ``supportsToken()`` -on your class (and any other authentication listeners) to figure out who should -handle the token. This is just a way to allow several authentication mechanisms -to be used for the same firewall (that way, you can for instance first try -to authenticate the user via a certificate or an API key and fall back to -a form login). - -Mostly, you just need to make sure that this method returns ``true`` for a -token that has been created by ``createToken()``. Your logic should probably -look exactly like this example. diff --git a/cookbook/security/access_control.rst b/cookbook/security/access_control.rst index 00b73837be6..07ea923651b 100644 --- a/cookbook/security/access_control.rst +++ b/cookbook/security/access_control.rst @@ -128,15 +128,13 @@ will match any ``ip``, ``host`` or ``method``: --------------------- Once Symfony has decided which ``access_control`` entry matches (if any), -it then *enforces* access restrictions based on the ``roles``, ``allow_if`` and ``requires_channel`` +it then *enforces* access restrictions based on the ``roles`` and ``requires_channel`` options: * ``role`` If the user does not have the given role(s), then access is denied (internally, an :class:`Symfony\\Component\\Security\\Core\\Exception\\AccessDeniedException` is thrown); -* ``allow_if`` If the expression returns false, then access is denied; - * ``requires_channel`` If the incoming request's channel (e.g. ``http``) does not match this value (e.g. ``https``), the user will be redirected (e.g. redirected from ``http`` to ``https``, or vice versa). @@ -241,55 +239,6 @@ address): * The second access rule is not examined as the first rule matched. -.. _book-security-allow-if: - -Securing by an Expression -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Once an ``access_control`` entry is matched, you can deny access via the -``roles`` key or use more complex logic with an expression in the ``allow_if`` -key: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/security.yml - security: - # ... - access_control: - - - path: ^/_internal/secure - allow_if: "'127.0.0.1' == request.getClientIp() or has_role('ROLE_ADMIN')" - - .. code-block:: xml - - - - - - .. code-block:: php - - 'access_control' => array( - array( - 'path' => '^/_internal/secure', - 'allow_if' => '"127.0.0.1" == request.getClientIp() or has_role("ROLE_ADMIN")', - ), - ), - -In this case, when the user tries to access any URL starting with ``/_internal/secure``, -they will only be granted access if the IP address is ``127.0.0.1`` or if -the user has the ``ROLE_ADMIN`` role. - -Inside the expression, you have access to a number of different variables -and functions including ``request``, which is the Symfony -:class:`Symfony\\Component\\HttpFoundation\\Request` object (see -:ref:`component-http-foundation-request`). - -For a list of the other functions and variables, see -:ref:`functions and variables `. - .. _book-security-securing-channel: Forcing a Channel (http, https) diff --git a/cookbook/security/acl.rst b/cookbook/security/acl.rst index df3b936b3f0..057ec39aca5 100644 --- a/cookbook/security/acl.rst +++ b/cookbook/security/acl.rst @@ -96,7 +96,7 @@ Fortunately, there is a task for this. Simply run the following command: .. code-block:: bash - $ php bin/console init:acl + $ php app/console init:acl Getting Started --------------- @@ -143,8 +143,8 @@ Creating an ACL and Adding an ACE $acl = $aclProvider->createAcl($objectIdentity); // retrieving the security identity of the currently logged-in user - $tokenStorage = $this->get('security.token_storage'); - $user = $tokenStorage->getToken()->getUser(); + $securityContext = $this->get('security.context'); + $user = $securityContext->getToken()->getUser(); $securityIdentity = UserSecurityIdentity::fromAccount($user); // grant owner access @@ -191,10 +191,10 @@ Checking Access public function editCommentAction(Comment $comment) { - $authorizationChecker = $this->get('security.authorization_checker'); + $securityContext = $this->get('security.context'); // check for edit access - if (false === $authorizationChecker->isGranted('EDIT', $comment)) { + if (false === $securityContext->isGranted('EDIT', $comment)) { throw new AccessDeniedException(); } diff --git a/cookbook/security/acl_advanced.rst b/cookbook/security/acl_advanced.rst index 13f3636076a..d4f18265d82 100644 --- a/cookbook/security/acl_advanced.rst +++ b/cookbook/security/acl_advanced.rst @@ -45,14 +45,6 @@ Security Identities This is analog to the object identity, but represents a user, or a role in your application. Each role, or user has its own security identity. -.. caution:: - - For users, the security identity is based on the username. This means that, - if for any reason, a user's username was to change, you must ensure its - security identity is updated too. The - :method:`MutableAclProvider::updateUserSecurityIdentity() ` - method is there to handle the update. - Database Table Structure ------------------------ diff --git a/cookbook/security/api_key_authentication.rst b/cookbook/security/api_key_authentication.rst index c7e66d256e3..745a5792830 100644 --- a/cookbook/security/api_key_authentication.rst +++ b/cookbook/security/api_key_authentication.rst @@ -4,11 +4,6 @@ How to Authenticate Users with API Keys ======================================= -.. tip:: - - Check out :doc:`/cookbook/security/guard-authentication` for a simpler and more - flexible way to accomplish custom authentication tasks like this. - Nowadays, it's quite usual to authenticate the user via an API key (when developing a web service for instance). The API key is provided for every request and is passed as a query string parameter or via an HTTP header. @@ -17,7 +12,7 @@ The API Key Authenticator ------------------------- Authenticating a user based on the Request information should be done via a -pre-authentication mechanism. The :class:`Symfony\\Component\\Security\\Http\\Authentication\\SimplePreAuthenticatorInterface` +pre-authentication mechanism. The :class:`Symfony\\Component\\Security\\Core\\Authentication\\SimplePreAuthenticatorInterface` allows you to implement such a scheme really easily. Your exact situation may differ, but in this example, a token is read @@ -27,14 +22,13 @@ value and then a User object is created:: // src/AppBundle/Security/ApiKeyAuthenticator.php namespace AppBundle\Security; - use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken; + use Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; - use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException; - use Symfony\Component\Security\Core\Exception\BadCredentialsException; + use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken; + use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\User\UserProviderInterface; - use Symfony\Component\Security\Http\Authentication\SimplePreAuthenticatorInterface; + use Symfony\Component\Security\Core\Exception\BadCredentialsException; class ApiKeyAuthenticator implements SimplePreAuthenticatorInterface { @@ -75,9 +69,7 @@ value and then a User object is created:: $username = $userProvider->getUsernameForApiKey($apiKey); if (!$username) { - // CAUTION: this message will be returned to the client - // (so don't put any un-trusted messages / error strings here) - throw new CustomUserMessageAuthenticationException( + throw new AuthenticationException( sprintf('API Key "%s" does not exist.', $apiKey) ); } @@ -281,9 +273,9 @@ you can use to create an error ``Response``. // src/AppBundle/Security/ApiKeyAuthenticator.php namespace AppBundle\Security; + use Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; - use Symfony\Component\Security\Http\Authentication\SimplePreAuthenticatorInterface; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; @@ -293,12 +285,7 @@ you can use to create an error ``Response``. public function onAuthenticationFailure(Request $request, AuthenticationException $exception) { - return new Response( - // this contains information about *why* authentication failed - // use it, or return your own message - strtr($exception->getMessageKey(), $exception->getMessageData()), - 403 - ); + return new Response("Authentication Failed.", 403); } } @@ -519,8 +506,8 @@ for security reasons. To take advantage of the session, update ``ApiKeyAuthentic to see if the stored token has a valid User object that can be used:: // src/AppBundle/Security/ApiKeyAuthenticator.php - // ... + class ApiKeyAuthenticator implements SimplePreAuthenticatorInterface { // ... @@ -550,8 +537,7 @@ to see if the stored token has a valid User object that can be used:: } if (!$username) { - // this message will be returned to the client - throw new CustomUserMessageAuthenticationException( + throw new AuthenticationException( sprintf('API Key "%s" does not exist.', $apiKey) ); } diff --git a/cookbook/security/csrf_in_login_form.rst b/cookbook/security/csrf_in_login_form.rst index b6ab7b23df4..e80cd7ea623 100644 --- a/cookbook/security/csrf_in_login_form.rst +++ b/cookbook/security/csrf_in_login_form.rst @@ -33,7 +33,7 @@ provider available in the Security component: # ... form_login: # ... - csrf_token_generator: security.csrf.token_manager + csrf_provider: security.csrf.token_manager .. code-block:: xml @@ -50,7 +50,7 @@ provider available in the Security component: - + @@ -66,7 +66,7 @@ provider available in the Security component: // ... 'form_login' => array( // ... - 'csrf_token_generator' => 'security.csrf.token_manager', + 'csrf_provider' => 'security.csrf.token_manager', ), ), ), @@ -107,7 +107,7 @@ using the login form: -
    + @@ -174,7 +174,7 @@ After this, you have protected your login form against CSRF attacks. 'form_login' => array( // ... 'csrf_parameter' => '_csrf_security_token', - 'csrf_token_id' => 'a_private_string' + 'intention' => 'a_private_string' ), ), ), diff --git a/cookbook/security/custom_authentication_provider.rst b/cookbook/security/custom_authentication_provider.rst index 220d8cdc5ac..fd3e4be3707 100644 --- a/cookbook/security/custom_authentication_provider.rst +++ b/cookbook/security/custom_authentication_provider.rst @@ -10,7 +10,6 @@ How to Create a custom Authentication Provider you through that process. But depending on your needs, you may be able to solve your problem in a simpler, or via a community bundle: - * :doc:`/cookbook/security/guard-authentication` * :doc:`/cookbook/security/custom_password_authenticator` * :doc:`/cookbook/security/api_key_authentication` * To authenticate via OAuth using a third-party service such as Google, Facebook @@ -214,6 +213,7 @@ the ``PasswordDigest`` header value matches with the user's password. use Symfony\Component\Security\Core\Exception\NonceExpiredException; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use AppBundle\Security\Authentication\Token\WsseUserToken; + use Symfony\Component\Security\Core\Util\StringUtils; class WsseProvider implements AuthenticationProviderInterface { @@ -275,7 +275,7 @@ the ``PasswordDigest`` header value matches with the user's password. // Validate Secret $expected = base64_encode(sha1(base64_decode($nonce).$created.$secret, true)); - return hash_equals($expected, $digest); + return StringUtils::equals($expected, $digest); } public function supports(TokenInterface $token) @@ -294,10 +294,11 @@ the ``PasswordDigest`` header value matches with the user's password. .. note:: - While the :phpfunction:`hash_equals` function was introduced in PHP 5.6, - you are safe to use it with any PHP version in your Symfony application. In - PHP versions prior to 5.6, `Symfony Polyfill`_ (which is included in - Symfony) will define the function for you. + The comparison of the expected and the provided digests uses a constant + time comparison provided by the + :method:`Symfony\\Component\\Security\\Core\\Util\\StringUtils::equals` + method of the ``StringUtils`` class. It is used to mitigate possible + `timing attacks`_. The Factory ----------- @@ -676,4 +677,3 @@ in the factory and consumed or passed to the other classes in the container. .. _`WSSE`: http://www.xml.com/pub/a/2003/12/17/dive.html .. _`nonce`: https://en.wikipedia.org/wiki/Cryptographic_nonce .. _`timing attacks`: https://en.wikipedia.org/wiki/Timing_attack -.. _`Symfony Polyfill`: https://github.com/symfony/polyfill diff --git a/cookbook/security/custom_password_authenticator.rst b/cookbook/security/custom_password_authenticator.rst index 9ed7bbf98b3..c8d54869c11 100644 --- a/cookbook/security/custom_password_authenticator.rst +++ b/cookbook/security/custom_password_authenticator.rst @@ -4,20 +4,20 @@ How to Create a Custom Form Password Authenticator ================================================== -.. tip:: - - Check out :doc:`/cookbook/security/guard-authentication` for a simpler and more - flexible way to accomplish custom authentication tasks like this. - Imagine you want to allow access to your website only between 2pm and 4pm -UTC. In this entry, you'll learn how to do this for a login form (i.e. where -your user submits their username and password). +UTC. Before Symfony 2.4, you had to create a custom token, factory, listener +and provider. In this entry, you'll learn how to do this for a login form +(i.e. where your user submits their username and password). +Before Symfony 2.6, you had to use the password encoder to authenticate the user password. The Password Authenticator -------------------------- +.. versionadded:: 2.6 + The ``UserPasswordEncoderInterface`` interface was introduced in Symfony 2.6. + First, create a new class that implements -:class:`Symfony\\Component\\Security\\Http\\Authentication\\SimpleFormAuthenticatorInterface`. +:class:`Symfony\\Component\\Security\\Core\\Authentication\\SimpleFormAuthenticatorInterface`. Eventually, this will allow you to create custom logic for authenticating the user:: @@ -25,13 +25,13 @@ the user:: namespace Acme\HelloBundle\Security; use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\Security\Core\Authentication\SimpleFormAuthenticatorInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; - use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException; + use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; use Symfony\Component\Security\Core\User\UserProviderInterface; - use Symfony\Component\Security\Http\Authentication\SimpleFormAuthenticatorInterface; class TimeAuthenticator implements SimpleFormAuthenticatorInterface { @@ -47,9 +47,7 @@ the user:: try { $user = $userProvider->loadUserByUsername($token->getUsername()); } catch (UsernameNotFoundException $e) { - // CAUTION: this message will be returned to the client - // (so don't put any un-trusted messages / error strings here) - throw new CustomUserMessageAuthenticationException('Invalid username or password'); + throw new AuthenticationException('Invalid username or password'); } $passwordValid = $this->encoder->isPasswordValid($user, $token->getCredentials()); @@ -57,9 +55,7 @@ the user:: if ($passwordValid) { $currentHour = date('G'); if ($currentHour < 14 || $currentHour > 16) { - // CAUTION: this message will be returned to the client - // (so don't put any un-trusted messages / error strings here) - throw new CustomUserMessageAuthenticationException( + throw new AuthenticationException( 'You can only log in between 2 and 4!', 100 ); @@ -73,9 +69,7 @@ the user:: ); } - // CAUTION: this message will be returned to the client - // (so don't put any un-trusted messages / error strings here) - throw new CustomUserMessageAuthenticationException('Invalid username or password'); + throw new AuthenticationException('Invalid username or password'); } public function supportsToken(TokenInterface $token, $providerKey) diff --git a/cookbook/security/entity_provider.rst b/cookbook/security/entity_provider.rst index 3c4ab69838b..0ca60421556 100644 --- a/cookbook/security/entity_provider.rst +++ b/cookbook/security/entity_provider.rst @@ -145,13 +145,13 @@ by running: .. code-block:: bash - $ php bin/console doctrine:generate:entities AppBundle/Entity/User + $ php app/console doctrine:generate:entities AppBundle/Entity/User Next, make sure to :ref:`create the database table `: .. code-block:: bash - $ php bin/console doctrine:schema:update --force + $ php app/console doctrine:schema:update --force What's this UserInterface? ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -291,6 +291,8 @@ name ``our_db_provider`` isn't important: it just needs to match the value of the ``provider`` key under your firewall. Or, if you don't set the ``provider`` key under your firewall, the first "user provider" is automatically used. +.. include:: /cookbook/security/_ircmaxwell_password-compat.rst.inc + Creating your First User ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -422,17 +424,19 @@ both are unique in the database. Unfortunately, the native entity provider is only able to handle querying via a single property on the user. To do this, make your ``UserRepository`` implement a special -:class:`Symfony\\Bridge\\Doctrine\\Security\\User\\UserLoaderInterface`. This -interface only requires one method: ``loadUserByUsername($username)``:: +:class:`Symfony\\Component\\Security\\Core\\User\\UserProviderInterface`. This +interface requires three methods: ``loadUserByUsername($username)``, +``refreshUser(UserInterface $user)``, and ``supportsClass($class)``:: // src/AppBundle/Entity/UserRepository.php namespace AppBundle\Entity; - use Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface; use Symfony\Component\Security\Core\User\UserInterface; + use Symfony\Component\Security\Core\User\UserProviderInterface; + use Symfony\Component\Security\Core\Exception\UnsupportedUserException; use Doctrine\ORM\EntityRepository; - class UserRepository extends EntityRepository implements UserLoaderInterface + class UserRepository extends EntityRepository implements UserProviderInterface { public function loadUserByUsername($username) { @@ -443,8 +447,31 @@ interface only requires one method: ``loadUserByUsername($username)``:: ->getQuery() ->getOneOrNullResult(); } + + public function refreshUser(UserInterface $user) + { + $class = get_class($user); + if (!$this->supportsClass($class)) { + throw new UnsupportedUserException( + sprintf( + 'Instances of "%s" are not supported.', + $class + ) + ); + } + + return $this->find($user->getId()); + } + + public function supportsClass($class) + { + return $this->getEntityName() === $class + || is_subclass_of($class, $this->getEntityName()); + } } +For more details on these methods, see :class:`Symfony\\Component\\Security\\Core\\User\\UserProviderInterface`. + .. tip:: Don't forget to add the repository class to the @@ -541,5 +568,9 @@ is simply called, and you can check whatever properties you want. Unless you understand this, you probably *won't* need to implement this interface or worry about it. +.. versionadded:: 2.1 + In Symfony 2.1, the ``equals`` method was removed from ``UserInterface`` + and the ``EquatableInterface`` was introduced in its place. + .. _fixtures: https://symfony.com/doc/master/bundles/DoctrineFixturesBundle/index.html .. _FOSUserBundle: https://github.com/FriendsOfSymfony/FOSUserBundle diff --git a/cookbook/security/firewall_restriction.rst b/cookbook/security/firewall_restriction.rst deleted file mode 100644 index 80e2bbc5212..00000000000 --- a/cookbook/security/firewall_restriction.rst +++ /dev/null @@ -1,185 +0,0 @@ -.. index:: - single: Security; Restrict Security Firewalls to a Request - -How to Restrict Firewalls to a Specific Request -=============================================== - -When using the Security component, you can create firewalls that match certain request options. -In most cases, matching against the URL is sufficient, but in special cases you can further -restrict the initialization of a firewall against other options of the request. - -.. note:: - - You can use any of these restrictions individually or mix them together to get - your desired firewall configuration. - -Restricting by Pattern ----------------------- - -This is the default restriction and restricts a firewall to only be initialized if the request URL -matches the configured ``pattern``. - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/security.yml - - # ... - security: - firewalls: - secured_area: - pattern: ^/admin - # ... - - .. code-block:: xml - - - - - - - - - - - - - - .. code-block:: php - - // app/config/security.php - - // ... - $container->loadFromExtension('security', array( - 'firewalls' => array( - 'secured_area' => array( - 'pattern' => '^/admin', - // ... - ), - ), - )); - -The ``pattern`` is a regular expression. In this example, the firewall will only be -activated if the URL starts (due to the ``^`` regex character) with ``/admin``. If -the URL does not match this pattern, the firewall will not be activated and subsequent -firewalls will have the opportunity to be matched for this request. - -Restricting by Host -------------------- - -If matching against the ``pattern`` only is not enough, the request can also be matched against -``host``. When the configuration option ``host`` is set, the firewall will be restricted to -only initialize if the host from the request matches against the configuration. - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/security.yml - - # ... - security: - firewalls: - secured_area: - host: ^admin\.example\.com$ - # ... - - .. code-block:: xml - - - - - - - - - - - - - - .. code-block:: php - - // app/config/security.php - - // ... - $container->loadFromExtension('security', array( - 'firewalls' => array( - 'secured_area' => array( - 'host' => '^admin\.example\.com$', - // ... - ), - ), - )); - -The ``host`` (like the ``pattern``) is a regular expression. In this example, -the firewall will only be activated if the host is equal exactly (due to -the ``^`` and ``$`` regex characters) to the hostname ``admin.example.com``. -If the hostname does not match this pattern, the firewall will not be activated -and subsequent firewalls will have the opportunity to be matched for this -request. - -Restricting by HTTP Methods ---------------------------- - -The configuration option ``methods`` restricts the initialization of the firewall to -the provided HTTP methods. - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/security.yml - - # ... - security: - firewalls: - secured_area: - methods: [GET, POST] - # ... - - .. code-block:: xml - - - - - - - - - - - - - - .. code-block:: php - - // app/config/security.php - - // ... - $container->loadFromExtension('security', array( - 'firewalls' => array( - 'secured_area' => array( - 'methods' => array('GET', 'POST'), - // ... - ), - ), - )); - -In this example, the firewall will only be activated if the HTTP method of the -request is either ``GET`` or ``POST``. If the method is not in the array of the -allowed methods, the firewall will not be activated and subsequent firewalls will again -have the opportunity to be matched for this request. diff --git a/cookbook/security/form_login.rst b/cookbook/security/form_login.rst index 27ba29d6f07..6d5f7c64f14 100644 --- a/cookbook/security/form_login.rst +++ b/cookbook/security/form_login.rst @@ -253,7 +253,7 @@ redirect to the URL defined by some ``account`` route, use the following:
    getMessage() ?>
    - + diff --git a/cookbook/security/form_login_setup.rst b/cookbook/security/form_login_setup.rst index f0b25bb527e..c0c9c77e6a1 100644 --- a/cookbook/security/form_login_setup.rst +++ b/cookbook/security/form_login_setup.rst @@ -144,15 +144,26 @@ form:: // src/AppBundle/Controller/SecurityController.php + // ... + use Symfony\Component\Security\Core\SecurityContextInterface; + + // ... public function loginAction(Request $request) { - $authenticationUtils = $this->get('security.authentication_utils'); + $session = $request->getSession(); // get the login error if there is one - $error = $authenticationUtils->getLastAuthenticationError(); + if ($request->attributes->has(SecurityContextInterface::AUTHENTICATION_ERROR)) { + $error = $request->attributes->get(SecurityContextInterface::AUTHENTICATION_ERROR); + } elseif (null !== $session && $session->has(SecurityContextInterface::AUTHENTICATION_ERROR)) { + $error = $session->get(SecurityContextInterface::AUTHENTICATION_ERROR); + $session->remove(SecurityContextInterface::AUTHENTICATION_ERROR); + } else { + $error = null; + } // last username entered by the user - $lastUsername = $authenticationUtils->getLastUsername(); + $lastUsername = (null === $session) ? '' : $session->get(SecurityContextInterface::LAST_USERNAME); return $this->render( 'security/login.html.twig', @@ -164,6 +175,11 @@ form:: ); } +.. versionadded:: 2.6 + The ``security.authentication_utils`` service and the + :class:`Symfony\\Component\\Security\\Http\\Authentication\\AuthenticationUtils` + class were introduced in Symfony 2.6. + Don't let this controller confuse you. As you'll see in a moment, when the user submits the form, the security system automatically handles the form submission for you. If the user had submitted an invalid username or password, @@ -210,7 +226,7 @@ Finally, create the template:
    getMessage() ?>
    - + diff --git a/cookbook/security/guard-authentication.rst b/cookbook/security/guard-authentication.rst deleted file mode 100644 index 1dd94e76645..00000000000 --- a/cookbook/security/guard-authentication.rst +++ /dev/null @@ -1,579 +0,0 @@ -.. index:: - single: Security; Custom Authentication - -How to Create a Custom Authentication System with Guard -======================================================= - -Whether you need to build a traditional login form, an API token authentication system -or you need to integrate with some proprietary single-sign-on system, the Guard -component can make it easy... and fun! - -In this example, you'll build an API token authentication system and learn how -to work with Guard. - -Create a User and a User Provider ---------------------------------- - -No matter how you authenticate, you need to create a User class that implements ``UserInterface`` -and configure a :doc:`user provider `. In this -example, users are stored in the database via Doctrine, and each user has an ``apiKey`` -property they use to access their account via the API:: - - // src/AppBundle/Entity/User.php - namespace AppBundle\Entity; - - use Symfony\Component\Security\Core\User\UserInterface; - use Doctrine\ORM\Mapping as ORM; - - /** - * @ORM\Entity - * @ORM\Table(name="user") - */ - class User implements UserInterface - { - /** - * @ORM\Id - * @ORM\GeneratedValue(strategy="AUTO") - * @ORM\Column(type="integer") - */ - private $id; - - /** - * @ORM\Column(type="string", unique=true) - */ - private $username; - - /** - * @ORM\Column(type="string", unique=true) - */ - private $apiKey; - - public function getUsername() - { - return $this->username; - } - - public function getRoles() - { - return ['ROLE_USER']; - } - - public function getPassword() - { - } - public function getSalt() - { - } - public function eraseCredentials() - { - } - - // more getters/setters - } - -.. tip:: - - This User doesn't have a password, but you can add a ``password`` property if - you also want to allow this user to login with a password (e.g. via a login form). - -Your ``User`` class doesn't need to be stored in Doctrine: do whatever you need. -Next, make sure you've configured a "user provider" for the user: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/security.yml - security: - # ... - - providers: - your_db_provider: - entity: - class: AppBundle:User - - # ... - - .. code-block:: xml - - - - - - - - - - - - - - - - - .. code-block:: php - - // app/config/security.php - $container->loadFromExtension('security', array( - // ... - - 'providers' => array( - 'your_db_provider' => array( - 'entity' => array( - 'class' => 'AppBundle:User', - ), - ), - ), - - // ... - )); - -That's it! Need more information about this step, see: - -* :doc:`/cookbook/security/entity_provider` -* :doc:`/cookbook/security/custom_provider` - -Step 1) Create the Authenticator Class --------------------------------------- - -Suppose you have an API where your clients will send an ``X-AUTH-TOKEN`` header -on each request with their API token. Your job is to read this and find the associated -user (if any). - -To create a custom authentication system, just create a class and make it implement -:class:`Symfony\\Component\\Security\\Guard\\GuardAuthenticatorInterface`. Or, extend -the simpler :class:`Symfony\\Component\\Security\\Guard\\AbstractGuardAuthenticator`. -This requires you to implement six methods:: - - // src/AppBundle/Security/TokenAuthenticator.php - namespace AppBundle\Security; - - use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\HttpFoundation\JsonResponse; - use Symfony\Component\Security\Core\User\UserInterface; - use Symfony\Component\Security\Guard\AbstractGuardAuthenticator; - use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; - use Symfony\Component\Security\Core\Exception\AuthenticationException; - use Symfony\Component\Security\Core\User\UserProviderInterface; - use Doctrine\ORM\EntityManager; - - class TokenAuthenticator extends AbstractGuardAuthenticator - { - private $em; - - public function __construct(EntityManager $em) - { - $this->em = $em; - } - - /** - * Called on every request. Return whatever credentials you want, - * or null to stop authentication. - */ - public function getCredentials(Request $request) - { - if (!$token = $request->headers->get('X-AUTH-TOKEN')) { - // no token? Return null and no other methods will be called - return; - } - - // What you return here will be passed to getUser() as $credentials - return array( - 'token' => $token, - ); - } - - public function getUser($credentials, UserProviderInterface $userProvider) - { - $apiKey = $credentials['token']; - - // if null, authentication will fail - // if a User object, checkCredentials() is called - return $this->em->getRepository('AppBundle:User') - ->findOneBy(array('apiKey' => $apiKey)); - } - - public function checkCredentials($credentials, UserInterface $user) - { - // check credentials - e.g. make sure the password is valid - // no credential check is needed in this case - - // return true to cause authentication success - return true; - } - - public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) - { - // on success, let the request continue - return null; - } - - public function onAuthenticationFailure(Request $request, AuthenticationException $exception) - { - $data = array( - 'message' => strtr($exception->getMessageKey(), $exception->getMessageData()) - - // or to translate this message - // $this->translator->trans($exception->getMessageKey(), $exception->getMessageData()) - ); - - return new JsonResponse($data, 403); - } - - /** - * Called when authentication is needed, but it's not sent - */ - public function start(Request $request, AuthenticationException $authException = null) - { - $data = array( - // you might translate this message - 'message' => 'Authentication Required' - ); - - return new JsonResponse($data, 401); - } - - public function supportsRememberMe() - { - return false; - } - } - -Nice work! Each method is explained below: :ref:`The Guard Authenticator Methods`. - -Step 2) Configure the Authenticator ------------------------------------ - -To finish this, register the class as a service: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/services.yml - services: - app.token_authenticator: - class: AppBundle\Security\TokenAuthenticator - arguments: ['@doctrine.orm.entity_manager'] - - .. code-block:: xml - - - - - - - - - .. code-block:: php - - // app/config/services.php - use Symfony\Component\DependencyInjection\Definition; - use Symfony\Component\DependencyInjection\Reference; - - $container->setDefinition('app.token_authenticator', new Definition( - 'AppBundle\Security\TokenAuthenticator', - array(new Reference('doctrine.orm.entity_manager')) - )); - -Finally, configure your ``firewalls`` key in ``security.yml`` to use this authenticator: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/security.yml - security: - # ... - - firewalls: - # ... - - main: - anonymous: ~ - logout: ~ - - guard: - authenticators: - - app.token_authenticator - - # if you want, disable storing the user in the session - # stateless: true - - # maybe other things, like form_login, remember_me, etc - # ... - - .. code-block:: xml - - - - - - - - - - - - app.token_authenticator - - - - - - - - .. code-block:: php - - // app/config/security.php - - // .. - - $container->loadFromExtension('security', array( - 'firewalls' => array( - 'main' => array( - 'pattern' => '^/', - 'anonymous' => true, - 'logout' => true, - 'guard' => array( - 'authenticators' => array( - 'app.token_authenticator' - ), - ), - // ... - ), - ), - )); - -You did it! You now have a fully-working API token authentication system. If your -homepage required ``ROLE_USER``, then you could test it under different conditions: - -.. code-block:: bash - - # test with no token - curl http://localhost:8000/ - # {"message":"Authentication Required"} - - # test with a bad token - curl -H "X-AUTH-TOKEN: FAKE" http://localhost:8000/ - # {"message":"Username could not be found."} - - # test with a working token - curl -H "X-AUTH-TOKEN: REAL" http://localhost:8000/ - # the homepage controller is executed: the page loads normally - -Now, learn more about what each method does. - -.. _guard-auth-methods: - -The Guard Authenticator Methods -------------------------------- - -Each authenticator needs the following methods: - -**getCredentials(Request $request)** - This will be called on *every* request and your job is to read the token (or - whatever your "authentication" information is) from the request and return it. - If you return ``null``, the rest of the authentication process is skipped. Otherwise, - ``getUser()`` will be called and the return value is passed as the first argument. - -**getUser($credentials, UserProviderInterface $userProvider)** - If ``getCredentials()`` returns a non-null value, then this method is called - and its return value is passed here as the ``$credentials`` argument. Your job - is to return an object that implements ``UserInterface``. If you do, then - ``checkCredentials()`` will be called. If you return ``null`` (or throw an - :ref:`AuthenticationException `) - authentication will fail. - -**checkCredentials($credentials, UserInterface $user)** - If ``getUser()`` returns a User object, this method is called. Your job is to - verify if the credentials are correct. For a login form, this is where you would - check that the password is correct for the user. To pass authentication, return - ``true``. If you return *anything* else - (or throw an :ref:`AuthenticationException `), - authentication will fail. - -**onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)** - This is called after successful authentication and your job is to either - return a :class:`Symfony\\Component\\HttpFoundation\\Response` object - that will be sent to the client or ``null`` to continue the request - (e.g. allow the route/controller to be called like normal). Since this - is an API where each request authenticates itself, you want to return - ``null``. - -**onAuthenticationFailure(Request $request, AuthenticationException $exception)** - This is called if authentication fails. Your job - is to return the :class:`Symfony\\Component\\HttpFoundation\\Response` - object that should be sent to the client. The ``$exception`` will tell you - *what* went wrong during authentication. - -**start(Request $request, AuthenticationException $authException = null)** - This is called if the client accesses a URI/resource that requires authentication, - but no authentication details were sent (i.e. you returned ``null`` from - ``getCredentials()``). Your job is to return a - :class:`Symfony\\Component\\HttpFoundation\\Response` object that helps - the user authenticate (e.g. a 401 response that says "token is missing!"). - -**supportsRememberMe** - If you want to support "remember me" functionality, return true from this method. - You will still need to active ``remember_me`` under your firewall for it to work. - Since this is a stateless API, you do not want to support "remember me" - functionality in this example. - -.. _guard-customize-error: - -Customizing Error Messages --------------------------- - -When ``onAuthenticationFailure()`` is called, it is passed an ``AuthenticationException`` -that describes *how* authentication failed via its ``$e->getMessageKey()`` (and -``$e->getMessageData()``) method. The message will be different based on *where* -authentication fails (i.e. ``getUser()`` versus ``checkCredentials()``). - -But, you can easily return a custom message by throwing a -:class:`Symfony\\Component\\Security\\Core\\Exception\\CustomUserMessageAuthenticationException`. -You can throw this from ``getCredentials()``, ``getUser()`` or ``checkCredentials()`` -to cause a failure:: - - // src/AppBundle/Security/TokenAuthenticator.php - // ... - - use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException; - - class TokenAuthenticator extends AbstractGuardAuthenticator - { - // ... - - public function getCredentials(Request $request) - { - // ... - - if ($token == 'ILuvAPIs') { - throw new CustomUserMessageAuthenticationException( - 'ILuvAPIs is not a real API key: it\'s just a silly phrase' - ); - } - - // ... - } - - // ... - } - -In this case, since "ILuvAPIs" is a ridiculous API key, you could include an easter -egg to return a custom message if someone tries this: - -.. code-block:: bash - - curl -H "X-AUTH-TOKEN: ILuvAPIs" http://localhost:8000/ - # {"message":"ILuvAPIs is not a real API key: it's just a silly phrase"} - -Frequently Asked Questions --------------------------- - -**Can I have Multiple Authenticators?** - Yes! But when you do, you'll need choose just *one* authenticator to be your - "entry_point". This means you'll need to choose *which* authenticator's ``start()`` - method should be called when an anonymous user tries to access a protected resource. - For example, suppose you have an ``app.form_login_authenticator`` that handles - a traditional form login. When a user accesses a protected page anonymously, you - want to use the ``start()`` method from the form authenticator and redirect them - to the login page (instead of returning a JSON response): - - .. configuration-block:: - - .. code-block:: yaml - - # app/config/security.yml - security: - # ... - - firewalls: - # ... - - main: - anonymous: ~ - logout: ~ - - guard: - authenticators: - - app.token_authenticator - - # if you want, disable storing the user in the session - # stateless: true - - # maybe other things, like form_login, remember_me, etc - # ... - - .. code-block:: xml - - - - - - - - - - - - app.token_authenticator - - - - - - - - .. code-block:: php - - // app/config/security.php - - // .. - - $container->loadFromExtension('security', array( - 'firewalls' => array( - 'main' => array( - 'pattern' => '^/', - 'anonymous' => true, - 'logout' => true, - 'guard' => array( - 'authenticators' => array( - 'app.token_authenticator' - ), - ), - // ... - ), - ), - )); - -**Can I use this with ``form_login``?** - Yes! ``form_login`` is *one* way to authenticate a user, so you could use - it *and* then add one or more authenticators. Using a guard authenticator doesn't - collide with other ways to authenticate. - -**Can I use this with FOSUserBundle?** - Yes! Actually, FOSUserBundle doesn't handle security: it simply gives you a - ``User`` object and some routes and controllers to help with login, registration, - forgot password, etc. When you use FOSUserBundle, you typically use ``form_login`` - to actually authenticate the user. You can continue doing that (see previous - question) or use the ``User`` object from FOSUserBundle and create your own - authenticator(s) (just like in this article). diff --git a/cookbook/security/host_restriction.rst b/cookbook/security/host_restriction.rst deleted file mode 100644 index 0ee0d334e30..00000000000 --- a/cookbook/security/host_restriction.rst +++ /dev/null @@ -1,6 +0,0 @@ -How to Restrict Firewalls to a Specific Host -============================================ - -As of Symfony 2.5, more possibilities to restrict firewalls have been added. -You can read everything about all the possibilities (including ``host``) -in ":doc:`/cookbook/security/firewall_restriction`". diff --git a/cookbook/security/impersonating_user.rst b/cookbook/security/impersonating_user.rst index 1dde8a7acfd..57aa20e329a 100644 --- a/cookbook/security/impersonating_user.rst +++ b/cookbook/security/impersonating_user.rst @@ -84,9 +84,11 @@ to show a link to exit impersonation: .. code-block:: html+php isGranted('ROLE_PREVIOUS_ADMIN')): ?> - + Exit impersonation @@ -97,11 +99,10 @@ over the user's roles until you find one that a ``SwitchUserRole`` object:: use Symfony\Component\Security\Core\Role\SwitchUserRole; - $authChecker = $this->get('security.authorization_checker'); - $tokenStorage = $this->get('security.token_storage'); + $securityContext = $this->get('security.context'); - if ($authChecker->isGranted('ROLE_PREVIOUS_ADMIN')) { - foreach ($tokenStorage->getToken()->getRoles() as $role) { + if ($securityContext->isGranted('ROLE_PREVIOUS_ADMIN')) { + foreach ($securityContext->getToken()->getRoles() as $role) { if ($role instanceof SwitchUserRole) { $impersonatingUser = $role->getSource()->getUser(); break; diff --git a/cookbook/security/index.rst b/cookbook/security/index.rst index 61efff1aa23..c9a478c927a 100644 --- a/cookbook/security/index.rst +++ b/cookbook/security/index.rst @@ -9,7 +9,6 @@ Authentication (Identifying/Logging in the User) form_login_setup entity_provider - guard-authentication remember_me impersonating_user form_login @@ -22,10 +21,8 @@ Authentication (Identifying/Logging in the User) csrf_in_login_form named_encoders multiple_user_providers - multiple_guard_authenticators firewall_restriction host_restriction - user_checkers Authorization (Denying Access) ------------------------------ diff --git a/cookbook/security/multiple_guard_authenticators.rst b/cookbook/security/multiple_guard_authenticators.rst deleted file mode 100644 index acb1f774422..00000000000 --- a/cookbook/security/multiple_guard_authenticators.rst +++ /dev/null @@ -1,172 +0,0 @@ -How to Use Multiple Guard Authenticators -======================================== - -.. versionadded:: 2.8 - The ``Guard`` component was introduced in Symfony 2.8. - -The Guard authentication component allows you to easily use many different -authenticators at a time. - -An entry point is a service id (of one of your authenticators) whose -``start()`` method is called to start the authentication process. - -Multiple Authenticators with Shared Entry Point ------------------------------------------------ - -Sometimes you want to offer your users different authentication mechanisms like -a form login and a Facebook login while both entry points redirect the user to -the same login page. -However, in your configuration you have to explicitly say which entry point -you want to use. - -This is how your security configuration can look in action: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/security.yml - security: - # ... - firewalls: - default: - anonymous: ~ - guard: - authenticators: - - app.form_login_authenticator - - app.facebook_connect_authenticator - entry_point: app.form_login_authenticator - - .. code-block:: xml - - - - - - - - - - - app.form_login_authenticator - app.facebook_connect_authenticator - - - - - - .. code-block:: php - - // app/config/security.php - $container->loadFromExtension('security', array( - // ... - 'firewalls' => array( - 'default' => array( - 'anonymous' => null, - 'guard' => array( - 'entry_point' => 'app.form_login_authenticator', - 'authenticators' => array( - 'app.form_login_authenticator', - 'app.facebook_connect_authenticator' - ), - ), - ), - ), - )); - -There is one limitation with this approach - you have to use exactly one entry point. - -Multiple Authenticators with Separate Entry Points --------------------------------------------------- - -However, there are use cases where you have authenticators that protect different -parts of your application. For example, you have a login form that protects -the secured area of your application front-end and API end points that are -protected with API tokens. As you can only configure one entry point per firewall, -the solution is to split the configuration into two separate firewalls: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/security.yml - security: - # ... - firewalls: - api: - pattern: ^/api/ - guard: - authenticators: - - app.api_token_authenticator - default: - anonymous: ~ - guard: - authenticators: - - app.form_login_authenticator - access_control: - - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } - - { path: ^/api, roles: ROLE_API_USER } - - { path: ^/, roles: ROLE_USER } - - .. code-block:: xml - - - - - - - - - - app.api_token_authenticator - - - - - - app.form_login_authenticator - - - - - - - - - .. code-block:: php - - // app/config/security.php - $container->loadFromExtension('security', array( - // ... - 'firewalls' => array( - 'api' => array( - 'pattern' => '^/api', - 'guard' => array( - 'authenticators' => array( - 'app.api_token_authenticator', - ), - ), - ), - 'default' => array( - 'anonymous' => null, - 'guard' => array( - 'authenticators' => array( - 'app.form_login_authenticator', - ), - ), - ), - ), - 'access_control' => array( - array('path' => '^/login', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY'), - array('path' => '^/api', 'role' => 'ROLE_API_USER'), - array('path' => '^/', 'role' => 'ROLE_USER'), - ), - )); diff --git a/cookbook/security/named_encoders.rst b/cookbook/security/named_encoders.rst deleted file mode 100644 index 0cdd0b2eb7b..00000000000 --- a/cookbook/security/named_encoders.rst +++ /dev/null @@ -1,124 +0,0 @@ -.. index:: - single: Security; Named Encoders - -How to Choose the Password Encoder Algorithm Dynamically -======================================================== - -Usually, the same password encoder is used for all users by configuring it -to apply to all instances of a specific class: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/security.yml - security: - # ... - encoders: - Symfony\Component\Security\Core\User\User: sha512 - - .. code-block:: xml - - - - - - - - - - - .. code-block:: php - - // app/config/security.php - $container->loadFromExtension('security', array( - // ... - 'encoders' => array( - 'Symfony\Component\Security\Core\User\User' => array( - 'algorithm' => 'sha512', - ), - ), - )); - -Another option is to use a "named" encoder and then select which encoder -you want to use dynamically. - -In the previous example, you've set the ``sha512`` algorithm for ``Acme\UserBundle\Entity\User``. -This may be secure enough for a regular user, but what if you want your admins -to have a stronger algorithm, for example ``bcrypt``. This can be done with -named encoders: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/security.yml - security: - # ... - encoders: - harsh: - algorithm: bcrypt - cost: 15 - - .. code-block:: xml - - - - - - - - - - - - .. code-block:: php - - // app/config/security.php - $container->loadFromExtension('security', array( - // ... - 'encoders' => array( - 'harsh' => array( - 'algorithm' => 'bcrypt', - 'cost' => '15' - ), - ), - )); - -This creates an encoder named ``harsh``. In order for a ``User`` instance -to use it, the class must implement -:class:`Symfony\\Component\\Security\\Core\\Encoder\\EncoderAwareInterface`. -The interface requires one method - ``getEncoderName`` - which should return -the name of the encoder to use:: - - // src/Acme/UserBundle/Entity/User.php - namespace Acme\UserBundle\Entity; - - use Symfony\Component\Security\Core\User\UserInterface; - use Symfony\Component\Security\Core\Encoder\EncoderAwareInterface; - - class User implements UserInterface, EncoderAwareInterface - { - public function getEncoderName() - { - if ($this->isAdmin()) { - return 'harsh'; - } - - return null; // use the default encoder - } - } diff --git a/cookbook/security/pre_authenticated.rst b/cookbook/security/pre_authenticated.rst index 37b177ccd6b..2d8e6202528 100644 --- a/cookbook/security/pre_authenticated.rst +++ b/cookbook/security/pre_authenticated.rst @@ -92,6 +92,9 @@ in the x509 firewall configuration respectively. REMOTE_USER Based Authentication -------------------------------- +.. versionadded:: 2.6 + REMOTE_USER pre authenticated firewall was introduced in Symfony 2.6. + A lot of authentication modules, like ``auth_kerb`` for Apache provide the username using the ``REMOTE_USER`` environment variable. This variable can be trusted by the application since the authentication happened before the request reached it. diff --git a/cookbook/security/remember_me.rst b/cookbook/security/remember_me.rst index 6e6650974f2..586aab92410 100644 --- a/cookbook/security/remember_me.rst +++ b/cookbook/security/remember_me.rst @@ -22,7 +22,7 @@ the session lasts using a cookie with the ``remember_me`` firewall option: main: # ... remember_me: - secret: '%secret%' + key: '%secret%' lifetime: 604800 # 1 week in seconds path: / # by default, the feature is enabled by checking a @@ -48,7 +48,7 @@ the session lasts using a cookie with the ``remember_me`` firewall option: - - - - - - - - - .. code-block:: php - - // app/config/services.php - $container->register('app.user_checker', 'AppBundle\Security\UserChecker'); - -All that's left to do is add the checker to the desired firewall where the value -is the service id of your user checker: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/security.yml - - # ... - security: - firewalls: - secured_area: - pattern: ^/ - user_checker: app.user_checker - # ... - - .. code-block:: xml - - - - - - - - - app.user_checker - - - - - - .. code-block:: php - - // app/config/security.php - - // ... - $container->loadFromExtension('security', array( - 'firewalls' => array( - 'secured_area' => array( - 'pattern' => '^/', - 'user_checker' => 'app.user_checker', - // ... - ), - ), - )); - - -Additional Configurations -------------------------- - -It's possible to have a different user checker per firewall. - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/security.yml - - # ... - security: - firewalls: - admin: - pattern: ^/admin - user_checker: app.admin_user_checker - # ... - secured_area: - pattern: ^/ - user_checker: app.user_checker - - .. code-block:: xml - - - - - - - - - app.admin_user_checker - - - - app.user_checker - - - - - - .. code-block:: php - - // app/config/security.php - - // ... - $container->loadFromExtension('security', array( - 'firewalls' => array( - 'admin' => array( - 'pattern' => '^/admin', - 'user_checkers' => 'app.admin_user_checker' - // ... - ), - 'secured_area' => array( - 'pattern' => '^/', - 'user_checker' => 'app.user_checker', - // ... - ), - ), - )); - -.. note:: - - Internally the user checkers are aliased per firewall. For ``secured_area`` - the alias ``security.user_checker.secured_area`` would point to ``app.user_checker``. diff --git a/cookbook/security/voters.rst b/cookbook/security/voters.rst index 8649295180a..9b7be023bd8 100644 --- a/cookbook/security/voters.rst +++ b/cookbook/security/voters.rst @@ -35,175 +35,120 @@ The Voter Interface A custom voter needs to implement :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface` -or extend :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\Voter`, +or extend :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\AbstractVoter`, which makes creating a voter even easier. .. code-block:: php - abstract class Voter implements VoterInterface + abstract class AbstractVoter implements VoterInterface { - abstract protected function supports($attribute, $subject); - abstract protected function voteOnAttribute($attribute, $subject, TokenInterface $token); + abstract protected function getSupportedClasses(); + abstract protected function getSupportedAttributes(); + abstract protected function isGranted($attribute, $object, $user = null); } -.. _how-to-use-the-voter-in-a-controller: - -Setup: Checking for Access in a Controller ------------------------------------------- - -Suppose you have a ``Post`` object and you need to decide whether or not the current -user can *edit* or *view* the object. In your controller, you'll check access with -code like this:: - - // src/AppBundle/Controller/PostController.php - // ... - - class PostController extends Controller - { - /** - * @Route("/posts/{id}", name="post_show") - */ - public function showAction($id) - { - // get a Post object - e.g. query for it - $post = ...; - - // check for "view" access: calls all voters - $this->denyAccessUnlessGranted('view', $post); - - // ... - } - - /** - * @Route("/posts/{id}/edit", name="post_edit") - */ - public function editAction($id) - { - // get a Post object - e.g. query for it - $post = ...; - - // check for "edit" access: calls all voters - $this->denyAccessUnlessGranted('edit', $post); - - // ... - } - } - -The ``denyAccessUnlessGranted()`` method (and also, the simpler ``isGranted()`` method) -calls out to the "voter" system. Right now, no voters will vote on whether or not -the user can "view" or "edit" a ``Post``. But you can create your *own* voter that -decides this using whatever logic you want. - -.. tip:: - - The ``denyAccessUnlessGranted()`` function and the ``isGranted()`` functions - are both just shortcuts to call ``isGranted()`` on the ``security.authorization_checker`` - service. +In this example, the voter will check if the user has access to a specific +object according to your custom conditions (e.g. they must be the owner of +the object). If the condition fails, you'll return +``VoterInterface::ACCESS_DENIED``, otherwise you'll return +``VoterInterface::ACCESS_GRANTED``. In case the responsibility for this decision +does not belong to this voter, it will return ``VoterInterface::ACCESS_ABSTAIN``. Creating the custom Voter ------------------------- -Suppose the logic to decide if a user can "view" or "edit" a ``Post`` object is -pretty complex. For example, a ``User`` can always edit or view a ``Post`` they created. -And if a ``Post`` is marked as "public", anyone can view it. A voter for this situation -would look like this:: +The goal is to create a voter that checks if a user has access to view or +edit a particular object. Here's an example implementation: - // src/AppBundle/Security/PostVoter.php - namespace AppBundle\Security; +.. code-block:: php - use AppBundle\Entity\Post; + // src/AppBundle/Security/Authorization/Voter/PostVoter.php + namespace AppBundle\Security\Authorization\Voter; + + use Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter; use AppBundle\Entity\User; - use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; - use Symfony\Component\Security\Core\Authorization\Voter\Voter; + use Symfony\Component\Security\Core\User\UserInterface; - class PostVoter extends Voter + class PostVoter extends AbstractVoter { - // these strings are just invented: you can use anything const VIEW = 'view'; const EDIT = 'edit'; - protected function supports($attribute, $subject) + protected function getSupportedAttributes() { - // if the attribute isn't one we support, return false - if (!in_array($attribute, array(self::VIEW, self::EDIT))) { - return false; - } - - // only vote on Post objects inside this voter - if (!$subject instanceof Post) { - return false; - } - - return true; + return array(self::VIEW, self::EDIT); } - protected function voteOnAttribute($attribute, $subject, TokenInterface $token) + protected function getSupportedClasses() { - $user = $token->getUser(); + return array('AppBundle\Entity\Post'); + } - if (!$user instanceof User) { - // the user must be logged in; if not, deny access + protected function isGranted($attribute, $post, $user = null) + { + // make sure there is a user object (i.e. that the user is logged in) + if (!$user instanceof UserInterface) { return false; } - // you know $subject is a Post object, thanks to supports - /** @var Post $post */ - $post = $subject; + // double-check that the User object is the expected entity (this + // only happens when you did not configure the security system properly) + if (!$user instanceof User) { + throw new \LogicException('The user is somehow not our User class!'); + } switch($attribute) { case self::VIEW: - return $this->canView($post, $user); - case self::EDIT: - return $this->canEdit($post, $user); - } + // the data object could have for example a method isPrivate() + // which checks the Boolean attribute $private + if (!$post->isPrivate()) { + return true; + } - throw new \LogicException('This code should not be reached!'); - } + break; + case self::EDIT: + // this assumes that the data object has a getOwner() method + // to get the entity of the user who owns this data object + if ($user->getId() === $post->getOwner()->getId()) { + return true; + } - private function canView(Post $post, User $user) - { - // if they can edit, they can view - if ($this->canEdit($post, $user)) { - return true; + break; } - // the Post object could have, for example, a method isPrivate() - // that checks a boolean $private property - return !$post->isPrivate(); - } - - private function canEdit(Post $post, User $user) - { - // this assumes that the data object has a getOwner() method - // to get the entity of the user who owns this data object - return $user === $post->getOwner(); + return false; } } -That's it! The voter is done! Next, :ref:`configure it `. +That's it! The voter is done. The next step is to inject the voter into +the security layer. + +To recap, here's what's expected from the three abstract methods: -To recap, here's what's expected from the two abstract methods: +:method:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\AbstractVoter::getSupportedClasses` + It tells Symfony that your voter should be called whenever an object of one + of the given classes is passed to ``isGranted()``. For example, if you return + ``array('AppBundle\Model\Product')``, Symfony will call your voter when a + ``Product`` object is passed to ``isGranted()``. -``Voter::supports($attribute, $subject)`` - When ``isGranted()`` (or ``denyAccessUnlessGranted()``) is called, the first - argument is passed here as ``$attribute`` (e.g. ``ROLE_USER``, ``edit``) and - the second argument (if any) is passed as ``$subject`` (e.g. ``null``, a ``Post`` - object). Your job is to determine if your voter should vote on the attribute/subject - combination. If you return true, ``voteOnAttribute()`` will be called. Otherwise, - your voter is done: some other voter should process this. In this example, you - return ``true`` if the attribue is ``view`` or ``edit`` and if the object is - a ``Post`` instance. +:method:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\AbstractVoter::getSupportedAttributes` + It tells Symfony that your voter should be called whenever one of these + strings is passed as the first argument to ``isGranted()``. For example, if + you return ``array('CREATE', 'READ')``, then Symfony will call your voter + when one of these is passed to ``isGranted()``. -``voteOnAttribute($attribute, $subject, TokenInterface $token)`` - If you return ``true`` from ``supports()``, then this method is called. Your - job is simple: return ``true`` to allow access and ``false`` to deny access. - The ``$token`` can be used to find the current user object (if any). In this - example, all of the complex business logic is included to determine access. +:method:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\AbstractVoter::isGranted` + It implements the business logic that verifies whether or not a given user is + allowed access to a given attribute (e.g. ``CREATE`` or ``READ``) on a given + object. This method must return a boolean. -.. _declaring-the-voter-as-a-service: +.. note:: + + Currently, to use the ``AbstractVoter`` base class, you must be creating a + voter where an object is always passed to ``isGranted()``. -Configuring the Voter ---------------------- +Declaring the Voter as a Service +-------------------------------- To inject the voter into the security layer, you must declare it as a service and tag it with ``security.voter``: @@ -214,12 +159,11 @@ and tag it with ``security.voter``: # app/config/services.yml services: - app.post_voter: - class: AppBundle\Security\PostVoter + security.access.post_voter: + class: AppBundle\Security\Authorization\Voter\PostVoter + public: false tags: - { name: security.voter } - # small performance boost - public: false .. code-block:: xml @@ -231,8 +175,8 @@ and tag it with ``security.voter``: http://symfony.com/schema/dic/services/services-1.0.xsd"> - @@ -246,124 +190,61 @@ and tag it with ``security.voter``: // app/config/services.php use Symfony\Component\DependencyInjection\Definition; - $container->register('app.post_voter', 'AppBundle\Security\PostVoter') + $definition = new Definition('AppBundle\Security\Authorization\Voter\PostVoter'); + $definition ->setPublic(false) ->addTag('security.voter') ; -You're done! Now, when you :ref:`call isGranted() with view/edit and a Post object `, -your voter will be executed and you can control access. + $container->setDefinition('security.access.post_voter', $definition); -Checking for Roles inside a Voter ---------------------------------- +How to Use the Voter in a Controller +------------------------------------ -What if you want to call ``isGranted()`` from *inside* your voter - e.g. you want -to see if the current user has ``ROLE_SUPER_ADMIN``. That's possible by injecting -the :class:`Symfony\\Component\\Security\\Core\\Authorization\\AccessDecisionManager` -into your voter. You can use this to, for example, *always* allow access to a user -with ``ROLE_SUPER_ADMIN``:: +The registered voter will then always be asked as soon as the method ``isGranted()`` +from the authorization checker is called. When extending the base ``Controller`` +class, you can simply call the +:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::denyAccessUnlessGranted()` +method:: - // src/AppBundle/Security/PostVoter.php + // src/AppBundle/Controller/PostController.php + namespace AppBundle\Controller; - // ... - use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; + use Symfony\Bundle\FrameworkBundle\Controller\Controller; + use Symfony\Component\HttpFoundation\Response; - class PostVoter extends Voter + class PostController extends Controller { - // ... - - private $decisionManager; - - public function __construct(AccessDecisionManagerInterface $decisionManager) - { - $this->decisionManager = $decisionManager; - } - - protected function voteOnAttribute($attribute, $subject, TokenInterface $token) + public function showAction($id) { - // ... + // get a Post instance + $post = ...; - // ROLE_SUPER_ADMIN can do anything! The power! - if ($this->decisionManager->decide($token, array('ROLE_SUPER_ADMIN'))) { - return true; - } + // keep in mind that this will call all registered security voters + $this->denyAccessUnlessGranted('view', $post, 'Unauthorized access!'); - // ... all the normal voter logic + return new Response('

    '.$post->getName().'

    '); } } -Next, update ``services.yml`` to inject the ``security.access.decision_manager`` -service: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/services.yml - services: - app.post_voter: - class: AppBundle\Security\PostVoter - arguments: ['@security.access.decision_manager'] - public: false - tags: - - { name: security.voter } - - .. code-block:: xml - - - - - - - - - - - - - - - .. code-block:: php - - // app/config/services.php - use Symfony\Component\DependencyInjection\Definition; - use Symfony\Component\DependencyInjection\Reference; - - $container->register('app.post_voter', 'AppBundle\Security\PostVoter') - ->addArgument(new Reference('security.access.decision_manager')) - ->setPublic(false) - ->addTag('security.voter') - ; - -That's it! Calling ``decide()`` on the ``AccessDecisionManager`` is essentially -the same as calling ``isGranted()`` from a controller or other places -(it's just a little lower-level, which is necessary for a voter). - -.. note:: +.. versionadded:: 2.6 + The ``denyAccessUnlessGranted()`` method was introduced in Symfony 2.6. + Prior to Symfony 2.6, you had to call the ``isGranted()`` method of the + ``security.context`` service and throw the exception yourself. - The ``security.access.decision_manager`` is private. This means you can't access - it directly from a controller: you can only inject it into other services. That's - ok: use ``security.authorization_checker`` instead in all cases except for voters. +It's that easy! .. _security-voters-change-strategy: Changing the Access Decision Strategy ------------------------------------- -Normally, only one voter will vote at any given time (the rest will "abstain", which -means they return ``false`` from ``supports()``). But in theory, you could make multiple -voters vote for one action and object. For instance, suppose you have one voter that -checks if the user is a member of the site and a second one that checks if the user -is older than 18. +Imagine you have multiple voters for one action for an object. For instance, +you have one voter that checks if the user is a member of the site and a second +one checking if the user is older than 18. To handle these cases, the access decision manager uses an access decision -strategy. You can configure this to suit your needs. There are three +strategy. You can configure this to suite your needs. There are three strategies available: ``affirmative`` (default) diff --git a/cookbook/serializer.rst b/cookbook/serializer.rst index 3a2b25ff158..9bf60060c1a 100644 --- a/cookbook/serializer.rst +++ b/cookbook/serializer.rst @@ -15,6 +15,10 @@ and encoders by reading the :doc:`Serializer Component ` 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: @@ -70,6 +74,11 @@ you need it or it can be used in a controller like the following:: Adding Normalizers and Encoders ------------------------------- +.. versionadded:: 2.7 + The :class:`Symfony\\Component\\Serializer\\Normalizer\\ObjectNormalizer` + is enabled by default in Symfony 2.7. In prior versions, you needed to load + your own normalizer. + 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 @@ -120,6 +129,9 @@ Here is an example on how to load the Using Serialization Groups Annotations -------------------------------------- +.. versionadded:: 2.7 + Support for serialization groups was introduced in Symfony 2.7. + Enable :ref:`serialization groups annotation ` with the following configuration: @@ -165,6 +177,10 @@ to your class and choose which groups to use when serializing:: Enabling the Metadata Cache --------------------------- +.. versionadded:: 2.7 + Serializer metadata and the ability to cache them were introduced in + Symfony 2.7. + Metadata used by the Serializer component such as groups can be cached to enhance application performance. Any service implementing the ``Doctrine\Common\Cache\Cache`` interface can be used. diff --git a/cookbook/service_container/compiler_passes.rst b/cookbook/service_container/compiler_passes.rst index d5b7595adc4..cf629a695ef 100644 --- a/cookbook/service_container/compiler_passes.rst +++ b/cookbook/service_container/compiler_passes.rst @@ -7,27 +7,25 @@ How to Work with Compiler Passes in Bundles Compiler passes give you an opportunity to manipulate other service definitions that have been registered with the service container. You -can read about how to create them in the components section -":ref:`components-di-compiler-pass`". +can read about how to create them in the components section ":doc:`/components/dependency_injection/compilation`". +To register a compiler pass from a bundle you need to add it to the build +method of the bundle definition class:: -When using :ref:`separate compiler passes `, -you need to register them in the ``build()`` method of the bundle class (this -is not needed when implementing the ``process()`` method in the extension):: - - // src/AppBundle/AppBundle.php - namespace AppBundle; + // src/Acme/MailerBundle/AcmeMailerBundle.php + namespace Acme\MailerBundle; use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\DependencyInjection\ContainerBuilder; - use AppBundle\DependencyInjection\Compiler\CustomPass; - class AppBundle extends Bundle + use Acme\MailerBundle\DependencyInjection\Compiler\CustomCompilerPass; + + class AcmeMailerBundle extends Bundle { public function build(ContainerBuilder $container) { parent::build($container); - $container->addCompilerPass(new CustomPass()); + $container->addCompilerPass(new CustomCompilerPass()); } } @@ -35,6 +33,6 @@ One of the most common use-cases of compiler passes is to work with tagged servi (read more about tags in the components section ":doc:`/components/dependency_injection/tags`"). If you are using custom tags in a bundle then by convention, tag names consist of the name of the bundle (lowercase, underscores as separators), followed -by a dot and finally the "real" name. For example, if you want to introduce -some sort of "mail_transport" tag in your AppBundle, you should call it -``app.mail_transport``. +by a dot, and finally the "real" name. For example, if you want to introduce +some sort of "transport" tag in your AcmeMailerBundle, you should call it +``acme_mailer.transport``. diff --git a/cookbook/service_container/index.rst b/cookbook/service_container/index.rst index 4c341ae4c1d..f66a455b788 100644 --- a/cookbook/service_container/index.rst +++ b/cookbook/service_container/index.rst @@ -4,5 +4,5 @@ Service Container .. toctree:: :maxdepth: 2 - shared + scopes compiler_passes diff --git a/cookbook/service_container/scopes.rst b/cookbook/service_container/scopes.rst new file mode 100644 index 00000000000..93227b0dd8f --- /dev/null +++ b/cookbook/service_container/scopes.rst @@ -0,0 +1,239 @@ +.. index:: + single: DependencyInjection; Scopes + +How to Work with Scopes +======================= + +This article 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, then this article 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 + :method:`Symfony\\Component\\HttpFoundation\\RequestStack::getCurrentRequest` + method (see :ref:`book-container-request-stack`). The rest of this entry + talks about scopes in a theoretical and more advanced way. If you're + dealing with scopes for the ``request`` service, simply inject ``request_stack``. + +Understanding Scopes +-------------------- + +The scope of a service controls how long an instance of a service is used +by the container. The DependencyInjection component provides two generic +scopes: + +``container`` (the default one): + The same instance is used each time you ask for it from this container. + +``prototype``: + A new instance is created each time you ask for the service. + +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). + +An Example: Client Scope +~~~~~~~~~~~~~~~~~~~~~~~~ + +Other than the ``request`` service (which has a simple solution, see the +above note), no services in the default Symfony container belong to any +scope other than ``container`` and ``prototype``. But for the purposes of +this article, imagine there is another scope ``client`` and a service ``client_configuration`` +that belongs to it. This is not a common situation, but the idea is that +you may enter and exit multiple ``client`` scopes during a request, and each +has its own ``client_configuration`` service. + +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 ``client_configuration`` service, +you will receive a +:class:`Symfony\\Component\\DependencyInjection\\Exception\\ScopeWideningInjectionException` +when compiling the container. Read the sidebar below for more details. + +.. sidebar:: Scopes and Dependencies + + Imagine you've configured a ``my_mailer`` service. You haven't configured + the scope of the service, so it defaults to ``container``. In other words, + every time you ask the container for the ``my_mailer`` service, you get + the same object back. This is usually how you want your services to work. + + Imagine, however, that you need the ``client_configuration`` service + in your ``my_mailer`` service, maybe because you're reading some details + from it, such as what the "sender" address should be. You add it as a + constructor argument. There are several reasons why this presents a problem: + + * When requesting ``my_mailer``, an instance of ``my_mailer`` (called + *MailerA* here) is created and the ``client_configuration`` service ( + called *ConfigurationA* here) is passed to it. Life is good! + + * Your application now needs to do something with another client, and + you've designed your application in such a way that you handle this + by entering a new ``client_configuration`` scope and setting a new + ``client_configuration`` service into the container. Call this + *ConfigurationB*. + + * Somewhere in your application, you once again ask for the ``my_mailer`` + service. Since your service is in the ``container`` scope, the same + instance (*MailerA*) is just re-used. But here's the problem: the + *MailerA* instance still contains the old *ConfigurationA* object, which + is now **not** the correct configuration object to have (*ConfigurationB* + is now the current ``client_configuration`` service). This is subtle, + but the mis-match could cause major problems, which is why it's not + allowed. + + So, that's the reason *why* scopes exist, and how they can cause + problems. Keep reading to find out the common solutions. + +.. note:: + + A service can of course depend on a service from a wider scope without + any issue. + +Using a Service from a Narrower Scope +------------------------------------- + +There are two solutions to the scope problem: + +* A) Put your service in the same scope as the dependency (or a narrower one). If + you depend on the ``client_configuration`` service, this means putting your + new service in the ``client`` scope (see :ref:`changing-service-scope`); + +* B) 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: + +.. note:: + + Prior to Symfony 2.7, there was another alternative based on ``synchronized`` + services. However, these kind of services have been deprecated starting from + Symfony 2.7. + +.. _changing-service-scope: + +A) Changing the Scope of your Service +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Changing the scope of a service should be done in its definition. This example +assumes that the ``Mailer`` class has a ``__construct`` function whose first +argument is the ``ClientConfiguration`` object: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/services.yml + services: + my_mailer: + class: AppBundle\Mail\Mailer + scope: client + arguments: ['@client_configuration'] + + .. code-block:: xml + + + + + + + + + .. code-block:: php + + // app/config/services.php + use Symfony\Component\DependencyInjection\Definition; + + $definition = $container->setDefinition( + 'my_mailer', + new Definition( + 'AppBundle\Mail\Mailer', + array(new Reference('client_configuration'), + )) + )->setScope('client'); + +.. _passing-container: + +B) 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/AppBundle/Mail/Mailer.php + namespace AppBundle\Mail; + + use Symfony\Component\DependencyInjection\ContainerInterface; + + class Mailer + { + protected $container; + + public function __construct(ContainerInterface $container) + { + $this->container = $container; + } + + public function sendEmail() + { + $request = $this->container->get('client_configuration'); + // ... do something using the client configuration here + } + } + +.. caution:: + + Take care not to store the client configuration in a property of the object + for a future call of the service as it would cause the same issue described + in the first section (except that Symfony cannot detect that you are + wrong). + +The service configuration for this class would look something like this: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/services.yml + services: + my_mailer: + class: AppBundle\Mail\Mailer + arguments: ['@service_container'] + # scope: container can be omitted as it is the default + + .. code-block:: xml + + + + + + + + + .. code-block:: php + + // app/config/services.php + use Symfony\Component\DependencyInjection\Definition; + use Symfony\Component\DependencyInjection\Reference; + + $container->setDefinition('my_mailer', new Definition( + 'AppBundle\Mail\Mailer', + array(new Reference('service_container')) + )); + +.. note:: + + Injecting the whole container into a service is generally not a good + idea (only inject what you need). diff --git a/cookbook/service_container/shared.rst b/cookbook/service_container/shared.rst deleted file mode 100644 index aec4943f188..00000000000 --- a/cookbook/service_container/shared.rst +++ /dev/null @@ -1,44 +0,0 @@ -.. index:: - single: Service Container; Shared Services - -How to Define Non Shared Services -================================= - -In the service container, all services are shared by default. This means that -each time you retrieve the service, you'll get the *same* instance. This is -often the behavior you want, but in some cases, you might want to always get a -*new* instance. - -In order to always get a new instance, set the ``shared`` setting to ``false`` -in your service definition: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/services.yml - services: - app.some_not_shared_service: - class: ... - shared: false - # ... - - .. code-block:: xml - - - - - - - .. code-block:: php - - // app/config/services.php - use Symfony\Component\DependencyInjection\Definition; - - $definition = new Definition('...'); - $definition->setShared(false); - - $container->setDefinition('app.some_not_shared_service', $definition); - -Now, whenever you call ``$container->get('app.some_not_shared_service')`` or -inject this service, you'll receive a new instance. diff --git a/cookbook/session/index.rst b/cookbook/session/index.rst index a3490ec0b39..0420126b48e 100644 --- a/cookbook/session/index.rst +++ b/cookbook/session/index.rst @@ -8,5 +8,4 @@ Sessions locale_sticky_session sessions_directory php_bridge - limit_metadata_writes - avoid_session_start + avoid_session_start \ No newline at end of file diff --git a/cookbook/session/limit_metadata_writes.rst b/cookbook/session/limit_metadata_writes.rst deleted file mode 100644 index 5708a793567..00000000000 --- a/cookbook/session/limit_metadata_writes.rst +++ /dev/null @@ -1,65 +0,0 @@ -.. index:: - single: Limit Metadata Writes; Session - -Limit Session Metadata Writes -============================= - -The default behavior of PHP session is to persist the session regardless of -whether the session data has changed or not. In Symfony, each time the session -is accessed, metadata is recorded (session created/last used) which can be used -to determine session age and idle time. - -If for performance reasons you wish to limit the frequency at which the session -persists, this feature can adjust the granularity of the metadata updates and -persist the session less often while still maintaining relatively accurate -metadata. If other session data is changed, the session will always persist. - -You can tell Symfony not to update the metadata "session last updated" time -until a certain amount of time has passed, by setting -``framework.session.metadata_update_threshold`` to a value in seconds greater -than zero: - -.. configuration-block:: - - .. code-block:: yaml - - framework: - session: - metadata_update_threshold: 120 - - .. code-block:: xml - - - - - - - - - - - .. code-block:: php - - $container->loadFromExtension('framework', array( - 'session' => array( - 'metadata_update_threshold' => 120, - ), - )); - -.. note:: - - PHP default's behavior is to save the session whether it has been changed or - not. When using ``framework.session.metadata_update_threshold`` Symfony - will wrap the session handler (configured at - ``framework.session.handler_id``) into the WriteCheckSessionHandler. This - will prevent any session write if the session was not modified. - -.. caution:: - - Be aware that if the session is not written at every request, it may be - garbage collected sooner than usual. This means that your users may be - logged out sooner than expected. diff --git a/cookbook/session/locale_sticky_session.rst b/cookbook/session/locale_sticky_session.rst index 8f6911c4718..867fc80a687 100644 --- a/cookbook/session/locale_sticky_session.rst +++ b/cookbook/session/locale_sticky_session.rst @@ -4,10 +4,11 @@ Making the Locale "Sticky" during a User's Session ================================================== -Symfony stores the locale setting in the Request, which means that this setting -is not available in subsequent requests. In this article, you'll learn how to -store the locale in the session, so that it'll be the same for every subsequent -request. +Prior to Symfony 2.1, the locale was stored in a session attribute called ``_locale``. +Since 2.1, it is stored in the Request, which means that it's not "sticky" +during a user's request. In this article, you'll learn how to make the locale +of a user "sticky" so that once it's set, that same locale will be used for +every subsequent request. Creating a LocaleListener ------------------------- diff --git a/cookbook/session/php_bridge.rst b/cookbook/session/php_bridge.rst index 2a953dbf959..80606654670 100644 --- a/cookbook/session/php_bridge.rst +++ b/cookbook/session/php_bridge.rst @@ -4,6 +4,9 @@ Bridge a legacy Application with Symfony Sessions ================================================= +.. versionadded:: 2.3 + The ability to integrate with a legacy PHP session was introduced 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. diff --git a/cookbook/symfony1.rst b/cookbook/symfony1.rst new file mode 100644 index 00000000000..1ae0dd07293 --- /dev/null +++ b/cookbook/symfony1.rst @@ -0,0 +1,371 @@ +.. index:: + single: symfony1 + +How Symfony2 Differs from Symfony1 +================================== + +The Symfony2 Framework embodies a significant evolution when compared with +the first version of the framework. Fortunately, with the MVC architecture +at its core, the skills used to master a symfony1 project continue to be +very relevant when developing in Symfony2. Sure, ``app.yml`` is gone, but +routing, controllers and templates all remain. + +This chapter walks through the differences between symfony1 and Symfony2. +As you'll see, many tasks are tackled in a slightly different way. You'll +come to appreciate these minor differences as they promote stable, predictable, +testable and decoupled code in your Symfony2 applications. + +So, sit back and relax as you travel from "then" to "now". + +Directory Structure +------------------- + +When looking at a Symfony2 project - for example, the `Symfony Standard Edition`_ - +you'll notice a very different directory structure than in symfony1. The +differences, however, are somewhat superficial. + +The ``app/`` Directory +~~~~~~~~~~~~~~~~~~~~~~ + +In symfony1, your project has one or more applications, and each lives inside +the ``apps/`` directory (e.g. ``apps/frontend``). By default in Symfony2, +you have just one application represented by the ``app/`` directory. Like +in symfony1, the ``app/`` directory contains configuration specific to that +application. It also contains application-specific cache, log and template +directories as well as a ``Kernel`` class (``AppKernel``), which is the base +object that represents the application. + +Unlike symfony1, almost no PHP code lives in the ``app/`` directory. This +directory is not meant to house modules or library files as it did in symfony1. +Instead, it's simply the home of configuration and other resources (templates, +translation files). + +The ``src/`` Directory +~~~~~~~~~~~~~~~~~~~~~~ + +Put simply, your actual code goes here. In Symfony2, all actual application-code +lives inside a bundle (roughly equivalent to a symfony1 plugin) and, by default, +each bundle lives inside the ``src`` directory. In that way, the ``src`` +directory is a bit like the ``plugins`` directory in symfony1, but much more +flexible. Additionally, while *your* bundles will live in the ``src/`` directory, +third-party bundles will live somewhere in the ``vendor/`` directory. + +To get a better picture of the ``src/`` directory, first think of the structure +of a symfony1 application. First, part of your code likely lives inside one or +more applications. Most commonly these include modules, but could also include +any other PHP classes you put in your application. You may have also created +a ``schema.yml`` file in the ``config`` directory of your project and built +several model files. Finally, to help with some common functionality, you're +using several third-party plugins that live in the ``plugins/`` directory. +In other words, the code that drives your application lives in many different +places. + +In Symfony2, life is much simpler because *all* Symfony2 code must live in +a bundle. In the pretend symfony1 project, all the code *could* be moved +into one or more plugins (which is a very good practice, in fact). Assuming +that all modules, PHP classes, schema, routing configuration, etc. were moved +into a plugin, the symfony1 ``plugins/`` directory would be very similar +to the Symfony2 ``src/`` directory. + +Put simply again, the ``src/`` directory is where your code, assets, +templates and most anything else specific to your project will live. + +The ``vendor/`` Directory +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``vendor/`` directory is basically equivalent to the ``lib/vendor/`` +directory in symfony1, which was the conventional directory for all vendor +libraries and bundles. By default, you'll find the Symfony2 library files in +this directory, along with several other dependent libraries such as Doctrine2, +Twig and Swift Mailer. 3rd party Symfony2 bundles live somewhere in the +``vendor/``. + +The ``web/`` Directory +~~~~~~~~~~~~~~~~~~~~~~ + +Not much has changed in the ``web/`` directory. The most noticeable difference +is the absence of the ``css/``, ``js/`` and ``images/`` directories. This +is intentional. Like with your PHP code, all assets should also live inside +a bundle. With the help of a console command, the ``Resources/public/`` +directory of each bundle is copied or symbolically-linked to the ``web/bundles/`` +directory. This allows you to keep assets organized inside your bundle, but +still make them available to the public. To make sure that all bundles are +available, run the following command: + +.. code-block:: bash + + $ php app/console assets:install web + +.. note:: + + This command is the Symfony2 equivalent to the symfony1 ``plugin:publish-assets`` + command. + +Autoloading +----------- + +One of the advantages of modern frameworks is never needing to worry about +requiring files. By making use of an autoloader, you can refer to any class +in your project and trust that it's available. Autoloading has changed in +Symfony2 to be more universal, faster, and independent of needing to clear +your cache. + +In symfony1, autoloading was done by searching the entire project for the +presence of PHP class files and caching this information in a giant array. +That array told symfony1 exactly which file contained each class. In the +production environment, this caused you to need to clear the cache when classes +were added or moved. + +In Symfony2, a tool named `Composer`_ handles this process. +The idea behind the autoloader is simple: the name of your class (including +the namespace) must match up with the path to the file containing that class. +Take the FrameworkExtraBundle from the Symfony2 Standard Edition as an +example:: + + namespace Sensio\Bundle\FrameworkExtraBundle; + + use Symfony\Component\HttpKernel\Bundle\Bundle; + // ... + + class SensioFrameworkExtraBundle extends Bundle + { + // ... + } + +The file itself lives at +``vendor/sensio/framework-extra-bundle/Sensio/Bundle/FrameworkExtraBundle/SensioFrameworkExtraBundle.php``. +As you can see, the second part of the path follows the namespace of the +class. The first part is equal to the package name of the SensioFrameworkExtraBundle. + +The namespace, ``Sensio\Bundle\FrameworkExtraBundle``, and package name, +``sensio/framework-extra-bundle``, spells out the directory that the file +should live in +(``vendor/sensio/framework-extra-bundle/Sensio/Bundle/FrameworkExtraBundle/``). +Composer can then look for the file at this specific place and load it very +fast. + +If the file did *not* live at this exact location, you'd receive a +``Class "Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle" does not exist.`` +error. In Symfony2, a "class does not exist" error means that the namespace of +the class and physical location do not match. Basically, Symfony2 is looking +in one exact location for that class, but that location doesn't exist (or +contains a different class). In order for a class to be autoloaded, you +**never need to clear your cache** in Symfony2. + +As mentioned before, for the autoloader to work, it needs to know that the +``Sensio`` namespace lives in the ``vendor/sensio/framework-extra-bundle`` +directory and that, for example, the ``Doctrine`` namespace lives in the +``vendor/doctrine/orm/lib/`` directory. This mapping is entirely controlled by +Composer. Each third-party library you load through Composer has its +settings defined and Composer takes care of everything for you. + +For this to work, all third-party libraries used by your project must be +defined in the ``composer.json`` file. + +If you look at the ``HelloController`` from the Symfony Standard Edition you +can see that it lives in the ``Acme\DemoBundle\Controller`` namespace. Yet, the +AcmeDemoBundle is not defined in your ``composer.json`` file. Nonetheless are +the files autoloaded. This is because you can tell Composer to autoload files +from specific directories without defining a dependency: + +.. code-block:: json + + { + "autoload": { + "psr-0": { "": "src/" } + } + } + +This means that if a class is not found in the ``vendor`` directory, Composer +will search in the ``src`` directory before throwing a "class does not exist" +exception. Read more about configuring the Composer autoloader in +`the Composer documentation`_. + +Using the Console +----------------- + +In symfony1, the console is in the root directory of your project and is +called ``symfony``: + +.. code-block:: bash + + $ php symfony + +In Symfony2, the console is now in the app sub-directory and is called +``console``: + +.. code-block:: bash + + $ php app/console + +Applications +------------ + +In a symfony1 project, it is common to have several applications: one for the +front-end and one for the back-end for instance. + +In a Symfony2 project, you only need to create one application (a blog +application, an intranet application, ...). Most of the time, if you want to +create a second application, you might instead create another project and +share some bundles between them. + +And if you need to separate the front-end and the back-end features of some +bundles, you can create sub-namespaces for controllers, sub-directories for +templates, different semantic configurations, separate routing configurations, +and so on. + +Of course, there's nothing wrong with having multiple applications in your +project, that's entirely up to you. A second application would mean a new +directory, e.g. ``my_app/``, with the same basic setup as the ``app/`` directory. + +.. tip:: + + Read the definition of a :term:`Project`, an :term:`Application`, and a + :term:`Bundle` in the glossary. + +Bundles and Plugins +------------------- + +In a symfony1 project, a plugin could contain configuration, modules, PHP +libraries, assets and anything else related to your project. In Symfony2, +the idea of a plugin is replaced by the "bundle". A bundle is even more powerful +than a plugin because the core Symfony2 Framework is brought in via a series +of bundles. In Symfony2, bundles are first-class citizens that are so flexible +that even core code itself is a bundle. + +In symfony1, a plugin must be enabled inside the ``ProjectConfiguration`` +class:: + + // config/ProjectConfiguration.class.php + public function setup() + { + // some plugins here + $this->enableAllPluginsExcept(array(...)); + } + +In Symfony2, the bundles are activated inside the application kernel:: + + // app/AppKernel.php + public function registerBundles() + { + $bundles = array( + new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), + new Symfony\Bundle\TwigBundle\TwigBundle(), + ..., + new Acme\DemoBundle\AcmeDemoBundle(), + ); + + return $bundles; + } + +Routing (``routing.yml``) and Configuration (``config.yml``) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In symfony1, the ``routing.yml`` and ``app.yml`` configuration files were +automatically loaded inside any plugin. In Symfony2, routing and application +configuration inside a bundle must be included manually. For example, to +include a routing resource from a bundle called AcmeDemoBundle, you can +do the following: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/routing.yml + _hello: + resource: '@AcmeDemoBundle/Resources/config/routing.yml' + + .. code-block:: xml + + + + + + + + + + .. code-block:: php + + // app/config/routing.php + use Symfony\Component\Routing\RouteCollection; + + $collection = new RouteCollection(); + $collection->addCollection($loader->import("@AcmeHelloBundle/Resources/config/routing.php")); + + return $collection; + +This will load the routes found in the ``Resources/config/routing.yml`` file +of the AcmeDemoBundle. The special ``@AcmeDemoBundle`` is a shortcut syntax +that, internally, resolves to the full path to that bundle. + +You can use this same strategy to bring in configuration from a bundle: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + imports: + - { resource: "@AcmeDemoBundle/Resources/config/config.yml" } + + .. code-block:: xml + + + + + + + .. code-block:: php + + // app/config/config.php + $this->import('@AcmeDemoBundle/Resources/config/config.php') + +In Symfony2, configuration is a bit like ``app.yml`` in symfony1, except much +more systematic. With ``app.yml``, you could simply create any keys you wanted. +By default, these entries were meaningless and depended entirely on how you +used them in your application: + +.. code-block:: yaml + + # some app.yml file from symfony1 + all: + email: + from_address: 'foo.bar@example.com' + +In Symfony2, you can also create arbitrary entries under the ``parameters`` +key of your configuration: + +.. configuration-block:: + + .. code-block:: yaml + + parameters: + email.from_address: 'foo.bar@example.com' + + .. code-block:: xml + + + foo.bar@example.com + + + .. code-block:: php + + $container->setParameter('email.from_address', 'foo.bar@example.com'); + +You can now access this from a controller, for example:: + + public function helloAction($name) + { + $fromAddress = $this->container->getParameter('email.from_address'); + } + +In reality, the Symfony2 configuration is much more powerful and is used +primarily to configure objects that you can use. For more information, see +the chapter titled ":doc:`/book/service_container`". + +.. _`Composer`: https://getcomposer.org +.. _`Symfony Standard Edition`: https://github.com/symfony/symfony-standard +.. _`the Composer documentation`: https://getcomposer.org/doc/04-schema.md#autoload diff --git a/cookbook/templating/PHP.rst b/cookbook/templating/PHP.rst index 03a16cf2d33..b91ed0323cf 100644 --- a/cookbook/templating/PHP.rst +++ b/cookbook/templating/PHP.rst @@ -306,11 +306,11 @@ updated by changing the configuration: .. code-block:: html+php - + Greet Thomas! -The ``path()`` method takes the route name and an array of parameters as +The ``generate()`` method takes the route name and an array of parameters as arguments. The route name is the main key under which routes are referenced and the parameters are the values of the placeholders defined in the route pattern: @@ -339,21 +339,6 @@ 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/templating/namespaced_paths.rst b/cookbook/templating/namespaced_paths.rst index b09fc36800a..5ecaf59cd02 100644 --- a/cookbook/templating/namespaced_paths.rst +++ b/cookbook/templating/namespaced_paths.rst @@ -4,6 +4,9 @@ How to Use and Register Namespaced Twig Paths ============================================= +.. versionadded:: 2.2 + Namespaced path support was introduced in 2.2. + Usually, when you refer to a template, you'll use the ``MyBundle:Subdir:filename.html.twig`` format (see :ref:`template-naming-locations`). @@ -71,6 +74,13 @@ directory: ); )); +.. caution:: + + Prior to 2.8, templates in custom namespaces are not pre-compiled by + Symfony's cache warmup process. They are compiled on demand. This may + cause problems if two simultaneous requests are trying to use the + template for the first time. + The registered namespace is called ``foo_bar``, which refers to the ``vendor/acme/foo-bar/templates`` directory. Assuming there's a file called ``sidebar.twig`` in that directory, you can use it easily: diff --git a/cookbook/templating/render_without_controller.rst b/cookbook/templating/render_without_controller.rst index d2a602ae4eb..41d7b2e4fdd 100644 --- a/cookbook/templating/render_without_controller.rst +++ b/cookbook/templating/render_without_controller.rst @@ -81,6 +81,10 @@ this is probably only useful if you'd like to cache this page partial (see Caching the static Template --------------------------- +.. versionadded:: 2.2 + The ability to cache templates rendered via ``FrameworkBundle:Template:template`` + was introduced in Symfony 2.2. + Since templates that are rendered in this way are typically static, it might make sense to cache them. Fortunately, this is easy! By configuring a few other variables in your route, you can control exactly how your page is cached: diff --git a/cookbook/templating/twig_extension.rst b/cookbook/templating/twig_extension.rst index 5b56c10ea08..679da017618 100644 --- a/cookbook/templating/twig_extension.rst +++ b/cookbook/templating/twig_extension.rst @@ -99,6 +99,16 @@ Now you must let the Service Container know about your newly created Twig Extens ->setPublic(false) ->addTag('twig.extension'); +.. note:: + + Keep in mind that Twig Extensions are not lazily loaded. This means that + there's a higher chance that you'll get a + :class:`Symfony\\Component\\DependencyInjection\\Exception\\ServiceCircularReferenceException` + or a + :class:`Symfony\\Component\\DependencyInjection\\Exception\\ScopeWideningInjectionException` + if any services (or your Twig Extension in this case) are dependent on + the request service. For more information take a look at :doc:`/cookbook/service_container/scopes`. + Using the custom Extension -------------------------- diff --git a/cookbook/testing/bootstrap.rst b/cookbook/testing/bootstrap.rst index 762651e2bd1..28f3e8b9c22 100644 --- a/cookbook/testing/bootstrap.rst +++ b/cookbook/testing/bootstrap.rst @@ -17,14 +17,14 @@ First, add the following file:: )); } - require __DIR__.'/autoload.php'; + require __DIR__.'/bootstrap.php.cache'; -Replace the test bootstrap file ``autoload.php`` in ``phpunit.xml.dist`` +Replace the test bootstrap file ``bootstrap.php.cache`` in ``app/phpunit.xml.dist`` with ``tests.bootstrap.php``: .. code-block:: xml - + + diff --git a/cookbook/testing/database.rst b/cookbook/testing/database.rst index 405a329f4e1..04c8d07ee48 100644 --- a/cookbook/testing/database.rst +++ b/cookbook/testing/database.rst @@ -33,7 +33,6 @@ class. Suppose the class you want to test looks like this:: - // src/AppBundle/Salary/SalaryCalculator.php namespace AppBundle\Salary; use Doctrine\Common\Persistence\ObjectManager; @@ -60,20 +59,14 @@ Suppose the class you want to test looks like this:: Since the ``ObjectManager`` gets injected into the class through the constructor, it's easy to pass a mock object within a test:: - // tests/AppBundle/Salary/SalaryCalculatorTest.php - namespace Tests\AppBundle\Salary; - use AppBundle\Salary\SalaryCalculator; - use AppBundle\Entity\Employee; - use Doctrine\ORM\EntityRepository; - use Doctrine\Common\Persistence\ObjectManager; class SalaryCalculatorTest extends \PHPUnit_Framework_TestCase { public function testCalculateTotalSalary() { // First, mock the object to be used in the test - $employee = $this->getMock(Employee::class); + $employee = $this->getMock('\AppBundle\Entity\Employee'); $employee->expects($this->once()) ->method('getSalary') ->will($this->returnValue(1000)); @@ -83,7 +76,7 @@ it's easy to pass a mock object within a test:: // Now, mock the repository so it returns the mock of the employee $employeeRepository = $this - ->getMockBuilder(EntityRepository::class) + ->getMockBuilder('\Doctrine\ORM\EntityRepository') ->disableOriginalConstructor() ->getMock(); $employeeRepository->expects($this->once()) @@ -92,7 +85,7 @@ it's easy to pass a mock object within a test:: // Last, mock the EntityManager to return the mock of the repository $entityManager = $this - ->getMockBuilder(ObjectManager::class) + ->getMockBuilder('\Doctrine\Common\Persistence\ObjectManager') ->disableOriginalConstructor() ->getMock(); $entityManager->expects($this->once()) diff --git a/cookbook/testing/doctrine.rst b/cookbook/testing/doctrine.rst index 9988b6f7469..e345b32b289 100644 --- a/cookbook/testing/doctrine.rst +++ b/cookbook/testing/doctrine.rst @@ -20,12 +20,12 @@ If you need to actually execute a query, you will need to boot the kernel to get a valid connection. In this case, you'll extend the ``KernelTestCase``, which makes all of this quite easy:: - // tests/AppBundle/Entity/ProductRepositoryTest.php - namespace Tests\AppBundle\Entity; + // src/AppBundle/Tests/Entity/ProductRepositoryFunctionalTest.php + namespace AppBundle\Tests\Entity; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; - class ProductRepositoryTest extends KernelTestCase + class ProductRepositoryFunctionalTest extends KernelTestCase { /** * @var \Doctrine\ORM\EntityManager @@ -38,10 +38,10 @@ which makes all of this quite easy:: protected function setUp() { self::bootKernel(); - $this->em = static::$kernel->getContainer() ->get('doctrine') - ->getManager(); + ->getManager() + ; } public function testSearchByCategoryName() @@ -60,7 +60,6 @@ which makes all of this quite easy:: protected function tearDown() { parent::tearDown(); - $this->em->close(); } } diff --git a/cookbook/testing/insulating_clients.rst b/cookbook/testing/insulating_clients.rst index dd4362e7e47..ae0ac239efa 100644 --- a/cookbook/testing/insulating_clients.rst +++ b/cookbook/testing/insulating_clients.rst @@ -7,23 +7,19 @@ How to Test the Interaction of several Clients If you need to simulate an interaction between different clients (think of a chat for instance), create several clients:: - // ... - $harry = static::createClient(); $sally = static::createClient(); $harry->request('POST', '/say/sally/Hello'); $sally->request('GET', '/messages'); - $this->assertEquals(Response::HTTP_CREATED, $harry->getResponse()->getStatusCode()); + $this->assertEquals(201, $harry->getResponse()->getStatusCode()); $this->assertRegExp('/Hello/', $sally->getResponse()->getContent()); This works except when your code maintains a global state or if it depends on a third-party library that has some kind of global state. In such a case, you can insulate your clients:: - // ... - $harry = static::createClient(); $sally = static::createClient(); @@ -33,7 +29,7 @@ can insulate your clients:: $harry->request('POST', '/say/sally/Hello'); $sally->request('GET', '/messages'); - $this->assertEquals(Response::HTTP_CREATED, $harry->getResponse()->getStatusCode()); + $this->assertEquals(201, $harry->getResponse()->getStatusCode()); $this->assertRegExp('/Hello/', $sally->getResponse()->getContent()); Insulated clients transparently execute their requests in a dedicated and diff --git a/cookbook/testing/profiling.rst b/cookbook/testing/profiling.rst index d809c4febe2..1789c69dbc9 100644 --- a/cookbook/testing/profiling.rst +++ b/cookbook/testing/profiling.rst @@ -15,9 +15,9 @@ spent in the framework, etc. But before writing assertions, enable the profiler and check that the profiler is indeed available (it is enabled by default in the ``test`` environment):: - class LuckyControllerTest extends WebTestCase + class HelloControllerTest extends WebTestCase { - public function testNumberAction() + public function testIndex() { $client = static::createClient(); @@ -25,7 +25,7 @@ the ``test`` environment):: // (it does nothing if the profiler is not available) $client->enableProfiler(); - $crawler = $client->request('GET', '/lucky/number'); + $crawler = $client->request('GET', '/hello/Fabien'); // ... write some assertions about the Response diff --git a/cookbook/testing/simulating_authentication.rst b/cookbook/testing/simulating_authentication.rst index 8777a67e2a1..f2e04acd612 100644 --- a/cookbook/testing/simulating_authentication.rst +++ b/cookbook/testing/simulating_authentication.rst @@ -15,8 +15,8 @@ Another way would be to create a token yourself and store it in a session. While doing this, you have to make sure that an appropriate cookie is sent with a request. The following example demonstrates this technique:: - // tests/AppBundle/Controller/DefaultControllerTest.php - namespace Tests\Appbundle\Controller; + // src/AppBundle/Tests/Controller/DefaultControllerTest.php + namespace Appbundle\Tests\Controller; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\BrowserKit\Cookie; diff --git a/cookbook/validation/custom_constraint.rst b/cookbook/validation/custom_constraint.rst index a349e6df40b..a248a8494aa 100644 --- a/cookbook/validation/custom_constraint.rst +++ b/cookbook/validation/custom_constraint.rst @@ -65,9 +65,18 @@ The validator class is also simple, and only has one required method ``validate( public function validate($value, Constraint $constraint) { if (!preg_match('/^[a-zA-Z0-9]+$/', $value, $matches)) { + // If you're using the new 2.5 validation API (you probably are!) $this->context->buildViolation($constraint->message) ->setParameter('%string%', $value) ->addViolation(); + + // If you're using the old 2.4 validation API + /* + $this->context->addViolation( + $constraint->message, + array('%string%' => $value) + ); + */ } } } @@ -219,9 +228,20 @@ With this, the validator ``validate()`` method gets an object as its first argum public function validate($protocol, Constraint $constraint) { if ($protocol->getFoo() != $protocol->getBar()) { + // If you're using the new 2.5 validation API (you probably are!) $this->context->buildViolation($constraint->message) ->atPath('foo') ->addViolation(); + + // If you're using the old 2.4 validation API + /* + $this->context->addViolationAt( + 'foo', + $constraint->message, + array(), + null + ); + */ } } } diff --git a/cookbook/validation/index.rst b/cookbook/validation/index.rst index d194c118025..3712610011d 100644 --- a/cookbook/validation/index.rst +++ b/cookbook/validation/index.rst @@ -5,4 +5,3 @@ Validation :maxdepth: 2 custom_constraint - severity diff --git a/cookbook/validation/severity.rst b/cookbook/validation/severity.rst index 34b091bd5c6..22cb267d6c3 100644 --- a/cookbook/validation/severity.rst +++ b/cookbook/validation/severity.rst @@ -21,6 +21,9 @@ The process to achieve this behavior consists of two steps: 1. Assigning the Error Level ---------------------------- +.. versionadded:: 2.6 + The ``payload`` option was introduced in Symfony 2.6. + Use the ``payload`` option to configure the error level for each constraint: .. configuration-block:: @@ -128,6 +131,10 @@ Use the ``payload`` option to configure the error level for each constraint: 2. Customize the Error Message Template --------------------------------------- +.. versionadded:: 2.6 + The ``getConstraint()`` method in the ``ConstraintViolation`` class was + introduced in Symfony 2.6. + When validation of the ``User`` object fails, you can retrieve the constraint that caused a particular failure using the :method:`Symfony\\Component\\Validator\\ConstraintViolation::getConstraint` diff --git a/cookbook/web_server/built_in.rst b/cookbook/web_server/built_in.rst index 396ed96c34e..70ba0de0cbe 100644 --- a/cookbook/web_server/built_in.rst +++ b/cookbook/web_server/built_in.rst @@ -4,6 +4,10 @@ How to Use PHP's built-in Web Server ==================================== +.. versionadded:: 2.6 + The ability to run the server as a background process was introduced + in Symfony 2.6. + Since PHP 5.4 the CLI SAPI comes with a `built-in web server`_. It can be used to run your PHP applications locally during development, for testing or for application demonstrations. This way, you don't have to bother configuring @@ -23,7 +27,7 @@ executing the ``server:start`` command: .. code-block:: bash - $ php bin/console server:start + $ php app/console server:start This starts the web server at ``localhost:8000`` in the background that serves your Symfony application. @@ -33,16 +37,7 @@ can change the socket passing an IP address and a port as a command-line argumen .. code-block:: bash - $ php bin/console server:start 192.168.0.1:8080 - -.. note:: - - You can use the ``--force`` option to force the web server start - if the process wasn't correctly stopped (without using the ``server:stop`` command). - - .. code-block:: bash - - $ php bin/console server:start --force + $ php app/console server:start 192.168.0.1:8080 .. note:: @@ -51,20 +46,20 @@ can change the socket passing an IP address and a port as a command-line argumen .. code-block:: bash - $ php bin/console server:status + $ php app/console server:status - $ php bin/console server:status 192.168.0.1:8080 + $ php app/console server:status 192.168.0.1:8080 The first command shows if your Symfony application will be server through ``localhost:8000``, the second one does the same for ``192.168.0.1:8080``. -.. tip:: +.. note:: - Some systems do not support the ``server:start`` command, in these cases - you can execute the ``server:run`` command. This command behaves slightly - different. Instead of starting the server in the background, it will block - the current terminal until you terminate it (this is usually done by - pressing Ctrl and C). + Before Symfony 2.6, the ``server:run`` command was used to start the built-in + web server. This command is still available and behaves slightly different. + Instead of starting the server in the background, it will block the current + terminal until you terminate it (this is usually done by pressing Ctrl + and C). .. sidebar:: Using the built-in Web Server from inside a Virtual Machine @@ -75,7 +70,7 @@ can change the socket passing an IP address and a port as a command-line argumen .. code-block:: bash - $ php bin/console server:start 0.0.0.0:8000 + $ php app/console server:start 0.0.0.0:8000 .. caution:: @@ -94,14 +89,14 @@ script: .. code-block:: bash - $ php bin/console server:start --env=test --router=app/config/router_test.php + $ php app/console server:start --env=test --router=app/config/router_test.php If your application's document root differs from the standard directory layout, you have to pass the correct location using the ``--docroot`` option: .. code-block:: bash - $ php bin/console server:start --docroot=public_html + $ php app/console server:start --docroot=public_html Stopping the Server ------------------- @@ -111,7 +106,7 @@ command: .. code-block:: bash - $ php bin/console server:stop + $ php app/console server:stop Like with the start command, if you omit the socket information, Symfony will stop the web server bound to ``localhost:8000``. Just pass the socket information @@ -119,7 +114,7 @@ when the web server listens to another IP address or to another port: .. code-block:: bash - $ php bin/console server:stop 192.168.0.1:8080 + $ php app/console server:stop 192.168.0.1:8080 .. _`built-in web server`: http://www.php.net/manual/en/features.commandline.webserver.php .. _`php.net`: http://php.net/manual/en/features.commandline.webserver.php#example-411 diff --git a/cookbook/workflow/new_project_svn.rst b/cookbook/workflow/new_project_svn.rst index 17e81b80d5c..8fe7e9eacd9 100644 --- a/cookbook/workflow/new_project_svn.rst +++ b/cookbook/workflow/new_project_svn.rst @@ -75,25 +75,24 @@ with these steps: .. code-block:: bash $ cd myproject/ - $ svn add --depth=empty app var var/cache var/logs app/config web + $ svn add --depth=empty app app/cache app/logs app/config web $ svn propset svn:ignore "vendor" . - $ svn propset svn:ignore "bootstrap*" var/ + $ svn propset svn:ignore "bootstrap*" app/ $ svn propset svn:ignore "parameters.yml" app/config/ - $ svn propset svn:ignore "*" var/cache/ - $ svn propset svn:ignore "*" var/logs/ - $ svn propset svn:ignore "*" var/sessions/ + $ svn propset svn:ignore "*" app/cache/ + $ svn propset svn:ignore "*" app/logs/ $ svn propset svn:ignore "bundles" web - $ svn ci -m "commit basic Symfony ignore list (vendor, var/bootstrap*, app/config/parameters.yml, var/cache/*, var/logs/*, web/bundles)" + $ svn ci -m "commit basic Symfony ignore list (vendor, app/bootstrap*, app/config/parameters.yml, app/cache/*, app/logs/*, web/bundles)" #. The rest of the files can now be added and committed to the project: .. code-block:: bash $ svn add --force . - $ svn ci -m "add basic Symfony Standard 3.X.Y" + $ svn ci -m "add basic Symfony Standard 2.X.Y" That's it! Since the ``app/config/parameters.yml`` file is ignored, you can store machine-specific settings like database passwords here without committing diff --git a/create_framework/dependency_injection.rst b/create_framework/dependency_injection.rst index 36fa99ffd84..f5ff56c1b38 100644 --- a/create_framework/dependency_injection.rst +++ b/create_framework/dependency_injection.rst @@ -100,11 +100,10 @@ Create a new file to host the dependency injection container configuration:: $sc->register('matcher', 'Symfony\Component\Routing\Matcher\UrlMatcher') ->setArguments(array($routes, new Reference('context'))) ; - $sc->register('request_stack', 'Symfony\Component\HttpFoundation\RequestStack'); $sc->register('resolver', 'Symfony\Component\HttpKernel\Controller\ControllerResolver'); $sc->register('listener.router', 'Symfony\Component\HttpKernel\EventListener\RouterListener') - ->setArguments(array(new Reference('matcher'), new Reference('request_stack'))) + ->setArguments(array(new Reference('matcher'))) ; $sc->register('listener.response', 'Symfony\Component\HttpKernel\EventListener\ResponseListener') ->setArguments(array('UTF-8')) @@ -215,7 +214,7 @@ And the related change in the front controller:: We have obviously barely scratched the surface of what you can do with the container: from class names as parameters, to overriding existing object -definitions, from shared service support to dumping a container to a plain PHP class, +definitions, from scope support to dumping a container to a plain PHP class, and much more. The Symfony dependency injection container is really powerful and is able to manage any kind of PHP class. diff --git a/create_framework/http_foundation.rst b/create_framework/http_foundation.rst index 1f984db858a..7c100cff3d4 100644 --- a/create_framework/http_foundation.rst +++ b/create_framework/http_foundation.rst @@ -125,7 +125,7 @@ containing the new requirement: { "require": { - "symfony/http-foundation": "^3.0" + "symfony/http-foundation": "^2.7" } } diff --git a/create_framework/introduction.rst b/create_framework/introduction.rst index 70aeeda2ce3..a69a4fc08d1 100644 --- a/create_framework/introduction.rst +++ b/create_framework/introduction.rst @@ -69,7 +69,7 @@ Before You Start Reading about how to create a framework is not enough. You will have to follow along and actually type all the examples included in this tutorial. For that, -you need a recent version of PHP (5.5.9 or later is good enough), a web server +you need a recent version of PHP (5.3.9 or later is good enough), a web server (like Apache, NGinx or PHP's built-in web server), a good knowledge of PHP and an understanding of Object Oriented programming. @@ -108,8 +108,8 @@ start with the simplest web application we can think of in PHP:: printf('Hello %s', $input); -You can use the PHP built-in server to test this great application in a browser -(``http://localhost:4321/index.php?name=Fabien``): +If you have PHP 5.4, you can use the PHP built-in server to test this great +application in a browser (``http://localhost:4321/index.php?name=Fabien``): .. code-block:: bash diff --git a/images/book/doctrine_web_debug_toolbar.png b/images/book/doctrine_web_debug_toolbar.png index dd5c3fffbb1..b7c5a690d72 100644 Binary files a/images/book/doctrine_web_debug_toolbar.png and b/images/book/doctrine_web_debug_toolbar.png differ diff --git a/images/book/security_anonymous_wdt.png b/images/book/security_anonymous_wdt.png index 4803ed1b108..d780c894d5a 100644 Binary files a/images/book/security_anonymous_wdt.png and b/images/book/security_anonymous_wdt.png differ diff --git a/images/book/symfony_loggedin_wdt.png b/images/book/symfony_loggedin_wdt.png index 6605c35edf7..7280d9978bb 100644 Binary files a/images/book/symfony_loggedin_wdt.png and b/images/book/symfony_loggedin_wdt.png differ diff --git a/images/book/translation/debug_1.png b/images/book/translation/debug_1.png deleted file mode 100644 index 8f175f4d7ff..00000000000 Binary files a/images/book/translation/debug_1.png and /dev/null differ diff --git a/images/book/translation/debug_2.png b/images/book/translation/debug_2.png deleted file mode 100644 index 04a57fa41d4..00000000000 Binary files a/images/book/translation/debug_2.png and /dev/null differ diff --git a/images/book/translation/debug_3.png b/images/book/translation/debug_3.png deleted file mode 100644 index 6ed595e097b..00000000000 Binary files a/images/book/translation/debug_3.png and /dev/null differ diff --git a/images/book/translation/debug_4.png b/images/book/translation/debug_4.png deleted file mode 100644 index db642b1773f..00000000000 Binary files a/images/book/translation/debug_4.png and /dev/null differ diff --git a/images/components/console/debug_formatter.png b/images/components/console/debug_formatter.png deleted file mode 100644 index 7482f39851f..00000000000 Binary files a/images/components/console/debug_formatter.png and /dev/null differ diff --git a/images/components/console/process-helper-debug.png b/images/components/console/process-helper-debug.png deleted file mode 100644 index 282e1336389..00000000000 Binary files a/images/components/console/process-helper-debug.png and /dev/null differ diff --git a/images/components/console/process-helper-error-debug.png b/images/components/console/process-helper-error-debug.png deleted file mode 100644 index 8d1145478f2..00000000000 Binary files a/images/components/console/process-helper-error-debug.png and /dev/null differ diff --git a/images/components/console/process-helper-verbose.png b/images/components/console/process-helper-verbose.png deleted file mode 100644 index c4c912e1433..00000000000 Binary files a/images/components/console/process-helper-verbose.png and /dev/null differ diff --git a/images/components/console/progressbar.gif b/images/components/console/progressbar.gif deleted file mode 100644 index 6c80e6e897f..00000000000 Binary files a/images/components/console/progressbar.gif and /dev/null differ diff --git a/images/components/phpunit_bridge/report.png b/images/components/phpunit_bridge/report.png deleted file mode 100644 index 3a4534c1383..00000000000 Binary files a/images/components/phpunit_bridge/report.png and /dev/null differ diff --git a/images/components/var_dumper/01-simple.png b/images/components/var_dumper/01-simple.png deleted file mode 100644 index a4d03147667..00000000000 Binary files a/images/components/var_dumper/01-simple.png and /dev/null differ diff --git a/images/components/var_dumper/02-multi-line-str.png b/images/components/var_dumper/02-multi-line-str.png deleted file mode 100644 index b40949bd981..00000000000 Binary files a/images/components/var_dumper/02-multi-line-str.png and /dev/null differ diff --git a/images/components/var_dumper/03-object.png b/images/components/var_dumper/03-object.png deleted file mode 100644 index 47fc5e5e245..00000000000 Binary files a/images/components/var_dumper/03-object.png and /dev/null differ diff --git a/images/components/var_dumper/04-dynamic-property.png b/images/components/var_dumper/04-dynamic-property.png deleted file mode 100644 index de7938c20cf..00000000000 Binary files a/images/components/var_dumper/04-dynamic-property.png and /dev/null differ diff --git a/images/components/var_dumper/05-soft-ref.png b/images/components/var_dumper/05-soft-ref.png deleted file mode 100644 index 964af97ffd3..00000000000 Binary files a/images/components/var_dumper/05-soft-ref.png and /dev/null differ diff --git a/images/components/var_dumper/06-constants.png b/images/components/var_dumper/06-constants.png deleted file mode 100644 index 26c735bd613..00000000000 Binary files a/images/components/var_dumper/06-constants.png and /dev/null differ diff --git a/images/components/var_dumper/07-hard-ref.png b/images/components/var_dumper/07-hard-ref.png deleted file mode 100644 index 02dc17c9c40..00000000000 Binary files a/images/components/var_dumper/07-hard-ref.png and /dev/null differ diff --git a/images/components/var_dumper/08-virtual-property.png b/images/components/var_dumper/08-virtual-property.png deleted file mode 100644 index 564a2731ec1..00000000000 Binary files a/images/components/var_dumper/08-virtual-property.png and /dev/null differ diff --git a/images/components/var_dumper/09-cut.png b/images/components/var_dumper/09-cut.png deleted file mode 100644 index 5229f48820c..00000000000 Binary files a/images/components/var_dumper/09-cut.png and /dev/null differ diff --git a/images/cookbook/controller/error_pages/exceptions-in-dev-environment.png b/images/cookbook/controller/error_pages/exceptions-in-dev-environment.png index 225dcdfa0dc..dffd1460b9b 100644 Binary files a/images/cookbook/controller/error_pages/exceptions-in-dev-environment.png and b/images/cookbook/controller/error_pages/exceptions-in-dev-environment.png differ diff --git a/images/quick_tour/hello_fabien.png b/images/quick_tour/hello_fabien.png new file mode 100644 index 00000000000..8329899b090 Binary files /dev/null and b/images/quick_tour/hello_fabien.png differ diff --git a/images/quick_tour/profiler.png b/images/quick_tour/profiler.png index 3b55b75f3af..795f5deb05f 100644 Binary files a/images/quick_tour/profiler.png and b/images/quick_tour/profiler.png differ diff --git a/images/quick_tour/web_debug_toolbar.png b/images/quick_tour/web_debug_toolbar.png index 86249e862f3..1e2b38d06cb 100644 Binary files a/images/quick_tour/web_debug_toolbar.png and b/images/quick_tour/web_debug_toolbar.png differ diff --git a/images/quick_tour/welcome.png b/images/quick_tour/welcome.png index 738105f715d..7eb0395eb43 100644 Binary files a/images/quick_tour/welcome.png and b/images/quick_tour/welcome.png differ diff --git a/images/reference/form/choice-example1.png b/images/reference/form/choice-example1.png deleted file mode 100644 index 00e47d0bb27..00000000000 Binary files a/images/reference/form/choice-example1.png and /dev/null differ diff --git a/images/reference/form/choice-example2.png b/images/reference/form/choice-example2.png deleted file mode 100644 index 147d82bcfca..00000000000 Binary files a/images/reference/form/choice-example2.png and /dev/null differ diff --git a/images/reference/form/choice-example3.png b/images/reference/form/choice-example3.png deleted file mode 100644 index 232f8519fee..00000000000 Binary files a/images/reference/form/choice-example3.png and /dev/null differ diff --git a/images/reference/form/choice-example4.png b/images/reference/form/choice-example4.png deleted file mode 100644 index 7f6071d3532..00000000000 Binary files a/images/reference/form/choice-example4.png and /dev/null differ diff --git a/images/reference/form/choice-example5.png b/images/reference/form/choice-example5.png deleted file mode 100644 index 188eeeec234..00000000000 Binary files a/images/reference/form/choice-example5.png and /dev/null differ diff --git a/quick_tour/the_architecture.rst b/quick_tour/the_architecture.rst index 27c8c6734d1..20e64e1301e 100644 --- a/quick_tour/the_architecture.rst +++ b/quick_tour/the_architecture.rst @@ -15,14 +15,8 @@ but the recommended structure is as follows: ``app/`` The application configuration, templates and translations. -``bin/`` - Executable files (e.g. ``bin/console``). ``src/`` The project's PHP code. -``tests/`` - Automatic tests (e.g. Unit tests). -``var/`` - Generated files (cache, logs, etc.). ``vendor/`` The third-party dependencies. ``web/`` @@ -36,7 +30,7 @@ stylesheets and JavaScript files. It is also where each :term:`front controller` lives, such as the production controller shown here:: // web/app.php - require_once __DIR__.'/../var/bootstrap.php.cache'; + require_once __DIR__.'/../app/bootstrap.php.cache'; require_once __DIR__.'/../app/AppKernel.php'; use Symfony\Component\HttpFoundation\Request; @@ -266,7 +260,7 @@ Symfony applications can contain several configuration files defined in several formats (YAML, XML, PHP, etc.). Instead of parsing and combining all those files for each request, Symfony uses its own cache system. In fact, the application configuration is only parsed for the very first request -and then compiled down to plain PHP code stored in the ``var/cache/`` +and then compiled down to plain PHP code stored in the ``app/cache/`` directory. In the development environment, Symfony is smart enough to update the cache @@ -277,16 +271,16 @@ the ``prod`` environment: .. code-block:: bash - $ php bin/console cache:clear --env=prod + $ php app/console cache:clear --env=prod When developing a web application, things can go wrong in many ways. The -log files in the ``var/logs/`` directory tell you everything about the requests +log files in the ``app/logs/`` directory tell you everything about the requests and help you fix the problem quickly. Using the Command Line Interface -------------------------------- -Each application comes with a command line interface tool (``bin/console``) +Each application comes with a command line interface tool (``app/console``) that helps you maintain your application. It provides commands that boost your productivity by automating tedious and repetitive tasks. @@ -294,13 +288,13 @@ Run it without any arguments to learn more about its capabilities: .. code-block:: bash - $ php bin/console + $ php app/console The ``--help`` option helps you discover the usage of a command: .. code-block:: bash - $ php bin/console debug:router --help + $ php app/console debug:router --help Final Thoughts -------------- diff --git a/redirection_map b/redirection_map index beb2459613e..6e8ea5d953f 100644 --- a/redirection_map +++ b/redirection_map @@ -25,29 +25,6 @@ /cookbook/console/generating_urls /cookbook/console/sending_emails /components/yaml /components/yaml/introduction /components/templating /components/templating/introduction -/components/filesystem /components/filesystem/introduction -/cmf/reference/configuration/block /cmf/bundles/block/configuration -/cmf/reference/configuration/content /cmf/bundles/content/configuration -/cmf/reference/configuration/core /cmf/bundles/core/configuration -/cmf/reference/configuration/create /cmf/bundles/create/configuration -/cmf/reference/configuration/media /cmf/bundles/media/configuration -/cmf/reference/configuration/menu /cmf/bundles/menu/configuration -/cmf/reference/configuration/phpcr_odm /cmf/bundles/phpcr_odm/configuration -/cmf/reference/configuration/routing /cmf/bundles/routing/configuration -/cmf/reference/configuration/search /cmf/bundles/search/configuration -/cmf/reference/configuration/seo /cmf/bundles/seo/configuration -/cmf/reference/configuration/simple_cms /cmf/bundles/simple_cms/configuration -/cmf/reference/configuration/tree_browser /cmf/bundles/tree_browser/configuration -/cmf/cookbook/exposing_content_via_rest /cmf/bundles/content/exposing_content_via_rest -/cmf/cookbook/creating_a_cms/auto-routing /cmf/tutorial/auto-routing -/cmf/cookbook/creating_a_cms/conclusion /cmf/tutorial/conclusion -/cmf/cookbook/creating_a_cms/content-to-controllers /cmf/tutorial/content-to-controllers -/cmf/cookbook/creating_a_cms/getting-started /cmf/tutorial/getting-started -/cmf/cookbook/creating_a_cms/index /cmf/tutorial/index -/cmf/cookbook/creating_a_cms/introduction /cmf/tutorial/introduction -/cmf/cookbook/creating_a_cms/make-homepage /cmf/tutorial/make-homepage -/cmf/cookbook/creating_a_cms/sonata-admin /cmf/tutorial/sonata-admin -/cmf/cookbook/creating_a_cms/the-frontend /cmf/tutorial/the-frontend /cookbook/upgrading /cookbook/upgrade/index /cookbook/security/voters_data_permission /cookbook/security/voters /cookbook/configuration/pdo_session_storage /cookbook/doctrine/pdo_session_storage diff --git a/reference/configuration/assetic.rst b/reference/configuration/assetic.rst index 394b828b307..90badb76fb0 100644 --- a/reference/configuration/assetic.rst +++ b/reference/configuration/assetic.rst @@ -4,8 +4,6 @@ AsseticBundle Configuration ("assetic") ======================================= -.. include:: /cookbook/assetic/_standard_edition_warning.inc - Full Default Configuration -------------------------- @@ -50,12 +48,6 @@ Full Default Configuration # An array of named filters (e.g. some_filter, some_other_filter) some_filter: [] - workers: - # see https://github.com/symfony/AsseticBundle/pull/119 - # Cache can also be busted via the framework.assets.version - # setting - see the "framework" configuration section - cache_busting: - enabled: false twig: functions: # An array of named functions (e.g. some_function, some_other_function) diff --git a/reference/configuration/debug.rst b/reference/configuration/debug.rst index 8a405e57e50..1f09def2f4a 100644 --- a/reference/configuration/debug.rst +++ b/reference/configuration/debug.rst @@ -10,6 +10,9 @@ Symfony full-stack framework and can be configured under the ``debug`` key in your application configuration. When using XML, you must use the ``http://symfony.com/schema/dic/debug`` namespace. +.. versionadded:: 2.6 + The DebugBundle was introduced in Symfony 2.6. + .. tip:: The XSD schema is available at diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 0827744b3f1..85ba39f3b89 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -31,6 +31,7 @@ Configuration * :ref:`enabled ` * `csrf_protection`_ * :ref:`enabled ` + * `field_name`_ (deprecated as of 2.4) * `esi`_ * :ref:`enabled ` * `fragments`_ @@ -94,6 +95,7 @@ Configuration * :ref:`enable_annotations ` * `translation_domain`_ * `strict_email`_ + * `api`_ * `annotations`_ * :ref:`cache ` * `file_cache_dir`_ @@ -102,7 +104,6 @@ Configuration * :ref:`enabled ` * :ref:`cache ` * :ref:`enable_annotations ` - * `name_converter`_ secret ~~~~~~ @@ -134,6 +135,9 @@ out all the application users. http_method_override ~~~~~~~~~~~~~~~~~~~~ +.. versionadded:: 2.3 + The ``http_method_override`` option was introduced in Symfony 2.3. + **type**: ``boolean`` **default**: ``true`` This determines whether the ``_method`` request parameter is used as the @@ -174,6 +178,10 @@ trusted_proxies Configures the IP addresses that should be trusted as proxies. For more details, see :doc:`/cookbook/request/load_balancer_reverse_proxy`. +.. versionadded:: 2.3 + CIDR notation support was introduced in Symfony 2.3, so you can whitelist + whole subnets (e.g. ``10.0.0.0/8``, ``fc00::/7``). + .. configuration-block:: .. code-block:: yaml @@ -219,6 +227,9 @@ using the following keys: * ``emacs`` * ``sublime`` +.. versionadded:: 2.3.14 + The ``emacs`` and ``sublime`` editors were introduced in Symfony 2.3.14. + You can also specify a custom URL string. If you do this, all percentage signs (``%``) must be doubled to escape that character. For example, if you use PHPstorm on the Mac OS platform, you will do something like: @@ -416,6 +427,18 @@ If you're using forms, but want to avoid starting your session (e.g. using forms in an API-only website), ``csrf_protection`` will need to be set to ``false``. +field_name +.......... + +.. caution:: + + The ``framework.csrf_protection.field_name`` setting is deprecated as + of Symfony 2.4, use ``framework.form.csrf_protection.field_name`` instead. + +**type**: ``string`` **default**: ``"_token"`` + +The name of the hidden field used to render the :ref:`CSRF token `. + esi ~~~ @@ -518,6 +541,12 @@ and ``test`` environments. collect ....... +.. versionadded:: 2.3 + The ``collect`` option was introduced in Symfony 2.3. Previously, when + ``profiler.enabled`` was ``false``, the profiler *was* actually enabled, + but the collectors were disabled. Now, the profiler and the collectors + can be controlled independently. + **type**: ``boolean`` **default**: ``true`` This option configures the way the profiler behaves when it is enabled. @@ -743,7 +772,7 @@ This determines whether cookies should only be sent over secure connections. cookie_httponly ............... -**type**: ``boolean`` **default**: ``true`` +**type**: ``boolean`` **default**: ``false`` This determines whether cookies should only be accessible through the HTTP protocol. This means that the cookie won't be accessible by scripting @@ -1249,6 +1278,12 @@ fallbacks **type**: ``string|array`` **default**: ``array('en')`` +.. versionadded:: 2.3.25 + The ``fallbacks`` option was introduced in Symfony 2.3.25. Prior + to Symfony 2.3.25, it was called ``fallback`` and only allowed one fallback + language defined as a string. Please note that you can still use the + old ``fallback`` option if you want define only one fallback. + This option is used when the translation key for the current locale wasn't found. @@ -1261,6 +1296,9 @@ found. logging ....... +.. versionadded:: 2.6 + The ``logging`` option was introduced in Symfony 2.6. + **default**: ``true`` when the debug mode is enabled, ``false`` otherwise. When ``true``, a log entry is made whenever the translator cannot find a translation @@ -1314,9 +1352,6 @@ cache The service that is used to persist class metadata in a cache. The service has to implement the :class:`Symfony\\Component\\Validator\\Mapping\\Cache\\CacheInterface`. -Set this option to ``validator.mapping.cache.doctrine.apc`` to use the APC -cache provide from the Doctrine project. - .. _reference-validation-enable_annotations: enable_annotations @@ -1343,6 +1378,30 @@ If this option is enabled, the `egulias/email-validator`_ library will be used by the :doc:`/reference/constraints/Email` constraint validator. Otherwise, the validator uses a simple regular expression to validate email addresses. +api +... + +**type**: ``string`` + +Starting with Symfony 2.5, the Validator component introduced a new validation +API. The ``api`` option is used to switch between the different implementations: + +``2.5`` + Use the validation API introduced in Symfony 2.5. + +``2.5-bc`` or ``auto`` + If you omit a value or set the ``api`` option to ``2.5-bc`` or ``auto``, + Symfony will use an API implementation that is compatible with both the + legacy ``2.4`` implementation and the ``2.5`` implementation. + +.. note:: + + The support for the native 2.4 API has been dropped since Symfony 2.7. + +To capture these logs in the ``prod`` environment, configure a +:doc:`channel handler ` in ``config_prod.yml`` for +the ``translation`` channel and set its ``level`` to ``debug``. + annotations ~~~~~~~~~~~ @@ -1422,21 +1481,6 @@ If this option is enabled, serialization groups can be defined using annotations For more information, see :ref:`cookbook-serializer-using-serialization-groups-annotations`. -name_converter -.............. - -**type**: ``string`` - -The name converter to use. -The :class:`Symfony\\Component\\Serializer\\NameConverter\\CamelCaseToSnakeCaseNameConverter` -name converter can enabled by using the ``serializer.name_converter.camel_case_to_snake_case`` -value. - -.. seealso:: - - For more information, see - :ref:`component-serializer-converting-property-names-when-serializing-and-deserializing`. - Full Default Configuration -------------------------- @@ -1454,6 +1498,7 @@ Full Default Configuration csrf_protection: enabled: false + field_name: _token # Deprecated since 2.4, to be removed in 3.0. Use form.csrf_protection.field_name instead # form configuration form: diff --git a/reference/configuration/monolog.rst b/reference/configuration/monolog.rst index cbcc118200b..8027cc3d369 100644 --- a/reference/configuration/monolog.rst +++ b/reference/configuration/monolog.rst @@ -29,13 +29,6 @@ Full Default Configuration action_level: WARNING buffer_size: 30 handler: custom - console: - type: console - verbosity_levels: - VERBOSITY_NORMAL: WARNING - VERBOSITY_VERBOSE: NOTICE - VERBOSITY_VERY_VERBOSE: INFO - VERBOSITY_DEBUG: DEBUG custom: type: service id: my_handler @@ -98,10 +91,6 @@ Full Default Configuration action-level="warning" handler="custom" /> - - + @@ -524,8 +521,8 @@ To use HTTP-Digest authentication you need to provide a realm and a secret: 'firewalls' => array( 'somename' => array( 'http_digest' => array( - 'secret' => '%secret%', - 'realm' => 'secure-api', + 'key' => 'a_random_string', + 'realm' => 'secure-api', ), ), ), diff --git a/reference/configuration/twig.rst b/reference/configuration/twig.rst index 0a8352816f7..ea7f51a1a83 100644 --- a/reference/configuration/twig.rst +++ b/reference/configuration/twig.rst @@ -20,9 +20,6 @@ TwigBundle Configuration ("twig") - bootstrap_3_layout.html.twig - bootstrap_3_horizontal_layout.html.twig - # Foundation - - foundation_5_layout.html.twig - # Example: - MyBundle::form.html.twig @@ -41,6 +38,7 @@ TwigBundle Configuration ("twig") value: ~ 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 diff --git a/reference/configuration/web_profiler.rst b/reference/configuration/web_profiler.rst index fc9e9ee8a0c..25e8d853cd9 100644 --- a/reference/configuration/web_profiler.rst +++ b/reference/configuration/web_profiler.rst @@ -26,14 +26,10 @@ Full Default Configuration # before following the redirect intercept_redirects: false - # Exclude AJAX requests in the web debug toolbar for specified paths - excluded_ajax_paths: ^/bundles|^/_wdt - .. code-block:: xml diff --git a/reference/constraints.rst b/reference/constraints.rst index e91e319b3cb..59cc6603c48 100644 --- a/reference/constraints.rst +++ b/reference/constraints.rst @@ -9,8 +9,11 @@ Validation Constraints Reference constraints/Blank constraints/NotNull constraints/IsNull + constraints/Null constraints/IsTrue + constraints/True constraints/IsFalse + constraints/False constraints/Type constraints/Email @@ -18,7 +21,6 @@ Validation Constraints Reference constraints/Url constraints/Regex constraints/Ip - constraints/Uuid constraints/Range @@ -50,12 +52,10 @@ Validation Constraints Reference constraints/Currency constraints/Luhn constraints/Iban - constraints/Bic constraints/Isbn constraints/Issn constraints/Callback - constraints/Expression constraints/All constraints/UserPassword constraints/Valid diff --git a/reference/constraints/All.rst b/reference/constraints/All.rst index 14b53c35cf8..157827df0cf 100644 --- a/reference/constraints/All.rst +++ b/reference/constraints/All.rst @@ -8,7 +8,6 @@ you to apply a collection of constraints to each element of the array. | Applies to | :ref:`property or method ` | +----------------+-------------------------------------------------------------------+ | Options | - `constraints`_ | -| | - `payload`_ | +----------------+-------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\All` | +----------------+-------------------------------------------------------------------+ @@ -108,5 +107,3 @@ constraints This required option is the array of validation constraints that you want to apply to each element of the underlying array. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Bic.rst b/reference/constraints/Bic.rst deleted file mode 100644 index 3288c2d2b16..00000000000 --- a/reference/constraints/Bic.rst +++ /dev/null @@ -1,95 +0,0 @@ -Bic -=== - -This constraint is used to ensure that a value has the proper format of a -`Business Identifier Code (BIC)`_. BIC is an internationally agreed means to -uniquely identify both financial and non-financial institutions. - -+----------------+-----------------------------------------------------------------------+ -| Applies to | :ref:`property or method ` | -+----------------+-----------------------------------------------------------------------+ -| Options | - `message`_ | -| | - `payload`_ | -+----------------+-----------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Validator\\Constraints\\Bic` | -+----------------+-----------------------------------------------------------------------+ -| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\BicValidator` | -+----------------+-----------------------------------------------------------------------+ - -Basic Usage ------------ - -To use the Bic validator, simply apply it to a property on an object that -will contain a Business Identifier Code (BIC). - -.. configuration-block:: - - .. code-block:: php-annotations - - // src/AppBundle/Entity/Transaction.php - namespace AppBundle\Entity; - - use Symfony\Component\Validator\Constraints as Assert; - - class Transaction - { - /** - * @Assert\Bic() - */ - protected $businessIdentifierCode; - } - - .. code-block:: yaml - - # src/AppBundle/Resources/config/validation.yml - AppBundle\Entity\Transaction: - properties: - businessIdentifierCode: - - Bic: ~ - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - // src/AppBundle/Entity/Transaction.php - namespace AppBundle\Entity; - - use Symfony\Component\Validator\Mapping\ClassMetadata; - use Symfony\Component\Validator\Constraints as Assert; - - class Transaction - { - protected $businessIdentifierCode; - - public static function loadValidatorMetadata(ClassMetadata $metadata) - { - $metadata->addPropertyConstraint('businessIdentifierCode', new Assert\Bic()); - } - } - -Available Options ------------------ - -message -~~~~~~~ - -**type**: ``string`` **default**: ``This is not a valid Business Identifier Code (BIC).`` - -The default message supplied when the value does not pass the BIC check. - -.. include:: /reference/constraints/_payload-option.rst.inc - -.. _`Business Identifier Code (BIC)`: https://en.wikipedia.org/wiki/Business_Identifier_Code diff --git a/reference/constraints/Blank.rst b/reference/constraints/Blank.rst index ffbf196f435..b46e9f508c7 100644 --- a/reference/constraints/Blank.rst +++ b/reference/constraints/Blank.rst @@ -10,7 +10,6 @@ to ``null``. To force that a value strictly be equal to ``null``, see the | Applies to | :ref:`property or method ` | +----------------+---------------------------------------------------------------------+ | Options | - `message`_ | -| | - `payload`_ | +----------------+---------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Blank` | +----------------+---------------------------------------------------------------------+ @@ -88,5 +87,3 @@ message **type**: ``string`` **default**: ``This value should be blank.`` This is the message that will be shown if the value is not blank. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Callback.rst b/reference/constraints/Callback.rst index c5588bbf2fe..7a11cc206de 100644 --- a/reference/constraints/Callback.rst +++ b/reference/constraints/Callback.rst @@ -40,6 +40,8 @@ Configuration use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Context\ExecutionContextInterface; + // if you're using the older 2.4 validation API, you'll need this instead + // use Symfony\Component\Validator\ExecutionContextInterface; class Author { @@ -97,6 +99,8 @@ field those errors should be attributed:: // ... use Symfony\Component\Validator\Context\ExecutionContextInterface; + // if you're using the older 2.4 validation API, you'll need this instead + // use Symfony\Component\Validator\ExecutionContextInterface; class Author { @@ -110,9 +114,18 @@ field those errors should be attributed:: // check if the name is actually a fake name if (in_array($this->getFirstName(), $fakeNames)) { + // If you're using the new 2.5 validation API (you probably are!) $context->buildViolation('This name sounds totally fake!') ->atPath('firstName') ->addViolation(); + + // If you're using the old 2.4 validation API + /* + $context->addViolationAt( + 'firstName', + 'This name sounds totally fake!' + ); + */ } } } @@ -130,10 +143,19 @@ have access to the object instance, they receive the object as the first argumen // check if the name is actually a fake name if (in_array($object->getFirstName(), $fakeNames)) { + // If you're using the new 2.5 validation API (you probably are!) $context->buildViolation('This name sounds totally fake!') ->atPath('firstName') ->addViolation() ; + + // If you're using the old 2.4 validation API + /* + $context->addViolationAt( + 'firstName', + 'This name sounds totally fake!' + ); + */ } } @@ -148,6 +170,8 @@ Suppose your validation function is ``Vendor\Package\Validator::validate()``:: namespace Vendor\Package; use Symfony\Component\Validator\Context\ExecutionContextInterface; + // if you're using the older 2.4 validation API, you'll need this instead + // use Symfony\Component\Validator\ExecutionContextInterface; class Validator { @@ -232,6 +256,8 @@ constructor of the Callback constraint:: namespace AppBundle\Entity; use Symfony\Component\Validator\Context\ExecutionContextInterface; + // if you're using the older 2.4 validation API, you'll need this instead + // use Symfony\Component\Validator\ExecutionContextInterface; use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints as Assert; diff --git a/reference/constraints/CardScheme.rst b/reference/constraints/CardScheme.rst index 7e9d4cd6eee..1e01cbea559 100644 --- a/reference/constraints/CardScheme.rst +++ b/reference/constraints/CardScheme.rst @@ -1,6 +1,9 @@ CardScheme ========== +.. versionadded:: 2.2 + The ``CardScheme`` constraint was introduced in Symfony 2.2. + This constraint ensures that a credit card number is valid for a given credit card company. It can be used to validate the number before trying to initiate a payment through a payment gateway. @@ -10,7 +13,6 @@ a payment through a payment gateway. +----------------+--------------------------------------------------------------------------+ | Options | - `schemes`_ | | | - `message`_ | -| | - `payload`_ | +----------------+--------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\CardScheme` | +----------------+--------------------------------------------------------------------------+ @@ -129,6 +131,4 @@ message The message shown when the value does not pass the ``CardScheme`` check. -.. include:: /reference/constraints/_payload-option.rst.inc - .. _`Wikipedia: Issuer identification number (IIN)`: https://en.wikipedia.org/wiki/Bank_card_number#Issuer_identification_number_.28IIN.29 diff --git a/reference/constraints/Choice.rst b/reference/constraints/Choice.rst index 00bfe88366f..aeeadee7a64 100644 --- a/reference/constraints/Choice.rst +++ b/reference/constraints/Choice.rst @@ -18,7 +18,6 @@ an array of items is one of those valid choices. | | - `minMessage`_ | | | - `maxMessage`_ | | | - `strict`_ | -| | - `payload`_ | +----------------+----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Choice` | +----------------+----------------------------------------------------------------------+ @@ -351,5 +350,3 @@ strict If true, the validator will also check the type of the input value. Specifically, this value is passed to as the third argument to the PHP :phpfunction:`in_array` method when checking to see if a value is in the valid choices array. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Collection.rst b/reference/constraints/Collection.rst index 97d6659f745..74a9ff9a355 100644 --- a/reference/constraints/Collection.rst +++ b/reference/constraints/Collection.rst @@ -19,7 +19,6 @@ and that extra keys are not present. | | - `extraFieldsMessage`_ | | | - `allowMissingFields`_ | | | - `missingFieldsMessage`_ | -| | - `payload`_ | +----------------+--------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Collection` | +----------------+--------------------------------------------------------------------------+ @@ -179,6 +178,10 @@ occur. Required and Optional Field Constraints ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. versionadded:: 2.3 + The ``Required`` and ``Optional`` constraints were moved to the namespace + ``Symfony\Component\Validator\Constraints\`` in Symfony 2.3. + Constraints for fields within a collection can be wrapped in the ``Required`` or ``Optional`` constraint to control whether they should always be applied (``Required``) or only applied when the field is present (``Optional``). @@ -332,5 +335,3 @@ missingFieldsMessage The message shown if `allowMissingFields`_ is false and one or more fields are missing from the underlying collection. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Count.rst b/reference/constraints/Count.rst index 49b61f9d616..a792c7056d1 100644 --- a/reference/constraints/Count.rst +++ b/reference/constraints/Count.rst @@ -12,7 +12,6 @@ Countable) element count is *between* some minimum and maximum value. | | - `minMessage`_ | | | - `maxMessage`_ | | | - `exactMessage`_ | -| | - `payload`_ | +----------------+---------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Count` | +----------------+---------------------------------------------------------------------+ @@ -142,5 +141,3 @@ exactMessage The message that will be shown if min and max values are equal and the underlying collection elements count is not exactly this value. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Country.rst b/reference/constraints/Country.rst index b38220b57a0..012151d6065 100644 --- a/reference/constraints/Country.rst +++ b/reference/constraints/Country.rst @@ -7,7 +7,6 @@ Validates that a value is a valid `ISO 3166-1 alpha-2`_ country code. | Applies to | :ref:`property or method ` | +----------------+------------------------------------------------------------------------+ | Options | - `message`_ | -| | - `payload`_ | +----------------+------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Country` | +----------------+------------------------------------------------------------------------+ @@ -83,6 +82,4 @@ message This message is shown if the string is not a valid country code. -.. include:: /reference/constraints/_payload-option.rst.inc - .. _`ISO 3166-1 alpha-2`: https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes diff --git a/reference/constraints/Currency.rst b/reference/constraints/Currency.rst index cd125a42655..a7c626342d8 100644 --- a/reference/constraints/Currency.rst +++ b/reference/constraints/Currency.rst @@ -1,13 +1,15 @@ Currency ======== +.. versionadded:: 2.3 + The ``Currency`` constraint was introduced in Symfony 2.3. + Validates that a value is a valid `3-letter ISO 4217`_ currency name. +----------------+---------------------------------------------------------------------------+ | Applies to | :ref:`property or method` | +----------------+---------------------------------------------------------------------------+ | Options | - `message`_ | -| | - `payload`_ | +----------------+---------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Currency` | +----------------+---------------------------------------------------------------------------+ @@ -86,6 +88,4 @@ message This is the message that will be shown if the value is not a valid currency. -.. include:: /reference/constraints/_payload-option.rst.inc - .. _`3-letter ISO 4217`: https://en.wikipedia.org/wiki/ISO_4217 diff --git a/reference/constraints/Date.rst b/reference/constraints/Date.rst index 8d3a7e26e99..2c4a7f90479 100644 --- a/reference/constraints/Date.rst +++ b/reference/constraints/Date.rst @@ -9,7 +9,6 @@ valid YYYY-MM-DD format. | Applies to | :ref:`property or method ` | +----------------+--------------------------------------------------------------------+ | Options | - `message`_ | -| | - `payload`_ | +----------------+--------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Date` | +----------------+--------------------------------------------------------------------+ @@ -84,5 +83,3 @@ message **type**: ``string`` **default**: ``This value is not a valid date.`` This message is shown if the underlying data is not a valid date. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/DateTime.rst b/reference/constraints/DateTime.rst index 5eeddff77c4..5332fca7d22 100644 --- a/reference/constraints/DateTime.rst +++ b/reference/constraints/DateTime.rst @@ -9,7 +9,6 @@ a valid YYYY-MM-DD HH:MM:SS format. | Applies to | :ref:`property or method ` | +----------------+------------------------------------------------------------------------+ | Options | - `message`_ | -| | - `payload`_ | +----------------+------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\DateTime` | +----------------+------------------------------------------------------------------------+ @@ -84,5 +83,3 @@ message **type**: ``string`` **default**: ``This value is not a valid datetime.`` This message is shown if the underlying data is not a valid datetime. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Email.rst b/reference/constraints/Email.rst index d9ec28c0334..8bf87e31a96 100644 --- a/reference/constraints/Email.rst +++ b/reference/constraints/Email.rst @@ -7,11 +7,9 @@ cast to a string before being validated. +----------------+---------------------------------------------------------------------+ | Applies to | :ref:`property or method ` | +----------------+---------------------------------------------------------------------+ -| Options | - `strict`_ | -| | - `message`_ | +| Options | - `message`_ | | | - `checkMX`_ | | | - `checkHost`_ | -| | - `payload`_ | +----------------+---------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Email` | +----------------+---------------------------------------------------------------------+ @@ -91,15 +89,6 @@ Basic Usage Options ------- -strict -~~~~~~ - -**type**: ``boolean`` **default**: ``false`` - -When false, the email will be validated against a simple regular expression. -If true, then the `egulias/email-validator`_ library is required to perform -an RFC compliant validation. - message ~~~~~~~ @@ -123,7 +112,3 @@ checkHost If true, then the :phpfunction:`checkdnsrr` PHP function will be used to check the validity of the MX *or* the A *or* the AAAA record of the host of the given email. - -.. include:: /reference/constraints/_payload-option.rst.inc - -.. _egulias/email-validator: https://packagist.org/packages/egulias/email-validator diff --git a/reference/constraints/EqualTo.rst b/reference/constraints/EqualTo.rst index 836d6cd1284..1603d938757 100644 --- a/reference/constraints/EqualTo.rst +++ b/reference/constraints/EqualTo.rst @@ -1,6 +1,9 @@ EqualTo ======= +.. versionadded:: 2.3 + The ``EqualTo`` constraint was introduced in Symfony 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`. @@ -15,7 +18,6 @@ To force that a value is *not* equal, see :doc:`/reference/constraints/NotEqualT +----------------+-----------------------------------------------------------------------+ | Options | - `value`_ | | | - `message`_ | -| | - `payload`_ | +----------------+-----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\EqualTo` | +----------------+-----------------------------------------------------------------------+ @@ -102,5 +104,3 @@ 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. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Expression.rst b/reference/constraints/Expression.rst index 1f0278ca9e3..9f5ce639966 100644 --- a/reference/constraints/Expression.rst +++ b/reference/constraints/Expression.rst @@ -216,6 +216,12 @@ more about the expression language syntax, see // ... } + .. versionadded:: 2.6 + In Symfony 2.6, the Expression constraint *is* executed if the value + is ``null``. Before 2.6, if the value was ``null``, the expression + was never executed and the value was considered valid (unless you + also had a constraint like ``NotBlank`` on the property). + For more information about the expression and what variables are available to you, see the :ref:`expression ` option details below. diff --git a/reference/constraints/False.rst b/reference/constraints/False.rst new file mode 100644 index 00000000000..3a895f5ae3d --- /dev/null +++ b/reference/constraints/False.rst @@ -0,0 +1,8 @@ +False +===== + +.. caution:: + + The ``False`` constraint is deprecated since Symfony 2.7 + and will be removed in Symfony 3.0. Use the + :doc:`/reference/constraints/IsFalse` constraint instead. diff --git a/reference/constraints/File.rst b/reference/constraints/File.rst index 842badb272a..2b975cf8369 100644 --- a/reference/constraints/File.rst +++ b/reference/constraints/File.rst @@ -8,8 +8,8 @@ Validates that a value is a valid "file", which can be one of the following: * A valid :class:`Symfony\\Component\\HttpFoundation\\File\\File` object (including objects of class :class:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile`). -This constraint is commonly used in forms with the :doc:`FileType ` -form field. +This constraint is commonly used in forms with the :doc:`file ` +form type. .. tip:: @@ -41,7 +41,7 @@ Basic Usage ----------- This constraint is most commonly used on a property that will be rendered -in a form as a :doc:`FileType ` field. For +in a form as a :doc:`file ` form type. For example, suppose you're creating an author form where you can upload a "bio" PDF for the author. In your form, the ``bioFile`` property would be a ``file`` type. The ``Author`` class might look as follows:: @@ -156,6 +156,9 @@ Options maxSize ~~~~~~~ +.. versionadded:: 2.6 + The suffixes ``Ki`` and ``Mi`` were introduced in Symfony 2.6. + **type**: ``mixed`` If set, the size of the underlying file must be below this file size in @@ -182,6 +185,9 @@ see `Wikipedia: Binary prefix`_. binaryFormat ~~~~~~~~~~~~ +.. versionadded:: 2.6 + The ``binaryFormat`` option was introduced in Symfony 2.6. + **type**: ``boolean`` **default**: ``null`` When ``true``, the sizes will be displayed in messages with binary-prefixed @@ -221,6 +227,10 @@ per the `mimeTypes`_ option. disallowEmptyMessage ~~~~~~~~~~~~~~~~~~~~ +.. versionadded:: 2.6 + The ``disallowEmptyMessage`` option was introduced in Symfony 2.6. Prior to 2.6, + if the user uploaded an empty file, no validation error occurred. + **type**: ``string`` **default**: ``An empty file is not allowed.`` This constraint checks if the uploaded file is empty (i.e. 0 bytes). If it is, diff --git a/reference/constraints/GreaterThan.rst b/reference/constraints/GreaterThan.rst index 8ff9c343e5c..cc1372f3bbd 100644 --- a/reference/constraints/GreaterThan.rst +++ b/reference/constraints/GreaterThan.rst @@ -1,6 +1,9 @@ GreaterThan =========== +.. versionadded:: 2.3 + The ``GreaterThan`` constraint was introduced in Symfony 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 @@ -90,6 +93,9 @@ If you want to ensure that the ``age`` of a ``Person`` class is greater than Comparing Dates --------------- +.. versionadded:: 2.6 + The feature to compare dates was introduced in Symfony 2.6. + This constraint can be used to compare ``DateTime`` objects against any date string `accepted by the DateTime constructor`_. For example, you could check that a date must at least be the next day: diff --git a/reference/constraints/GreaterThanOrEqual.rst b/reference/constraints/GreaterThanOrEqual.rst index b5510c79f66..822b8bc10bc 100644 --- a/reference/constraints/GreaterThanOrEqual.rst +++ b/reference/constraints/GreaterThanOrEqual.rst @@ -1,6 +1,9 @@ GreaterThanOrEqual ================== +.. versionadded:: 2.3 + The ``GreaterThanOrEqual`` constraint was introduced in Symfony 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`. @@ -89,6 +92,9 @@ or equal to ``18``, you could do the following: Comparing Dates --------------- +.. versionadded:: 2.6 + The feature to compare dates was introduced in Symfony 2.6. + This constraint can be used to compare ``DateTime`` objects against any date string `accepted by the DateTime constructor`_. For example, you could check that a date must at least be the current day: diff --git a/reference/constraints/Iban.rst b/reference/constraints/Iban.rst index 8775b941320..0710f802634 100644 --- a/reference/constraints/Iban.rst +++ b/reference/constraints/Iban.rst @@ -1,6 +1,9 @@ Iban ==== +.. versionadded:: 2.3 + The Iban constraint was introduced 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 @@ -10,7 +13,6 @@ borders with a reduced risk of propagating transcription errors. | Applies to | :ref:`property or method` | +----------------+-----------------------------------------------------------------------+ | Options | - `message`_ | -| | - `payload`_ | +----------------+-----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Iban` | +----------------+-----------------------------------------------------------------------+ @@ -100,6 +102,4 @@ message The default message supplied when the value does not pass the Iban check. -.. include:: /reference/constraints/_payload-option.rst.inc - .. _`International Bank Account Number (IBAN)`: https://en.wikipedia.org/wiki/International_Bank_Account_Number diff --git a/reference/constraints/IdenticalTo.rst b/reference/constraints/IdenticalTo.rst index 410df810679..aead27a3fb3 100644 --- a/reference/constraints/IdenticalTo.rst +++ b/reference/constraints/IdenticalTo.rst @@ -1,6 +1,9 @@ IdenticalTo =========== +.. versionadded:: 2.3 + The ``IdenticalTo`` constraint was introduced in Symfony 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`. @@ -16,7 +19,6 @@ To force that a value is *not* identical, see +----------------+--------------------------------------------------------------------------+ | Options | - `value`_ | | | - `message`_ | -| | - `payload`_ | +----------------+--------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\IdenticalTo` | +----------------+--------------------------------------------------------------------------+ @@ -103,5 +105,3 @@ 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. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Image.rst b/reference/constraints/Image.rst index fb792878276..e8058beed14 100644 --- a/reference/constraints/Image.rst +++ b/reference/constraints/Image.rst @@ -5,8 +5,8 @@ The Image constraint works exactly like the :doc:`File ` constraint for the bulk of the documentation on this constraint. @@ -19,22 +19,12 @@ of 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\\Image` | @@ -46,7 +36,7 @@ Basic Usage ----------- This constraint is most commonly used on a property that will be rendered -in a form as a :doc:`FileType ` field. For +in a form as a :doc:`file ` form type. For example, suppose you're creating an author form where you can upload a "headshot" image for the author. In your form, the ``headshot`` property would be a ``file`` type. The ``Author`` class might look as follows:: @@ -134,13 +124,13 @@ that it is between a certain size, add the following: namespace AppBundle\Entity; use Symfony\Component\Validator\Mapping\ClassMetadata; - use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Constraints\Image; class Author { public static function loadValidatorMetadata(ClassMetadata $metadata) { - $metadata->addPropertyConstraint('headshot', new Assert\Image(array( + $metadata->addPropertyConstraint('headshot', new Image(array( 'minWidth' => 200, 'maxWidth' => 400, 'minHeight' => 200, @@ -152,75 +142,6 @@ that 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:: php-annotations - - // src/AppBundle/Entity/Author.php - namespace AppBundle\Entity; - - use Symfony\Component\Validator\Constraints as Assert; - - class Author - { - /** - * @Assert\Image( - * allowLandscape = false, - * allowPortrait = false - * ) - */ - protected $headshot; - } - - .. code-block:: yaml - - # src/AppBundle/Resources/config/validation.yml - AppBundle\Entity\Author - properties: - headshot: - - Image: - allowLandscape: false - allowPortrait: false - - .. code-block:: xml - - - - - - - - - - - - .. code-block:: php - - // src/AppBundle/Entity/Author.php - namespace AppBundle\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 ------- @@ -272,124 +193,41 @@ 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 size constraint +be displayed. This will only occur when at least one of the four 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/Ip.rst b/reference/constraints/Ip.rst index c48b57d95d1..85611b75d36 100644 --- a/reference/constraints/Ip.rst +++ b/reference/constraints/Ip.rst @@ -10,7 +10,6 @@ IPv6 and many other combinations. +----------------+---------------------------------------------------------------------+ | Options | - `version`_ | | | - `message`_ | -| | - `payload`_ | +----------------+---------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Ip` | +----------------+---------------------------------------------------------------------+ @@ -129,5 +128,3 @@ message **type**: ``string`` **default**: ``This is not a valid IP address.`` This message is shown if the string is not a valid IP address. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/IsFalse.rst b/reference/constraints/IsFalse.rst index a4171bcf598..92eb02fa934 100644 --- a/reference/constraints/IsFalse.rst +++ b/reference/constraints/IsFalse.rst @@ -11,7 +11,6 @@ Also see :doc:`IsTrue `. | Applies to | :ref:`property or method ` | +----------------+-----------------------------------------------------------------------+ | Options | - `message`_ | -| | - `payload`_ | +----------------+-----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\IsFalse` | +----------------+-----------------------------------------------------------------------+ @@ -111,5 +110,3 @@ message **type**: ``string`` **default**: ``This value should be false.`` This message is shown if the underlying data is not false. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/IsNull.rst b/reference/constraints/IsNull.rst index 7c281fd1592..24629e9700d 100644 --- a/reference/constraints/IsNull.rst +++ b/reference/constraints/IsNull.rst @@ -11,7 +11,6 @@ Also see :doc:`NotNull `. | Applies to | :ref:`property or method ` | +----------------+-----------------------------------------------------------------------+ | Options | - `message`_ | -| | - `payload`_ | +----------------+-----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\IsNull` | +----------------+-----------------------------------------------------------------------+ @@ -89,5 +88,3 @@ message **type**: ``string`` **default**: ``This value should be null.`` This is the message that will be shown if the value is not ``null``. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/IsTrue.rst b/reference/constraints/IsTrue.rst index 526f68a9093..dbbfd31ca97 100644 --- a/reference/constraints/IsTrue.rst +++ b/reference/constraints/IsTrue.rst @@ -11,7 +11,6 @@ Also see :doc:`IsFalse `. | Applies to | :ref:`property or method ` | +----------------+---------------------------------------------------------------------+ | Options | - `message`_ | -| | - `payload`_ | +----------------+---------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\True` | +----------------+---------------------------------------------------------------------+ @@ -125,5 +124,3 @@ message **type**: ``string`` **default**: ``This value should be true.`` This message is shown if the underlying data is not true. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Isbn.rst b/reference/constraints/Isbn.rst index 1e82fa4c36d..70c21799724 100644 --- a/reference/constraints/Isbn.rst +++ b/reference/constraints/Isbn.rst @@ -1,6 +1,16 @@ Isbn ==== +.. versionadded:: 2.3 + The Isbn constraint was introduced in Symfony 2.3. + +.. caution:: + + The ``isbn10`` and ``isbn13`` options are deprecated since Symfony 2.5 + and will be removed in Symfony 3.0. Use the ``type`` option instead. + Furthermore, when using the ``type`` option, lowercase characters are no + longer supported starting in Symfony 2.5, as they are not allowed in ISBNs. + This constraint validates that an `International Standard Book Number (ISBN)`_ is either a valid ISBN-10 or a valid ISBN-13. diff --git a/reference/constraints/Issn.rst b/reference/constraints/Issn.rst index 7e70d3d078f..9f276b0e084 100644 --- a/reference/constraints/Issn.rst +++ b/reference/constraints/Issn.rst @@ -1,6 +1,9 @@ Issn ==== +.. versionadded:: 2.3 + The Issn constraint was introduced in Symfony 2.3. + Validates that a value is a valid `International Standard Serial Number (ISSN)`_. @@ -10,7 +13,6 @@ Validates that a value is a valid | Options | - `message`_ | | | - `caseSensitive`_ | | | - `requireHyphen`_ | -| | - `payload`_ | +----------------+-----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Issn` | +----------------+-----------------------------------------------------------------------+ @@ -102,6 +104,4 @@ requireHyphen The validator will allow non hyphenated ISSN values by default. When switching this to ``true``, the validator requires a hyphenated ISSN value. -.. include:: /reference/constraints/_payload-option.rst.inc - .. _`International Standard Serial Number (ISSN)`: https://en.wikipedia.org/wiki/Issn diff --git a/reference/constraints/Language.rst b/reference/constraints/Language.rst index c1ae7bbf561..e112374dfb2 100644 --- a/reference/constraints/Language.rst +++ b/reference/constraints/Language.rst @@ -8,7 +8,6 @@ Validates that a value is a valid language *Unicode language identifier* | Applies to | :ref:`property or method ` | +----------------+------------------------------------------------------------------------+ | Options | - `message`_ | -| | - `payload`_ | +----------------+------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Language` | +----------------+------------------------------------------------------------------------+ @@ -83,5 +82,3 @@ message **type**: ``string`` **default**: ``This value is not a valid language.`` This message is shown if the string is not a valid language code. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Length.rst b/reference/constraints/Length.rst index 628a54212fa..a52f314a760 100644 --- a/reference/constraints/Length.rst +++ b/reference/constraints/Length.rst @@ -13,7 +13,6 @@ value. | | - `minMessage`_ | | | - `maxMessage`_ | | | - `exactMessage`_ | -| | - `payload`_ | +----------------+----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Length` | +----------------+----------------------------------------------------------------------+ @@ -161,5 +160,3 @@ exactMessage The message that will be shown if min and max values are equal and the underlying value's length is not exactly this value. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/LessThan.rst b/reference/constraints/LessThan.rst index 9bfaefaacfa..65f171bf834 100644 --- a/reference/constraints/LessThan.rst +++ b/reference/constraints/LessThan.rst @@ -1,6 +1,9 @@ LessThan ======== +.. versionadded:: 2.3 + The ``LessThan`` constraint was introduced in Symfony 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 @@ -90,6 +93,9 @@ If you want to ensure that the ``age`` of a ``Person`` class is less than Comparing Dates --------------- +.. versionadded:: 2.6 + The feature to compare dates was introduced in Symfony 2.6. + This constraint can be used to compare ``DateTime`` objects against any date string `accepted by the DateTime constructor`_. For example, you could check that a date must be in the past like this: diff --git a/reference/constraints/LessThanOrEqual.rst b/reference/constraints/LessThanOrEqual.rst index b780aef3510..48d3b1cef61 100644 --- a/reference/constraints/LessThanOrEqual.rst +++ b/reference/constraints/LessThanOrEqual.rst @@ -1,6 +1,9 @@ LessThanOrEqual =============== +.. versionadded:: 2.3 + The ``LessThanOrEqual`` constraint was introduced in Symfony 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`. @@ -89,6 +92,9 @@ equal to ``80``, you could do the following: Comparing Dates --------------- +.. versionadded:: 2.6 + The feature to compare dates was introduced in Symfony 2.6. + This constraint can be used to compare ``DateTime`` objects against any date string `accepted by the DateTime constructor`_. For example, you could check that a date must be today or in the past like this: diff --git a/reference/constraints/Locale.rst b/reference/constraints/Locale.rst index e4728a9d293..58802d60de3 100644 --- a/reference/constraints/Locale.rst +++ b/reference/constraints/Locale.rst @@ -12,7 +12,6 @@ French/France). | Applies to | :ref:`property or method ` | +----------------+------------------------------------------------------------------------+ | Options | - `message`_ | -| | - `payload`_ | +----------------+------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Locale` | +----------------+------------------------------------------------------------------------+ @@ -88,7 +87,5 @@ message This message is shown if the string is not a valid locale. -.. include:: /reference/constraints/_payload-option.rst.inc - .. _`ISO 639-1`: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes .. _`ISO 3166-1 alpha-2`: https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes diff --git a/reference/constraints/Luhn.rst b/reference/constraints/Luhn.rst index 89975e73ca6..6db96b08300 100644 --- a/reference/constraints/Luhn.rst +++ b/reference/constraints/Luhn.rst @@ -1,6 +1,9 @@ Luhn ==== +.. versionadded:: 2.2 + The ``Luhn`` constraint was introduced in Symfony 2.2. + This constraint is used to ensure that a credit card number passes the `Luhn algorithm`_. It is useful as a first step to validating a credit card: before communicating with a payment gateway. @@ -9,7 +12,6 @@ card: before communicating with a payment gateway. | Applies to | :ref:`property or method ` | +----------------+-----------------------------------------------------------------------+ | Options | - `message`_ | -| | - `payload`_ | +----------------+-----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Luhn` | +----------------+-----------------------------------------------------------------------+ @@ -95,6 +97,4 @@ message The default message supplied when the value does not pass the Luhn check. -.. include:: /reference/constraints/_payload-option.rst.inc - .. _`Luhn algorithm`: https://en.wikipedia.org/wiki/Luhn_algorithm diff --git a/reference/constraints/NotBlank.rst b/reference/constraints/NotBlank.rst index b9db5bcc58a..7ea54243d4f 100644 --- a/reference/constraints/NotBlank.rst +++ b/reference/constraints/NotBlank.rst @@ -10,7 +10,6 @@ a value is simply not equal to ``null``, see the | Applies to | :ref:`property or method ` | +----------------+------------------------------------------------------------------------+ | Options | - `message`_ | -| | - `payload`_ | +----------------+------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\NotBlank` | +----------------+------------------------------------------------------------------------+ @@ -88,5 +87,3 @@ message **type**: ``string`` **default**: ``This value should not be blank.`` This is the message that will be shown if the value is blank. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/NotEqualTo.rst b/reference/constraints/NotEqualTo.rst index 4b3ac0c3cec..1902da92512 100644 --- a/reference/constraints/NotEqualTo.rst +++ b/reference/constraints/NotEqualTo.rst @@ -1,6 +1,9 @@ NotEqualTo ========== +.. versionadded:: 2.3 + The ``NotEqualTo`` constraint was introduced in Symfony 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`. @@ -16,7 +19,6 @@ options. To force that a value is equal, see +----------------+-------------------------------------------------------------------------+ | Options | - `value`_ | | | - `message`_ | -| | - `payload`_ | +----------------+-------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\NotEqualTo` | +----------------+-------------------------------------------------------------------------+ @@ -103,5 +105,3 @@ 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 equal. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/NotIdenticalTo.rst b/reference/constraints/NotIdenticalTo.rst index d8e2a228707..018b86dbf6e 100644 --- a/reference/constraints/NotIdenticalTo.rst +++ b/reference/constraints/NotIdenticalTo.rst @@ -1,6 +1,9 @@ NotIdenticalTo ============== +.. versionadded:: 2.3 + The ``NotIdenticalTo`` constraint was introduced in Symfony 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`. @@ -16,7 +19,6 @@ the options. To force that a value is identical, see +----------------+-----------------------------------------------------------------------------+ | Options | - `value`_ | | | - `message`_ | -| | - `payload`_ | +----------------+-----------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\NotIdenticalTo` | +----------------+-----------------------------------------------------------------------------+ @@ -103,5 +105,3 @@ 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. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/NotNull.rst b/reference/constraints/NotNull.rst index 7b25d13d048..b435449f05e 100644 --- a/reference/constraints/NotNull.rst +++ b/reference/constraints/NotNull.rst @@ -9,7 +9,6 @@ constraint. | Applies to | :ref:`property or method ` | +----------------+-----------------------------------------------------------------------+ | Options | - `message`_ | -| | - `payload`_ | +----------------+-----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\NotNull` | +----------------+-----------------------------------------------------------------------+ @@ -87,5 +86,3 @@ message **type**: ``string`` **default**: ``This value should not be null.`` This is the message that will be shown if the value is ``null``. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Null.rst b/reference/constraints/Null.rst new file mode 100644 index 00000000000..fd07a456eec --- /dev/null +++ b/reference/constraints/Null.rst @@ -0,0 +1,8 @@ +Null +==== + +.. caution:: + + The ``Null`` constraint is deprecated since Symfony 2.7 + and will be removed in Symfony 3.0. Use the + :doc:`/reference/constraints/IsNull` constraint instead. diff --git a/reference/constraints/Range.rst b/reference/constraints/Range.rst index 6b433e6ae0c..ae9599c1217 100644 --- a/reference/constraints/Range.rst +++ b/reference/constraints/Range.rst @@ -11,7 +11,6 @@ Validates that a given number is *between* some minimum and maximum number. | | - `minMessage`_ | | | - `maxMessage`_ | | | - `invalidMessage`_ | -| | - `payload`_ | +----------------+---------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Range` | +----------------+---------------------------------------------------------------------+ @@ -99,221 +98,6 @@ you might add the following: } } -Date Ranges ------------ - -This constraint can be used to compare ``DateTime`` objects against date ranges. -The minimum and maximum date of the range should be given as any date string -`accepted by the DateTime constructor`_. For example, you could check that a -date must lie within the current year like this: - -.. configuration-block:: - - .. code-block:: php-annotations - - // src/AppBundle/Entity/Event.php - namespace AppBundle\Entity; - - use Symfony\Component\Validator\Constraints as Assert; - - class Event - { - /** - * @Assert\Range( - * min = "first day of January", - * max = "first day of January next year" - * ) - */ - protected $startDate; - } - - .. code-block:: yaml - - # src/AppBundle/Resources/config/validation.yml - AppBundle\Entity\Event: - properties: - startDate: - - Range: - min: first day of January - max: first day of January next year - - .. code-block:: xml - - - - - - - - - - - - - - - - .. code-block:: php - - // src/AppBundle/Entity/Event.php - namespace AppBundle\Entity; - - use Symfony\Component\Validator\Mapping\ClassMetadata; - use Symfony\Component\Validator\Constraints as Assert; - - class Event - { - public static function loadValidatorMetadata(ClassMetadata $metadata) - { - $metadata->addPropertyConstraint('startDate', new Assert\Range(array( - 'min' => 'first day of January', - 'max' => 'first day of January next year', - ))); - } - } - -Be aware that PHP will use the server's configured timezone to interpret these -dates. If you want to fix the timezone, append it to the date string: - -.. configuration-block:: - - .. code-block:: php-annotations - - // src/AppBundle/Entity/Event.php - namespace AppBundle\Entity; - - use Symfony\Component\Validator\Constraints as Assert; - - class Event - { - /** - * @Assert\Range( - * min = "first day of January UTC", - * max = "first day of January next year UTC" - * ) - */ - protected $startDate; - } - - .. code-block:: yaml - - # src/AppBundle/Resources/config/validation.yml - AppBundle\Entity\Event: - properties: - startDate: - - Range: - min: first day of January UTC - max: first day of January next year UTC - - .. code-block:: xml - - - - - - - - - - - - - - - - .. code-block:: php - - // src/AppBundle/Entity/Person.php - namespace AppBundle\Entity; - - use Symfony\Component\Validator\Mapping\ClassMetadata; - use Symfony\Component\Validator\Constraints as Assert; - - class Event - { - public static function loadValidatorMetadata(ClassMetadata $metadata) - { - $metadata->addPropertyConstraint('startDate', new Assert\Range(array( - 'min' => 'first day of January UTC', - 'max' => 'first day of January next year UTC', - ))); - } - } - -The ``DateTime`` class also accepts relative dates or times. For example, you -can check that a delivery date starts within the next five hours like this: - -.. configuration-block:: - - .. code-block:: php-annotations - - // src/AppBundle/Entity/Order.php - namespace AppBundle\Entity; - - use Symfony\Component\Validator\Constraints as Assert; - - class Order - { - /** - * @Assert\Range( - * min = "now", - * max = "+5 hours" - * ) - */ - protected $deliveryDate; - } - - .. code-block:: yaml - - # src/AppBundle/Resources/config/validation.yml - AppBundle\Entity\Order: - properties: - deliveryDate: - - Range: - min: now - max: +5 hours - - .. code-block:: xml - - - - - - - - - - - - - - - - .. code-block:: php - - // src/AppBundle/Entity/Order.php - namespace AppBundle\Entity; - - use Symfony\Component\Validator\Mapping\ClassMetadata; - use Symfony\Component\Validator\Constraints as Assert; - - class Order - { - public static function loadValidatorMetadata(ClassMetadata $metadata) - { - $metadata->addPropertyConstraint('deliveryDate', new Assert\Range(array( - 'min' => 'now', - 'max' => '+5 hours', - ))); - } - } - Options ------- @@ -357,7 +141,4 @@ invalidMessage The message that will be shown if the underlying value is not a number (per the `is_numeric`_ PHP function). -.. include:: /reference/constraints/_payload-option.rst.inc - .. _`is_numeric`: http://www.php.net/manual/en/function.is-numeric.php -.. _`accepted by the DateTime constructor`: http://www.php.net/manual/en/datetime.formats.php diff --git a/reference/constraints/Regex.rst b/reference/constraints/Regex.rst index 458cf93e139..956fd63f93a 100644 --- a/reference/constraints/Regex.rst +++ b/reference/constraints/Regex.rst @@ -10,7 +10,6 @@ Validates that a value matches a regular expression. | | - `htmlPattern`_ | | | - `match`_ | | | - `message`_ | -| | - `payload`_ | +----------------+-----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Regex` | +----------------+-----------------------------------------------------------------------+ @@ -178,6 +177,9 @@ fail if the input string *does* match this pattern. htmlPattern ~~~~~~~~~~~ +.. versionadded:: 2.1 + The ``htmlPattern`` option was introduced in Symfony 2.1 + **type**: ``string|boolean`` **default**: null This option specifies the pattern to use in the HTML5 ``pattern`` attribute. @@ -276,5 +278,3 @@ message **type**: ``string`` **default**: ``This value is not valid.`` This is the message that will be shown if this validator fails. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Time.rst b/reference/constraints/Time.rst index 64acb618abe..f739dd7cc18 100644 --- a/reference/constraints/Time.rst +++ b/reference/constraints/Time.rst @@ -9,7 +9,6 @@ a valid "HH:MM:SS" format. | Applies to | :ref:`property or method ` | +----------------+------------------------------------------------------------------------+ | Options | - `message`_ | -| | - `payload`_ | +----------------+------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Time` | +----------------+------------------------------------------------------------------------+ @@ -87,5 +86,3 @@ message **type**: ``string`` **default**: ``This value is not a valid time.`` This message is shown if the underlying data is not a valid time. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/True.rst b/reference/constraints/True.rst new file mode 100644 index 00000000000..ba54ecbd637 --- /dev/null +++ b/reference/constraints/True.rst @@ -0,0 +1,8 @@ +True +==== + +.. caution:: + + The ``True`` constraint is deprecated since Symfony 2.7 + and will be removed in Symfony 3.0. Use the + :doc:`/reference/constraints/IsTrue` constraint instead. diff --git a/reference/constraints/Type.rst b/reference/constraints/Type.rst index 20d458a393b..abf93fe5b75 100644 --- a/reference/constraints/Type.rst +++ b/reference/constraints/Type.rst @@ -10,7 +10,6 @@ option to validate this. +----------------+---------------------------------------------------------------------+ | Options | - :ref:`type ` | | | - `message`_ | -| | - `payload`_ | +----------------+---------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Type` | +----------------+---------------------------------------------------------------------+ @@ -141,5 +140,3 @@ message **type**: ``string`` **default**: ``This value should be of type {{ type }}.`` The message if the underlying data is not of the given type. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/UniqueEntity.rst b/reference/constraints/UniqueEntity.rst index 211fb0a3753..87aa7208427 100644 --- a/reference/constraints/UniqueEntity.rst +++ b/reference/constraints/UniqueEntity.rst @@ -14,7 +14,6 @@ using an email address that already exists in the system. | | - `repositoryMethod`_ | | | - `errorPath`_ | | | - `ignoreNull`_ | -| | - `payload`_ | +----------------+-------------------------------------------------------------------------------------+ | Class | :class:`Symfony\\Bridge\\Doctrine\\Validator\\Constraints\\UniqueEntity` | +----------------+-------------------------------------------------------------------------------------+ @@ -158,6 +157,9 @@ errorPath **type**: ``string`` **default**: The name of the first field in `fields`_ +.. versionadded:: 2.1 + The ``errorPath`` option was introduced in Symfony 2.1. + If the entity violates the constraint the error message is bound to the first field in `fields`_. If there is more than one field, you may want to map the error message to another field. @@ -256,9 +258,10 @@ ignoreNull **type**: ``boolean`` **default**: ``true`` +.. versionadded:: 2.1 + The ``ignoreNull`` option was introduced 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 also has a ``null`` value, validation would fail. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Url.rst b/reference/constraints/Url.rst index 2de6b989358..14380b00f94 100644 --- a/reference/constraints/Url.rst +++ b/reference/constraints/Url.rst @@ -229,6 +229,9 @@ the ``ftp://`` type URLs to be valid, redefine the ``protocols`` array, listing checkDNS ~~~~~~~~ +.. versionadded:: 2.7 + The ``checkDNS`` option was introduced in Symfony 2.7. + **type**: ``boolean`` **default**: ``false`` By default, this constraint just validates the syntax of the given URL. If you @@ -303,6 +306,9 @@ of the ``ANY`` DNS record corresponding to the host associated with the given UR dnsMessage ~~~~~~~~~~ +.. versionadded:: 2.7 + The ``dnsMessage`` option was introduced in Symfony 2.7. + **type**: ``string`` **default**: ``The host could not be resolved.`` This message is shown when the ``checkDNS`` option is set to ``true`` and the diff --git a/reference/constraints/UserPassword.rst b/reference/constraints/UserPassword.rst index caa792b8776..95ad0d3fdef 100644 --- a/reference/constraints/UserPassword.rst +++ b/reference/constraints/UserPassword.rst @@ -1,6 +1,15 @@ UserPassword ============ +.. note:: + + Since Symfony 2.2, the ``UserPassword*`` classes in the + :namespace:`Symfony\\Component\\Security\\Core\\Validator\\Constraint ` + namespace are deprecated and will be removed in Symfony 2.3. Please + use the ``UserPassword*`` classes in the + :namespace:`Symfony\\Component\\Security\\Core\\Validator\\Constraints ` + namespace instead. + This validates that an input value is equal to the current authenticated user's password. This is useful in a form where a user can change their password, but needs to enter their old password for security. @@ -14,7 +23,6 @@ password, but needs to enter their old password for security. | Applies to | :ref:`property or method ` | +----------------+--------------------------------------------------------------------------------------------+ | Options | - `message`_ | -| | - `payload`_ | +----------------+--------------------------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Security\\Core\\Validator\\Constraints\\UserPassword` | +----------------+--------------------------------------------------------------------------------------------+ @@ -107,5 +115,3 @@ message This is the message that's displayed when the underlying string does *not* match the current user's password. - -.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Uuid.rst b/reference/constraints/Uuid.rst deleted file mode 100644 index a6ff7876560..00000000000 --- a/reference/constraints/Uuid.rst +++ /dev/null @@ -1,125 +0,0 @@ -Uuid -==== - -Validates that a value is a valid `Universally unique identifier (UUID)`_ per `RFC 4122`_. -By default, this will validate the format according to the RFC's guidelines, but this can -be relaxed to accept non-standard UUIDs that other systems (like PostgreSQL) accept. -UUID versions can also be restricted using a whitelist. - -+----------------+---------------------------------------------------------------------+ -| Applies to | :ref:`property or method ` | -+----------------+---------------------------------------------------------------------+ -| Options | - `message`_ | -| | - `strict`_ | -| | - `versions`_ | -| | - `payload`_ | -+----------------+---------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Validator\\Constraints\\Uuid` | -+----------------+---------------------------------------------------------------------+ -| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\UuidValidator` | -+----------------+---------------------------------------------------------------------+ - -Basic Usage ------------ - -.. configuration-block:: - - .. code-block:: yaml - - # src/AppBundle/Resources/config/validation.yml - AppBundle\Entity\File: - properties: - identifier: - - Uuid: ~ - - .. code-block:: php-annotations - - // src/AppBundle/Entity/File.php - namespace AppBundle\Entity; - - use Symfony\Component\Validator\Constraints as Assert; - - class File - { - /** - * @Assert\Uuid - */ - protected $identifier; - } - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - // src/AppBundle/Entity/File.php - namespace AppBundle\Entity; - - use Symfony\Component\Validator\Mapping\ClassMetadata; - use Symfony\Component\Validator\Constraints as Assert; - - class File - { - public static function loadValidatorMetadata(ClassMetadata $metadata) - { - $metadata->addPropertyConstraint('identifier', new Assert\Uuid()); - } - } - - -Options -------- - -message -~~~~~~~ - -**type**: ``string`` **default**: ``This is not a valid UUID.`` - -This message is shown if the string is not a valid UUID. - -strict -~~~~~~ - -**type**: ``boolean`` **default**: ``true`` - -If this option is set to ``true`` the constraint will check if the UUID is formatted per the -RFC's input format rules: ``216fff40-98d9-11e3-a5e2-0800200c9a66``. Setting this to ``false`` -will allow alternate input formats like: - -* ``216f-ff40-98d9-11e3-a5e2-0800-200c-9a66`` -* ``{216fff40-98d9-11e3-a5e2-0800200c9a66}`` -* ``216fff4098d911e3a5e20800200c9a66`` - -versions -~~~~~~~~ - -**type**: ``int[]`` **default**: ``[1,2,3,4,5]`` - -This option can be used to only allow specific `UUID versions`_. Valid versions are 1 - 5. -The following PHP constants can also be used: - -* ``Uuid::V1_MAC`` -* ``Uuid::V2_DCE`` -* ``Uuid::V3_MD5`` -* ``Uuid::V4_RANDOM`` -* ``Uuid::V5_SHA1`` - -All five versions are allowed by default. - -.. include:: /reference/constraints/_payload-option.rst.inc - -.. _`Universally unique identifier (UUID)`: http://en.wikipedia.org/wiki/Universally_unique_identifier -.. _`RFC 4122`: http://tools.ietf.org/html/rfc4122 -.. _`UUID versions`: http://en.wikipedia.org/wiki/Universally_unique_identifier#Variants_and_versions diff --git a/reference/constraints/Valid.rst b/reference/constraints/Valid.rst index e52e9e53bf1..67ec4bc86a6 100644 --- a/reference/constraints/Valid.rst +++ b/reference/constraints/Valid.rst @@ -9,6 +9,7 @@ an object and all sub-objects associated with it. | Applies to | :ref:`property or method ` | +----------------+---------------------------------------------------------------------+ | Options | - `traverse`_ | +| | - `deep`_ (deprecated as of 2.5) | | | - `payload`_ | +----------------+---------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\Valid` | @@ -267,4 +268,19 @@ If this constraint is applied to a property that holds an array of objects, then each object in that array will be validated only if this option is set to ``true``. +deep +~~~~ + +.. caution:: + + The ``deep`` option was deprecated in Symfony 2.5 and will be removed + in Symfony 3.0. When traversing arrays, nested arrays are always traversed. + When traversing nested objects, their traversal strategy is used. + +**type**: ``boolean`` **default**: ``false`` + +If this constraint is applied to a property that holds an array of objects, +then each object in that array will be validated recursively if this option +is set to ``true``. + .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/_payload-option.rst.inc b/reference/constraints/_payload-option.rst.inc index c32ad633989..30c6d46bbc8 100644 --- a/reference/constraints/_payload-option.rst.inc +++ b/reference/constraints/_payload-option.rst.inc @@ -3,6 +3,9 @@ payload **type**: ``mixed`` **default**: ``null`` +.. versionadded:: 2.6 + The ``payload`` option was introduced in Symfony 2.6. + This option can be used to attach arbitrary domain-specific data to a constraint. The configured payload is not used by the Validator component, but its processing is completely up to you. diff --git a/reference/constraints/map.rst.inc b/reference/constraints/map.rst.inc index b3e767b66bd..9ff2a7de7e4 100644 --- a/reference/constraints/map.rst.inc +++ b/reference/constraints/map.rst.inc @@ -20,7 +20,6 @@ String Constraints * :doc:`Url ` * :doc:`Regex ` * :doc:`Ip ` -* :doc:`Uuid` Number Constraints ~~~~~~~~~~~~~~~~~~ @@ -66,7 +65,6 @@ File Constraints Financial and other Number Constraints ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* :doc:`Bic ` * :doc:`CardScheme ` * :doc:`Currency ` * :doc:`Luhn ` @@ -78,7 +76,6 @@ Other Constraints ~~~~~~~~~~~~~~~~~ * :doc:`Callback ` -* :doc:`Expression ` * :doc:`All ` * :doc:`UserPassword ` * :doc:`Valid ` diff --git a/reference/dic_tags.rst b/reference/dic_tags.rst index 5a9fba64137..2d847f0a1aa 100644 --- a/reference/dic_tags.rst +++ b/reference/dic_tags.rst @@ -231,6 +231,9 @@ The tagged service will be removed from the container if auto_alias ---------- +.. versionadded:: 2.7 + The ``auto_alias`` tag was introduced in Symfony 2.7. + **Purpose**: Define aliases based on the value of container parameters Consider the following configuration that defines three different but related @@ -703,9 +706,9 @@ channel when injecting the logger in a service. .. tip:: - You can also configure custom channels in the configuration and retrieve - the corresponding logger service from the service container directly (see - :ref:`cookbook-monolog-channels-config`). + If you use MonologBundle 2.4 or higher, you can configure custom channels + in the configuration and retrieve the corresponding logger service from + the service container directly (see :ref:`cookbook-monolog-channels-config`). .. _dic_tags-monolog-processor: @@ -881,6 +884,10 @@ For more information, see :doc:`/cookbook/routing/custom_route_loader`. routing.expression_language_provider ------------------------------------ +.. versionadded:: 2.6 + The ``routing.expression_language_provider`` tag was introduced in Symfony + 2.6. + **Purpose**: Register a provider for expression language functions in routing This tag is used to automatically register @@ -891,6 +898,10 @@ functions to the routing expression language. security.expression_language_provider ------------------------------------- +.. versionadded:: 2.6 + The ``security.expression_language_provider`` tag was introduced in Symfony + 2.6. + **Purpose**: Register a provider for expression language functions in security This tag is used to automatically register :ref:`expression function providers diff --git a/reference/events.rst b/reference/events.rst index 800c47039d1..d596cab0947 100644 --- a/reference/events.rst +++ b/reference/events.rst @@ -158,37 +158,6 @@ Listener Class Name :class:`Symfony\\Component\\HttpKernel\\EventListener\\StreamedResponseListener` -1024 =================================================================================== ======== -``kernel.finish_request`` -~~~~~~~~~~~~~~~~~~~~~~~~~ - -**Event Class**: :class:`Symfony\\Component\\HttpKernel\\Event\\FinishRequestEvent` - -The purpose of this event is to allow you to reset the global and environmental -state of the application after a sub-request has finished (for example, the -translator listener resets the translator's locale to the one of the parent -request):: - - public function onKernelFinishRequest(FinishRequestEvent $event) - { - if (null === $parentRequest = $this->requestStack->getParentRequest()) { - return; - } - - //Reset the locale of the subrequest to the locale of the parent request - $this->setLocale($parentRequest); - } - -These are the built-in Symfony listeners related to this event: - -========================================================================== ======== -Listener Class Name Priority -========================================================================== ======== -:class:`Symfony\\Component\\HttpKernel\\EventListener\\LocaleListener` 0 -:class:`Symfony\\Component\\HttpKernel\\EventListener\\TranslatorListener` 0 -:class:`Symfony\\Component\\HttpKernel\\EventListener\\RouterListener` 0 -:class:`Symfony\\Component\\Security\\Http\\Firewall` 0 -========================================================================== ======== - ``kernel.terminate`` ~~~~~~~~~~~~~~~~~~~~ diff --git a/reference/forms/twig_reference.rst b/reference/forms/twig_reference.rst index d0de12242dc..f5b1c58fdda 100644 --- a/reference/forms/twig_reference.rst +++ b/reference/forms/twig_reference.rst @@ -180,6 +180,24 @@ obvious (since it'll render the field for you). {{ form_rest(form) }} +.. _reference-forms-twig-enctype: + +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: + +.. code-block:: html+twig + + + Form Tests Reference -------------------- @@ -313,6 +331,9 @@ done by using a public ``vars`` property on the get('name')->vars['label'] ?> +.. versionadded:: 2.3 + The ``method`` and ``action`` variables were introduced in Symfony 2.3. + +------------------------+-------------------------------------------------------------------------------------+ | Variable | Usage | +========================+=====================================================================================+ @@ -337,11 +358,19 @@ done by using a public ``vars`` property on the +------------------------+-------------------------------------------------------------------------------------+ | ``value`` | The value that will be used when rendering (commonly the ``value`` HTML attribute). | +------------------------+-------------------------------------------------------------------------------------+ +| ``read_only`` | If ``true``, ``readonly="readonly"`` is added to the field. | ++------------------------+-------------------------------------------------------------------------------------+ | ``disabled`` | If ``true``, ``disabled="disabled"`` is added to the field. | +------------------------+-------------------------------------------------------------------------------------+ | ``required`` | If ``true``, a ``required`` attribute is added to the field to activate HTML5 | | | validation. Additionally, a ``required`` class is added to the label. | +------------------------+-------------------------------------------------------------------------------------+ +| ``max_length`` | Adds a ``maxlength`` HTML attribute to the element. (deprecated as of 2.5, to be | +| | removed in 3.0, use ``attr["maxlength"]`` instead) | ++------------------------+-------------------------------------------------------------------------------------+ +| ``pattern`` | Adds a ``pattern`` HTML attribute to the element. (deprecated as of 2.5, to be | +| | removed in 3.0, use ``attr["pattern"]`` instead) | ++------------------------+-------------------------------------------------------------------------------------+ | ``label`` | The string label that will be rendered. | +------------------------+-------------------------------------------------------------------------------------+ | ``multipart`` | If ``true``, ``form_enctype`` will render ``enctype="multipart/form-data"``. | diff --git a/reference/forms/types.rst b/reference/forms/types.rst index b5afd300a63..413c5bc2bc4 100644 --- a/reference/forms/types.rst +++ b/reference/forms/types.rst @@ -18,7 +18,6 @@ Form Types Reference types/percent types/search types/url - types/range types/choice types/entity @@ -49,7 +48,7 @@ Form Types Reference types/form A form is composed of *fields*, each of which are built with the help of -a field *type* (e.g. ``TextType``, ``ChoiceType``, etc). Symfony comes +a field *type* (e.g. a ``text`` type, ``choice`` type, etc). Symfony comes standard with a large list of field types that can be used in your application. Supported Field Types diff --git a/reference/forms/types/birthday.rst b/reference/forms/types/birthday.rst index b9b39d65070..cb1e28cedad 100644 --- a/reference/forms/types/birthday.rst +++ b/reference/forms/types/birthday.rst @@ -1,16 +1,16 @@ .. index:: - single: Forms; Fields; BirthdayType + single: Forms; Fields; birthday -BirthdayType Field -================== +birthday Field Type +=================== -A :doc:`DateType ` field that specializes in handling +A :doc:`date ` field that specializes in handling birthdate data. Can be rendered as a single text box, three text boxes (month, day and year), or three select boxes. -This type is essentially the same as the :doc:`DateType ` +This type is essentially the same as the :doc:`date ` type, but with a more appropriate default for the `years`_ option. The `years`_ option defaults to 120 years ago to the current year. @@ -22,7 +22,7 @@ option defaults to 120 years ago to the current year. +----------------------+-------------------------------------------------------------------------------+ | Overridden options | - `years`_ | +----------------------+-------------------------------------------------------------------------------+ -| Inherited options | from the :doc:`DateType `: | +| Inherited options | from the :doc:`date ` type: | | | | | | - `days`_ | | | - `placeholder`_ | @@ -33,7 +33,7 @@ option defaults to 120 years ago to the current year. | | - `view_timezone`_ | | | - `widget`_ | | | | -| | from the :doc:`FormType `: | +| | from the :doc:`form ` type: | | | | | | - `data`_ | | | - `disabled`_ | @@ -41,8 +41,9 @@ option defaults to 120 years ago to the current year. | | - `invalid_message`_ | | | - `invalid_message_parameters`_ | | | - `mapped`_ | +| | - `read_only`_ | +----------------------+-------------------------------------------------------------------------------+ -| Parent type | :doc:`DateType ` | +| Parent type | :doc:`date ` | +----------------------+-------------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\BirthdayType` | +----------------------+-------------------------------------------------------------------------------+ @@ -61,13 +62,18 @@ relevant when the ``widget`` option is set to ``choice``. Inherited Options ----------------- -These options inherit from the :doc:`DateType `: +These options inherit from the :doc:`date ` +type: .. include:: /reference/forms/types/options/days.rst.inc placeholder ~~~~~~~~~~~ +.. versionadded:: 2.6 + The ``placeholder`` option was introduced in Symfony 2.6 and replaces + ``empty_value``, which is available prior to 2.6. + **type**: ``string`` | ``array`` If your widget option is set to ``choice``, then this field will be represented @@ -99,7 +105,8 @@ values for the year, month and day fields:: .. include:: /reference/forms/types/options/date_widget.rst.inc -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc @@ -112,3 +119,5 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/mapped.rst.inc + +.. include:: /reference/forms/types/options/read_only.rst.inc diff --git a/reference/forms/types/button.rst b/reference/forms/types/button.rst index 6cc4e864247..20fbf3030dd 100644 --- a/reference/forms/types/button.rst +++ b/reference/forms/types/button.rst @@ -1,8 +1,11 @@ .. index:: - single: Forms; Fields; ButtonType + single: Forms; Fields; button -ButtonType Field -================ +button Field Type +================= + +.. versionadded:: 2.3 + The ``button`` type was introduced in Symfony 2.3. A simple, non-responsive button. @@ -25,7 +28,7 @@ Inherited Options The following options are defined in the :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\BaseType` class. The ``BaseType`` class is the parent class for both the ``button`` type -and the :doc:`FormType `, but it is not part +and the :doc:`form type `, but it is not part of the form type tree (i.e. it can not be used as a form type on its own). .. include:: /reference/forms/types/options/button_attr.rst.inc diff --git a/reference/forms/types/checkbox.rst b/reference/forms/types/checkbox.rst index 8f87683f180..b0c657a2add 100644 --- a/reference/forms/types/checkbox.rst +++ b/reference/forms/types/checkbox.rst @@ -1,8 +1,8 @@ .. index:: - single: Forms; Fields; CheckboxType + single: Forms; Fields; checkbox -CheckboxType Field -================== +checkbox Field Type +=================== Creates a single input checkbox. This should always be used for a field that has a boolean value: if the box is checked, the field will be set to @@ -22,11 +22,11 @@ true, if the box is unchecked, the value will be set to false. | | - `error_mapping`_ | | | - `label`_ | | | - `label_attr`_ | -| | - `label_format`_ | | | - `mapped`_ | +| | - `read_only`_ | | | - `required`_ | +-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | +| Parent type | :doc:`form ` | +-------------+------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CheckboxType` | +-------------+------------------------------------------------------------------------+ @@ -36,10 +36,7 @@ Example Usage .. code-block:: php - use Symfony\Component\Form\Extension\Core\Type\CheckboxType; - // ... - - $builder->add('public', CheckboxType::class, array( + $builder->add('public', 'checkbox', array( 'label' => 'Show this entry publicly?', 'required' => false, )); @@ -59,7 +56,8 @@ Overridden Options Inherited Options ----------------- -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc @@ -73,10 +71,10 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/label_attr.rst.inc -.. include:: /reference/forms/types/options/label_format.rst.inc - .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc Form Variables diff --git a/reference/forms/types/choice.rst b/reference/forms/types/choice.rst index 31d528875d6..556053c5336 100644 --- a/reference/forms/types/choice.rst +++ b/reference/forms/types/choice.rst @@ -1,8 +1,8 @@ .. index:: - single: Forms; Fields; ChoiceType + single: Forms; Fields; choice -ChoiceType Field (select drop-downs, radio buttons & checkboxes) -================================================================ +choice Field Type (select drop-downs, radio buttons & checkboxes) +================================================================= A multi-purpose field used to allow the user to "choose" one or more options. It can be rendered as a ``select`` tag, radio buttons, or checkboxes. @@ -15,6 +15,7 @@ To use this field, you must specify *either* ``choices`` or ``choice_loader`` op | Options | - `choices`_ | | | - `choice_attr`_ | | | - `choice_label`_ | +| | - `choice_list`_ (deprecated) | | | - `choice_loader`_ | | | - `choice_name`_ | | | - `choice_translation_domain`_ | @@ -39,10 +40,11 @@ To use this field, you must specify *either* ``choices`` or ``choice_loader`` op | | - `label_attr`_ | | | - `label_format`_ | | | - `mapped`_ | +| | - `read_only`_ | | | - `required`_ | | | - `translation_domain`_ | +-------------+------------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | +| Parent type | :doc:`form ` | +-------------+------------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\ChoiceType` | +-------------+------------------------------------------------------------------------------+ @@ -53,15 +55,14 @@ Example Usage The easiest way to use this field is to specify the choices directly via the ``choices`` option:: - use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - // ... - - $builder->add('isAttending', ChoiceType::class, array( + $builder->add('isAttending', 'choice', array( 'choices' => array( 'Maybe' => null, 'Yes' => true, 'No' => false, ), + // *this line is important* + 'choices_as_values' => true, )); This will create a ``select`` drop-down like this: @@ -74,6 +75,14 @@ if the starting data for this field is ``true``, then ``Yes`` will be auto-selec In other words, the **value** of each item is the value you want to get/set in PHP code, while the **key** is what will be shown to the user. +.. caution:: + + The ``choices_as_values`` *must* be set to ``true`` in all cases. This activates + the "new" choice type API, which was introduced in Symfony 2.7. If you omit this + option (or set it to ``false``), you'll activate the old API, which is deprecated + and will be removed in 3.0. To read about the old API, read an older version of + the docs. + Advanced Example (with Objects!) -------------------------------- @@ -81,17 +90,14 @@ This field has a *lot* of options and most control how the field is displayed. I this example, the underlying data is some ``Category`` object that has a ``getName()`` method:: - use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - use AppBundle\Entity\Category; - // ... - - $builder->add('category', ChoiceType::class, [ + $builder->add('category', 'choice', [ 'choices' => [ new Category('Cat1'), new Category('Cat2'), new Category('Cat3'), new Category('Cat4'), ], + 'choices_as_values' => true, 'choice_label' => function($category, $key, $index) { /** @var Category $category */ return strtoupper($category->getName()); @@ -129,10 +135,7 @@ Grouping Options You can easily "group" options in a select by passing a multi-dimensional choices array:: - use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - // ... - - $builder->add('stockStatus', ChoiceType::class, [ + $builder->add('stockStatus', 'choice', [ 'choices' => [ 'Main Statuses' => [ 'Yes' => 'stock_yes', @@ -143,6 +146,7 @@ You can easily "group" options in a select by passing a multi-dimensional choice 'Discontinued' => 'stock_discontinued', ] ], + 'choices_as_values' => true, ); .. image:: /images/reference/form/choice-example4.png @@ -162,10 +166,7 @@ This is the most basic way to specify the choices that should be used by this field. The ``choices`` option is an array, where the array key is the item's label and the array value is the item's value:: - use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - // ... - - $builder->add('inStock', ChoiceType::class, array( + $builder->add('inStock', 'choice', array( 'choices' => array('In Stock' => true, 'Out of Stock' => false), // always include this 'choices_as_values' => true, @@ -177,9 +178,55 @@ is the item's label and the array value is the item's value:: .. include:: /reference/forms/types/options/choice_label.rst.inc +choice_list +~~~~~~~~~~~ + +.. caution:: + + The ``choice_list`` option of ChoiceType was deprecated in Symfony 2.7. + You should use `choices`_ or `choice_loader`_ now. + +**type**: :class:`Symfony\\Component\\Form\\Extension\\Core\\ChoiceList\\ChoiceListInterface` + +This is one way of specifying the options to be used for this field. +The ``choice_list`` option must be an instance of the ``ChoiceListInterface``. +For more advanced cases, a custom class that implements the interface +can be created to supply the choices. + +With this option you can also allow float values to be selected as data. +For example:: + + use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList; + + // ... + $builder->add('status', 'choice', array( + 'choice_list' => new ChoiceList( + array(1, 0.5, 0.1), + array('Full', 'Half', 'Almost empty') + ) + )); + +The ``status`` field created by the code above will be rendered as: + +.. code-block:: html + + + +But don't be confused! If ``Full`` is selected (value ``0`` in HTML), ``1`` +will be returned in your form. If ``Almost empty`` is selected (value ``2`` +in HTML), ``0.1`` will be returned. + choice_loader ~~~~~~~~~~~~~ +.. versionadded:: 2.7 + + The ``choice_loader`` option was added in Symfony 2.7. + **type**: :class:`Symfony\\Component\\Form\\ChoiceList\\Loader\\ChoiceLoaderInterface` The ``choice_loader`` can be used to only partially load the choices in cases where @@ -218,7 +265,7 @@ to the user. * Since 2.7:: - $builder->add('gender', ChoiceType::class, array( + $builder->add('gender', 'choice', array( // Shows "Male" to the user, returns "m" when selected 'choices' => array('Male' => 'm', 'Female' => 'f'), 'choices_as_values' => true, @@ -229,7 +276,7 @@ type behaves as if it were set to true: * Default for 3.0:: - $builder->add('gender', ChoiceType::class, array( + $builder->add('gender', 'choice', array( 'choices' => array('Male' => 'm', 'Female' => 'f'), )); @@ -277,7 +324,8 @@ the parent field (the form in most cases). Inherited Options ----------------- -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/by_reference.rst.inc @@ -297,6 +345,8 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc .. include:: /reference/forms/types/options/choice_type_translation_domain.rst.inc diff --git a/reference/forms/types/collection.rst b/reference/forms/types/collection.rst index 977d64412b2..02913dcd6d7 100644 --- a/reference/forms/types/collection.rst +++ b/reference/forms/types/collection.rst @@ -1,29 +1,30 @@ .. index:: - single: Forms; Fields; CollectionType + single: Forms; Fields; collection -CollectionType Field -==================== +collection Field Type +===================== This field type is used to render a "collection" of some field or form. -In the easiest sense, it could be an array of ``TextType`` fields that populate -an array ``emails`` values. In more complex examples, you can embed entire +In the easiest sense, it could be an array of ``text`` fields that populate +an array ``emails`` field. In more complex examples, you can embed entire forms, which is useful when creating forms that expose one-to-many relationships (e.g. a product from where you can manage many related product photos). +-------------+-----------------------------------------------------------------------------+ -| Rendered as | depends on the `entry_type`_ option | +| Rendered as | depends on the `type`_ option | +-------------+-----------------------------------------------------------------------------+ | Options | - `allow_add`_ | | | - `allow_delete`_ | | | - `delete_empty`_ | -| | - `entry_options`_ | -| | - `entry_type`_ | +| | - `options`_ | | | - `prototype`_ | | | - `prototype_name`_ | +| | - `type`_ | +-------------+-----------------------------------------------------------------------------+ | Inherited | - `by_reference`_ | -| options | - `empty_data`_ | +| options | - `cascade_validation`_ | +| | - `empty_data`_ | | | - `error_bubbling`_ | | | - `error_mapping`_ | | | - `label`_ | @@ -32,7 +33,7 @@ photos). | | - `mapped`_ | | | - `required`_ | +-------------+-----------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | +| Parent type | :doc:`form ` | +-------------+-----------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CollectionType` | +-------------+-----------------------------------------------------------------------------+ @@ -52,16 +53,12 @@ in a form. For example, suppose you have an ``emails`` field that corresponds to an array of email addresses. In the form, you want to expose each email address as its own input text box:: - use Symfony\Component\Form\Extension\Core\Type\CollectionType; - use Symfony\Component\Form\Extension\Core\Type\EmailType; - // ... - - $builder->add('emails', CollectionType::class, array( - // each entry in the array will be an "email" field - 'entry_type' => EmailType::class, + $builder->add('emails', 'collection', array( + // each item in the array will be an "email" field + 'type' => 'email', // these options are passed to each "email" type - 'entry_options' => array( - 'attr' => array('class' => 'email-box') + 'options' => array( + 'attr' => array('class' => 'email-box') ), )); @@ -276,44 +273,30 @@ form you have to set this option to true. However, existing collection entries will only be deleted if you have the allow_delete_ option enabled. Otherwise the empty values will be kept. -entry_options -~~~~~~~~~~~~~ +options +~~~~~~~ **type**: ``array`` **default**: ``array()`` -This is the array that's passed to the form type specified in the `entry_type`_ -option. For example, if you used the :doc:`ChoiceType ` -as your `entry_type`_ option (e.g. for a collection of drop-down menus), +This is the array that's passed to the form type specified in the `type`_ +option. For example, if you used the :doc:`choice ` +type as your `type`_ option (e.g. for a collection of drop-down menus), then you'd need to at least pass the ``choices`` option to the underlying type:: - use Symfony\Component\Form\Extension\Core\Type\CollectionType; - use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - // ... - - $builder->add('favorite_cities', CollectionType::class, array( - 'entry_type' => ChoiceType::class, - 'entry_options' => array( + $builder->add('favorite_cities', 'collection', array( + 'type' => 'choice', + 'options' => array( 'choices' => array( 'Nashville' => 'nashville', 'Paris' => 'paris', 'Berlin' => 'berlin', 'London' => 'london', ), + 'choices_as_values' => true, ), )); -entry_type -~~~~~~~~~~ - -**type**: ``string`` or :class:`Symfony\\Component\\Form\\FormTypeInterface` **required** - -This is the field type for each item in this collection (e.g. ``TextType``, -``ChoiceType``, etc). For example, if you have an array of email addresses, -you'd use the :doc:`EmailType `. If you want -to embed a collection of some other form, create a new instance of your -form type and pass it as this option. - prototype ~~~~~~~~~ @@ -362,16 +345,30 @@ If you have several collections in your form, or worse, nested collections you may want to change the placeholder so that unrelated placeholders are not replaced with the same value. +type +~~~~ + +**type**: ``string`` or :class:`Symfony\\Component\\Form\\FormTypeInterface` **required** + +This is the field type for each item in this collection (e.g. ``text``, +``choice``, etc). For example, if you have an array of email addresses, +you'd use the :doc:`email ` type. If you want +to embed a collection of some other form, create a new instance of your +form type and pass it as this option. + Inherited Options ----------------- -These options inherit from the :doc:`FormType `. -Not all options are listed here - only the most applicable to this type: +These options inherit from the :doc:`form ` +type. Not all options are listed here - only the most applicable to this +type: .. _reference-form-types-by-reference: .. include:: /reference/forms/types/options/by_reference.rst.inc +.. include:: /reference/forms/types/options/cascade_validation.rst.inc + .. include:: /reference/forms/types/options/empty_data.rst.inc :end-before: DEFAULT_PLACEHOLDER diff --git a/reference/forms/types/country.rst b/reference/forms/types/country.rst index edeb9225e24..4c4f3c436ea 100644 --- a/reference/forms/types/country.rst +++ b/reference/forms/types/country.rst @@ -1,10 +1,10 @@ .. index:: single: Forms; Fields; country -CountryType Field -================= +country Field Type +================== -The ``CountryType`` is a subset of the ``ChoiceType`` that displays countries +The ``country`` type is a subset of the ``ChoiceType`` that displays countries of the world. As an added bonus, the country names are displayed in the language of the user. @@ -14,9 +14,10 @@ The "value" for each country is the two-letter country code. The locale of your user is guessed using :phpmethod:`Locale::getDefault` -Unlike the ``ChoiceType``, you don't need to specify a ``choices`` option as the -field type automatically uses all of the countries of the world. You *can* specify -the option manually, but then you should just use the ``ChoiceType`` directly. +Unlike the ``choice`` type, you don't need to specify a ``choices`` or +``choice_list`` option as the field type automatically uses all of the countries +of the world. You *can* specify either of these options manually, but then +you should just use the ``choice`` type directly. +-------------+-----------------------------------------------------------------------+ | Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | @@ -24,7 +25,7 @@ the option manually, but then you should just use the ``ChoiceType`` directly. | Overridden | - `choices`_ | | options | | +-------------+-----------------------------------------------------------------------+ -| Inherited | from the :doc:`ChoiceType ` | +| Inherited | from the :doc:`choice ` type | | options | | | | - `error_bubbling`_ | | | - `error_mapping`_ | @@ -33,7 +34,7 @@ the option manually, but then you should just use the ``ChoiceType`` directly. | | - `placeholder`_ | | | - `preferred_choices`_ | | | | -| | from the :doc:`FormType ` | +| | from the :doc:`form ` type | | | | | | - `data`_ | | | - `disabled`_ | @@ -42,9 +43,10 @@ the option manually, but then you should just use the ``ChoiceType`` directly. | | - `label_attr`_ | | | - `label_format`_ | | | - `mapped`_ | +| | - `read_only`_ | | | - `required`_ | +-------------+-----------------------------------------------------------------------+ -| Parent type | :doc:`ChoiceType ` | +| Parent type | :doc:`choice ` | +-------------+-----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CountryType` | +-------------+-----------------------------------------------------------------------+ @@ -63,7 +65,8 @@ The locale is used to translate the countries names. Inherited Options ----------------- -These options inherit from the :doc:`ChoiceType `: +These options inherit from the :doc:`choice ` +type: .. include:: /reference/forms/types/options/error_bubbling.rst.inc @@ -77,7 +80,8 @@ These options inherit from the :doc:`ChoiceType ` .. include:: /reference/forms/types/options/preferred_choices.rst.inc -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc @@ -103,4 +107,6 @@ The actual default value of this option depends on other field options: .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc diff --git a/reference/forms/types/currency.rst b/reference/forms/types/currency.rst index 6bdedd99d1c..4ca2fdf72aa 100644 --- a/reference/forms/types/currency.rst +++ b/reference/forms/types/currency.rst @@ -1,15 +1,17 @@ .. index:: single: Forms; Fields; currency -CurrencyType Field -================== +currency Field Type +=================== -The ``CurrencyType`` is a subset of the :doc:`ChoiceType ` -that allows the user to select from a large list of `3-letter ISO 4217`_ currencies. +The ``currency`` type is a subset of the +:doc:`choice type ` that allows the user +to select from a large list of `3-letter ISO 4217`_ currencies. -Unlike the ``ChoiceType``, you don't need to specify a ``choices`` option as the -field type automatically uses a large list of currencies. You *can* specify the option -manually, but then you should just use the ``ChoiceType`` directly. +Unlike the ``choice`` type, you don't need to specify a ``choices`` or +``choice_list`` option as the field type automatically uses a large list +of currencies. You *can* specify either of these options manually, but then +you should just use the ``choice`` type directly. +-------------+------------------------------------------------------------------------+ | Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | @@ -17,7 +19,7 @@ manually, but then you should just use the ``ChoiceType`` directly. | Overridden | - `choices`_ | | options | | +-------------+------------------------------------------------------------------------+ -| Inherited | from the :doc:`ChoiceType ` | +| Inherited | from the :doc:`choice ` type | | options | | | | - `error_bubbling`_ | | | - `expanded`_ | @@ -25,7 +27,7 @@ manually, but then you should just use the ``ChoiceType`` directly. | | - `placeholder`_ | | | - `preferred_choices`_ | | | | -| | from the :doc:`FormType ` type | +| | from the :doc:`form ` type | | | | | | - `data`_ | | | - `disabled`_ | @@ -34,9 +36,10 @@ manually, but then you should just use the ``ChoiceType`` directly. | | - `label_attr`_ | | | - `label_format`_ | | | - `mapped`_ | +| | - `read_only`_ | | | - `required`_ | +-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`ChoiceType ` | +| Parent type | :doc:`choice ` | +-------------+------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CurrencyType` | +-------------+------------------------------------------------------------------------+ @@ -54,7 +57,8 @@ The choices option defaults to all currencies. Inherited Options ----------------- -These options inherit from the :doc:`ChoiceType `: +These options inherit from the :doc:`choice` +type: .. include:: /reference/forms/types/options/error_bubbling.rst.inc @@ -66,7 +70,8 @@ These options inherit from the :doc:`ChoiceType ` .. include:: /reference/forms/types/options/preferred_choices.rst.inc -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form` +type: .. include:: /reference/forms/types/options/data.rst.inc @@ -92,6 +97,8 @@ The actual default value of this option depends on other field options: .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc .. _`3-letter ISO 4217`: https://en.wikipedia.org/wiki/ISO_4217 diff --git a/reference/forms/types/date.rst b/reference/forms/types/date.rst index 720ae9e05e9..86df6afaee8 100644 --- a/reference/forms/types/date.rst +++ b/reference/forms/types/date.rst @@ -1,8 +1,8 @@ .. index:: - single: Forms; Fields; DateType + single: Forms; Fields; date -DateType Field -============== +date Field Type +=============== A field that allows the user to modify date information via a variety of different HTML elements. @@ -42,8 +42,9 @@ day and year) or three select boxes (see the `widget`_ option). | | - `invalid_message`_ | | | - `invalid_message_parameters`_ | | | - `mapped`_ | +| | - `read_only`_ | +----------------------+-----------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | +| Parent type | :doc:`form ` | +----------------------+-----------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\DateType` | +----------------------+-----------------------------------------------------------------------------+ @@ -55,13 +56,10 @@ This field type is highly configurable, but easy to use. The most important options are ``input`` and ``widget``. Suppose that you have a ``publishedAt`` field whose underlying date is a -``DateTime`` object. The following configures the ``DateType`` type for that +``DateTime`` object. The following configures the ``date`` type for that field as three different choice fields:: - use Symfony\Component\Form\Extension\Core\Type\DateType; - // ... - - $builder->add('publishedAt', DateType::class, array( + $builder->add('publishedAt', 'date', array( 'input' => 'datetime', 'widget' => 'choice', )); @@ -70,10 +68,7 @@ The ``input`` option *must* be changed to match the type of the underlying date data. For example, if the ``publishedAt`` field's data were a unix timestamp, you'd need to set ``input`` to ``timestamp``:: - use Symfony\Component\Form\Extension\Core\Type\DateType; - // ... - - $builder->add('publishedAt', DateType::class, array( + $builder->add('publishedAt', 'date', array( 'input' => 'timestamp', 'widget' => 'choice', )); @@ -89,20 +84,24 @@ Field Options placeholder ~~~~~~~~~~~ +.. versionadded:: 2.6 + The ``placeholder`` option was introduced in Symfony 2.6 and replaces + ``empty_value``, which is available prior to 2.6. + **type**: ``string`` | ``array`` If your widget option is set to ``choice``, then this field will be represented as a series of ``select`` boxes. When the placeholder value is a string, it will be used as the **blank value** of all select boxes:: - $builder->add('dueDate', DateType::class, array( + $builder->add('dueDate', 'date', array( 'placeholder' => 'Select a value', )); Alternatively, you can use an array that configures different placeholder values for the year, month and day fields:: - $builder->add('dueDate', DateType::class, array( + $builder->add('dueDate', 'date', array( 'placeholder' => array( 'year' => 'Year', 'month' => 'Month', 'day' => 'Day' ) @@ -150,7 +149,8 @@ error_bubbling Inherited Options ----------------- -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc @@ -166,6 +166,8 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/read_only.rst.inc + Field Variables --------------- diff --git a/reference/forms/types/datetime.rst b/reference/forms/types/datetime.rst index 0b341795263..fade67e2c89 100644 --- a/reference/forms/types/datetime.rst +++ b/reference/forms/types/datetime.rst @@ -1,8 +1,8 @@ .. index:: - single: Forms; Fields; DateTimeType + single: Forms; Fields; datetime -DateTimeType Field -================== +datetime Field Type +=================== This field type allows the user to modify data that represents a specific date and time (e.g. ``1984-06-05 12:15:30``). @@ -45,8 +45,9 @@ the data can be a ``DateTime`` object, a string, a timestamp or an array. | | - `invalid_message`_ | | | - `invalid_message_parameters`_ | | | - `mapped`_ | +| | - `read_only`_ | +----------------------+-----------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | +| Parent type | :doc:`form ` | +----------------------+-----------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\DateTimeType` | +----------------------+-----------------------------------------------------------------------------+ @@ -60,7 +61,7 @@ date_format **type**: ``integer`` or ``string`` **default**: ``IntlDateFormatter::MEDIUM`` Defines the ``format`` option that will be passed down to the date field. -See the :ref:`DateType's format option ` +See the :ref:`date type's format option ` for more details. date_widget @@ -73,6 +74,10 @@ date_widget placeholder ~~~~~~~~~~~ +.. versionadded:: 2.6 + The ``placeholder`` option was introduced in Symfony 2.6 and replaces + ``empty_value``, which is available prior to 2.6. + **type**: ``string`` | ``array`` If your widget option is set to ``choice``, then this field will be represented @@ -139,7 +144,8 @@ time_widget **type**: ``string`` **default**: ``choice`` -Defines the ``widget`` option for the :doc:`TimeType `. +Defines the ``widget`` option for the :doc:`time ` +type .. include:: /reference/forms/types/options/view_timezone.rst.inc @@ -148,8 +154,8 @@ widget **type**: ``string`` **default**: ``null`` -Defines the ``widget`` option for both the :doc:`DateType ` -and :doc:`TimeType `. This can be overridden +Defines the ``widget`` option for both the :doc:`date ` +type and :doc:`time ` type. This can be overridden with the `date_widget`_ and `time_widget`_ options. .. include:: /reference/forms/types/options/with_minutes.rst.inc @@ -180,7 +186,8 @@ error_bubbling Inherited Options ----------------- -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc @@ -194,6 +201,8 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/read_only.rst.inc + Field Variables --------------- diff --git a/reference/forms/types/email.rst b/reference/forms/types/email.rst index 70ee3e6036e..ee174e6922c 100644 --- a/reference/forms/types/email.rst +++ b/reference/forms/types/email.rst @@ -1,10 +1,10 @@ .. index:: - single: Forms; Fields; EmailType + single: Forms; Fields; email -EmailType Field -=============== +email Field Type +================ -The ``EmailType`` field is a text field that is rendered using the HTML5 +The ``email`` field is a text field that is rendered using the HTML5 ```` tag. +-------------+---------------------------------------------------------------------+ @@ -19,10 +19,12 @@ The ``EmailType`` field is a text field that is rendered using the HTML5 | | - `label_attr`_ | | | - `label_format`_ | | | - `mapped`_ | +| | - `max_length`_ (deprecated as of 2.5) | +| | - `read_only`_ | | | - `required`_ | | | - `trim`_ | +-------------+---------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | +| Parent type | :doc:`text ` | +-------------+---------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\EmailType` | +-------------+---------------------------------------------------------------------+ @@ -30,7 +32,8 @@ The ``EmailType`` field is a text field that is rendered using the HTML5 Inherited Options ----------------- -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc @@ -56,6 +59,10 @@ The default value is ``''`` (the empty string). .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/max_length.rst.inc + +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc .. include:: /reference/forms/types/options/trim.rst.inc diff --git a/reference/forms/types/entity.rst b/reference/forms/types/entity.rst index a3dcf0da857..e73cfa13845 100644 --- a/reference/forms/types/entity.rst +++ b/reference/forms/types/entity.rst @@ -1,10 +1,10 @@ .. index:: - single: Forms; Fields; EntityType + single: Forms; Fields; choice -EntityType Field -================ +entity Field Type +================= -A special ``ChoiceType`` field that's designed to load options from a Doctrine +A special ``choice`` field that's designed to load options from a Doctrine entity. For example, if you have a ``Category`` entity, you could use this field to display a ``select`` field of all, or some, of the ``Category`` objects from the database. @@ -20,7 +20,7 @@ objects from the database. | Overridden | - `choices`_ | | options | - `data_class`_ | +-------------+------------------------------------------------------------------+ -| Inherited | from the :doc:`ChoiceType `: | +| Inherited | from the :doc:`choice ` type: | | options | | | | - `choice_attr`_ | | | - `choice_name`_ | @@ -33,7 +33,7 @@ objects from the database. | | - `preferred_choices`_ | | | - `translation_domain`_ | | | | -| | from the :doc:`FormType `: | +| | from the :doc:`form ` type: | | | | | | - `data`_ | | | - `disabled`_ | @@ -44,9 +44,10 @@ objects from the database. | | - `label_attr`_ | | | - `label_format`_ | | | - `mapped`_ | +| | - `read_only`_ | | | - `required`_ | +-------------+------------------------------------------------------------------+ -| Parent type | :doc:`ChoiceType ` | +| Parent type | :doc:`choice ` | +-------------+------------------------------------------------------------------+ | Class | :class:`Symfony\\Bridge\\Doctrine\\Form\\Type\\EntityType` | +-------------+------------------------------------------------------------------+ @@ -57,22 +58,16 @@ Basic Usage The ``entity`` type has just one required option: the entity which should be listed inside the choice field:: - use Symfony\Bridge\Doctrine\Form\Type\EntityType; - // ... - - $builder->add('users', EntityType::class, array( - 'class' => 'AppBundle:User', + $builder->add('users', 'entity', array( + 'class' => 'AcmeHelloBundle:User', 'choice_label' => 'username', )); In this case, all ``User`` objects will be loaded from the database and rendered as either a ``select`` tag, a set or radio buttons or a series of checkboxes (this depends on the ``multiple`` and ``expanded`` values). -Because of the `choice_label`_ option, the ``username`` property (usually by calling -``getUsername()``) will be used as the text to display in the field. - -If you omit the ``choice_label`` option, then your entity *must* have a ``__toString()`` -method. +If the entity object does not have a ``__toString()`` method the ``choice_label`` +option is needed. Using a Custom Query for the Entities ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -82,11 +77,10 @@ If you need to specify a custom query to use when fetching the entities the ``query_builder`` option. The easiest way to use the option is as follows:: use Doctrine\ORM\EntityRepository; - use Symfony\Bridge\Doctrine\Form\Type\EntityType; // ... - $builder->add('users', EntityType::class, array( - 'class' => 'AppBundle:User', + $builder->add('users', 'entity', array( + 'class' => 'AcmeHelloBundle:User', 'query_builder' => function (EntityRepository $er) { return $er->createQueryBuilder('u') ->orderBy('u.username', 'ASC'); @@ -104,11 +98,8 @@ For example, if you have a ``$group`` variable (passed into your form perhaps as a form option) and ``getUsers`` returns a collection of ``User`` entities, then you can supply the ``choices`` option directly:: - use Symfony\Bridge\Doctrine\Form\Type\EntityType; - // ... - - $builder->add('users', EntityType::class, array( - 'class' => 'AppBundle:User', + $builder->add('users', 'entity', array( + 'class' => 'AcmeHelloBundle:User', 'choices' => $group->getUsers(), )); @@ -120,15 +111,16 @@ Field Options choice_label ~~~~~~~~~~~~ +.. versionadded:: 2.7 + The ``choice_label`` option was introduced in Symfony 2.7. Prior to Symfony + 2.7, it was called ``property`` (which has the same functionality). + **type**: ``string`` or ``callable`` This is the property that should be used for displaying the entities as text in the HTML element:: - use Symfony\Bridge\Doctrine\Form\Type\EntityType; - // ... - - $builder->add('category', EntityType::class, array( + $builder->add('category', 'entity', array( 'class' => 'AppBundle:Category', 'choice_label' => 'displayName', )); @@ -136,10 +128,7 @@ the HTML element:: If left blank, the entity object will be cast to a string and so must have a ``__toString()`` method. You can also pass a callback function for more control:: - use Symfony\Bridge\Doctrine\Form\Type\EntityType; - // ... - - $builder->add('category', EntityType::class, array( + $builder->add('category', 'entity', array( 'class' => 'AppBundle:Category', 'choice_label' => function ($category) { return $category->getDisplayName(); @@ -158,11 +147,8 @@ more detais, see the main :ref:`choice_label ` docu For example, if the translations property is actually an associative array of objects, each with a name property, then you could do this:: - use Symfony\Bridge\Doctrine\Form\Type\EntityType; - // ... - - $builder->add('gender', EntityType::class, array( - 'class' => 'AppBundle:Category', + $builder->add('gender', 'entity', array( + 'class' => 'MyBundle:Gender', 'choice_label' => 'translations[en].name', )); @@ -171,8 +157,8 @@ class **type**: ``string`` **required** -The class of your entity (e.g. ``AppBundle:Category``). This can be -a fully-qualified class name (e.g. ``AppBundle\Entity\Category``) +The class of your entity (e.g. ``AcmeStoreBundle:Category``). This can be +a fully-qualified class name (e.g. ``Acme\StoreBundle\Entity\Category``) or the short alias name (as shown prior). em @@ -217,7 +203,8 @@ to query the entities. Inherited Options ----------------- -These options inherit from the :doc:`ChoiceType `: +These options inherit from the :doc:`choice ` +type: .. include:: /reference/forms/types/options/choice_attr.rst.inc @@ -247,8 +234,8 @@ These options inherit from the :doc:`ChoiceType ` .. note:: - This option expects an array of entity objects (that's actually the same as with - the ``ChoiceType`` field, whichs requires an array of the preferred "values"). + This option expects an array of entity objects, unlike the ``choice`` + field that requires an array of keys. .. include:: /reference/forms/types/options/choice_type_translation_domain.rst.inc @@ -283,4 +270,6 @@ The actual default value of this option depends on other field options: .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc diff --git a/reference/forms/types/file.rst b/reference/forms/types/file.rst index 8ebacb16020..4b5faaa41d7 100644 --- a/reference/forms/types/file.rst +++ b/reference/forms/types/file.rst @@ -1,16 +1,14 @@ .. index:: - single: Forms; Fields; FileType + single: Forms; Fields; file -FileType Field -============== +file Field Type +=============== -The ``FileType`` represents a file input in your form. +The ``file`` type represents a file input in your form. +-------------+---------------------------------------------------------------------+ | Rendered as | ``input`` ``file`` field | +-------------+---------------------------------------------------------------------+ -| Options | - `multiple`_ | -+-------------+---------------------------------------------------------------------+ | Overridden | - `compound`_ | | options | - `data_class`_ | | | - `empty_data`_ | @@ -20,11 +18,11 @@ The ``FileType`` represents a file input in your form. | | - `error_mapping`_ | | | - `label`_ | | | - `label_attr`_ | -| | - `label_format`_ | | | - `mapped`_ | +| | - `read_only`_ | | | - `required`_ | +-------------+---------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | +| Parent type | :doc:`form ` | +-------------+---------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\FileType` | +-------------+---------------------------------------------------------------------+ @@ -34,10 +32,7 @@ Basic Usage Say you have this form definition:: - use Symfony\Component\Form\Extension\Core\Type\FileType; - // ... - - $builder->add('attachment', FileType::class); + $builder->add('attachment', 'file'); When the form is submitted, the ``attachment`` field will be an instance of :class:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile`. It can @@ -82,16 +77,6 @@ before using it directly. Read the :doc:`cookbook ` for an example of how to manage a file upload associated with a Doctrine entity. -Field Options -------------- - -multiple -~~~~~~~~ - -**type**: ``Boolean`` **default**: ``false`` - -When set to true, the user will be able to upload multiple files at the same time. - Overridden Options ------------------ @@ -115,7 +100,8 @@ value is empty. Inherited Options ----------------- -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/disabled.rst.inc @@ -127,10 +113,10 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/label_attr.rst.inc -.. include:: /reference/forms/types/options/label_format.rst.inc - .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc Form Variables diff --git a/reference/forms/types/form.rst b/reference/forms/types/form.rst index 448e110bd40..a2ed009fb9d 100644 --- a/reference/forms/types/form.rst +++ b/reference/forms/types/form.rst @@ -1,16 +1,17 @@ .. index:: - single: Forms; Fields; FormType + single: Forms; Fields; form -FormType Field -============== +form Field Type +=============== -The ``FormType`` predefines a couple of options that are then available -on all types for which ``FormType`` is the parent. +The ``form`` type predefines a couple of options that are then available +on all types for which ``form`` is the parent type. +-----------+--------------------------------------------------------------------+ | Options | - `action`_ | | | - `allow_extra_fields`_ | | | - `by_reference`_ | +| | - `cascade_validation`_ | | | - `compound`_ | | | - `constraints`_ | | | - `data`_ | @@ -25,9 +26,12 @@ on all types for which ``FormType`` is the parent. | | - `label_attr`_ | | | - `label_format`_ | | | - `mapped`_ | +| | - `max_length`_ (deprecated as of 2.5) | | | - `method`_ | +| | - `pattern`_ (deprecated as of 2.5) | | | - `post_max_size_message`_ | | | - `property_path`_ | +| | - `read_only`_ | | | - `required`_ | | | - `trim`_ | +-----------+--------------------------------------------------------------------+ @@ -53,6 +57,9 @@ Field Options allow_extra_fields ~~~~~~~~~~~~~~~~~~ +.. versionadded:: 2.6 + The ``allow_extra_fields`` option was introduced in Symfony 2.6. + **type**: ``boolean`` **default**: ``false`` Usually, if you submit extra fields that aren't configured in your form, @@ -63,6 +70,8 @@ option on the form. .. include:: /reference/forms/types/options/by_reference.rst.inc +.. include:: /reference/forms/types/options/cascade_validation.rst.inc + .. include:: /reference/forms/types/options/compound.rst.inc .. include:: /reference/forms/types/options/constraints.rst.inc @@ -108,16 +117,26 @@ The actual default value of this option depends on other field options: .. include:: /reference/forms/types/options/mapped.rst.inc +.. _reference-form-option-max_length: + +.. include:: /reference/forms/types/options/max_length.rst.inc + .. _form-option-method: .. include:: /reference/forms/types/options/method.rst.inc +.. _reference-form-option-pattern: + +.. include:: /reference/forms/types/options/pattern.rst.inc + .. include:: /reference/forms/types/options/post_max_size_message.rst.inc .. _reference-form-option-property-path: .. include:: /reference/forms/types/options/property_path.rst.inc +.. include:: /reference/forms/types/options/read_only.rst.inc + .. _reference-form-option-required: .. include:: /reference/forms/types/options/required.rst.inc @@ -130,7 +149,7 @@ Inherited Options The following options are defined in the :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\BaseType` class. The ``BaseType`` class is the parent class for both the ``form`` type and -the :doc:`ButtonType `, but it is not part +the :doc:`button type `, but it is not part of the form type tree (i.e. it can not be used as a form type on its own). .. include:: /reference/forms/types/options/attr.rst.inc diff --git a/reference/forms/types/hidden.rst b/reference/forms/types/hidden.rst index e211c526f63..272eb853852 100644 --- a/reference/forms/types/hidden.rst +++ b/reference/forms/types/hidden.rst @@ -1,8 +1,8 @@ .. index:: single: Forms; Fields; hidden -HiddenType Field -================ +hidden Field Type +================= The hidden type represents a hidden input field. @@ -18,7 +18,7 @@ The hidden type represents a hidden input field. | | - `mapped`_ | | | - `property_path`_ | +-------------+----------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | +| Parent type | :doc:`form ` | +-------------+----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\HiddenType` | +-------------+----------------------------------------------------------------------+ @@ -45,7 +45,8 @@ Hidden fields cannot have a required attribute. Inherited Options ----------------- -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc diff --git a/reference/forms/types/integer.rst b/reference/forms/types/integer.rst index 1b87d8f690e..4fb6eff152e 100644 --- a/reference/forms/types/integer.rst +++ b/reference/forms/types/integer.rst @@ -1,8 +1,8 @@ .. index:: - single: Forms; Fields; IntegerType + single: Forms; Fields; integer -IntegerType Field -================= +integer Field Type +================== Renders an input "number" field. Basically, this is a text field that's good at handling data that's in an integer form. The input ``number`` field @@ -17,7 +17,7 @@ integers. By default, all non-integer values (e.g. 6.78) will round down | Rendered as | ``input`` ``number`` field | +-------------+-----------------------------------------------------------------------+ | Options | - `grouping`_ | -| | - `scale`_ | +| | - `precision`_ | | | - `rounding_mode`_ | +-------------+-----------------------------------------------------------------------+ | Overridden | - `compound`_ | @@ -32,11 +32,11 @@ integers. By default, all non-integer values (e.g. 6.78) will round down | | - `invalid_message_parameters`_ | | | - `label`_ | | | - `label_attr`_ | -| | - `label_format`_ | | | - `mapped`_ | +| | - `read_only`_ | | | - `required`_ | +-------------+-----------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | +| Parent type | :doc:`form ` | +-------------+-----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\IntegerType` | +-------------+-----------------------------------------------------------------------+ @@ -46,7 +46,7 @@ Field Options .. include:: /reference/forms/types/options/grouping.rst.inc -.. include:: /reference/forms/types/options/scale.rst.inc +.. include:: /reference/forms/types/options/precision.rst.inc rounding_mode ~~~~~~~~~~~~~ @@ -57,25 +57,17 @@ By default, if the user enters a non-integer number, it will be rounded down. There are several other rounding methods and each is a constant on the :class:`Symfony\\Component\\Form\\Extension\\Core\\DataTransformer\\IntegerToLocalizedStringTransformer`: -* ``IntegerToLocalizedStringTransformer::ROUND_DOWN`` Round towards zero. +* ``IntegerToLocalizedStringTransformer::ROUND_DOWN`` Rounding mode to + round towards zero. -* ``IntegerToLocalizedStringTransformer::ROUND_FLOOR`` Round towards negative - infinity. +* ``IntegerToLocalizedStringTransformer::ROUND_FLOOR`` Rounding mode to + round towards negative infinity. -* ``IntegerToLocalizedStringTransformer::ROUND_UP`` Round away from zero. +* ``IntegerToLocalizedStringTransformer::ROUND_UP`` Rounding mode to round + away from zero. -* ``IntegerToLocalizedStringTransformer::ROUND_CEILING`` Round towards - positive infinity. - -* ``IntegerToLocalizedStringTransformer::ROUND_HALF_DOWN`` Round towards the - "nearest neighbor". If both neighbors are equidistant, round down. - -* ``IntegerToLocalizedStringTransformer::ROUND_HALF_EVEN`` Round towards the - "nearest neighbor". If both neighbors are equidistant, round towards the - even neighbor. - -* ``IntegerToLocalizedStringTransformer::ROUND_HALF_UP`` Round towards the - "nearest neighbor". If both neighbors are equidistant, round up. +* ``IntegerToLocalizedStringTransformer::ROUND_CEILING`` Rounding mode + to round towards positive infinity. Overridden Options ------------------ @@ -85,7 +77,8 @@ Overridden Options Inherited Options ----------------- -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc @@ -111,8 +104,8 @@ The default value is ``''`` (the empty string). .. include:: /reference/forms/types/options/label_attr.rst.inc -.. include:: /reference/forms/types/options/label_format.rst.inc - .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc diff --git a/reference/forms/types/language.rst b/reference/forms/types/language.rst index cdd5e461ed4..6eb57950620 100644 --- a/reference/forms/types/language.rst +++ b/reference/forms/types/language.rst @@ -1,10 +1,10 @@ .. index:: - single: Forms; Fields; LanguageType + single: Forms; Fields; language -LanguageType Field -================== +language Field Type +=================== -The ``LanguageType`` is a subset of the ``ChoiceType`` that allows the +The ``language`` type is a subset of the ``ChoiceType`` that allows the user to select from a large list of languages. As an added bonus, the language names are displayed in the language of the user. @@ -15,9 +15,10 @@ in the `International Components for Unicode`_ (e.g. ``fr`` or ``zh_Hant``). The locale of your user is guessed using :phpmethod:`Locale::getDefault` -Unlike the ``ChoiceType``, you don't need to specify a ``choices`` option as the -field type automatically uses a large list of languages. You *can* specify the option -manually, but then you should just use the ``ChoiceType`` directly. +Unlike the ``choice`` type, you don't need to specify a ``choices`` or +``choice_list`` option as the field type automatically uses a large list +of languages. You *can* specify either of these options manually, but then +you should just use the ``choice`` type directly. +-------------+------------------------------------------------------------------------+ | Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | @@ -25,7 +26,7 @@ manually, but then you should just use the ``ChoiceType`` directly. | Overridden | - `choices`_ | | options | | +-------------+------------------------------------------------------------------------+ -| Inherited | from the :doc:`ChoiceType ` | +| Inherited | from the :doc:`choice ` type | | options | | | | - `error_bubbling`_ | | | - `error_mapping`_ | @@ -34,7 +35,7 @@ manually, but then you should just use the ``ChoiceType`` directly. | | - `placeholder`_ | | | - `preferred_choices`_ | | | | -| | from the :doc:`FormType ` | +| | from the :doc:`form ` type | | | | | | - `data`_ | | | - `disabled`_ | @@ -43,9 +44,10 @@ manually, but then you should just use the ``ChoiceType`` directly. | | - `label_attr`_ | | | - `label_format`_ | | | - `mapped`_ | +| | - `read_only`_ | | | - `required`_ | +-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`ChoiceType ` | +| Parent type | :doc:`choice ` | +-------------+------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\LanguageType` | +-------------+------------------------------------------------------------------------+ @@ -64,7 +66,8 @@ The default locale is used to translate the languages names. Inherited Options ----------------- -These options inherit from the :doc:`ChoiceType `: +These options inherit from the :doc:`choice ` +type: .. include:: /reference/forms/types/options/error_bubbling.rst.inc @@ -78,7 +81,8 @@ These options inherit from the :doc:`ChoiceType ` .. include:: /reference/forms/types/options/preferred_choices.rst.inc -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc @@ -104,6 +108,8 @@ The actual default value of this option depends on other field options: .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc .. _`International Components for Unicode`: http://site.icu-project.org diff --git a/reference/forms/types/locale.rst b/reference/forms/types/locale.rst index 5a54d179ceb..a629c5ac4fe 100644 --- a/reference/forms/types/locale.rst +++ b/reference/forms/types/locale.rst @@ -1,10 +1,10 @@ .. index:: - single: Forms; Fields; LocaleType + single: Forms; Fields; locale -LocaleType Field -================ +locale Field Type +================= -The ``LocaleType`` is a subset of the ``ChoiceType`` that allows the user +The ``locale`` type is a subset of the ``ChoiceType`` that allows the user to select from a large list of locales (language+country). As an added bonus, the locale names are displayed in the language of the user. @@ -17,9 +17,10 @@ for French/France). The locale of your user is guessed using :phpmethod:`Locale::getDefault` -Unlike the ``ChoiceType``, you don't need to specify a ``choices`` option as the -field type automatically uses a large list of locales. You *can* specify these options -manually, but then you should just use the ``ChoiceType`` directly. +Unlike the ``choice`` type, you don't need to specify a ``choices`` or +``choice_list`` option as the field type automatically uses a large list +of locales. You *can* specify either of these options manually, but then +you should just use the ``choice`` type directly. +-------------+------------------------------------------------------------------------+ | Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | @@ -27,7 +28,7 @@ manually, but then you should just use the ``ChoiceType`` directly. | Overridden | - `choices`_ | | options | | +-------------+------------------------------------------------------------------------+ -| Inherited | from the :doc:`ChoiceType ` | +| Inherited | from the :doc:`choice ` type | | options | | | | - `error_bubbling`_ | | | - `error_mapping`_ | @@ -36,7 +37,7 @@ manually, but then you should just use the ``ChoiceType`` directly. | | - `placeholder`_ | | | - `preferred_choices`_ | | | | -| | from the :doc:`FormType ` | +| | from the :doc:`form ` type | | | | | | - `data`_ | | | - `disabled`_ | @@ -45,9 +46,10 @@ manually, but then you should just use the ``ChoiceType`` directly. | | - `label_attr`_ | | | - `label_format`_ | | | - `mapped`_ | +| | - `read_only`_ | | | - `required`_ | +-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`ChoiceType ` | +| Parent type | :doc:`choice ` | +-------------+------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\LocaleType` | +-------------+------------------------------------------------------------------------+ @@ -66,7 +68,8 @@ specify the language. Inherited Options ----------------- -These options inherit from the :doc:`ChoiceType `: +These options inherit from the :doc:`choice ` +type: .. include:: /reference/forms/types/options/error_bubbling.rst.inc @@ -80,7 +83,8 @@ These options inherit from the :doc:`ChoiceType ` .. include:: /reference/forms/types/options/preferred_choices.rst.inc -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc @@ -106,6 +110,8 @@ The actual default value of this option depends on other field options: .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc .. _`ISO 639-1`: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes diff --git a/reference/forms/types/map.rst.inc b/reference/forms/types/map.rst.inc index 4351908de8a..b4362b3f318 100644 --- a/reference/forms/types/map.rst.inc +++ b/reference/forms/types/map.rst.inc @@ -1,63 +1,62 @@ Text Fields ~~~~~~~~~~~ -* :doc:`TextType ` -* :doc:`TextareaType ` -* :doc:`EmailType ` -* :doc:`IntegerType ` -* :doc:`MoneyType ` -* :doc:`NumberType ` -* :doc:`PasswordType ` -* :doc:`PercentType ` -* :doc:`SearchType ` -* :doc:`UrlType ` -* :doc:`RangeType ` +* :doc:`text ` +* :doc:`textarea ` +* :doc:`email ` +* :doc:`integer ` +* :doc:`money ` +* :doc:`number ` +* :doc:`password ` +* :doc:`percent ` +* :doc:`search ` +* :doc:`url ` Choice Fields ~~~~~~~~~~~~~ -* :doc:`ChoiceType ` -* :doc:`EntityType ` -* :doc:`CountryType ` -* :doc:`LanguageType ` -* :doc:`LocaleType ` -* :doc:`TimezoneType ` -* :doc:`CurrencyType ` +* :doc:`choice ` +* :doc:`entity ` +* :doc:`country ` +* :doc:`language ` +* :doc:`locale ` +* :doc:`timezone ` +* :doc:`currency ` Date and Time Fields ~~~~~~~~~~~~~~~~~~~~ -* :doc:`DateType ` -* :doc:`DateTimeType ` -* :doc:`TimeType ` -* :doc:`BirthdayType ` +* :doc:`date ` +* :doc:`datetime ` +* :doc:`time ` +* :doc:`birthday ` Other Fields ~~~~~~~~~~~~ -* :doc:`CheckboxType ` -* :doc:`FileType ` -* :doc:`RadioType ` +* :doc:`checkbox ` +* :doc:`file ` +* :doc:`radio ` Field Groups ~~~~~~~~~~~~ -* :doc:`CollectionType ` -* :doc:`RepeatedType ` +* :doc:`collection ` +* :doc:`repeated ` Hidden Fields ~~~~~~~~~~~~~ -* :doc:`HiddenType ` +* :doc:`hidden ` Buttons ~~~~~~~ -* :doc:`ButtonType ` -* :doc:`ResetType ` -* :doc:`SubmitType ` +* :doc:`button` +* :doc:`reset` +* :doc:`submit` Base Fields ~~~~~~~~~~~ -* :doc:`FormType ` +* :doc:`form ` diff --git a/reference/forms/types/money.rst b/reference/forms/types/money.rst index 3f6af5941ef..59243f1c836 100644 --- a/reference/forms/types/money.rst +++ b/reference/forms/types/money.rst @@ -1,8 +1,8 @@ .. index:: - single: Forms; Fields; MoneyType + single: Forms; Fields; money -MoneyType Field -=============== +money Field Type +================ Renders an input text field and specializes in handling submitted "money" data. @@ -17,7 +17,7 @@ how the input and output of the data is handled. | Options | - `currency`_ | | | - `divisor`_ | | | - `grouping`_ | -| | - `scale`_ | +| | - `precision`_ | +-------------+---------------------------------------------------------------------+ | Overridden | - `compound`_ | | options | | @@ -31,11 +31,11 @@ how the input and output of the data is handled. | | - `invalid_message_parameters`_ | | | - `label`_ | | | - `label_attr`_ | -| | - `label_format`_ | | | - `mapped`_ | +| | - `read_only`_ | | | - `required`_ | +-------------+---------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | +| Parent type | :doc:`form ` | +-------------+---------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\MoneyType` | +-------------+---------------------------------------------------------------------+ @@ -65,10 +65,7 @@ If, for some reason, you need to divide your starting value by a number before rendering it to the user, you can use the ``divisor`` option. For example:: - use Symfony\Component\Form\Extension\Core\Type\MoneyType; - // ... - - $builder->add('price', MoneyType::class, array( + $builder->add('price', 'money', array( 'divisor' => 100, )); @@ -79,14 +76,18 @@ be set back on your object. .. include:: /reference/forms/types/options/grouping.rst.inc -scale -~~~~~ +precision +~~~~~~~~~ + +.. versionadded:: 2.7 + The ``scale`` option was introduced in Symfony 2.7. Prior to Symfony 2.7, + it was known as ``precision``. **type**: ``integer`` **default**: ``2`` -If, for some reason, you need some scale other than 2 decimal places, +For some reason, if you need some precision other than 2 decimal places, you can modify this value. You probably won't need to do this unless, -for example, you want to round to the nearest dollar (set the scale +for example, you want to round to the nearest dollar (set the precision to ``0``). Overridden Options @@ -97,7 +98,8 @@ Overridden Options Inherited Options ----------------- -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc @@ -123,10 +125,10 @@ The default value is ``''`` (the empty string). .. include:: /reference/forms/types/options/label_attr.rst.inc -.. include:: /reference/forms/types/options/label_format.rst.inc - .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc Form Variables diff --git a/reference/forms/types/number.rst b/reference/forms/types/number.rst index de5ae737aba..509f10917f3 100644 --- a/reference/forms/types/number.rst +++ b/reference/forms/types/number.rst @@ -1,18 +1,18 @@ .. index:: - single: Forms; Fields; NumberType + single: Forms; Fields; number -NumberType Field -================ +number Field Type +================= Renders an input text field and specializes in handling number input. This -type offers different options for the scale, rounding and grouping +type offers different options for the precision, rounding and grouping that you want to use for your number. +-------------+----------------------------------------------------------------------+ | Rendered as | ``input`` ``text`` field | +-------------+----------------------------------------------------------------------+ | Options | - `grouping`_ | -| | - `scale`_ | +| | - `precision`_ | | | - `rounding_mode`_ | +-------------+----------------------------------------------------------------------+ | Overridden | - `compound`_ | @@ -27,11 +27,11 @@ that you want to use for your number. | | - `invalid_message_parameters`_ | | | - `label`_ | | | - `label_attr`_ | -| | - `label_format`_ | | | - `mapped`_ | +| | - `read_only`_ | | | - `required`_ | +-------------+----------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | +| Parent type | :doc:`form ` | +-------------+----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\NumberType` | +-------------+----------------------------------------------------------------------+ @@ -41,36 +41,41 @@ Field Options .. include:: /reference/forms/types/options/grouping.rst.inc -.. include:: /reference/forms/types/options/scale.rst.inc +.. include:: /reference/forms/types/options/precision.rst.inc rounding_mode ~~~~~~~~~~~~~ -**type**: ``integer`` **default**: ``NumberToLocalizedStringTransformer::ROUND_HALFUP`` +**type**: ``integer`` **default**: ``IntegerToLocalizedStringTransformer::ROUND_HALFUP`` -If a submitted number needs to be rounded (based on the `scale`_ +If a submitted number needs to be rounded (based on the ``precision`` option), you have several configurable options for that rounding. Each -option is a constant on the :class:`Symfony\\Component\\Form\\Extension\\Core\\DataTransformer\\NumberToLocalizedStringTransformer`: - -* ``NumberToLocalizedStringTransformer::ROUND_DOWN`` Round towards zero. +option is a constant on the +:class:`Symfony\\Component\\Form\\Extension\\Core\\DataTransformer\\IntegerToLocalizedStringTransformer`: -* ``NumberToLocalizedStringTransformer::ROUND_FLOOR`` Round towards negative - infinity. +* ``IntegerToLocalizedStringTransformer::ROUND_DOWN`` Rounding mode to + round towards zero. -* ``NumberToLocalizedStringTransformer::ROUND_UP`` Round away from zero. +* ``IntegerToLocalizedStringTransformer::ROUND_FLOOR`` Rounding mode to + round towards negative infinity. -* ``NumberToLocalizedStringTransformer::ROUND_CEILING`` Round towards - positive infinity. +* ``IntegerToLocalizedStringTransformer::ROUND_UP`` Rounding mode to round + away from zero. -* ``NumberToLocalizedStringTransformer::ROUND_HALF_DOWN`` Round towards the - "nearest neighbor". If both neighbors are equidistant, round down. +* ``IntegerToLocalizedStringTransformer::ROUND_CEILING`` Rounding mode + to round towards positive infinity. -* ``NumberToLocalizedStringTransformer::ROUND_HALF_EVEN`` Round towards the - "nearest neighbor". If both neighbors are equidistant, round towards the - even neighbor. +* ``IntegerToLocalizedStringTransformer::ROUND_HALFDOWN`` Rounding mode + to round towards "nearest neighbor" unless both neighbors are equidistant, + in which case round down. -* ``NumberToLocalizedStringTransformer::ROUND_HALF_UP`` Round towards the - "nearest neighbor". If both neighbors are equidistant, round up. +* ``IntegerToLocalizedStringTransformer::ROUND_HALFEVEN`` Rounding mode + to round towards the "nearest neighbor" unless both neighbors are equidistant, + in which case, round towards the even neighbor. + +* ``IntegerToLocalizedStringTransformer::ROUND_HALFUP`` Rounding mode + to round towards "nearest neighbor" unless both neighbors are equidistant, + in which case round up. Overridden Options ------------------ @@ -80,7 +85,8 @@ Overridden Options Inherited Options ----------------- -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc @@ -106,8 +112,8 @@ The default value is ``''`` (the empty string). .. include:: /reference/forms/types/options/label_attr.rst.inc -.. include:: /reference/forms/types/options/label_format.rst.inc - .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc diff --git a/reference/forms/types/options/action.rst.inc b/reference/forms/types/options/action.rst.inc index a878355cc38..dcc557a717f 100644 --- a/reference/forms/types/options/action.rst.inc +++ b/reference/forms/types/options/action.rst.inc @@ -1,6 +1,9 @@ action ~~~~~~ +.. versionadded:: 2.3 + The ``action`` option was introduced in Symfony 2.3. + **type**: ``string`` **default**: empty string This option specifies where to send the form's data on submission (usually diff --git a/reference/forms/types/options/attr.rst.inc b/reference/forms/types/options/attr.rst.inc index 46238ac023b..bbee5888a4a 100644 --- a/reference/forms/types/options/attr.rst.inc +++ b/reference/forms/types/options/attr.rst.inc @@ -7,6 +7,6 @@ If you want to add extra attributes to an HTML field representation you can use the ``attr`` option. It's an associative array with HTML attributes as keys. This can be useful when you need to set a custom class for some widget:: - $builder->add('body', TextareaType::class, array( + $builder->add('body', 'textarea', array( 'attr' => array('class' => 'tinymce'), )); diff --git a/reference/forms/types/options/button_attr.rst.inc b/reference/forms/types/options/button_attr.rst.inc index 93f70017d7e..20265677042 100644 --- a/reference/forms/types/options/button_attr.rst.inc +++ b/reference/forms/types/options/button_attr.rst.inc @@ -7,9 +7,6 @@ If you want to add extra attributes to the HTML representation of the button, you can use ``attr`` option. It's an associative array with HTML attribute as a key. This can be useful when you need to set a custom class for the button:: - use Symfony\Component\Form\Extension\Core\Type\ButtonType; - // ... - - $builder->add('save', ButtonType::class, array( + $builder->add('save', 'button', array( 'attr' => array('class' => 'save'), )); diff --git a/reference/forms/types/options/by_reference.rst.inc b/reference/forms/types/options/by_reference.rst.inc index e2552817470..a2e80e1d544 100644 --- a/reference/forms/types/options/by_reference.rst.inc +++ b/reference/forms/types/options/by_reference.rst.inc @@ -10,18 +10,13 @@ called in all cases. To explain this further, here's a simple example:: - use Symfony\Component\Form\Extension\Core\Type\TextType; - use Symfony\Component\Form\Extension\Core\Type\EmailType; - use Symfony\Component\Form\Extension\Core\Type\FormType; - // ... - $builder = $this->createFormBuilder($article); $builder - ->add('title', TextType::class) + ->add('title', 'text') ->add( - $builder->create('author', FormType::class, array('by_reference' => ?)) - ->add('name', TextType::class) - ->add('email', EmailType::class) + $builder->create('author', 'form', array('by_reference' => ?)) + ->add('name', 'text') + ->add('email', 'email') ) If ``by_reference`` is true, the following takes place behind the scenes @@ -44,8 +39,8 @@ If you set ``by_reference`` to false, submitting looks like this:: So, all that ``by_reference=false`` really does is force the framework to call the setter on the parent object. -Similarly, if you're using the :doc:`CollectionType ` -field where your underlying collection data is an object (like with +Similarly, if you're using the :doc:`collection` +form type where your underlying collection data is an object (like with Doctrine's ``ArrayCollection``), then ``by_reference`` must be set to ``false`` if you need the adder and remover (e.g. ``addAuthor()`` and ``removeAuthor()``) to be called. diff --git a/reference/forms/types/options/cascade_validation.rst.inc b/reference/forms/types/options/cascade_validation.rst.inc new file mode 100644 index 00000000000..de75044ba73 --- /dev/null +++ b/reference/forms/types/options/cascade_validation.rst.inc @@ -0,0 +1,20 @@ +cascade_validation +~~~~~~~~~~~~~~~~~~ + +**type**: ``boolean`` **default**: ``false`` + +Set this option to ``true`` to force validation on embedded form types. +For example, if you have a ``ProductType`` with an embedded ``CategoryType``, +setting ``cascade_validation`` to ``true`` on ``ProductType`` will cause +the data from ``CategoryType`` to also be validated. + +.. tip:: + + Instead of using this option, it is recommended that you use the ``Valid`` + constraint in your model to force validation on a child object stored + on a property. This cascades only the validation but not the use of + the ``validation_groups`` option on child forms. You can read more + about this in the section about + :ref:`Embedding a Single Object `. + +.. include:: /reference/forms/types/options/_error_bubbling_hint.rst.inc diff --git a/reference/forms/types/options/checkbox_empty_data.rst.inc b/reference/forms/types/options/checkbox_empty_data.rst.inc index 62bd00c58d0..9e3c2e79427 100644 --- a/reference/forms/types/options/checkbox_empty_data.rst.inc +++ b/reference/forms/types/options/checkbox_empty_data.rst.inc @@ -3,6 +3,6 @@ empty_data **type**: ``string`` **default**: ``mixed`` -This option determines what value the field will return when the ``placeholder`` +This option determines what value the field will return when the ``empty_value`` choice is selected. In the checkbox and the radio type, the value of ``empty_data`` is overriden by the value returned by the data transformer (see :doc:`/cookbook/form/data_transformers`). diff --git a/reference/forms/types/options/choice_attr.rst.inc b/reference/forms/types/options/choice_attr.rst.inc index 4dcfe601881..4b4d8f187ac 100644 --- a/reference/forms/types/options/choice_attr.rst.inc +++ b/reference/forms/types/options/choice_attr.rst.inc @@ -1,6 +1,9 @@ choice_attr ~~~~~~~~~~~ +.. versionadded:: 2.7 + The ``choice_attr`` option was introduced in Symfony 2.7. + **type**: ``array``, ``callable`` or ``string`` **default**: ``array()`` Use this to add additional HTML attributes to each choice. This can be an array @@ -9,10 +12,7 @@ of attributes (if they are the same for each choice), a callable or a property p If an array, the keys of the ``choices`` array must be used as keys:: - use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - // ... - - $builder->add('attending', ChoiceType::class, array( + $builder->add('attending', 'choice', array( 'choices' => array( 'Yes' => true, 'No' => false, diff --git a/reference/forms/types/options/choice_label.rst.inc b/reference/forms/types/options/choice_label.rst.inc index deb961d2eea..b92c47b6874 100644 --- a/reference/forms/types/options/choice_label.rst.inc +++ b/reference/forms/types/options/choice_label.rst.inc @@ -1,16 +1,16 @@ choice_label ~~~~~~~~~~~~ +.. versionadded:: 2.7 + The ``choice_label`` option was introduced in Symfony 2.7. + **type**: ``string``, ``callable`` or ``false`` **default**: ``null`` Normally, the array key of each item in the ``choices`` option is used as the text that's shown to the user. The ``choice_label`` option allows you to take more control:: - use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - // ... - - $builder->add('attending', ChoiceType::class, array( + $builder->add('attending', 'choice', array( 'choices' => array( 'yes' => true, 'no' => false, @@ -39,10 +39,7 @@ If your choice values are objects, then ``choice_label`` can also be a :ref:`property path `. Imagine you have some ``Status`` class with a ``getDisplayName()`` method:: - use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - // ... - - $builder->add('attending', ChoiceType::class, array( + $builder->add('attending', 'choice', array( 'choices' => array( new Status(Status::YES), new Status(Status::NO), diff --git a/reference/forms/types/options/choice_name.rst.inc b/reference/forms/types/options/choice_name.rst.inc index 341e0a686fb..45a228489a3 100644 --- a/reference/forms/types/options/choice_name.rst.inc +++ b/reference/forms/types/options/choice_name.rst.inc @@ -1,6 +1,9 @@ choice_name ~~~~~~~~~~~ +.. versionadded:: 2.7 + The ``choice_name`` option was introduced in Symfony 2.7. + **type**: ``callable`` or ``string`` **default**: ``null`` Controls the internal field name of the choice. You normally don't care about this, diff --git a/reference/forms/types/options/choice_translation_domain.rst.inc b/reference/forms/types/options/choice_translation_domain.rst.inc index ebd6329eb04..1d42f222e2e 100644 --- a/reference/forms/types/options/choice_translation_domain.rst.inc +++ b/reference/forms/types/options/choice_translation_domain.rst.inc @@ -1,6 +1,9 @@ choice_translation_domain ~~~~~~~~~~~~~~~~~~~~~~~~~ +.. versionadded:: 2.7 + The ``choice_translation_domain`` option was introduced in Symfony 2.7. + **type**: ``string``, ``boolean`` or ``null`` This option determines if the choice values should be translated and in which diff --git a/reference/forms/types/options/choice_type_translation_domain.rst.inc b/reference/forms/types/options/choice_type_translation_domain.rst.inc deleted file mode 100644 index 87cd76cff9a..00000000000 --- a/reference/forms/types/options/choice_type_translation_domain.rst.inc +++ /dev/null @@ -1,8 +0,0 @@ -translation_domain -~~~~~~~~~~~~~~~~~~ - -**type**: ``string`` **default**: ``messages`` - -In case `choice_translation_domain`_ is set to ``true`` or ``null``, this -configures the exact translation domain that will be used for any labels or -options that are rendered for this field diff --git a/reference/forms/types/options/choice_value.rst.inc b/reference/forms/types/options/choice_value.rst.inc index d2616fbfd27..fda5a4e7542 100644 --- a/reference/forms/types/options/choice_value.rst.inc +++ b/reference/forms/types/options/choice_value.rst.inc @@ -1,6 +1,9 @@ choice_value ~~~~~~~~~~~~ +.. versionadded:: 2.7 + The ``choice_value`` option was introduced in Symfony 2.7. + **type**: ``callable`` or ``string`` **default**: ``null`` Returns the string "value" for each choice. This is used in the ``value`` attribute diff --git a/reference/forms/types/options/data.rst.inc b/reference/forms/types/options/data.rst.inc index 63ca91cbf5c..c9bf76424c5 100644 --- a/reference/forms/types/options/data.rst.inc +++ b/reference/forms/types/options/data.rst.inc @@ -8,10 +8,7 @@ corresponding property of the form's domain object (if an object is bound to the form). If you want to override the initial value for the form or just an individual field, you can set it in the data option:: - use Symfony\Component\Form\Extension\Core\Type\HiddenType; - // ... - - $builder->add('token', HiddenType::class, array( + $builder->add('token', 'hidden', array( 'data' => 'abcdef', )); diff --git a/reference/forms/types/options/data_class.rst.inc b/reference/forms/types/options/data_class.rst.inc index 0d81c0659e4..991e68635ea 100644 --- a/reference/forms/types/options/data_class.rst.inc +++ b/reference/forms/types/options/data_class.rst.inc @@ -8,9 +8,6 @@ form, so you can use it for any form field type which requires an object. .. code-block:: php - use AppBundle\Form\MediaType; - // ... - - $builder->add('media', MediaType::class, array( + $builder->add('media', 'sonata_media_type', array( 'data_class' => 'Acme\DemoBundle\Entity\Media', )); diff --git a/reference/forms/types/options/date_format.rst.inc b/reference/forms/types/options/date_format.rst.inc index 283a6c13d87..62152ac48ac 100644 --- a/reference/forms/types/options/date_format.rst.inc +++ b/reference/forms/types/options/date_format.rst.inc @@ -13,10 +13,7 @@ override it by passing the format as a string. For more information on valid formats, see `Date/Time Format Syntax`_:: - use Symfony\Component\Form\Extension\Core\Type\DateType; - // ... - - $builder->add('date_created', DateType::class, array( + $builder->add('date_created', 'date', array( 'widget' => 'single_text', // this is actually the default format for single_text 'format' => 'yyyy-MM-dd', diff --git a/reference/forms/types/options/disabled.rst.inc b/reference/forms/types/options/disabled.rst.inc index 9338b1bc48c..3585aa2438d 100644 --- a/reference/forms/types/options/disabled.rst.inc +++ b/reference/forms/types/options/disabled.rst.inc @@ -1,6 +1,9 @@ disabled ~~~~~~~~ +.. versionadded:: 2.1 + The ``disabled`` option was introduced in Symfony 2.1. + **type**: ``boolean`` **default**: ``false`` If you don't want a user to modify the value of a field, you can set the diff --git a/reference/forms/types/options/empty_data.rst.inc b/reference/forms/types/options/empty_data.rst.inc index 02eb8d12d4c..f856d8d73fe 100644 --- a/reference/forms/types/options/empty_data.rst.inc +++ b/reference/forms/types/options/empty_data.rst.inc @@ -16,16 +16,13 @@ But you can customize this to your needs. For example, if you want the ``gender`` choice field to be explicitly set to ``null`` when no value is selected, you can do it like this:: - use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - // ... - - $builder->add('gender', ChoiceType::class, array( + $builder->add('gender', 'choice', array( 'choices' => array( 'm' => 'Male', 'f' => 'Female' ), 'required' => false, - 'placeholder' => 'Choose your gender', + 'empty_value' => 'Choose your gender', 'empty_data' => null )); diff --git a/reference/forms/types/options/placeholder.rst.inc b/reference/forms/types/options/empty_value.rst.inc similarity index 63% rename from reference/forms/types/options/placeholder.rst.inc rename to reference/forms/types/options/empty_value.rst.inc index a486db35639..ca065be6bbe 100644 --- a/reference/forms/types/options/placeholder.rst.inc +++ b/reference/forms/types/options/empty_value.rst.inc @@ -1,6 +1,14 @@ placeholder ~~~~~~~~~~~ +.. versionadded:: 2.6 + The ``placeholder`` option was introduced in Symfony 2.6 and replaces + ``empty_value``, which is available prior to 2.6. + +.. versionadded:: 2.3 + Since Symfony 2.3, empty values are also supported if the ``expanded`` + option is set to true. + **type**: ``string`` or ``boolean`` This option determines whether or not a special "empty" option (e.g. "Choose @@ -9,19 +17,13 @@ applies if the ``multiple`` option is set to false. * Add an empty value with "Choose an option" as the text:: - use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - // ... - - $builder->add('states', ChoiceType::class, array( + $builder->add('states', 'choice', array( 'placeholder' => 'Choose an option', )); * Guarantee that no "empty" value option is displayed:: - use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - // ... - - $builder->add('states', ChoiceType::class, array( + $builder->add('states', 'choice', array( 'placeholder' => false, )); @@ -29,10 +31,7 @@ If you leave the ``placeholder`` option unset, then a blank (with no text) option will automatically be added if and only if the ``required`` option is false:: - use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - // ... - // a blank (with no text) option will be added - $builder->add('states', ChoiceType::class, array( + $builder->add('states', 'choice', array( 'required' => false, )); diff --git a/reference/forms/types/options/error_mapping.rst.inc b/reference/forms/types/options/error_mapping.rst.inc index 851f4b5287b..1e85ed98459 100644 --- a/reference/forms/types/options/error_mapping.rst.inc +++ b/reference/forms/types/options/error_mapping.rst.inc @@ -1,6 +1,9 @@ error_mapping ~~~~~~~~~~~~~ +.. versionadded:: 2.1 + The ``error_mapping`` option was introduced in Symfony 2.1. + **type**: ``array`` **default**: ``array()`` This option allows you to modify the target of a validation error. @@ -13,7 +16,7 @@ of the form. With customized error mapping, you can do better: map the error to the city field so that it displays above it:: - public function configureOptions(OptionsResolver $resolver) + public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( 'error_mapping' => array( diff --git a/reference/forms/types/options/group_by.rst.inc b/reference/forms/types/options/group_by.rst.inc index f5047145057..9147a0a09bf 100644 --- a/reference/forms/types/options/group_by.rst.inc +++ b/reference/forms/types/options/group_by.rst.inc @@ -1,6 +1,9 @@ group_by ~~~~~~~~ +.. versionadded:: 2.7 + The ``group_by`` option was introduced in Symfony 2.7. + **type**: ``array``, ``callable`` or ``string`` **default**: ``null`` You can easily "group" options in a select simply by passing a multi-dimensional @@ -12,10 +15,7 @@ a bit more flexibility. Take the following example:: - use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - // ... - - $builder->add('publishAt', ChoiceType::class, array( + $builder->add('publishAt', 'choice', array( 'choices' => array( 'now' => new \DateTime('now'), 'tomorrow' => new \DateTime('+1 day'), diff --git a/reference/forms/types/options/html5.rst.inc b/reference/forms/types/options/html5.rst.inc index 30ba9762c4e..1022412f3b3 100644 --- a/reference/forms/types/options/html5.rst.inc +++ b/reference/forms/types/options/html5.rst.inc @@ -1,6 +1,9 @@ html5 ~~~~~ +.. versionadded:: 2.6 + The ``html5`` option was introduced in Symfony 2.6. + **type**: ``boolean`` **default**: ``true`` If this is set to ``true`` (the default), it'll use the HTML5 type (date, time diff --git a/reference/forms/types/options/inherit_data.rst.inc b/reference/forms/types/options/inherit_data.rst.inc index 716952bbecd..c65ff78c7e3 100644 --- a/reference/forms/types/options/inherit_data.rst.inc +++ b/reference/forms/types/options/inherit_data.rst.inc @@ -1,6 +1,10 @@ inherit_data ~~~~~~~~~~~~ +.. versionadded:: 2.3 + The ``inherit_data`` option was introduced in Symfony 2.3. Before, it + was known as ``virtual``. + **type**: ``boolean`` **default**: ``false`` This option determines if the form will inherit data from its parent form. diff --git a/reference/forms/types/options/invalid_message.rst.inc b/reference/forms/types/options/invalid_message.rst.inc index 07e0de74267..d96705bf7d2 100644 --- a/reference/forms/types/options/invalid_message.rst.inc +++ b/reference/forms/types/options/invalid_message.rst.inc @@ -7,7 +7,7 @@ This is the validation error message that's used if the data entered into this field doesn't make sense (i.e. fails validation). This might happen, for example, if the user enters a nonsense string into -a :doc:`TimeType ` field that cannot be converted +a :doc:`time` field that cannot be converted into a real time or if the user enters a string (e.g. ``apple``) into a number field. diff --git a/reference/forms/types/options/invalid_message_parameters.rst.inc b/reference/forms/types/options/invalid_message_parameters.rst.inc index b877f04bb72..72a327351a4 100644 --- a/reference/forms/types/options/invalid_message_parameters.rst.inc +++ b/reference/forms/types/options/invalid_message_parameters.rst.inc @@ -7,7 +7,7 @@ When setting the ``invalid_message`` option, you may need to include some variables in the string. This can be done by adding placeholders to that option and including the variables in this option:: - $builder->add('some_field', SomeFormType::class, array( + $builder->add('some_field', 'some_type', array( // ... 'invalid_message' => 'You entered an invalid value, it should include %num% letters', 'invalid_message_parameters' => array('%num%' => 6), diff --git a/reference/forms/types/options/label_format.rst.inc b/reference/forms/types/options/label_format.rst.inc deleted file mode 100644 index 73f7eee0e7e..00000000000 --- a/reference/forms/types/options/label_format.rst.inc +++ /dev/null @@ -1,47 +0,0 @@ -label_format -~~~~~~~~~~~~ - -.. versionadded:: 2.6 - The ``label_format`` option was introduced in Symfony 2.6. - -**type**: ``string`` **default**: ``null`` - -Configures the string used as the label of the field, in case the ``label`` -option was not set. This is useful when using -:ref:`keyword translation messages `. - -If you're using keyword translation messages as labels, you often end up having -multiple keyword messages for the same label (e.g. ``profile_address_street``, -``invoice_address_street``). This is because the label is build for each "path" -to a field. To avoid duplicated keyword messages, you can configure the label -format to a static value, like:: - - // ... - $profileFormBuilder->add('address', new AddressType(), array( - 'label_format' => 'form.address.%name%', - )); - - $invoiceFormBuilder->add('invoice', new AddressType(), array( - 'label_format' => 'form.address.%name%', - )); - -This option is inherited by the child types. With the code above, the label of -the ``street`` field of both forms will use the ``form.address.street`` keyword -message. - -Two variables are available in the label format: - -``%id%`` - A unique identifier for the field, consisting of the complete path to the - field and the field name (e.g. ``profile_address_street``); -``%name%`` - The field name (e.g. ``street``). - -The default value (``null``) results in a -:ref:`"humanized" version ` of the field name. - -.. note:: - - The ``label_format`` option is evaluated in the form theme. Make sure to - update your templates in case you - :doc:`customized form theming `. diff --git a/reference/forms/types/options/max_length.rst.inc b/reference/forms/types/options/max_length.rst.inc new file mode 100644 index 00000000000..c108451bed0 --- /dev/null +++ b/reference/forms/types/options/max_length.rst.inc @@ -0,0 +1,17 @@ +max_length +~~~~~~~~~~ + +.. caution:: + + The ``max_length`` option was deprecated in Symfony 2.5 and will be removed + in Symfony 3.0. Use the ``attr`` option instead by setting it to an array + with a ``maxlength`` key. + +**type**: ``integer`` **default**: ``null`` + +If this option is not null, an attribute ``maxlength`` is added, which +is used by some browsers to limit the amount of text in a field. + +This is just a browser validation, so data must still be validated +server-side. + diff --git a/reference/forms/types/options/method.rst.inc b/reference/forms/types/options/method.rst.inc index b333fef8d6c..55cf3118775 100644 --- a/reference/forms/types/options/method.rst.inc +++ b/reference/forms/types/options/method.rst.inc @@ -1,6 +1,9 @@ method ~~~~~~ +.. versionadded:: 2.3 + The ``method`` option was introduced in Symfony 2.3. + **type**: ``string`` **default**: ``POST`` This option specifies the HTTP method used to submit the form's data. Its diff --git a/reference/forms/types/options/pattern.rst.inc b/reference/forms/types/options/pattern.rst.inc new file mode 100644 index 00000000000..0f8f0f237e8 --- /dev/null +++ b/reference/forms/types/options/pattern.rst.inc @@ -0,0 +1,24 @@ +pattern +~~~~~~~ + +.. caution:: + + The ``pattern`` option was deprecated in Symfony 2.5 and will be removed + in Symfony 3.0. Use the ``attr`` option instead by setting it to an array + with a ``pattern`` key. + +**type**: ``string`` **default**: ``null`` + +This adds an HTML5 ``pattern`` attribute to restrict the field input by +a given regular expression. + +.. caution:: + + The ``pattern`` attribute provides client-side validation for convenience + purposes only and must not be used as a replacement for reliable + server-side validation. + +.. note:: + + When using validation constraints, this option is set automatically + for some constraints to match the server-side validation. diff --git a/reference/forms/types/options/precision.rst.inc b/reference/forms/types/options/precision.rst.inc new file mode 100644 index 00000000000..ac606eb8a5d --- /dev/null +++ b/reference/forms/types/options/precision.rst.inc @@ -0,0 +1,9 @@ +precision +~~~~~~~~~ + +**type**: ``integer`` **default**: Locale-specific (usually around ``3``) + +This specifies how many decimals will be allowed until the field rounds +the submitted value (via ``rounding_mode``). For example, if ``precision`` +is set to ``2``, a submitted value of ``20.123`` will be rounded to, +for example, ``20.12`` (depending on your ``rounding_mode``). diff --git a/reference/forms/types/options/preferred_choices.rst.inc b/reference/forms/types/options/preferred_choices.rst.inc index 5b968d945a6..2d841a21b2a 100644 --- a/reference/forms/types/options/preferred_choices.rst.inc +++ b/reference/forms/types/options/preferred_choices.rst.inc @@ -7,10 +7,7 @@ This option allows you to move certain choices to the top of your list with a vi separator between them and the rest of the options. If you have a form of languages, you can list the most popular on top, like Bork Bork and Pirate:: - use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - // ... - - $builder->add('language', ChoiceType::class, array( + $builder->add('language', 'choice', array( 'choices' => array( 'English' => 'en', 'Spanish' => 'es', @@ -21,13 +18,13 @@ you can list the most popular on top, like Bork Bork and Pirate:: 'preferred_choices' => array('muppets', 'arr') )); +.. versionadded:: 2.7 + Setting a callable or propery path was introduced in Symfony 2.7. + This options can also be a callback function to give you more flexibility. This might be especially useful if your values are objects:: - use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - // ... - - $builder->add('publishAt', ChoiceType::class, array( + $builder->add('publishAt', 'choice', array( 'choices' => array( 'now' => new \DateTime('now'), 'tomorrow' => new \DateTime('+1 day'), diff --git a/reference/forms/types/options/property_path.rst.inc b/reference/forms/types/options/property_path.rst.inc index 49fa503bef1..0c3e1394b78 100644 --- a/reference/forms/types/options/property_path.rst.inc +++ b/reference/forms/types/options/property_path.rst.inc @@ -15,3 +15,6 @@ If you wish the field to be ignored when reading or writing to the object you can set the ``property_path`` option to ``false``, but using ``property_path`` for this purpose is deprecated, you should use the ``mapped`` option. + +.. versionadded:: 2.1 + The ``mapped`` option was introduced in Symfony 2.1 for this use-case. diff --git a/reference/forms/types/options/read_only.rst.inc b/reference/forms/types/options/read_only.rst.inc new file mode 100644 index 00000000000..7988f0378c8 --- /dev/null +++ b/reference/forms/types/options/read_only.rst.inc @@ -0,0 +1,7 @@ +read_only +~~~~~~~~~ + +**type**: ``boolean`` **default**: ``false`` + +If this option is true, the field will be rendered with the ``readonly`` +attribute so that the field is not editable. diff --git a/reference/forms/types/options/scale.rst.inc b/reference/forms/types/options/scale.rst.inc index 49d038bc686..82df7d60d3c 100644 --- a/reference/forms/types/options/scale.rst.inc +++ b/reference/forms/types/options/scale.rst.inc @@ -1,6 +1,10 @@ scale ~~~~~ +.. versionadded:: 2.7 + The ``scale`` option was introduced in Symfony 2.7. Prior to Symfony 2.7, + it was known as ``precision``. + **type**: ``integer`` **default**: Locale-specific (usually around ``3``) This specifies how many decimals will be allowed until the field rounds diff --git a/reference/forms/types/options/with_minutes.rst.inc b/reference/forms/types/options/with_minutes.rst.inc index 636a2c7a3c1..7661b7f02df 100644 --- a/reference/forms/types/options/with_minutes.rst.inc +++ b/reference/forms/types/options/with_minutes.rst.inc @@ -1,6 +1,9 @@ with_minutes ~~~~~~~~~~~~ +.. versionadded:: 2.2 + The ``with_minutes`` option was introduced in Symfony 2.2. + **type**: ``boolean`` **default**: ``true`` Whether or not to include minutes in the input. This will result in an additional diff --git a/reference/forms/types/password.rst b/reference/forms/types/password.rst index b2491a31015..4c2b4eb3bff 100644 --- a/reference/forms/types/password.rst +++ b/reference/forms/types/password.rst @@ -1,10 +1,10 @@ .. index:: - single: Forms; Fields; PasswordType + single: Forms; Fields; password -PasswordType Field -================== +password Field Type +=================== -The ``PasswordType`` field renders an input password text box. +The ``password`` field renders an input password text box. +-------------+------------------------------------------------------------------------+ | Rendered as | ``input`` ``password`` field | @@ -22,9 +22,11 @@ The ``PasswordType`` field renders an input password text box. | | - `label_attr`_ | | | - `label_format`_ | | | - `mapped`_ | +| | - `max_length`_ (deprecated as of 2.5) | +| | - `read_only`_ | | | - `required`_ | +-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | +| Parent type | :doc:`text ` | +-------------+------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\PasswordType` | +-------------+------------------------------------------------------------------------+ @@ -53,7 +55,7 @@ trim **type**: ``boolean`` **default**: ``false`` -Unlike the rest of form types, the ``PasswordType`` doesn't apply the +Unlike the rest of form types, the ``password`` type doesn't apply the :phpfunction:`trim` function to the value submitted by the user. This ensures that the password is merged back onto the underlying object exactly as it was typed by the user. @@ -61,7 +63,8 @@ by the user. Inherited Options ----------------- -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/disabled.rst.inc @@ -85,4 +88,8 @@ The default value is ``''`` (the empty string). .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/max_length.rst.inc + +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc diff --git a/reference/forms/types/percent.rst b/reference/forms/types/percent.rst index a2156d63d13..1a3024a518c 100644 --- a/reference/forms/types/percent.rst +++ b/reference/forms/types/percent.rst @@ -1,11 +1,11 @@ .. index:: - single: Forms; Fields; PercentType + single: Forms; Fields; percent -PercentType Field -================= +percent Field Type +================== -The ``PercentType`` renders an input text field and specializes in handling +The ``percent`` type renders an input text field and specializes in handling percentage data. If your percentage data is stored as a decimal (e.g. ``.95``), you can use this field out-of-the-box. If you store your data as a number (e.g. ``95``), you should set the ``type`` option to ``integer``. @@ -15,7 +15,7 @@ This field adds a percentage sign "``%``" after the input box. +-------------+-----------------------------------------------------------------------+ | Rendered as | ``input`` ``text`` field | +-------------+-----------------------------------------------------------------------+ -| Options | - `scale`_ | +| Options | - `precision`_ | | | - `type`_ | +-------------+-----------------------------------------------------------------------+ | Overridden | - `compound`_ | @@ -30,11 +30,11 @@ This field adds a percentage sign "``%``" after the input box. | | - `invalid_message_parameters`_ | | | - `label`_ | | | - `label_attr`_ | -| | - `label_format`_ | | | - `mapped`_ | +| | - `read_only`_ | | | - `required`_ | +-------------+-----------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | +| Parent type | :doc:`form ` | +-------------+-----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\PercentType` | +-------------+-----------------------------------------------------------------------+ @@ -42,13 +42,17 @@ This field adds a percentage sign "``%``" after the input box. Field Options ------------- -scale -~~~~~ +precision +~~~~~~~~~ + +.. versionadded:: 2.7 + The ``scale`` option was introduced in Symfony 2.7. Prior to Symfony 2.7, + it was known as ``precision``. **type**: ``integer`` **default**: ``0`` -By default, the input numbers are rounded. To allow for more decimal places, -use this option. +By default, the input numbers are rounded. To allow for more decimal +places, use this option. type ~~~~ @@ -78,7 +82,8 @@ Overridden Options Inherited Options ----------------- -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc @@ -104,8 +109,8 @@ The default value is ``''`` (the empty string). .. include:: /reference/forms/types/options/label_attr.rst.inc -.. include:: /reference/forms/types/options/label_format.rst.inc - .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc diff --git a/reference/forms/types/radio.rst b/reference/forms/types/radio.rst index 87cbbdfda5a..771f5b13490 100644 --- a/reference/forms/types/radio.rst +++ b/reference/forms/types/radio.rst @@ -1,26 +1,26 @@ .. index:: - single: Forms; Fields; RadioType + single: Forms; Fields; radio -RadioType Field -=============== +radio Field Type +================ Creates a single radio button. If the radio button is selected, the field will be set to the specified value. Radio buttons cannot be unchecked - the value only changes when another radio button with the same name gets checked. -The ``RadioType`` isn't usually used directly. More commonly it's used -internally by other types such as :doc:`ChoiceType `. -If you want to have a boolean field, use :doc:`CheckboxType `. +The ``radio`` type isn't usually used directly. More commonly it's used +internally by other types such as :doc:`choice `. +If you want to have a boolean field, use :doc:`checkbox `. +-------------+---------------------------------------------------------------------+ | Rendered as | ``input`` ``radio`` field | +-------------+---------------------------------------------------------------------+ -| Inherited | from the :doc:`CheckboxType `: | +| Inherited | from the :doc:`checkbox ` type: | | options | | | | - `value`_ | | | | -| | from the :doc:`FormType `: | +| | from the :doc:`form ` type: | | | | | | - `data`_ | | | - `disabled`_ | @@ -29,11 +29,11 @@ If you want to have a boolean field, use :doc:`CheckboxType ` | +| Parent type | :doc:`checkbox ` | +-------------+---------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RadioType` | +-------------+---------------------------------------------------------------------+ @@ -41,11 +41,13 @@ If you want to have a boolean field, use :doc:`CheckboxType `: +These options inherit from the :doc:`checkbox ` +type: .. include:: /reference/forms/types/options/value.rst.inc -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc @@ -61,10 +63,10 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/label_attr.rst.inc -.. include:: /reference/forms/types/options/label_format.rst.inc - .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc Form Variables diff --git a/reference/forms/types/range.rst b/reference/forms/types/range.rst deleted file mode 100644 index a59082adb78..00000000000 --- a/reference/forms/types/range.rst +++ /dev/null @@ -1,76 +0,0 @@ -.. index:: - single: Forms; Fields; RangeType - -RangeType Field -=============== - -The ``RangeType`` field is a slider that is rendered using the HTML5 -```` tag. - -+-------------+---------------------------------------------------------------------+ -| Rendered as | ``input`` ``range`` field (slider in HTML5 supported browser) | -+-------------+---------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `trim`_ | -+-------------+---------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | -+-------------+---------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RangeType` | -+-------------+---------------------------------------------------------------------+ - -Basic Usage ------------ - -.. code-block:: php - - use Symfony\Component\Form\Extension\Core\Type\RangeType; - // ... - - $builder->add('name', RangeType::class, array( - 'attr' => array( - 'min' => 5, - 'max' => 50 - ) - )); - -Inherited Options ------------------ - -These options inherit from the :doc:`FormType `: - -.. include:: /reference/forms/types/options/attr.rst.inc - -.. include:: /reference/forms/types/options/data.rst.inc - -.. include:: /reference/forms/types/options/disabled.rst.inc - -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER - -The default value is ``''`` (the empty string). - -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER - -.. include:: /reference/forms/types/options/error_bubbling.rst.inc - -.. include:: /reference/forms/types/options/error_mapping.rst.inc - -.. include:: /reference/forms/types/options/label.rst.inc - -.. include:: /reference/forms/types/options/label_attr.rst.inc - -.. include:: /reference/forms/types/options/mapped.rst.inc - -.. include:: /reference/forms/types/options/required.rst.inc - -.. include:: /reference/forms/types/options/trim.rst.inc diff --git a/reference/forms/types/repeated.rst b/reference/forms/types/repeated.rst index 8c7bca02a87..fd38fe4d191 100644 --- a/reference/forms/types/repeated.rst +++ b/reference/forms/types/repeated.rst @@ -1,8 +1,8 @@ .. index:: - single: Forms; Fields; RepeatedType + single: Forms; Fields; repeated -RepeatedType Field -================== +repeated Field Type +=================== This is a special field "group", that creates two identical fields whose values must match (or a validation error is thrown). The most common use @@ -28,7 +28,7 @@ accuracy. | | - `invalid_message_parameters`_ | | | - `mapped`_ | +-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | +| Parent type | :doc:`form ` | +-------------+------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RepeatedType` | +-------------+------------------------------------------------------------------------+ @@ -38,12 +38,8 @@ Example Usage .. code-block:: php - use Symfony\Component\Form\Extension\Core\Type\RepeatedType; - use Symfony\Component\Form\Extension\Core\Type\PasswordType; - // ... - - $builder->add('password', RepeatedType::class, array( - 'type' => PasswordType::class, + $builder->add('password', 'repeated', array( + 'type' => 'password', 'invalid_message' => 'The password fields must match.', 'options' => array('attr' => array('class' => 'password-field')), 'required' => true, @@ -59,7 +55,7 @@ single value (usually a string) that you need. The most important option is ``type``, which can be any field type and determines the actual type of the two underlying fields. The ``options`` option is passed to each of those individual fields, meaning - in this example - any -option supported by the ``PasswordType`` can be passed in this array. +option supported by the ``password`` type can be passed in this array. Rendering ~~~~~~~~~ @@ -121,7 +117,7 @@ first_name This is the actual field name to be used for the first field. This is mostly meaningless, however, as the actual data entered into both of the fields -will be available under the key assigned to the ``RepeatedType`` field itself +will be available under the key assigned to the ``repeated`` field itself (e.g. ``password``). However, if you don't specify a label, this field name is used to "guess" the label for you. @@ -134,10 +130,7 @@ Additional options (will be merged into `options`_ below) that should be passed *only* to the first field. This is especially useful for customizing the label:: - use Symfony\Component\Form\Extension\Core\Type\RepeatedType; - // ... - - $builder->add('password', RepeatedType::class, array( + $builder->add('password', 'repeated', array( 'first_options' => array('label' => 'Password'), 'second_options' => array('label' => 'Repeat Password'), )); @@ -151,7 +144,7 @@ This options array will be passed to each of the two underlying fields. In other words, these are the options that customize the individual field types. For example, if the ``type`` option is set to ``password``, this array might contain the options ``always_empty`` or ``required`` - both -options that are supported by the ``PasswordType`` field. +options that are supported by the ``password`` field type. second_name ~~~~~~~~~~~ @@ -175,7 +168,7 @@ type **type**: ``string`` **default**: ``text`` The two underlying fields will be of this field type. For example, passing -``PasswordType::class`` will render two password fields. +a type of ``password`` will render two password fields. Overridden Options ------------------ @@ -188,7 +181,8 @@ error_bubbling Inherited Options ----------------- -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc diff --git a/reference/forms/types/reset.rst b/reference/forms/types/reset.rst index 60b7d365fac..efa1b4f99cf 100644 --- a/reference/forms/types/reset.rst +++ b/reference/forms/types/reset.rst @@ -1,8 +1,11 @@ .. index:: - single: Forms; Fields; ResetType + single: Forms; Fields; reset -ResetType Field -=============== +reset Field Type +================ + +.. versionadded:: 2.3 + The ``reset`` type was introduced in Symfony 2.3. A button that resets all fields to their original values. @@ -15,7 +18,7 @@ A button that resets all fields to their original values. | | - `label_attr`_ | | | - `translation_domain`_ | +----------------------+---------------------------------------------------------------------+ -| Parent type | :doc:`ButtonType ` | +| Parent type | :doc:`button` | +----------------------+---------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\ResetType` | +----------------------+---------------------------------------------------------------------+ diff --git a/reference/forms/types/search.rst b/reference/forms/types/search.rst index 37f7f69da44..c14021392b8 100644 --- a/reference/forms/types/search.rst +++ b/reference/forms/types/search.rst @@ -1,8 +1,8 @@ .. index:: - single: Forms; Fields; SearchType + single: Forms; Fields; search -SearchType Field -================ +search Field Type +================= This renders an ```` field, which is a text box with special functionality supported by some browsers. @@ -20,10 +20,12 @@ Read about the input search field at `DiveIntoHTML5.info`_ | | - `label_attr`_ | | | - `label_format`_ | | | - `mapped`_ | +| | - `max_length`_ (deprecated as of 2.5) | +| | - `read_only`_ | | | - `required`_ | | | - `trim`_ | +-------------+----------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | +| Parent type | :doc:`text ` | +-------------+----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\SearchType` | +-------------+----------------------------------------------------------------------+ @@ -31,7 +33,8 @@ Read about the input search field at `DiveIntoHTML5.info`_ Inherited Options ----------------- -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/disabled.rst.inc @@ -55,6 +58,10 @@ The default value is ``''`` (the empty string). .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/max_length.rst.inc + +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc .. include:: /reference/forms/types/options/trim.rst.inc diff --git a/reference/forms/types/submit.rst b/reference/forms/types/submit.rst index c87a2f472cf..9feb60a1c32 100644 --- a/reference/forms/types/submit.rst +++ b/reference/forms/types/submit.rst @@ -1,8 +1,11 @@ .. index:: - single: Forms; Fields; SubmitType + single: Forms; Fields; submit -SubmitType Field -================ +submit Field Type +================= + +.. versionadded:: 2.3 + The ``submit`` type was introduced in Symfony 2.3. A submit button. @@ -13,11 +16,10 @@ A submit button. | options | - `disabled`_ | | | - `label`_ | | | - `label_attr`_ | -| | - `label_format`_ | | | - `translation_domain`_ | | | - `validation_groups`_ | +----------------------+----------------------------------------------------------------------+ -| Parent type | :doc:`ButtonType` | +| Parent type | :doc:`button` | +----------------------+----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\SubmitType` | +----------------------+----------------------------------------------------------------------+ @@ -43,8 +45,6 @@ Inherited Options .. include:: /reference/forms/types/options/label_attr.rst.inc -.. include:: /reference/forms/types/options/label_format.rst.inc - .. include:: /reference/forms/types/options/button_translation_domain.rst.inc validation_groups @@ -56,14 +56,11 @@ When your form contains multiple submit buttons, you can change the validation group based on the button which was used to submit the form. Imagine a registration form wizard with buttons to go to the previous or the next step:: - use Symfony\Component\Form\Extension\Core\Type\SubmitType; - // ... - $form = $this->createFormBuilder($user) - ->add('previousStep', SubmitType::class, array( + ->add('previousStep', 'submit', array( 'validation_groups' => false, )) - ->add('nextStep', SubmitType::class, array( + ->add('nextStep', 'submit', array( 'validation_groups' => array('Registration'), )) ->getForm(); diff --git a/reference/forms/types/text.rst b/reference/forms/types/text.rst index fd61506659d..d8fe83822c3 100644 --- a/reference/forms/types/text.rst +++ b/reference/forms/types/text.rst @@ -1,10 +1,10 @@ .. index:: - single: Forms; Fields; TextType + single: Forms; Fields; text -TextType Field -============== +text Field Type +=============== -The TextType field represents the most basic input text field. +The text field represents the most basic input text field. +-------------+--------------------------------------------------------------------+ | Rendered as | ``input`` ``text`` field | @@ -18,13 +18,15 @@ The TextType field represents the most basic input text field. | | - `label_attr`_ | | | - `label_format`_ | | | - `mapped`_ | +| | - `max_length`_ (deprecated as of 2.5) | +| | - `read_only`_ | | | - `required`_ | | | - `trim`_ | +-------------+--------------------------------------------------------------------+ | Overridden | - `compound`_ | | options | | +-------------+--------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | +| Parent type | :doc:`form ` | +-------------+--------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TextType` | +-------------+--------------------------------------------------------------------+ @@ -32,7 +34,8 @@ The TextType field represents the most basic input text field. Inherited Options ----------------- -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc @@ -58,6 +61,10 @@ The default value is ``''`` (the empty string). .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/max_length.rst.inc + +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc .. include:: /reference/forms/types/options/trim.rst.inc diff --git a/reference/forms/types/textarea.rst b/reference/forms/types/textarea.rst index 7a811a5f67d..68022990dbb 100644 --- a/reference/forms/types/textarea.rst +++ b/reference/forms/types/textarea.rst @@ -1,8 +1,8 @@ .. index:: - single: Forms; Fields; TextareaType + single: Forms; Fields; textarea -TextareaType Field -================== +textarea Field Type +=================== Renders a ``textarea`` HTML element. @@ -19,10 +19,12 @@ Renders a ``textarea`` HTML element. | | - `label_attr`_ | | | - `label_format`_ | | | - `mapped`_ | +| | - `max_length`_ (deprecated as of 2.5) | +| | - `read_only`_ | | | - `required`_ | | | - `trim`_ | +-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | +| Parent type | :doc:`text ` | +-------------+------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TextareaType` | +-------------+------------------------------------------------------------------------+ @@ -36,7 +38,8 @@ Renders a ``textarea`` HTML element. Inherited Options ----------------- -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/attr.rst.inc @@ -64,6 +67,10 @@ The default value is ``''`` (the empty string). .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/max_length.rst.inc + +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc .. include:: /reference/forms/types/options/trim.rst.inc diff --git a/reference/forms/types/time.rst b/reference/forms/types/time.rst index a4e54b75660..d531cc09f86 100644 --- a/reference/forms/types/time.rst +++ b/reference/forms/types/time.rst @@ -1,8 +1,8 @@ .. index:: - single: Forms; Fields; TimeType + single: Forms; Fields; time -TimeType Field -============== +time Field Type +=============== A field to capture time input. @@ -15,9 +15,8 @@ stored as a ``DateTime`` object, a string, a timestamp or an array. +----------------------+-----------------------------------------------------------------------------+ | Rendered as | can be various tags (see below) | +----------------------+-----------------------------------------------------------------------------+ -| Options | - `placeholder`_ | +| Options | - `empty_value`_ | | | - `hours`_ | -| | - `html5`_ | | | - `input`_ | | | - `minutes`_ | | | - `model_timezone`_ | @@ -39,8 +38,9 @@ stored as a ``DateTime`` object, a string, a timestamp or an array. | | - `invalid_message`_ | | | - `invalid_message_parameters`_ | | | - `mapped`_ | +| | - `read_only`_ | +----------------------+-----------------------------------------------------------------------------+ -| Parent type | FormType | +| Parent type | form | +----------------------+-----------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TimeType` | +----------------------+-----------------------------------------------------------------------------+ @@ -52,13 +52,10 @@ This field type is highly configurable, but easy to use. The most important options are ``input`` and ``widget``. Suppose that you have a ``startTime`` field whose underlying time data is -a ``DateTime`` object. The following configures the ``TimeType`` for that +a ``DateTime`` object. The following configures the ``time`` type for that field as two different choice fields:: - use Symfony\Component\Form\Extension\Core\Type\TimeType; - // ... - - $builder->add('startTime', TimeType::class, array( + $builder->add('startTime', 'time', array( 'input' => 'datetime', 'widget' => 'choice', )); @@ -67,10 +64,7 @@ The ``input`` option *must* be changed to match the type of the underlying date data. For example, if the ``startTime`` field's data were a unix timestamp, you'd need to set ``input`` to ``timestamp``:: - use Symfony\Component\Form\Extension\Core\Type\TimeType; - // ... - - $builder->add('startTime', TimeType::class, array( + $builder->add('startTime', 'time', array( 'input' => 'timestamp', 'widget' => 'choice', )); @@ -81,36 +75,10 @@ values. Field Options ------------- -placeholder -~~~~~~~~~~~ - -.. versionadded:: 2.6 - The ``placeholder`` option was introduced in Symfony 2.6 and replaces - ``empty_value``, which is available prior to 2.6. - -**type**: ``string`` | ``array`` - -If your widget option is set to ``choice``, then this field will be represented -as a series of ``select`` boxes. When the placeholder value is a string, -it will be used as the **blank value** of all select boxes:: - - $builder->add('startTime', 'time', array( - 'placeholder' => 'Select a value', - )); - -Alternatively, you can use an array that configures different placeholder -values for the hour, minute and second fields:: - - $builder->add('startTime', 'time', array( - 'placeholder' => array( - 'hour' => 'Hour', 'minute' => 'Minute', 'second' => 'Second', - ) - )); +.. include:: /reference/forms/types/options/empty_value.rst.inc .. include:: /reference/forms/types/options/hours.rst.inc -.. include:: /reference/forms/types/options/html5.rst.inc - input ~~~~~ @@ -185,7 +153,8 @@ error_bubbling Inherited Options ----------------- -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc @@ -201,6 +170,8 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/read_only.rst.inc + Form Variables -------------- diff --git a/reference/forms/types/timezone.rst b/reference/forms/types/timezone.rst index e46aa9f4fe3..cf937bf80a8 100644 --- a/reference/forms/types/timezone.rst +++ b/reference/forms/types/timezone.rst @@ -1,18 +1,19 @@ .. index:: - single: Forms; Fields; TimezoneType + single: Forms; Fields; timezone -TimezoneType Field -================== +timezone Field Type +=================== -The ``TimezoneType`` is a subset of the ``ChoiceType`` that allows the +The ``timezone`` type is a subset of the ``ChoiceType`` that allows the user to select from all possible timezones. The "value" for each timezone is the full timezone name, such as ``America/Chicago`` or ``Europe/Istanbul``. -Unlike the ``ChoiceType``, you don't need to specify a ``choices`` option as the -field type automatically uses a large list of timezones. You *can* specify the option -manually, but then you should just use the ``ChoiceType`` directly. +Unlike the ``choice`` type, you don't need to specify a ``choices`` or +``choice_list`` option as the field type automatically uses a large list +of timezones. You *can* specify either of these options manually, but then +you should just use the ``choice`` type directly. +-------------+------------------------------------------------------------------------+ | Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | @@ -20,14 +21,14 @@ manually, but then you should just use the ``ChoiceType`` directly. | Overridden | - `choices`_ | | options | | +-------------+------------------------------------------------------------------------+ -| Inherited | from the :doc:`ChoiceType ` | +| Inherited | from the :doc:`choice ` type | | options | | | | - `expanded`_ | | | - `multiple`_ | | | - `placeholder`_ | | | - `preferred_choices`_ | | | | -| | from the :doc:`FormType ` | +| | from the :doc:`form ` type | | | | | | - `data`_ | | | - `disabled`_ | @@ -38,9 +39,10 @@ manually, but then you should just use the ``ChoiceType`` directly. | | - `label_attr`_ | | | - `label_format`_ | | | - `mapped`_ | +| | - `read_only`_ | | | - `required`_ | +-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`ChoiceType ` | +| Parent type | :doc:`choice ` | +-------------+------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TimezoneType` | +-------------+------------------------------------------------------------------------+ @@ -51,7 +53,7 @@ Overridden Options choices ~~~~~~~ -**default**: An array of timezones. +**default**: :class:`Symfony\\Component\\Form\\Extension\\Core\\ChoiceList\\TimezoneChoiceList` The Timezone type defaults the choices to all timezones returned by :phpmethod:`DateTimeZone::listIdentifiers`, broken down by continent. @@ -59,7 +61,8 @@ The Timezone type defaults the choices to all timezones returned by Inherited Options ----------------- -These options inherit from the :doc:`ChoiceType `: +These options inherit from the :doc:`choice ` +type: .. include:: /reference/forms/types/options/expanded.rst.inc @@ -69,7 +72,8 @@ These options inherit from the :doc:`ChoiceType ` .. include:: /reference/forms/types/options/preferred_choices.rst.inc -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc @@ -99,4 +103,6 @@ The actual default value of this option depends on other field options: .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc diff --git a/reference/forms/types/url.rst b/reference/forms/types/url.rst index 8c58f007e1d..39bd1171535 100644 --- a/reference/forms/types/url.rst +++ b/reference/forms/types/url.rst @@ -1,10 +1,10 @@ .. index:: - single: Forms; Fields; UrlType + single: Forms; Fields; url -UrlType Field -============= +url Field Type +============== -The ``UrlType`` field is a text field that prepends the submitted value with +The ``url`` field is a text field that prepends the submitted value with a given protocol (e.g. ``http://``) if the submitted value doesn't already have a protocol. @@ -22,10 +22,12 @@ have a protocol. | | - `label_attr`_ | | | - `label_format`_ | | | - `mapped`_ | +| | - `max_length`_ (deprecated as of 2.5) | +| | - `read_only`_ | | | - `required`_ | | | - `trim`_ | +-------------+-------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | +| Parent type | :doc:`text ` | +-------------+-------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\UrlType` | +-------------+-------------------------------------------------------------------+ @@ -45,7 +47,8 @@ the data is submitted to the form. Inherited Options ----------------- -These options inherit from the :doc:`FormType `: +These options inherit from the :doc:`form ` +type: .. include:: /reference/forms/types/options/data.rst.inc @@ -71,6 +74,10 @@ The default value is ``''`` (the empty string). .. include:: /reference/forms/types/options/mapped.rst.inc +.. include:: /reference/forms/types/options/max_length.rst.inc + +.. include:: /reference/forms/types/options/read_only.rst.inc + .. include:: /reference/forms/types/options/required.rst.inc .. include:: /reference/forms/types/options/trim.rst.inc diff --git a/reference/index.rst b/reference/index.rst index 8dcd0ae955e..9d07c4c4609 100644 --- a/reference/index.rst +++ b/reference/index.rst @@ -12,7 +12,6 @@ Reference Documents configuration/twig configuration/monolog configuration/web_profiler - configuration/debug configuration/kernel diff --git a/reference/map.rst.inc b/reference/map.rst.inc index 8339192ab96..1d322527c61 100644 --- a/reference/map.rst.inc +++ b/reference/map.rst.inc @@ -13,7 +13,7 @@ * :doc:`twig ` * :doc:`monolog ` * :doc:`web_profiler ` - * :doc:`debug ` + * :doc:`debug ` (new in 2.6) * :doc:`Configuring the Kernel (e.g. AppKernel) ` diff --git a/reference/requirements.rst b/reference/requirements.rst index 269ade07489..b3765ac819f 100644 --- a/reference/requirements.rst +++ b/reference/requirements.rst @@ -14,18 +14,23 @@ your requirements from the command line via: .. code-block:: bash - $ php bin/symfony_requirements + $ php app/check.php Below is the list of required and optional requirements. Required -------- -* PHP needs to be a minimum version of PHP 5.5.9 +* PHP needs to be a minimum version of PHP 5.3.9 * JSON needs to be enabled * ctype needs to be enabled * Your ``php.ini`` needs to have the ``date.timezone`` setting +.. caution:: + + Be aware that Symfony has some known limitations when using PHP 5.3.16. + For more information see the `Requirements section of the README`_. + Optional -------- @@ -50,3 +55,5 @@ Doctrine If you want to use Doctrine, you will need to have PDO installed. Additionally, you need to have the PDO driver installed for the database server you want to use. + +.. _`Requirements section of the README`: https://github.com/symfony/symfony/blob/2.7/README.md#requirements diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index ed202594354..717d0dbf6e2 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -98,12 +98,16 @@ asset .. code-block:: twig - {{ asset(path, packageName = null) }} + {{ asset(path, packageName = null, absolute = false, version = null) }} ``path`` **type**: ``string`` ``packageName`` *(optional)* **type**: ``string`` | ``null`` **default**: ``null`` +``absolute`` (deprecated as of 2.7) + **type**: ``boolean`` **default**: ``false`` +``version`` (deprecated as of 2.7) + **type**: ``string`` **default** ``null`` Returns a public path to ``path``, which takes into account the base path set for the package and the URL path. More information in @@ -168,6 +172,20 @@ Renders the HTML end tag of a form together with all fields that have not been rendered yet, more information in :ref:`the Twig Form reference `. +form_enctype +~~~~~~~~~~~~ + +.. code-block:: twig + + {{ form_enctype(view) }} + +``view`` + **type**: ``FormView`` + +Renders the required ``enctype="multipart/form-data"`` attribute if the +form contains at least one file upload field, more information in +:ref:`the Twig Form reference `. + form_widget ~~~~~~~~~~~ @@ -344,6 +362,9 @@ information in :ref:`book-templating-pages`. absolute_url ~~~~~~~~~~~~ +.. versionadded:: 2.6 + The ``absolute_url`` function was introduced in Symfony 2.7 + .. code-block:: jinja {{ absolute_url(path) }} @@ -361,6 +382,9 @@ an existing path: relative_path ~~~~~~~~~~~~~ +.. versionadded:: 2.6 + The ``relative_path`` function was introduced in Symfony 2.7 + .. code-block:: jinja {{ relative_path(path) }} @@ -400,6 +424,10 @@ Makes a technical name human readable (i.e. replaces underscores by spaces or transforms camelCase text like ``helloWorld`` to ``hello world`` and then capitalizes the string). +.. versionadded:: 2.3 + Transforming camelCase text into human readable text was introduced in + Symfony 2.3. + trans ~~~~~ @@ -699,6 +727,12 @@ The available attributes are: * ``app.session`` * ``app.environment`` * ``app.debug`` +* ``app.security`` (deprecated as of 2.6) + +.. caution:: + + The ``app.security`` global is deprecated as of 2.6. The user is already + available as ``app.user`` and ``is_granted()`` is registered as function. Symfony Standard Edition Extensions ----------------------------------- @@ -708,7 +742,10 @@ Those bundles can have other Twig extensions: * **Twig Extensions** includes some interesting extensions that do not belong to the Twig core. You can read more in `the official Twig Extensions - documentation`_. + documentation`_; +* **Assetic** adds the ``{% stylesheets %}``, ``{% javascripts %}`` and + ``{% image %}`` tags. You can read more about them in + :doc:`the Assetic Documentation `. .. _`Twig Reference`: http://twig.sensiolabs.org/documentation#reference .. _`the official Twig Extensions documentation`: http://twig.sensiolabs.org/doc/extensions/index.html