diff --git a/_build/redirection_map b/_build/redirection_map index 006e76f890e..e9f46a06bb2 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -100,6 +100,7 @@ /cookbook/configuration/environments /configuration/environments /cookbook/configuration/external_parameters /configuration/external_parameters /cookbook/configuration/front_controllers_and_kernel /configuration/front_controllers_and_kernel +/cookbook/configuration/micro-kernel-trait /configuration/micro_kernel_trait /cookbook/configuration/index /configuration /cookbook/configuration/override_dir_structure /configuration/override_dir_structure /cookbook/configuration/using_parameters_in_dic /configuration/using_parameters_in_dic @@ -213,8 +214,11 @@ /cookbook/security/force_https /security/force_https /cookbook/security/form_login /security/form_login /cookbook/security/form_login_setup /security/form_login_setup +/cookbook/security/guard-authentication /security/guard_authentication /cookbook/security/host_restriction /security/host_restriction /cookbook/security/impersonating_user /security/impersonating_user +/cookbook/security/ldap /security/ldap +/cookbook/security/multiple_guard_authenticators /security/multiple_guard_authenticators /cookbook/security/index /security /cookbook/security/multiple_user_providers /security/multiple_user_providers /cookbook/security/named_encoders /security/named_encoders @@ -222,11 +226,13 @@ /cookbook/security/remember_me /security/remember_me /cookbook/security/securing_services /security/securing_services /cookbook/security/target_path /security/target_path +/cookbook/security/user_checkers /security/user_checkers /cookbook/security/voters /security/voters /cookbook/serializer /serializer /cookbook/service_container/compiler_passes /service_container/compiler_passes /cookbook/service_container/index /service_container /cookbook/service_container/scopes /service_container/scopes +/cookbook/service_container/shared /service_container/shared /cookbook/session/avoid_session_start /session/avoid_session_start /cookbook/session/index /session /cookbook/session/limit_metadata_writes /session/limit_metadata_writes diff --git a/_images/controller/error_pages/exceptions-in-dev-environment.png b/_images/controller/error_pages/exceptions-in-dev-environment.png index dffd1460b9b..225dcdfa0dc 100644 Binary files a/_images/controller/error_pages/exceptions-in-dev-environment.png and b/_images/controller/error_pages/exceptions-in-dev-environment.png differ diff --git a/_images/doctrine/web_debug_toolbar.png b/_images/doctrine/web_debug_toolbar.png index b7c5a690d72..dd5c3fffbb1 100644 Binary files a/_images/doctrine/web_debug_toolbar.png and b/_images/doctrine/web_debug_toolbar.png differ diff --git a/_images/quick_tour/hello_fabien.png b/_images/quick_tour/hello_fabien.png deleted file mode 100644 index 8329899b090..00000000000 Binary files a/_images/quick_tour/hello_fabien.png and /dev/null differ diff --git a/_images/quick_tour/profiler.png b/_images/quick_tour/profiler.png index 795f5deb05f..3b55b75f3af 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 1e2b38d06cb..86249e862f3 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 9091b6bf908..738105f715d 100644 Binary files a/_images/quick_tour/welcome.png and b/_images/quick_tour/welcome.png differ diff --git a/_images/security/anonymous_wdt.png b/_images/security/anonymous_wdt.png index d780c894d5a..4803ed1b108 100644 Binary files a/_images/security/anonymous_wdt.png and b/_images/security/anonymous_wdt.png differ diff --git a/_images/security/symfony_loggedin_wdt.png b/_images/security/symfony_loggedin_wdt.png index 7280d9978bb..6605c35edf7 100644 Binary files a/_images/security/symfony_loggedin_wdt.png and b/_images/security/symfony_loggedin_wdt.png differ diff --git a/assetic.rst b/assetic.rst index b9226f09d4d..59f8d06ecba 100644 --- a/assetic.rst +++ b/assetic.rst @@ -1,6 +1,8 @@ Assetic ======= +.. include:: /assetic/_standard_edition_warning.rst.inc + .. toctree:: :maxdepth: 1 :glob: diff --git a/assetic/_standard_edition_warning.rst.inc b/assetic/_standard_edition_warning.rst.inc new file mode 100644 index 00000000000..f114bf2d43f --- /dev/null +++ b/assetic/_standard_edition_warning.rst.inc @@ -0,0 +1,5 @@ +.. 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/assetic/apply_to_option.rst b/assetic/apply_to_option.rst index 92bde81dd4a..b7f7b151aae 100644 --- a/assetic/apply_to_option.rst +++ b/assetic/apply_to_option.rst @@ -4,6 +4,8 @@ How to Apply an Assetic Filter to a specific File Extension =========================================================== +.. include:: /assetic/_standard_edition_warning.rst.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/assetic/asset_management.rst b/assetic/asset_management.rst index 66673ba5477..99cca285629 100644 --- a/assetic/asset_management.rst +++ b/assetic/asset_management.rst @@ -4,6 +4,89 @@ 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 @@ -515,7 +598,7 @@ each time you deploy), you should run the following command: .. code-block:: bash - $ php app/console assetic:dump --env=prod --no-debug + $ php bin/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 @@ -567,7 +650,7 @@ need to dump them manually. To do so, run the following command: .. code-block:: bash - $ php app/console assetic:dump + $ php bin/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 @@ -576,7 +659,7 @@ assets will be regenerated automatically *as they change*: .. code-block:: bash - $ php app/console assetic:watch + $ php bin/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/assetic/jpeg_optimize.rst b/assetic/jpeg_optimize.rst index 8d94266ae8e..7fc039e3f17 100644 --- a/assetic/jpeg_optimize.rst +++ b/assetic/jpeg_optimize.rst @@ -4,6 +4,8 @@ How to Use Assetic for Image Optimization with Twig Functions ============================================================= +.. include:: /assetic/_standard_edition_warning.rst.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/assetic/php.rst b/assetic/php.rst index 3b2ea99e5b1..68afb9788bd 100644 --- a/assetic/php.rst +++ b/assetic/php.rst @@ -4,6 +4,8 @@ Combining, Compiling and Minimizing Web Assets with PHP Libraries ================================================================= +.. include:: /assetic/_standard_edition_warning.rst.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. diff --git a/assetic/uglifyjs.rst b/assetic/uglifyjs.rst index 0e6d50ae7b3..b2ec9c5eb58 100644 --- a/assetic/uglifyjs.rst +++ b/assetic/uglifyjs.rst @@ -4,6 +4,8 @@ How to Minify CSS/JS Files (Using UglifyJS and UglifyCSS) ========================================================= +.. include:: /assetic/_standard_edition_warning.rst.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/assetic/yuicompressor.rst b/assetic/yuicompressor.rst index 392db7cdeee..9b83aa99f48 100644 --- a/assetic/yuicompressor.rst +++ b/assetic/yuicompressor.rst @@ -10,6 +10,8 @@ How to Minify JavaScripts and Stylesheets with YUI Compressor **strongly advised to avoid using YUI utilities** unless strictly necessary. Read :doc:`/assetic/uglifyjs` for a modern and up-to-date alternative. +.. include:: /assetic/_standard_edition_warning.rst.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/best_practices/business-logic.rst b/best_practices/business-logic.rst index b05ec44df1b..08f0e678762 100644 --- a/best_practices/business-logic.rst +++ b/best_practices/business-logic.rst @@ -21,6 +21,8 @@ Inside here, you can create whatever directories you want to organize things: │ └─ AppBundle/ │ └─ Utils/ │ └─ MyClass.php + ├─ tests/ + ├─ var/ ├─ vendor/ └─ web/ @@ -40,6 +42,8 @@ and put things there: │ │ └─ Utils/ │ │ └─ MyClass.php │ └─ AppBundle/ + ├─ tests/ + ├─ var/ ├─ vendor/ └─ web/ @@ -318,7 +322,7 @@ command: .. code-block:: bash - $ php app/console doctrine:fixtures:load + $ php bin/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 8139c22e60a..3fcb46bf586 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. -Since version 2.3, Symfony includes a configuration file called ``parameters.yml.dist``, -which stores the canonical list of configuration parameters for the application. +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 c70df8db7bd..e19e6ebe872 100644 --- a/best_practices/creating-the-project.rst +++ b/best_practices/creating-the-project.rst @@ -27,7 +27,6 @@ to create files and execute the following commands: .. code-block:: bash - # Linux, Mac OS X $ cd projects/ $ symfony new blog @@ -63,13 +62,18 @@ 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/ @@ -77,13 +81,16 @@ 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 @@ -107,8 +114,7 @@ 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. Starting in Symfony 2.6, the official -Symfony documentation uses the AppBundle name. +more concise and easier to understand. .. note:: @@ -128,13 +134,18 @@ 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 @@ -147,7 +158,7 @@ that follows these best practices: .. code-block:: bash - $ php app/console generate:bundle --namespace=AppBundle --dir=src --format=annotation --no-interaction + $ php bin/console generate:bundle --namespace=AppBundle --dir=src --format=annotation --no-interaction Extending the Directory Structure --------------------------------- @@ -157,27 +168,6 @@ 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 6722d09cb58..d63bf8faccb 100644 --- a/best_practices/forms.rst +++ b/best_practices/forms.rst @@ -22,6 +22,9 @@ 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 { @@ -29,10 +32,10 @@ form in its own PHP class:: { $builder ->add('title') - ->add('summary', 'textarea') - ->add('content', 'textarea') - ->add('authorEmail', 'email') - ->add('publishedAt', 'datetime') + ->add('summary', TextareaType::class) + ->add('content', TextareaType::class) + ->add('authorEmail', EmailType::class) + ->add('publishedAt', DateTimeType::class) ; } @@ -42,11 +45,6 @@ form in its own PHP class:: 'data_class' => 'AppBundle\Entity\Post' )); } - - public function getName() - { - return 'post'; - } } .. best-practice:: @@ -54,7 +52,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 instantiate the new class:: +To use the class, use ``createForm()`` and pass the fully qualified class name:: // ... use AppBundle\Form\PostType; @@ -63,7 +61,7 @@ To use the class, use ``createForm()`` and instantiate the new class:: public function newAction(Request $request) { $post = new Post(); - $form = $this->createForm(new PostType(), $post); + $form = $this->createForm(PostType::class, $post); // ... } @@ -71,15 +69,10 @@ To use the class, use ``createForm()`` and instantiate the new class:: Registering Forms as Services ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can also -:ref:`register your form type as a service `. -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. +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. Form Button Configuration ------------------------- @@ -91,9 +84,10 @@ makes them easier to re-use later. Add buttons in the templates, not in the form classes or the controllers. -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: +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: .. code-block:: php @@ -103,7 +97,7 @@ directly in your form class, this would effectively limit the scope of that form { $builder // ... - ->add('save', 'submit', array('label' => 'Create Post')) + ->add('save', SubmitType::class, array('label' => 'Create Post')) ; } @@ -118,6 +112,7 @@ 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; @@ -128,8 +123,8 @@ some developers configure form buttons in the controller:: public function newAction(Request $request) { $post = new Post(); - $form = $this->createForm(new PostType(), $post); - $form->add('submit', 'submit', array( + $form = $this->createForm(PostType::class, $post); + $form->add('submit', SubmitType::class, array( 'label' => 'Create', 'attr' => array('class' => 'btn btn-default pull-right') )); @@ -212,21 +207,3 @@ 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 cfbd5fb47e2..39473373df1 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 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. +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. .. tip:: diff --git a/best_practices/introduction.rst b/best_practices/introduction.rst index 2c5661c6671..dad135249e6 100644 --- a/best_practices/introduction.rst +++ b/best_practices/introduction.rst @@ -76,12 +76,8 @@ 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 00b52f9910b..fcc991c1e9d 100644 --- a/best_practices/security.rst +++ b/best_practices/security.rst @@ -264,37 +264,65 @@ the same ``getAuthorEmail`` logic you used above: namespace AppBundle\Security; - use Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter; + 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\User\UserInterface; + use AppBundle\Entity\Post; - // AbstractVoter class requires Symfony 2.6 or higher version - class PostVoter extends AbstractVoter + class PostVoter extends Voter { const CREATE = 'create'; const EDIT = 'edit'; - protected function getSupportedAttributes() + /** + * @var AccessDecisionManagerInterface + */ + private $decisionManager; + + public function __construct(AccessDecisionManagerInterface $decisionManager) { - return array(self::CREATE, self::EDIT); + $this->decisionManager = $decisionManager; } - protected function getSupportedClasses() + protected function supports($attribute, $subject) { - return array('AppBundle\Entity\Post'); + if (!in_array($attribute, array(self::CREATE, self::EDIT))) { + return false; + } + + if (!$subject instanceof Post) { + return false; + } + + return true; } - protected function isGranted($attribute, $post, $user = null) + protected function voteOnAttribute($attribute, $subject, TokenInterface $token) { + $user = $token->getUser(); + /** @var Post */ + $post = $subject; // $subject must be a Post instance, thanks to the supports method + if (!$user instanceof UserInterface) { return false; } - if ($attribute === self::CREATE && in_array('ROLE_ADMIN', $user->getRoles(), true)) { - return true; - } - - if ($attribute === self::EDIT && $user->getEmail() === $post->getAuthorEmail()) { - return true; + 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; } return false; @@ -310,6 +338,7 @@ 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 } @@ -337,7 +366,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 1f41afb9de7..1e9490d7aac 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:: - // src/AppBundle/Tests/ApplicationAvailabilityFunctionalTest.php - namespace AppBundle\Tests; + // tests/AppBundle/ApplicationAvailabilityFunctionalTest.php + namespace Tests\AppBundle; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; diff --git a/best_practices/web-assets.rst b/best_practices/web-assets.rst index 62398ebed93..7c3fe8a7ee0 100644 --- a/best_practices/web-assets.rst +++ b/best_practices/web-assets.rst @@ -35,6 +35,8 @@ much more concise: Using Assetic ------------- +.. include:: /assetic/_standard_edition_warning.rst.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/bundles.rst b/bundles.rst index f73cdf54e99..7e7decbc1dc 100644 --- a/bundles.rst +++ b/bundles.rst @@ -40,7 +40,6 @@ the ``registerBundles()`` method of the ``AppKernel`` class:: new Symfony\Bundle\MonologBundle\MonologBundle(), new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(), new Symfony\Bundle\DoctrineBundle\DoctrineBundle(), - new Symfony\Bundle\AsseticBundle\AsseticBundle(), new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), new AppBundle\AppBundle(), ); @@ -107,6 +106,7 @@ Now that you've created the bundle, enable it via the ``AppKernel`` class:: { $bundles = array( // ... + // register your bundle new Acme\TestBundle\AcmeTestBundle(), ); @@ -122,7 +122,7 @@ generating a basic bundle skeleton: .. code-block:: bash - $ php app/console generate:bundle --namespace=Acme/TestBundle + $ php bin/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/bundles/best_practices.rst b/bundles/best_practices.rst index 6d0b7aff034..d245763b35e 100644 --- a/bundles/best_practices.rst +++ b/bundles/best_practices.rst @@ -414,55 +414,6 @@ 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 ---------- diff --git a/bundles/installation.rst b/bundles/installation.rst index 80dfafc008e..1c97cfad435 100644 --- a/bundles/installation.rst +++ b/bundles/installation.rst @@ -108,14 +108,14 @@ via the ``config:dump-reference`` command: .. code-block:: bash - $ app/console config:dump-reference AsseticBundle + $ bin/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 - $ app/console config:dump-reference assetic + $ bin/console config:dump-reference assetic The output will look like this: diff --git a/bundles/override.rst b/bundles/override.rst index 933adbd1d92..d67a47154f6 100644 --- a/bundles/override.rst +++ b/bundles/override.rst @@ -105,17 +105,16 @@ associations. Learn more about this feature and its limitations in Forms ----- -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.:: +Form types are referred to by their fully-qualified class name:: - $builder->add('name', 'custom_type'); + $builder->add('name', CustomType::class); -rather than:: +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). - $builder->add('name', new CustomType()); +Instead, you should use a "form type extension" to modify the existing form type. +For more information, see :doc:`/form/create_form_type_extension`. .. _override-validation: diff --git a/changelog.rst b/changelog.rst index d4aa9c0a289..3fd24562c87 100644 --- a/changelog.rst +++ b/changelog.rst @@ -19,6 +19,7 @@ July, 2016 New Documentation ~~~~~~~~~~~~~~~~~ +* `#6744 `_ [Form] Ambiguous block prefixes render incorrectly (foaly-nr1) * `#6611 `_ Discourage the use of controllers as services (javiereguiluz) * `#5672 `_ Add constants to BC promise (WouterJ) * `#6707 `_ Describe serialization config location in cookbook (jcrombez, WouterJ) @@ -32,13 +33,17 @@ Fixed Documentation * `#6634 `_ Update custom_constraint.rst (axelvnk) * `#6719 `_ [Components][Browser-Kit]Fix typo with CookieJar (Denis-Florin Rendler) * `#6687 `_ Namespace fix (JhonnyL) +* `#6714 `_ UppercaseRot13Transformer wrong class name used (jevgenijusr) * `#6704 `_ Encountered an error when following the steps for contribution (chancegarcia) +* `#6708 `_ Routes should be just imported, not mounted (OndraM) Minor Documentation Changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~ * `#6778 `_ fix syntax errors (xabbuh) * `#6777 `_ fix code block indentation (xabbuh) +* `#109 `_ after merge fixes (xabbuh) +* `#107 `_ fix bugs due to choosing the wrong base branch (xabbuh) * `#108 `_ fix another bug due to choosing the wrong branch (xabbuh) * `#105 `_ fix bugs due to choosing the wrong base branch (xabbuh) * `#102 `_ Updated the Global Composer Installation article (javiereguiluz) @@ -53,6 +58,7 @@ Minor Documentation Changes * `#91 `_ Create a section for "Getting Started" so we can generate a book (javiereguiluz) * `#77 `_ Proofing the controller chapter (weaverryan) * `#90 `_ Fixed doc build issues (javiereguiluz) +* `#82 `_ Bootstrapping property info doc (weaverryan) * `#79 `_ Shortening the setup section (weaverryan) * `#81 `_ Merging setup and install directories (weaverryan) * `#84 `_ Bootstrapping the validator components (weaverryan) @@ -79,6 +85,7 @@ Minor Documentation Changes * `#6600 `_ Removing some extra details from #6444 (weaverryan) * `#6715 `_ [Book] Remove DI extension info and link the cookbook article instead (WouterJ) * `#6745 `_ Branch fix (Talita Kocjan Zager, weaverryan) +* `#6743 `_ Finishing #6252 (Talita Kocjan Zager, weaverryan) * `#6656 `_ Clarify usage of handler channel configuration (shkkmo) * `#6664 `_ replace occurrences of `_ Add little comment indicating meaning of $firewall variable (ruslan-fidesio, WouterJ) @@ -98,10 +105,12 @@ Minor Documentation Changes * `#6613 `_ Clarify documentation on serving files (raphaelm) * `#6721 `_ [Finder] Fixed typo in RealPath method on SplFileInfo class (acrobat) * `#6716 `_ Typo fix "they the name" => "that the name" (jevgenijusr) +* `#6702 `_ Removed empty ``Notes on previous versions`` (mickaelandrieu) * `#6709 `_ Fix URL in http basic screenshot (WouterJ) * `#6706 `_ Update "How to Authenticate Users with API Keys" (gondo, WouterJ) * `#5892 `_ Updated the session proxy article (javiereguiluz) * `#6697 `_ [Asset] add versionadded directive (xabbuh) +* `#6698 `_ [Ldap] add versionadded directive (xabbuh) June, 2016 @@ -110,6 +119,7 @@ June, 2016 New Documentation ~~~~~~~~~~~~~~~~~ +* `#6690 `_ Added an example for a different method of verbosity level usage. (smatyas) * `#6587 `_ Updating recommended email settings for monolog (jorgelbg) Fixed Documentation @@ -123,7 +133,9 @@ Minor Documentation Changes * `#6597 `_ [Validator] Add shorter examples using the default option (alexmart) * `#6696 `_ Typo fix (jevgenijusr) +* `#6693 `_ Add missing parameter (rodnaph) * `#6614 `_ Updated the CS rule about return null; and return; (javiereguiluz) +* `#6680 `_ Fix ldap security examples (jvasseur) * `#6692 `_ Update date.rst - Fixes typo (fdarre) * `#6689 `_ Hard values for the driver option (iltar) * `#6685 `_ NullOutput should be passed to $command->run() (Ma27) @@ -140,11 +152,13 @@ Minor Documentation Changes * `#6652 `_ ``Finder::path()`` method matching directories and files (soyuka) * `#6662 `_ preg_match throw an warning (nicolae-stelian) * `#6658 `_ [Process] tweak a sentence (xabbuh) +* `#6599 `_ Fixed null description of query_builder option (HeahDude) * `#6638 `_ swap terminate and exception event descriptions (xabbuh) * `#6615 `_ Minor grammar fix (aalaap) * `#6637 `_ Update security.rst (norbert-n) * `#6644 `_ [Console] Fix wrong quotes in QuestionHelper::setInputStream() (chalasr) * `#6645 `_ Fix bootstrap class name help-block (foaly-nr1) +* `#6642 `_ do not reference unused interface (xabbuh) * `#6641 `_ [Book][Form] fix reference to renamed document (xabbuh) * `#6579 `_ Added callable validation_groups example (gnat42) * `#6626 `_ reflect the EOM of Symfony 2.3 (xabbuh) @@ -160,22 +174,28 @@ May, 2016 New Documentation ~~~~~~~~~~~~~~~~~ +* `#6402 `_ [RFR] Documentation for the Ldap component (csarrazi) * `#6040 `_ Remove old File Upload article + improve the new one (WouterJ) * `#6412 `_ added a maintenance document (fabpot) * `#6554 `_ Adding information about using the date type as usable date picker field (weaverryan) * `#6590 `_ Added note on YAML mappings as objects (dantleech) +* `#6378 `_ refs #5898 Fix updates of testing.rst for 3.0 (guilliamxavier) * `#6583 `_ Adding a description for the use_microseconds parameter introduced in MonologBundle v2.11 (jorgelbg) * `#6582 `_ Advanced YAML component usage (dantleech) +* `#6594 `_ Allowed to return null for query_builder (JonEastman) * `#6405 `_ Added the explanation about addClassesToCompile() method (javiereguiluz) * `#6539 `_ Documented the "autoescape" TwigBundle config option (javiereguiluz) * `#5574 `_ [2.7] Update Twig docs for asset features (javiereguiluz, WouterJ) +* `#6302 `_ [Form] add ``choice_translation_domain`` option to date types (HeahDude) Fixed Documentation ~~~~~~~~~~~~~~~~~~~ * `#6619 `_ Fix wrong variable name in comment (zanardigit) +* `#6608 `_ deprecated 'datettime' Form Type (dsmink) * `#6606 `_ fix #6602 (yamiko-ninja) * `#6578 `_ [Cookbook][Profiler] Fix arguments for Profiler::find() (hason) +* `#6546 `_ Make ClockMock Tests\\ namespace matching less specific (teohhanhui) * `#6564 `_ [PhpUnitBridge] Remove section about clock mocking (z38) * `#6552 `_ Typo fix in the Serializer deserialization example for existing object (fre5h) * `#6545 `_ Replace property_accessor by property_access (jbenoit2011) @@ -184,9 +204,12 @@ Fixed Documentation Minor Documentation Changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +* `#6601 `_ Deprecated usage of AsseticBundle removed from bundles.rst (Vehsamrak) +* `#6624 `_ remove versionadded directive for 2.x features (xabbuh) * `#6620 `_ Move PSR to correct place on index page (WouterJ) * `#6609 `_ Use a better escaping mechanism for data-prototype attr (javiereguiluz) * `#6380 `_ [book] [validation] Constraints can be applied to an entire class too (sustmi) +* `#6459 `_ Remove choices as values in 3.0 (weaverryan) * `#6444 `_ [Form] fixed EntityType choice options (HeahDude) * `#6367 `_ Simplified the contribution article for Symfony Docs (javiereguiluz) * `#6419 `_ Update routing.rst (tamtamchik) @@ -207,15 +230,23 @@ Minor Documentation Changes * `#6553 `_ EntityType: query_builder link to usage (weaverryan) * `#6572 `_ Edited BowerPHP tip (SecondeJK) * `#6575 `_ Rename command logging services (sroze) +* `#6577 `_ [Cookbook][Profiler] Remove mention of import/export (hason) * `#6571 `_ [Cookbook][Console] Minor: Fix typo (andreia) +* `#6570 `_ Fix typo (jdreesen) * `#6568 `_ fix RequestDataCollector class namespace (xabbuh) * `#6566 `_ Update options_resolver.rst (snake77se) +* `#6548 `_ merge choice_translation_domain files (xabbuh) +* `#6547 `_ remove 2.x versionadded directives (xabbuh) +* `#6563 `_ [PhpUnitBridge] Add versionadded directive to clock mocking section (z38) +* `#6549 `_ drop AppBundle examples in components section (xabbuh) * `#6562 `_ Remove extra spaces in Nginx template (bocharsky-bw) * `#6557 `_ [ClassLoader] Add missed link to the external PSR-4 specification (nicolas-grekas, fre5h) * `#6511 `_ [DependencyInjection] Improved "optional argument" documentation (dantleech) * `#6455 `_ Editing the Doctrine section to improve accuracy and readability (natechicago) * `#6526 `_ Documented how to configure Symfony correctly with regards to the Forwarded header (magnusnordlander) * `#6535 `_ Improved the description of the Twig global variables (javiereguiluz) +* `#6536 `_ [DomCrawler] Removed references to CssSelector (aerialls) +* `#6529 `_ [DependencyInjection] Unquote services FQCN in autowiring examples (chalasr) * `#6530 `_ [DependencyInjection] Unquote services FQCN in parent-services examples (chalasr) * `#6517 `_ Add a warning about using same user for cli and web server (pasdeloup) * `#6504 `_ Improved the docs for the DependencyInjection component (javiereguiluz) @@ -233,6 +264,8 @@ New Documentation * `#6470 `_ Documented the config options of TwigBundle (javiereguiluz) * `#6427 `_ [Testing] Explain how to add or remove data in a collection of forms (alexislefebvre) +* `#6465 `_ Added ldap to the list of user providers (AAstakhov) +* `#6450 `_ [Form] added prototype_data option in CollectionType (kgilden, HeahDude) * `#6394 `_ Updated Heroku instructions (magnusnordlander) Fixed Documentation @@ -255,11 +288,14 @@ Minor Documentation Changes * `#6472 `_ Avoid confusion (gerryvdm) * `#6300 `_ Document constraint validator alias optional (Triiistan) * `#6513 `_ remove documentation of not supported "verbose" option value (TobiasXy) +* `#6507 `_ fix typo (tyx) +* `#6509 `_ Update http_kernel_httpkernel_class.rst (AchillesKal) * `#6510 `_ use port 587 in Amazon SES example (snoek09) * `#6464 `_ Added possible values for access_decision_manager.strategy (AAstakhov) * `#6478 `_ Replace reference to the request service (gerryvdm) * `#6479 `_ Update php.rst (carlos-granados) * `#6481 `_ Remove reference to Symfony2 in request-flow.png (Daniel Cotton) +* `#6471 `_ fix broken merge (xabbuh) * `#6449 `_ [Form] fixed ChoiceType example in CollectionType (HeahDude) * `#6445 `_ updated the core team (fabpot) * `#6423 `_ Added a caution note about REMOTE_USER and user impersonation (javiereguiluz) @@ -268,6 +304,7 @@ Minor Documentation Changes * `#6456 `_ Fixed array [] notation and trailing spaces (iltar) * `#6420 `_ Added tip for optional second parameter for form submissions. (Michael Phillips) * `#6418 `_ fix spelling of the flashBag() method (xabbuh) +* `#6432 `_ fixed yaml config error (RickieL) March, 2016 @@ -276,6 +313,7 @@ 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) @@ -284,20 +322,28 @@ 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) @@ -315,6 +361,7 @@ 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) @@ -324,8 +371,10 @@ 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) @@ -338,15 +387,21 @@ 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) @@ -354,38 +409,49 @@ 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) @@ -394,10 +460,16 @@ 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) @@ -409,6 +481,8 @@ 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) @@ -418,37 +492,55 @@ 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) @@ -461,13 +553,18 @@ 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) @@ -478,6 +575,7 @@ 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) @@ -486,10 +584,13 @@ 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) @@ -503,6 +604,9 @@ 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) @@ -510,11 +614,13 @@ 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) @@ -522,7 +628,10 @@ 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 @@ -531,9 +640,24 @@ 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) @@ -564,6 +688,7 @@ 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) @@ -575,6 +700,7 @@ 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) @@ -596,10 +722,15 @@ 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 ~~~~~~~~~~~~~~~~~~~ @@ -615,6 +746,7 @@ 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) @@ -628,14 +760,17 @@ 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) @@ -727,6 +862,7 @@ 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) @@ -760,13 +896,16 @@ 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) @@ -795,6 +934,7 @@ 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) @@ -847,6 +987,7 @@ 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) @@ -854,6 +995,7 @@ 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) @@ -869,6 +1011,7 @@ 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 ~~~~~~~~~~~~~~~~~~~ @@ -915,6 +1058,7 @@ 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) @@ -1188,6 +1332,7 @@ 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) @@ -1228,7 +1373,6 @@ 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.rst b/components/asset.rst index d8b71deeff7..0791d7bf84a 100644 --- a/components/asset.rst +++ b/components/asset.rst @@ -8,9 +8,6 @@ The Asset Component The Asset component manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files. -.. versionadded:: 2.7 - The Asset component was introduced in Symfony 2.7. - In the past, it was common for web applications to hardcode URLs of web assets. For example: diff --git a/components/class_loader/debug_class_loader.rst b/components/class_loader/debug_class_loader.rst index e316eeb8084..1bd3446af27 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 will be removed in Symfony 3.0. Use the + in Symfony 2.5 and removed in Symfony 3.0. Use the :ref:`DebugClassLoader provided by the Debug component `. diff --git a/components/config/definition.rst b/components/config/definition.rst index bfcb98dac0f..e7654c0c14c 100644 --- a/components/config/definition.rst +++ b/components/config/definition.rst @@ -446,10 +446,6 @@ 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/events.rst b/components/console/events.rst index afe24f3ab56..69f451c1fe9 100644 --- a/components/console/events.rst +++ b/components/console/events.rst @@ -4,9 +4,6 @@ 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:: @@ -59,9 +56,6 @@ 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 7eacce3464e..89609da8419 100644 --- a/components/console/helpers/debug_formatter.rst +++ b/components/console/helpers/debug_formatter.rst @@ -4,9 +4,6 @@ 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 f45c1e1e95f..8618ffcba17 100644 --- a/components/console/helpers/dialoghelper.rst +++ b/components/console/helpers/dialoghelper.rst @@ -6,286 +6,7 @@ Dialog Helper .. caution:: - The Dialog Helper was deprecated in Symfony 2.5 and will be removed in + The Dialog Helper was deprecated in Symfony 2.5 and 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/map.rst.inc b/components/console/helpers/map.rst.inc index d0913db4033..68e1e722a87 100644 --- a/components/console/helpers/map.rst.inc +++ b/components/console/helpers/map.rst.inc @@ -1,9 +1,6 @@ -* :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/tablehelper` (deprecated as of 2.5) -* :doc:`/components/console/helpers/debug_formatter` (new in 2.6) +* :doc:`/components/console/helpers/debug_formatter` diff --git a/components/console/helpers/processhelper.rst b/components/console/helpers/processhelper.rst index 7ba70340b4e..e517aab7b72 100644 --- a/components/console/helpers/processhelper.rst +++ b/components/console/helpers/processhelper.rst @@ -4,9 +4,6 @@ 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 9b77d168955..0e63e2e37a2 100644 --- a/components/console/helpers/progressbar.rst +++ b/components/console/helpers/progressbar.rst @@ -40,14 +40,6 @@ 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 @@ -57,9 +49,6 @@ 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:: @@ -307,9 +296,6 @@ 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 da2b8f507cb..aec5c9b62ea 100644 --- a/components/console/helpers/progresshelper.rst +++ b/components/console/helpers/progresshelper.rst @@ -4,91 +4,9 @@ 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 will be removed in - Symfony 3.0. You should now use the + The Progress Helper was deprecated in Symfony 2.5 and 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 c9d700eb80d..6ea453beeb7 100644 --- a/components/console/helpers/questionhelper.rst +++ b/components/console/helpers/questionhelper.rst @@ -65,10 +65,6 @@ 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 2c37d379a8e..5dc4e827bb3 100644 --- a/components/console/helpers/table.rst +++ b/components/console/helpers/table.rst @@ -147,9 +147,6 @@ 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 cc853ebdad2..f0f88a7b57c 100644 --- a/components/console/helpers/tablehelper.rst +++ b/components/console/helpers/tablehelper.rst @@ -4,61 +4,9 @@ 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 will be removed in + The Table Helper was deprecated in Symfony 2.5 and 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/css_selector.rst b/components/css_selector.rst index 5b7b8648f02..e416711c7dc 100644 --- a/components/css_selector.rst +++ b/components/css_selector.rst @@ -47,11 +47,12 @@ The CssSelector Component ~~~~~~~~~~~~~~~~~~~~~~~~~ The component's only goal is to convert CSS selectors to their XPath -equivalents:: +equivalents, using :method:`Symfony\\Component\\CssSelector\\CssSelectorConverter::toXPath`:: - use Symfony\Component\CssSelector\CssSelector; + use Symfony\Component\CssSelector\CssSelectorConverter; - var_dump(CssSelector::toXPath('div.item > h4 > a')); + $converter = new CssSelectorConverter(); + var_dump($converter->toXPath('div.item > h4 > a')); This gives the following output: diff --git a/components/debug.rst b/components/debug.rst index 21671975416..85a9f04af84 100644 --- a/components/debug.rst +++ b/components/debug.rst @@ -7,10 +7,6 @@ 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 ------------ diff --git a/components/dependency_injection/autowiring.rst b/components/dependency_injection/autowiring.rst new file mode 100644 index 00000000000..24bcf92edd1 --- /dev/null +++ b/components/dependency_injection/autowiring.rst @@ -0,0 +1,396 @@ +.. index:: + single: DependencyInjection; Autowiring + +Defining Services Dependencies Automatically (Autowiring) +========================================================= + +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:: + + namespace Acme; + + class Rot13Transformer + { + public function transform($value) + { + return str_rot13($value); + } + } + +And now a Twitter client using this transformer:: + + namespace Acme; + + 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 + + services: + twitter_client: + class: Acme\TwitterClient + autowire: true + + .. code-block:: xml + + + + + + + + + + .. code-block:: php + + use Symfony\Component\DependencyInjection\Definition; + + // ... + $definition = new Definition('Acme\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:: + + namespace Acme\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``:: + + namespace Acme; + + 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 + + services: + rot13_transformer: + class: Acme\Rot13Transformer + + twitter_client: + class: Acme\TwitterClient + autowire: true + + .. code-block:: xml + + + + + + + + + + + + .. code-block:: php + + use Symfony\Component\DependencyInjection\Definition; + + // ... + $container->register('rot13_transformer', 'Acme\Rot13Transformer'); + + $clientDefinition = new Definition('Acme\TwitterClient'); + $clientDefinition->setAutowired(true); + $container->setDefinition('twitter_client', $clientDefinition); + +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:: + + namespace Acme; + + 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 any transformer and return its value uppercased. + +The controller can now be refactored to add a new endpoint using this uppercase +transformer:: + + namespace Acme\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 + + services: + rot13_transformer: + class: Acme\Rot13Transformer + autowiring_types: Acme\TransformerInterface + + twitter_client: + class: Acme\TwitterClient + autowire: true + + uppercase_transformer: + class: Acme\UppercaseTransformer + autowire: true + + uppercase_twitter_client: + class: Acme\TwitterClient + arguments: ['@uppercase_transformer'] + + .. code-block:: xml + + + + + + + Acme\TransformerInterface + + + + + + + + + + + + + .. code-block:: php + + use Symfony\Component\DependencyInjection\Reference; + use Symfony\Component\DependencyInjection\Definition; + + // ... + $rot13Definition = new Definition('Acme\Rot13Transformer'); + $rot13Definition->setAutowiringTypes(array('Acme\TransformerInterface')); + $container->setDefinition('rot13_transformer', $rot13Definition); + + $clientDefinition = new Definition('Acme\TwitterClient'); + $clientDefinition->setAutowired(true); + $container->setDefinition('twitter_client', $clientDefinition); + + $uppercaseDefinition = new Definition('Acme\UppercaseTransformer'); + $uppercaseDefinition->setAutowired(true); + $container->setDefinition('uppercase_transformer', $uppercaseDefinition); + + $uppercaseClientDefinition = new Definition('Acme\TwitterClient', array( + new Reference('uppercase_transformer'), + )); + $container->setDefinition('uppercase_twitter_client', $uppercaseClientDefinition); + +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 "Acme\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_transformer`` and ``twitter_client`` services. For +the ``uppercase_twitter_client``, a standard service definition is used to +inject the specific ``uppercase_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 0fe80e32564..01c1bb6d60f 100644 --- a/components/dependency_injection/compilation.rst +++ b/components/dependency_injection/compilation.rst @@ -306,46 +306,89 @@ For more details, see :doc:`/bundles/prepend_extension`, which is specific to the Symfony Framework, but contains more details about this feature. -Creating a Compiler Pass ------------------------- +.. _creating-a-compiler-pass: +.. _components-di-compiler-pass: -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` -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. +Execute Code During Compilation +------------------------------- -The compiler pass must have the ``process`` method which is passed the container -being compiled:: +You can also execute custom code during compilation by writing your own +compiler pass. By implementing +:class:`Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface` +in your extension, the added ``process()`` method will be called during +compilation:: + // ... use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; - use Symfony\Component\DependencyInjection\ContainerBuilder; - class CustomCompilerPass implements CompilerPassInterface + class AcmeDemoExtension implements ExtensionInterface, 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 the :doc:`/service_container/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. +methods described in :doc:`/service_container/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. -Registering a Compiler Pass ---------------------------- +.. _components-di-separate-compiler-passes: -You need to register your custom pass with the container. Its process method -will then be called when the container is compiled:: +Creating Separate Compiler Passes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sometimes, you need to do more than one thing during compilation, 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:: use Symfony\Component\DependencyInjection\ContainerBuilder; $container = new ContainerBuilder(); - $container->addCompilerPass(new CustomCompilerPass); + $container->addCompilerPass(new CustomPass()); .. note:: @@ -354,17 +397,16 @@ will then be called when the container is compiled:: 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. You can choose where in -the order any custom passes you add are run. By default they will be run -before the optimization passes. +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. -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: +You can use the following constants to determine when your pass is executed: * ``PassConfig::TYPE_BEFORE_OPTIMIZATION`` * ``PassConfig::TYPE_OPTIMIZE`` @@ -373,14 +415,11 @@ a pass with the container to control where it goes in the order: * ``PassConfig::TYPE_AFTER_REMOVING`` For example, to run your custom pass after the default removal passes have -been run:: +been run, use:: - use Symfony\Component\DependencyInjection\ContainerBuilder; - use Symfony\Component\DependencyInjection\Compiler\PassConfig; - - $container = new ContainerBuilder(); + // ... $container->addCompilerPass( - new CustomCompilerPass, + new CustomPass(), PassConfig::TYPE_AFTER_REMOVING ); diff --git a/components/dom_crawler.rst b/components/dom_crawler.rst index 55b832848b7..922c46d07a4 100644 --- a/components/dom_crawler.rst +++ b/components/dom_crawler.rst @@ -129,9 +129,6 @@ aliases both with :method:`Symfony\\Component\\DomCrawler\\Crawler::filterXPath` and :method:`Symfony\\Component\\DomCrawler\\Crawler::filter`:: - use Symfony\Component\CssSelector\CssSelector; - - CssSelector::disableHtmlExtension(); $crawler = $crawler->filter('default|entry media|group yt|aspectRatio'); .. note:: @@ -150,12 +147,6 @@ Namespaces can be explicitly registered with the $crawler->registerNamespace('m', 'http://search.yahoo.com/mrss/'); $crawler = $crawler->filterXPath('//m:group//yt:aspectRatio'); -.. caution:: - - To query XML with a CSS selector, the HTML extension needs to be disabled with - :method:`CssSelector::disableHtmlExtension ` - to avoid converting the selector to lowercase. - Node Traversing ~~~~~~~~~~~~~~~ @@ -190,10 +181,6 @@ 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 @@ -227,11 +214,6 @@ 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. @@ -298,8 +280,6 @@ and :phpclass:`DOMNode` objects: $html = $crawler->html(); - The ``html`` method is new in Symfony 2.3. - Links ~~~~~ diff --git a/components/expression_language/extending.rst b/components/expression_language/extending.rst index fa90165014d..eeb9963c6c6 100644 --- a/components/expression_language/extending.rst +++ b/components/expression_language/extending.rst @@ -56,9 +56,6 @@ 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/filesystem.rst b/components/filesystem.rst index e799dfa2813..619d90210f1 100644 --- a/components/filesystem.rst +++ b/components/filesystem.rst @@ -6,10 +6,6 @@ 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 ------------ @@ -239,9 +235,6 @@ 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. @@ -252,8 +245,6 @@ complete new file (but never a partially-written file):: The ``file.txt`` file contains ``Hello World`` now. -A desired file mode can be passed as the third argument. - Error Handling -------------- diff --git a/components/filesystem/lock_handler.rst b/components/filesystem/lock_handler.rst index 5d442e79547..90efe6b1033 100644 --- a/components/filesystem/lock_handler.rst +++ b/components/filesystem/lock_handler.rst @@ -1,9 +1,6 @@ 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 6d77cdedd98..370c8aedf07 100644 --- a/components/finder.rst +++ b/components/finder.rst @@ -95,10 +95,6 @@ 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__); diff --git a/components/form.rst b/components/form.rst index 99e71ce2062..4b8a2500fc6 100644 --- a/components/form.rst +++ b/components/form.rst @@ -67,9 +67,6 @@ 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:: @@ -380,9 +377,14 @@ 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', 'text') - ->add('dueDate', 'date') + ->add('task', TextType::class) + ->add('dueDate', DateType::class) ->getForm(); var_dump($twig->render('new.html.twig', array( @@ -396,6 +398,8 @@ 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 { @@ -403,9 +407,10 @@ 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', 'text') - ->add('dueDate', 'date') + ->add('task', TextType::class) + ->add('dueDate', DateType::class) ->getForm(); return $this->render('AcmeTaskBundle:Default:new.html.twig', array( @@ -416,8 +421,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 field "type". The Form component -comes with a lot of :doc:`built-in types `. +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 `. Now that you've built your form, learn how to :ref:`render ` it and :ref:`process the form submission `. @@ -433,24 +438,35 @@ 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('form', $defaults) - ->add('task', 'text') - ->add('dueDate', 'date') + $form = $formFactory->createBuilder(FormType::class, $defaults) + ->add('task', TextType::class) + ->add('dueDate', DateType::class) ->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', 'text') - ->add('dueDate', 'date') + ->add('task', TextType::class) + ->add('dueDate', DateType::class) ->getForm(); .. tip:: @@ -489,10 +505,6 @@ to do that in the ":doc:`/form/rendering`" 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 @@ -502,7 +514,11 @@ by ``handleRequest()`` to determine whether a form has been submitted): .. code-block:: php-standalone - $formBuilder = $formFactory->createBuilder('form', null, array( + use Symfony\Component\Form\Extension\Core\Type\FormType; + + // ... + + $formBuilder = $formFactory->createBuilder(FormType::class, null, array( 'action' => '/search', 'method' => 'GET', )); @@ -511,6 +527,8 @@ 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() @@ -537,10 +555,14 @@ 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', 'text') - ->add('dueDate', 'date') + ->add('task', TextType::class) + ->add('dueDate', DateType::class) ->getForm(); $request = Request::createFromGlobals(); @@ -562,13 +584,16 @@ 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', 'text') - ->add('dueDate', 'date') + ->add('task', TextType::class) + ->add('dueDate', DateType::class) ->getForm(); $form->handleRequest($request); @@ -613,12 +638,14 @@ 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', 'text', array( + ->add('task', TextType::class, array( 'constraints' => new NotBlank(), )) - ->add('dueDate', 'date', array( + ->add('dueDate', DateType::class, array( 'constraints' => array( new NotBlank(), new Type('\DateTime'), @@ -630,12 +657,14 @@ 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', 'text', array( + ->add('task', TextType::class, array( 'constraints' => new NotBlank(), )) - ->add('dueDate', 'date', array( + ->add('dueDate', DateType::class, array( 'constraints' => array( new NotBlank(), new Type('\DateTime'), @@ -677,17 +706,6 @@ method to access the list of errors. It returns a // a FormErrorIterator instance representing the form tree structure $errors = $form->getErrors(true, false); -.. 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()); - - This is useful, for example, if you want to use PHP's ``array_`` function - on the form errors. - Learn more ---------- diff --git a/components/http_foundation.rst b/components/http_foundation.rst index 7c4caf8e68e..03f054412e4 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -128,9 +128,6 @@ has some methods to filter the input values: :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,39 +137,35 @@ 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 three arguments: the first one is the parameter name +All getters take up to two 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', 'bar'); - // returns 'bar' + $request->query->get('bar', 'baz'); + // returns 'baz' 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. 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:: +``foo`` parameter and you will get back an array with a ``bar`` element:: - // the query string is '?foo[bar]=bar' + // the query string is '?foo[bar]=baz' $request->query->get('foo'); - // returns array('bar' => 'bar') + // returns array('bar' => 'baz') $request->query->get('foo[bar]'); // returns null - $request->query->get('foo[bar]', null, true); - // returns 'bar' + $request->query->get('foo')['bar']; + // returns 'baz' .. _component-foundation-attributes: @@ -521,9 +514,6 @@ 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 461d6ddac57..dc4cf2bff70 100644 --- a/components/http_foundation/trusting_proxies.rst +++ b/components/http_foundation/trusting_proxies.rst @@ -19,10 +19,6 @@ 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.rst b/components/http_kernel.rst index 04330019252..9212b3b2d30 100644 --- a/components/http_kernel.rst +++ b/components/http_kernel.rst @@ -613,6 +613,7 @@ 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; @@ -638,7 +639,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)); + $dispatcher->addSubscriber(new RouterListener($matcher, new RequestStack())); $resolver = new ControllerResolver(); $kernel = new HttpKernel($dispatcher, $resolver); diff --git a/components/intl.rst b/components/intl.rst index 4837fd5993e..040042c7e83 100644 --- a/components/intl.rst +++ b/components/intl.rst @@ -8,10 +8,6 @@ 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 diff --git a/components/ldap.rst b/components/ldap.rst new file mode 100644 index 00000000000..b1f51043dd4 --- /dev/null +++ b/components/ldap.rst @@ -0,0 +1,72 @@ +.. index:: + single: Ldap + single: Components; Ldap + +The Ldap Component +================== + + The Ldap component provides a means to connect to an LDAP server (OpenLDAP or Active Directory). + +Installation +------------ + +You can install the component in 2 different ways: + +* :doc:`Install it via Composer ` (``symfony/ldap`` on `Packagist`_); +* Use the official Git repository (https://github.com/symfony/ldap). + +.. include:: /components/require_autoload.rst.inc + +Usage +----- + +The :class:`Symfony\\Component\\Ldap\\LdapClient` class provides methods +to authenticate and query against an LDAP server. + +The :class:`Symfony\\Component\\Ldap\\LdapClient` class can be configured +using the following options: + +``host`` + IP or hostname of the LDAP server + +``port`` + Port used to access the LDAP server + +``version`` + The version of the LDAP protocol to use + +``useSsl`` + Whether or not to secure the connection using SSL + +``useStartTls`` + Whether or not to secure the connection using StartTLS + +``optReferrals`` + Specifies whether to automatically follow referrals + returned by the LDAP server + +For example, to connect to a start-TLS secured LDAP server:: + + use Symfony\Component\Ldap\LdapClient; + + $ldap = new LdapClient('my-server', 389, 3, false, true); + +The :method:`Symfony\\Component\\Ldap\\LdapClient::bind` method +authenticates a previously configured connection using both the +distinguished name (DN) and the password of a user:: + + use Symfony\Component\Ldap\LdapClient; + // ... + + $ldap->bind($dn, $password); + +Once bound (or if you enabled anonymous authentication on your +LDAP server), you may query the LDAP server using the +:method:`Symfony\\Component\\Ldap\\LdapClient::find` method:: + + use Symfony\Component\Ldap\LdapClient; + // ... + + $ldap->find('dc=symfony,dc=com', '(&(objectclass=person)(ou=Maintainers))'); + +.. _Packagist: https://packagist.org/packages/symfony/ldap diff --git a/components/options_resolver.rst b/components/options_resolver.rst index 212b993d6bd..ba1cc1124dd 100644 --- a/components/options_resolver.rst +++ b/components/options_resolver.rst @@ -19,14 +19,6 @@ You can install the component in 2 different ways: .. include:: /components/require_autoload.rst.inc -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 ----- @@ -222,10 +214,6 @@ 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:: @@ -250,11 +238,6 @@ 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 @@ -275,11 +258,6 @@ 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` @@ -362,11 +340,6 @@ 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 ~~~~~~~~~~~~~~~~ @@ -412,11 +385,6 @@ 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 ~~~~~~~~~~~~~~~~~~~~ @@ -447,11 +415,6 @@ 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:: @@ -586,11 +549,6 @@ 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 @@ -642,11 +600,6 @@ 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:: @@ -732,4 +685,3 @@ options in your code. .. _Packagist: https://packagist.org/packages/symfony/options-resolver .. _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 index 4c438486109..966d8bb10ad 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -6,7 +6,7 @@ The PHPUnit Bridge ================== The PHPUnit Bridge provides utilities to report legacy tests and usage of - deprecated code. + deprecated code and a helper for time-sensitive tests. It comes with the following features: @@ -18,9 +18,7 @@ It comes with the following features: * Displays the stack trace of a deprecation on-demand; -.. 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). +* Provides a ``ClockMock`` helper class for time-sensitive tests. Installation ------------ @@ -120,6 +118,120 @@ 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 namespace is ``App\Watch``. + +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 @@ -127,3 +239,4 @@ compatibility reasons. .. _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.org/ diff --git a/components/process.rst b/components/process.rst index 675ea0e644e..b99fc3b2bc2 100644 --- a/components/process.rst +++ b/components/process.rst @@ -131,9 +131,6 @@ 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 @@ -170,10 +167,6 @@ 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. @@ -249,9 +242,6 @@ 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:: @@ -275,9 +265,6 @@ 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. diff --git a/components/property_access.rst b/components/property_access.rst index e646ce90ea3..041f7543b89 100644 --- a/components/property_access.rst +++ b/components/property_access.rst @@ -31,10 +31,6 @@ 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 ------------------- @@ -215,9 +211,6 @@ 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 diff --git a/components/property_info.rst b/components/property_info.rst new file mode 100644 index 00000000000..5a7f76e2cfe --- /dev/null +++ b/components/property_info.rst @@ -0,0 +1,443 @@ +.. index:: + single: PropertyInfo + single: Components; PropertyInfo + +The PropertyInfo Component +========================== + + The PropertyInfo component provides the functionality to get information + about class properties using metadata of popular sources. + +While the :doc:`PropertyAccess component ` +allows you to read and write values to/from objects and arrays, the PropertyInfo +component works solely with class definitions to provide information such +as data type and visibility about properties within that class. + +Similar to PropertyAccess, the PropertyInfo component combines both class +properties (such as ``$property``) and properties defined via accessor and +mutator methods such as ``getProperty()``, ``isProperty()``, ``setProperty()``, +``addProperty()``, ``removeProperty()``, etc. + +.. _`components-property-information-installation`: + +Installation +------------ + +You can install the component in two different ways: + +* :doc:`Install it via Composer ` (``symfony/property-info`` + on `Packagist`_); +* Use the official Git repository (https://github.com/symfony/property-info). + +.. include:: /components/require_autoload.rst.inc + +Additional dependencies may be required for some of the +:ref:`extractors provided with this component `. + +.. _`components-property-information-usage`: + +Usage +----- + +The entry point of this component is a new instance of the +:class:`Symfony\\Component\\PropertyInfo\\PropertyInfoExtractor` +class, providing sets of information extractors. + +.. code-block:: php + + use Symfony\Component\PropertyInfo\PropertyInfoExtractor; + + $propertyInfo = new PropertyInfoExtractor( + $arrayOfListExtractors, + $arrayOfTypeExtractors, + $arrayOfDescriptionExtractors, + $arrayOfAccessExtractors + ); + +The order of extractor instances within an array matters, as the first non-null +result will be returned. That is why you must provide each category of extractors +as a separate array, even if an extractor provides information for more than +one category. + +For example, while the :class:`Symfony\\Component\\PropertyInfo\\Extractor\\ReflectionExtractor` +and :class:`Symfony\\Bridge\\Doctrine\\PropertyInfo\\DoctrineExtractor` +both provide list and type information it is probably better that: + +* The :class:`Symfony\\Component\\PropertyInfo\\Extractor\\ReflectionExtractor` + has priority for list information so that all properties in a class (not + just mapped properties) are returned. +* The :class:`Symfony\\Bridge\\Doctrine\\PropertyInfo\\DoctrineExtractor` + has priority for type information so that entity metadata is used instead + of type-hinting to provide more accurate type information. + +.. code-block:: php + + use Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor; + use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; + use Symfony\Component\PropertyInfo\PropertyInfoExtractor; + + $reflectionExtractor = new ReflectionExtractor(); + $doctrineExtractor = new DoctrineExtractor(/* ... */); + + $propertyInfo = new PropertyInfoExtractor( + // List extractors + array( + $reflectionExtractor, + $doctrineExtractor + ), + // Type extractors + array( + $doctrineExtractor, + $reflectionExtractor + ) + ); + +.. _`components-property-information-extractable-information`: + +Extractable Information +----------------------- + +The :class:`Symfony\\Component\\PropertyInfo\\PropertyInfoExtractor` +class exposes public methods to extract four types of information: list, +type, description and access information. The first type of information is +about the class, while the remaining three are about the individual properties. + +.. note:: + + When specifiying a class that the PropertyInfo component should work + with, use the fully-qualified class name. Do not directly pass an object + as some extractors (the + :class:`Symfony\\Component\\PropertyInfo\\Extractor\\SerializerExtractor` + is an example) may not automatically resolve objects to their class + names - use the ``get_class()`` function. + + Since the PropertyInfo component requires PHP 5.5 or greater, you can + also make use of the `class constant`_. + +List Information +~~~~~~~~~~~~~~~~ + +Extractors that implement :class:`Symfony\\Component\\PropertyInfo\\PropertyListExtractorInterface` +provide the list of properties that are available on a class as an array +containing each property name as a string. + +.. code-block:: php + + $properties = $propertyInfo->getProperties($class); + /* + Example Result + -------------- + array(3) { + [0] => string(8) "username" + [1] => string(8) "password" + [2] => string(6) "active" + } + */ + +Type Information +~~~~~~~~~~~~~~~~ + +Extractors that implement :class:`Symfony\\Component\\PropertyInfo\\PropertyTypeExtractorInterface` +provide :ref:`extensive data type information ` +for a property. + +.. code-block:: php + + $types = $propertyInfo->getTypes($class, $property); + + /* + Example Result + -------------- + array(1) { + [0] => + class Symfony\Component\PropertyInfo\Type (6) { + private $builtinType => string(6) "string" + private $nullable => bool(false) + private $class => NULL + private $collection => bool(false) + private $collectionKeyType => NULL + private $collectionValueType => NULL + } + } + */ + +Description Information +~~~~~~~~~~~~~~~~~~~~~~~ + +Extractors that implement :class:`Symfony\\Component\\PropertyInfo\\PropertyDescriptionExtractorInterface` +provide long and short descriptions from a properties annotations as +strings. + +.. code-block:: php + + $title = $propertyInfo->getShortDescription($class, $property); + /* + Example Result + -------------- + string(41) "This is the first line of the DocComment." + */ + + $paragraph = $propertyInfo->getLongDescription($class, $property); + /* + Example Result + -------------- + string(79): + These is the subsequent paragraph in the DocComment. + It can span multiple lines. + */ + +Access Information +~~~~~~~~~~~~~~~~~~ + +Extractors that implement :class:`Symfony\\Component\\PropertyInfo\\PropertyAccessExtractorInterface` +provide whether properties are readable or writable as booleans. + +.. code-block:: php + + $propertyInfo->isReadable($class, $property); + // Example Result: bool(true) + + $propertyInfo->isWritable($class, $property); + // Example Result: bool(false) + +.. tip:: + + The main :class:`Symfony\\Component\\PropertyInfo\\PropertyInfoExtractor` + class implements all four interfaces, delegating the extraction of property + information to the extractors that have been registered with it. + + This means that any method available on each of the extractors is also + available on the main :class:`Symfony\\Component\\PropertyInfo\\PropertyInfoExtractor` + class. + +.. _`components-property-info-type`: + +Type Objects +------------ + +Compared to the other extractors, type information extractors provide much +more information than can be represented as simple scalar values - because +of this, type extractors return an array of objects. The array will contain +an instance of the :class:`Symfony\\Component\\PropertyInfo\\Type` +class for each type that the property supports. + +For example, if a property supports both ``integer`` and ``string`` (via +the ``@return int|string`` annotation), +:method:`PropertyInfoExtractor::getTypes() ` +will return an array containing **two** instances of the :class:`Symfony\\Component\\PropertyInfo\\Type` +class. + +.. note:: + + Most extractors will return only one :class:`Symfony\\Component\\PropertyInfo\\Type` + instance. The :class:`Symfony\\Component\\PropertyInfo\\Extractor\\PhpDocExtractor` + is currently the only extractor that returns multiple instances in the array. + +Each object will provide 6 attributes; the first four (built-in type, nullable, +class and collection) are scalar values and the last two (collection key +type and collection value type) are more instances of the :class:`Symfony\\Component\\PropertyInfo\\Type` +class again if collection is ``true``. + +.. _`components-property-info-type-builtin`: + +Built-in Type +~~~~~~~~~~~~~ + +The :method:`Type::getBuiltinType() ` +method will return the built-in PHP data type, which can be one of 9 possible +string values: ``array``, ``bool``, ``callable``, ``float``, ``int``, ``null``, +``object``, ``resource`` or ``string``. + +Constants inside the :class:`Symfony\\Component\\PropertyInfo\\Type` +class, in the form ``Type::BUILTIN_TYPE_*``, are provided for convenience. + +Nullable +~~~~~~~~ + +The :method:`Type::isNullable() ` +method will return a boolean value indicating whether the property parameter +can be set to ``null``. + +Class +~~~~~ + +If the :ref:`built-in PHP data type ` +is ``object``, the :method:`Type::getClassName() ` +method will return the fully-qualified class or interface name accepted. + +Collection +~~~~~~~~~~ + +The :method:`Type::isCollection() ` +method will return a boolean value indicating if the property parameter is +a collection - a non-scalar value capable of containing other values. Currently +this returns ``true`` if: + +* The :ref:`built-in PHP data type ` + is ``array``, or +* The mutator method the property is derived from has a prefix of ``add`` + or ``remove`` (which are defined as the list of array mutator prefixes). + +Collection Key & Value Types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the property is a collection, additional type objects may be returned +for both the key and value types of the collection (if the information is +available), via the :method:`Type::getCollectionKeyType() ` +and :method:`Type::getCollectionValueType() ` +methods. + +.. _`components-property-info-extractors`: + +Extractors +---------- + +The extraction of property information is performed by *extractor classes*. +An extraction class can provide one or more types of property information +by implementing the correct interface(s). + +The :class:`Symfony\\Component\\PropertyInfo\\PropertyInfoExtractor` will +iterate over the relevant extractor classes in the order they were set, call +the appropriate method and return the first result that is not ``null``. + +.. _`components-property-information-extractors-available`: + +While you can create your own extractors, the following are already available +to cover most use-cases: + +ReflectionExtractor +~~~~~~~~~~~~~~~~~~~ + +Using PHP reflection, the :class:`Symfony\\Component\\PropertyInfo\\Extractor\\ReflectionExtractor` +provides list, type and access information from setter and accessor methods. +It can also provide return and scalar types for PHP 7+. + +This service is automatically registered with the ``property_info`` service. + +.. code-block:: php + + use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; + + $reflectionExtractor = new ReflectionExtractor; + + // List information. + $reflectionExtractor->getProperties($class); + // Type information. + $reflectionExtractor->getTypes($class, $property); + // Access information. + $reflectionExtractor->isReadable($class, $property); + $reflectionExtractor->isWritable($class, $property); + +PhpDocExtractor +~~~~~~~~~~~~~~~ + +.. note:: + + This extractor depends on the `phpdocumentor/reflection`_ library. + +Using `phpDocumentor Reflection`_ to parse property and method annotations, +the :class:`Symfony\\Component\\PropertyInfo\\Extractor\\PhpDocExtractor` +provides type and description information. This extractor is automatically +registered with the ``property_info`` providing its dependencies are detected. + +.. code-block:: php + + use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; + + $phpDocExtractor = new PhpDocExtractor; + + // Type information. + $phpDocExtractor->getTypes($class, $property); + // Description information. + $phpDocExtractor->getShortDescription($class, $property); + $phpDocExtractor->getLongDescription($class, $property); + +SerializerExtractor +~~~~~~~~~~~~~~~~~~~ + +.. note:: + + This extractor depends on the `symfony/serializer`_ library. + +Using groups metadata from the :doc:`Serializer component `, +the :class:`Symfony\\Component\\PropertyInfo\\Extractor\\SerializerExtractor` +provides list information. This extractor is not registered automatically +with the ``property_info`` service. + +.. code-block:: php + + use Doctrine\Common\Annotations\AnnotationReader; + use Symfony\Component\PropertyInfo\Extractor\SerializerExtractor; + use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; + use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; + + $serializerClassMetadataFactory = new ClassMetadataFactory( + new AnnotationLoader(new AnnotationReader) + ); + $serializerExtractor = new SerializerExtractor($serializerClassMetadataFactory); + + // List information. + $serializerExtractor->getProperties($class); + +DoctrineExtractor +~~~~~~~~~~~~~~~~~ + +.. note:: + + This extractor depends on the `symfony/doctrine-bridge`_ and `doctrine/orm`_ + libraries. + +Using entity mapping data from `Doctrine ORM`_, the +:class:`Symfony\\Bridge\\Doctrine\\PropertyInfo\\DoctrineExtractor` +- located in the Doctrine bridge - provides list and type information. +This extractor is not registered automatically with the ``property_info`` +service. + +.. code-block:: php + + use Doctrine\ORM\EntityManager; + use Doctrine\ORM\Tools\Setup; + use Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor; + + $config = Setup::createAnnotationMetadataConfiguration([__DIR__], true); + $entityManager = EntityManager::create([ + 'driver' => 'pdo_sqlite', + // ... + ], $config); + $doctrineExtractor = new DoctrineExtractor($entityManager->getMetadataFactory()); + + // List information. + $doctrineExtractor->getProperties($class); + // Type information. + $doctrineExtractor->getTypes($class, $property); + +.. _`components-property-information-extractors-creation`: + +Creating Your Own Extractors +---------------------------- + +You can create your own property information extractors by creating a +class that implements one or more of the following interfaces: +:class:`Symfony\\Component\\PropertyInfo\\PropertyAccessExtractorInterface`, +:class:`Symfony\\Component\\PropertyInfo\\PropertyDescriptionExtractorInterface`, +:class:`Symfony\\Component\\PropertyInfo\\PropertyListExtractorInterface` +and :class:`Symfony\\Component\\PropertyInfo\\PropertyTypeExtractorInterface`. + +If you have enabled the PropertyInfo component with the FrameworkBundle, +you can automatically register your extractor class with the ``property_info`` +service by defining it as a service with one or more of the following +:doc:`tags `: + +* ``property_info.list_extractor`` if it provides list information. +* ``property_info.type_extractor`` if it provides type information. +* ``property_info.description_extractor`` if it provides description information. +* ``property_info.access_extractor`` if it provides access information. + +.. _Packagist: https://packagist.org/packages/symfony/property-info +.. _`phpDocumentor Reflection`: https://github.com/phpDocumentor/Reflection +.. _`phpdocumentor/reflection`: https://packagist.org/packages/phpdocumentor/reflection +.. _`Doctrine ORM`: http://www.doctrine-project.org/projects/orm.html +.. _`symfony/serializer`: https://packagist.org/packages/symfony/serializer +.. _`symfony/doctrine-bridge`: https://packagist.org/packages/symfony/doctrine-bridge +.. _`doctrine/orm`: https://packagist.org/packages/doctrine/orm +.. _`class constant`: http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.class.class diff --git a/components/security/authentication.rst b/components/security/authentication.rst index 7360d898ea1..fb6fc4d32bd 100644 --- a/components/security/authentication.rst +++ b/components/security/authentication.rst @@ -4,11 +4,6 @@ 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 diff --git a/components/security/authorization.rst b/components/security/authorization.rst index 389b56a4433..5f5287bd64c 100644 --- a/components/security/authorization.rst +++ b/components/security/authorization.rst @@ -29,11 +29,6 @@ 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 @@ -90,13 +85,6 @@ 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`, diff --git a/components/security/firewall.rst b/components/security/firewall.rst index 64603efb319..c3fe82f4c49 100644 --- a/components/security/firewall.rst +++ b/components/security/firewall.rst @@ -34,11 +34,6 @@ certain action or resource of the application:: 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` diff --git a/components/security/secure_tools.rst b/components/security/secure_tools.rst index a7060c26597..16a2c5256f8 100644 --- a/components/security/secure_tools.rst +++ b/components/security/secure_tools.rst @@ -1,5 +1,5 @@ -Securely Comparing Strings and Generating Random Values -======================================================= +Securely 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 9a2c852ee35..93d3bca3855 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -178,10 +178,6 @@ 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. @@ -320,14 +316,6 @@ 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` @@ -344,13 +332,11 @@ 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. @@ -416,10 +402,6 @@ 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. @@ -529,21 +511,9 @@ 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 @@ -632,6 +602,50 @@ 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/translation/custom_formats.rst b/components/translation/custom_formats.rst index 14c6e65c8b0..d5d9ddcd446 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 { - protected function format(MessageCatalogue $messages, $domain = 'messages') + public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = array()) { $output = ''; @@ -102,7 +102,14 @@ will save a few lines:: } } -The :method:`Symfony\\Component\\Translation\\Dumper\\FileDumper::format` +.. 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` 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 @@ -116,4 +123,3 @@ 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/usage.rst b/components/translation/usage.rst index dae457f2f2a..00887e5bb12 100644 --- a/components/translation/usage.rst +++ b/components/translation/usage.rst @@ -378,7 +378,11 @@ 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:: - $messages = $translator->getMessages('fr_FR'); + $catalogue = $translator->getCatalogue('fr_FR'); + $messages = $catalogue->all(); + while ($catalogue = $catalogue->getFallbackCatalogue()) { + $messages = array_replace_recursive($catalogue->all(), $messages); + } The ``$messages`` variable will have the following structure:: diff --git a/components/var_dumper.rst b/components/var_dumper.rst index df256eb2d53..673f3e270e6 100644 --- a/components/var_dumper.rst +++ b/components/var_dumper.rst @@ -9,9 +9,6 @@ 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 ------------ @@ -84,7 +81,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 standard edition since version 2.6. +environment of the Symfony Standard Edition. 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 @@ -111,10 +108,6 @@ 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. @@ -150,11 +143,6 @@ 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.rst b/components/yaml.rst index 5b2c165f20d..6e6791413c8 100644 --- a/components/yaml.rst +++ b/components/yaml.rst @@ -130,9 +130,6 @@ error occurred: Objects for Mappings .................... -.. versionadded:: 2.7 - Support for parsing mappings as objects was introduced in Symfony 2.7. - Yaml :ref:`mappings ` are basically associative arrays. You can instruct the parser to return mappings as objects (i.e. ``\stdClass`` instances) by setting the fourth argument to ``true``:: diff --git a/configuration.rst b/configuration.rst index d176c366110..8d8da27b2a4 100644 --- a/configuration.rst +++ b/configuration.rst @@ -119,7 +119,7 @@ dump of all available configuration options by running: .. code-block:: bash - $ php app/console config:dump twig + $ php bin/console config:dump twig .. index:: single: Environments; Introduction diff --git a/configuration/apache_router.rst b/configuration/apache_router.rst index a8b4f8a7c33..69c7ec14307 100644 --- a/configuration/apache_router.rst +++ b/configuration/apache_router.rst @@ -19,139 +19,7 @@ handle routes directly, rather than using Symfony for this task. .. caution:: - 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(); + 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). diff --git a/configuration/configuration_organization.rst b/configuration/configuration_organization.rst index 093141f43e9..7d5a6074e4d 100644 --- a/configuration/configuration_organization.rst +++ b/configuration/configuration_organization.rst @@ -34,8 +34,9 @@ default Symfony Standard Edition follow this structure: .. code-block:: text - / + your-project/ ├─ app/ + │ ├─ ... │ └─ config/ │ ├─ config.yml │ ├─ config_dev.yml @@ -46,9 +47,7 @@ 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. @@ -65,8 +64,9 @@ name as the environment: .. code-block:: text - / + your-project/ ├─ app/ + │ ├─ ... │ └─ config/ │ ├─ common/ │ │ ├─ config.yml @@ -83,9 +83,7 @@ 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` @@ -161,8 +159,9 @@ and several files to define all application services: .. code-block:: text - / + your-project/ ├─ app/ + │ ├─ ... │ └─ config/ │ ├─ bundles/ │ │ ├─ bundle1.yml @@ -182,9 +181,7 @@ 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/configuration/environments.rst b/configuration/environments.rst index a66424fa000..32dde88385f 100644 --- a/configuration/environments.rst +++ b/configuration/environments.rst @@ -179,10 +179,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 if errors should be displayed or if cache files are + such as displaying stacktraces on error pages 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 `. @@ -213,10 +213,6 @@ 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -227,13 +223,13 @@ behavior: .. code-block:: bash # 'dev' environment and debug enabled - $ php app/console command_name + $ php bin/console command_name # 'prod' environment (debug is always disabled for 'prod') - $ php app/console command_name --env=prod + $ php bin/console command_name --env=prod # 'test' environment and debug disabled - $ php app/console command_name --env=test --no-debug + $ php bin/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 @@ -348,13 +344,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 ``app/cache`` directory. +By default, these cached files are largely stored in the ``var/cache`` directory. However, each environment caches its own set of files: .. code-block:: text - / - ├─ app/ + your-project/ + ├─ var/ │ ├─ cache/ │ │ ├─ dev/ # cache directory for the *dev* environment │ │ └─ prod/ # cache directory for the *prod* environment @@ -363,7 +359,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 ``app/cache/dev`` directory +developing and debugging). While it can vary, the ``var/cache/dev`` directory includes the following: ``appDevDebugProjectContainer.php`` diff --git a/configuration/front_controllers_and_kernel.rst b/configuration/front_controllers_and_kernel.rst index 7f365931298..f5287ed4c2e 100644 --- a/configuration/front_controllers_and_kernel.rst +++ b/configuration/front_controllers_and_kernel.rst @@ -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 `app/console`_ script used when running Symfony on the command +Technically, the `bin/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 -.. _app/console: https://github.com/symfony/symfony-standard/blob/master/app/console +.. _bin/console: https://github.com/symfony/symfony-standard/blob/master/bin/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/configuration/micro_kernel_trait.rst b/configuration/micro_kernel_trait.rst new file mode 100644 index 00000000000..1906d02dc76 --- /dev/null +++ b/configuration/micro_kernel_trait.rst @@ -0,0 +1,318 @@ +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->import('@WebProfilerBundle/Resources/config/routing/wdt.xml', '/_wdt'); + $routes->import('@WebProfilerBundle/Resources/config/routing/profiler.xml', '/_profiler'); + } + + // load the annotation routes + $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/configuration/override_dir_structure.rst b/configuration/override_dir_structure.rst index 6bcdcd46dd4..cb9d73286a5 100644 --- a/configuration/override_dir_structure.rst +++ b/configuration/override_dir_structure.rst @@ -12,12 +12,18 @@ directory structure is: your-project/ ├─ app/ - │ ├─ cache/ │ ├─ config/ - │ ├─ logs/ + │ └─ ... + ├─ bin/ │ └─ ... ├─ src/ │ └─ ... + ├─ tests/ + │ └─ ... + ├─ var/ + │ ├─ cache/ + │ ├─ logs/ + │ └─ ... ├─ vendor/ │ └─ ... └─ web/ @@ -41,13 +47,13 @@ in the ``AppKernel`` class of your application:: public function getCacheDir() { - return $this->rootDir.'/'.$this->environment.'/cache'; + return dirname(__DIR__).'/var/'.$this->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``. +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``. .. caution:: @@ -74,11 +80,11 @@ method:: public function getLogDir() { - return $this->rootDir.'/'.$this->environment.'/logs'; + return dirname(__DIR__).'/var/'.$this->environment.'/logs'; } } -Here you have changed the location of the directory to ``app/{environment}/logs``. +Here you have changed the location of the directory to ``var/{environment}/logs``. .. _override-web-dir: @@ -86,23 +92,22 @@ 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 ``app`` directory is still correct +need to guarantee is that the path to the ``var`` 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__.'/../Symfony/app/bootstrap.php.cache'; - require_once __DIR__.'/../Symfony/app/AppKernel.php'; + require_once __DIR__.'/../path/to/app/autoload.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:: javascript +.. code-block:: json { - ... + "...": "...", "extra": { - ... + "...": "...", "symfony-web-dir": "my_new_web_dir" } } @@ -163,8 +168,8 @@ file: .. code-block:: bash - $ php app/console cache:clear --env=prod - $ php app/console assetic:dump --env=prod --no-debug + $ php bin/console cache:clear --env=prod + $ php bin/console assetic:dump --env=prod --no-debug Override the ``vendor`` Directory --------------------------------- @@ -186,6 +191,7 @@ 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/console.rst b/console.rst index 30cd2dfb84a..6a20d6c30db 100644 --- a/console.rst +++ b/console.rst @@ -4,8 +4,8 @@ Console Commands ================ -The Symfony framework provide lots of commands through the ``app/console`` script -(e.g. the well-known ``app/console cache:clear`` command). These commands are +The Symfony framework provide lots of commands through the ``bin/console`` script +(e.g. the well-known ``bin/console cache:clear`` command). These commands are created with the :doc:`Console component `. You can also use it to create your own commands. @@ -49,10 +49,10 @@ method. Then you can optionally define a help message and the protected function configure() { $this - // the name of the command (the part after "app/console") + // the name of the command (the part after "bin/console") ->setName('app:create-users') - // the short description shown while running "php app/console list" + // the short description shown while running "php bin/console list" ->setDescription('Creates new users.') // the full command description shown when running the command with @@ -68,7 +68,7 @@ After configuring the command, you can execute it in the terminal: .. code-block:: bash - $ php app/console app:create-users + $ php bin/console app:create-users As you might expect, this command will do nothing as you didn't write any logic yet. Add your own logic inside the ``execute()`` method, which has access to the @@ -97,7 +97,7 @@ Now, try executing the command: .. code-block:: bash - $ php app/console app:create-user + $ php bin/console app:create-user User Creator ============ @@ -138,7 +138,7 @@ Now, you can pass the username to the command: .. code-block:: bash - $ php app/console app:create-user Wouter + $ php bin/console app:create-user Wouter User Creator ============ diff --git a/console/logging.rst b/console/logging.rst index 531ac15acc1..bfa844d6915 100644 --- a/console/logging.rst +++ b/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 ``app/logs/dev.log`` or ``app/logs/prod.log``. +setup), you should see the logged entries in ``var/logs/dev.log`` or ``var/logs/prod.log``. Enabling automatic Exceptions Logging ------------------------------------- @@ -73,9 +73,6 @@ 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/console/style.rst b/console/style.rst index 4c5cc705281..fcf2d84c942 100644 --- a/console/style.rst +++ b/console/style.rst @@ -4,9 +4,6 @@ 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/console/usage.rst b/console/usage.rst index 6275f760aa0..8bdd134913e 100644 --- a/console/usage.rst +++ b/console/usage.rst @@ -17,13 +17,13 @@ clear and warm the ``prod`` cache you need to run: .. code-block:: bash - $ php app/console cache:clear --env=prod + $ php bin/console cache:clear --env=prod or the equivalent: .. code-block:: bash - $ php app/console cache:clear -e prod + $ php bin/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,35 +31,4 @@ but avoid the performance hit of collecting debug data: .. code-block:: bash - $ 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. + $ php bin/console list --no-debug diff --git a/console/verbosity.rst b/console/verbosity.rst index b6b9e1af8fe..aa3393721f6 100644 --- a/console/verbosity.rst +++ b/console/verbosity.rst @@ -1,10 +1,6 @@ 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`: @@ -39,6 +35,12 @@ level. For example:: if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { $output->writeln('User class: '.get_class($user)); } + + // alternatively you can pass the verbosity level to writeln() + $output->writeln( + 'Will only be printed in verbose mode or higher', + OutputInterface::VERBOSITY_VERBOSE + ); } } diff --git a/contributing/code/core_team.rst b/contributing/code/core_team.rst index 78b2344e3d5..a865df7d889 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 PropertyInfo_, - Serializer_ component; + * **Kévin Dunglas** (`dunglas`_) can merge into the Serializer_ + component; * **Abdellatif AitBoudad** (`aitboudad`_) can merge into the Translation_ component; diff --git a/contributing/code/patches.rst b/contributing/code/patches.rst index 90781ed5193..dcd705256fc 100644 --- a/contributing/code/patches.rst +++ b/contributing/code/patches.rst @@ -14,13 +14,13 @@ Before working on Symfony, setup a friendly environment with the following software: * Git; -* PHP version 5.3.9 or above. +* PHP version 5.5.9 or above. .. caution:: - 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. + 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. Configure Git ~~~~~~~~~~~~~ diff --git a/controller.rst b/controller.rst index 05fb8f28e53..2e70d5be558 100644 --- a/controller.rst +++ b/controller.rst @@ -180,10 +180,6 @@ and ``redirect()`` methods:: return $this->redirect('http://symfony.com/doc'); } -.. versionadded:: 2.6 - The ``redirectToRoute()`` method was introduced in Symfony 2.6. Previously (and still now), you - could use ``redirect()`` and ``generateUrl()`` together for this. - For more information, see the :doc:`Routing chapter `. .. tip:: @@ -254,10 +250,7 @@ console command: .. code-block:: bash - $ php app/console debug:container - -.. versionadded:: 2.6 - Prior to Symfony 2.6, this command was called ``container:debug``. + $ php bin/console debug:container For more information, see the :doc:`/service_container` chapter. @@ -270,10 +263,6 @@ For more information, see the :doc:`/service_container` chapter. $from = $this->getParameter('app.mailer.from'); - .. versionadded:: 2.7 - The ``Controller::getParameter()`` method was introduced in Symfony - 2.7. Use ``$this->container->getParameter()`` in versions prior to 2.7. - .. index:: single: Controller; Managing errors single: Controller; 404 pages diff --git a/controller/csrf_token_validation.rst b/controller/csrf_token_validation.rst index 5bf60980925..8775362a63d 100644 --- a/controller/csrf_token_validation.rst +++ b/controller/csrf_token_validation.rst @@ -15,14 +15,3 @@ method to check the validity of a CSRF token:: // ... do something, like deleting an object } } - -.. 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')); diff --git a/controller/error_pages.rst b/controller/error_pages.rst index 58511b5e998..601f87d4550 100644 --- a/controller/error_pages.rst +++ b/controller/error_pages.rst @@ -99,8 +99,7 @@ To override the 404 error template for HTML pages, create a new {% block body %}

Page not found

- {# example security usage, see below #} - {% if app.user and is_granted('IS_AUTHENTICATED_FULLY') %} + {% if is_granted('IS_AUTHENTICATED_FULLY') %} {# ... #} {% endif %} @@ -128,24 +127,6 @@ 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 @@ -158,10 +139,6 @@ 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/controller/service.rst b/controller/service.rst index dfffc7ddd54..546fb8f7001 100644 --- a/controller/service.rst +++ b/controller/service.rst @@ -137,9 +137,6 @@ 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/controller/upload_file.rst b/controller/upload_file.rst index 0d2686c7ae5..12adc139169 100644 --- a/controller/upload_file.rst +++ b/controller/upload_file.rst @@ -57,6 +57,7 @@ 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 { @@ -64,7 +65,7 @@ Then, add a new ``brochure`` field to the form that manages the ``Product`` enti { $builder // ... - ->add('brochure', 'file', array('label' => 'Brochure (PDF file)')) + ->add('brochure', FileType::class, array('label' => 'Brochure (PDF file)')) // ... ; } @@ -75,11 +76,6 @@ 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`` @@ -127,7 +123,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(new ProductType(), $product); + $form = $this->createForm(ProductType::class, $product); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { diff --git a/create_framework/dependency_injection.rst b/create_framework/dependency_injection.rst index f5ff56c1b38..36fa99ffd84 100644 --- a/create_framework/dependency_injection.rst +++ b/create_framework/dependency_injection.rst @@ -100,10 +100,11 @@ 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'))) + ->setArguments(array(new Reference('matcher'), new Reference('request_stack'))) ; $sc->register('listener.response', 'Symfony\Component\HttpKernel\EventListener\ResponseListener') ->setArguments(array('UTF-8')) @@ -214,7 +215,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 scope support to dumping a container to a plain PHP class, +definitions, from shared service 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 f8cc458d10f..a1919f9fb66 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": "^2.7" + "symfony/http-foundation": "^3.0" } } diff --git a/create_framework/http_kernel_httpkernel_class.rst b/create_framework/http_kernel_httpkernel_class.rst index d6b3b6db543..5cfee4fb6d7 100644 --- a/create_framework/http_kernel_httpkernel_class.rst +++ b/create_framework/http_kernel_httpkernel_class.rst @@ -41,6 +41,7 @@ And the new front controller:: use Symfony\Component\Routing; use Symfony\Component\HttpKernel; use Symfony\Component\EventDispatcher\EventDispatcher; + use Symfony\Component\HttpFoundation\RequestStack; $request = Request::createFromGlobals(); $routes = include __DIR__.'/../src/app.php'; @@ -50,7 +51,7 @@ And the new front controller:: $resolver = new HttpKernel\Controller\ControllerResolver(); $dispatcher = new EventDispatcher(); - $dispatcher->addSubscriber(new HttpKernel\EventListener\RouterListener($matcher)); + $dispatcher->addSubscriber(new HttpKernel\EventListener\RouterListener($matcher, new RequestStack())); $framework = new Simplex\Framework($dispatcher, $resolver); diff --git a/create_framework/introduction.rst b/create_framework/introduction.rst index d747f32e214..8bd718e711e 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.3.9 or later is good enough), a web server +you need a recent version of PHP (5.5.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); -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``): +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/debug/debugging.rst b/debug/debugging.rst index dacf9eab285..ed8cbd917e9 100644 --- a/debug/debugging.rst +++ b/debug/debugging.rst @@ -19,31 +19,32 @@ 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 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. +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. The ``app_dev.php`` front controller reads as follows by default:: // ... - $loader = require_once __DIR__.'/../app/bootstrap.php.cache'; - require_once __DIR__.'/../app/AppKernel.php'; + $loader = require __DIR__.'/../app/autoload.php'; + Debug::enable(); $kernel = new AppKernel('dev', true); $kernel->loadClassCache(); $request = Request::createFromGlobals(); + // ... -To make your debugger happier, disable all PHP class caches by removing the -call to ``loadClassCache()`` and by replacing the require statements like -below:: +To make your debugger happier, disable the loading of all PHP class caches +by removing the call to ``loadClassCache()``:: // ... - // $loader = require_once __DIR__.'/../app/bootstrap.php.cache'; $loader = require_once __DIR__.'/../app/autoload.php'; - require_once __DIR__.'/../app/AppKernel.php'; + Debug::enable(); $kernel = new AppKernel('dev', true); // $kernel->loadClassCache(); @@ -55,7 +56,5 @@ below:: session. Some IDEs do not like the fact that some classes are stored in different -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'); +locations. To avoid problems, you can tell your IDE to ignore the PHP cache +file. diff --git a/deployment.rst b/deployment.rst index 079c1c9160f..2d284eaca4b 100644 --- a/deployment.rst +++ b/deployment.rst @@ -157,7 +157,7 @@ Make sure you clear (and warm-up) your Symfony cache: .. code-block:: bash - $ php app/console cache:clear --env=prod --no-debug + $ php bin/console cache:clear --env=prod --no-debug E) Dump your Assetic Assets ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -166,7 +166,7 @@ If you're using Assetic, you'll also want to dump your assets: .. code-block:: bash - $ php app/console assetic:dump --env=prod --no-debug + $ php bin/console assetic:dump --env=prod --no-debug F) Other Things! ~~~~~~~~~~~~~~~~ diff --git a/deployment/azure-website.rst b/deployment/azure-website.rst index 43c2e302f69..70a0880c627 100644 --- a/deployment/azure-website.rst +++ b/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.3.9 to run, it's always recommended -to use the most recent PHP version whenever possible. PHP 5.3 is no longer +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 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 - /app/bootstrap.php.cache - /app/cache/* + /var/bootstrap.php.cache + /var/cache/* /app/config/parameters.yml - /app/logs/* - !app/cache/.gitkeep - !app/logs/.gitkeep - /app/SymfonyRequirements.php + /var/logs/* + !var/cache/.gitkeep + !var/logs/.gitkeep + /var/SymfonyRequirements.php /build/ /vendor/ /bin/ @@ -388,7 +388,7 @@ MySQL database. .. code-block:: bash - $ php app/console doctrine:schema:update --force + $ php bin/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/deployment/heroku.rst b/deployment/heroku.rst index 8386d49e4ec..3ac0cb31a71 100644 --- a/deployment/heroku.rst +++ b/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": [ - "app/console assetic:dump" + "bin/console assetic:dump" ] } } diff --git a/deployment/platformsh.rst b/deployment/platformsh.rst index 4848e38f3fe..0b1b79a42df 100644 --- a/deployment/platformsh.rst +++ b/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: - '/app/cache': 'shared:files/cache' - '/app/logs': 'shared:files/logs' + '/var/cache': 'shared:files/cache' + '/var/logs': 'shared:files/logs' # The hooks that will be performed when the package is deployed. hooks: build: | rm web/app_dev.php - app/console --env=prod assetic:dump --no-debug + bin/console --env=prod assetic:dump --no-debug deploy: | - app/console --env=prod cache:clear + bin/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/doctrine.rst b/doctrine.rst index fbd87c757d2..72dc5a60fb9 100644 --- a/doctrine.rst +++ b/doctrine.rst @@ -116,7 +116,7 @@ can automatically generate an empty ``test_project`` database for you: .. code-block:: bash - $ php app/console doctrine:database:create + $ php bin/console doctrine:database:create .. sidebar:: Setting up the Database to be UTF8 @@ -128,12 +128,8 @@ can automatically generate an empty ``test_project`` database for you: .. code-block:: bash - $ 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. + $ php bin/console doctrine:database:drop --force + $ php bin/console doctrine:database:create Setting UTF8 defaults for MySQL is as simple as adding a few lines to your configuration file (typically ``my.cnf``): @@ -145,6 +141,55 @@ 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`_. @@ -227,7 +272,7 @@ just a simple PHP class. .. code-block:: bash - $ php app/console doctrine:generate:entity + $ php bin/console doctrine:generate:entity .. index:: single: Doctrine; Adding mapping metadata @@ -396,7 +441,7 @@ the following command can generate these boilerplate methods automatically: .. code-block:: bash - $ php app/console doctrine:generate:entities AppBundle/Entity/Product + $ php bin/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 @@ -437,10 +482,10 @@ mapping information) of a bundle or an entire namespace: .. code-block:: bash # generates all entities in the AppBundle - $ php app/console doctrine:generate:entities AppBundle + $ php bin/console doctrine:generate:entities AppBundle # generates all entities of bundles in the Acme namespace - $ php app/console doctrine:generate:entities Acme + $ php bin/console doctrine:generate:entities Acme .. _doctrine-creating-the-database-tables-schema: @@ -455,7 +500,7 @@ in your application. To do this, run: .. code-block:: bash - $ php app/console doctrine:schema:update --force + $ php bin/console doctrine:schema:update --force .. tip:: diff --git a/doctrine/associations.rst b/doctrine/associations.rst index 51d7a245285..c49b5e8f2f2 100644 --- a/doctrine/associations.rst +++ b/doctrine/associations.rst @@ -14,7 +14,7 @@ the class for you. .. code-block:: bash - $ php app/console doctrine:generate:entity --no-interaction \ + $ php bin/console doctrine:generate:entity --no-interaction \ --entity="AppBundle:Category" \ --fields="name:string(255)" @@ -193,7 +193,7 @@ classes, tell Doctrine to generate the missing getter and setter methods for you .. code-block:: bash - $ php app/console doctrine:generate:entities AppBundle + $ php bin/console doctrine:generate:entities AppBundle Ignore the Doctrine metadata for a moment. You now have two classes - ``Product`` and ``Category``, with a natural many-to-one relationship. The ``Product`` @@ -224,7 +224,7 @@ table, the new ``product.category_id`` column, and the new foreign key: .. code-block:: bash - $ php app/console doctrine:schema:update --force + $ php bin/console doctrine:schema:update --force Saving Related Entities ----------------------- diff --git a/doctrine/console.rst b/doctrine/console.rst index 09eade986e3..317d895a2dd 100644 --- a/doctrine/console.rst +++ b/doctrine/console.rst @@ -11,7 +11,7 @@ command: .. code-block:: bash - $ php app/console list doctrine + $ php bin/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 app/console help doctrine:database:create + $ php bin/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 app/console doctrine:ensure-production-settings --env=prod + $ php bin/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/doctrine/mapping_model_classes.rst b/doctrine/mapping_model_classes.rst index acace8725f2..da5943dc915 100644 --- a/doctrine/mapping_model_classes.rst +++ b/doctrine/mapping_model_classes.rst @@ -16,19 +16,6 @@ register the mappings for your model classes. for one of the ODMs. For reusable bundles, rather than duplicate model classes just to get the auto-mapping, use the compiler pass. -.. versionadded:: 2.3 - The base mapping compiler pass was 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 be adapted for your case:: diff --git a/doctrine/multiple_entity_managers.rst b/doctrine/multiple_entity_managers.rst index e6d0ec53472..b3bd384399a 100644 --- a/doctrine/multiple_entity_managers.rst +++ b/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 app/console doctrine:database:create + $ php bin/console doctrine:database:create # Play only with "customer" connection - $ php app/console doctrine:database:create --connection=customer + $ php bin/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 app/console doctrine:schema:update --force + $ php bin/console doctrine:schema:update --force # Play only with "customer" mappings - $ php app/console doctrine:schema:update --force --em=customer + $ php bin/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/doctrine/pdo_session_storage.rst b/doctrine/pdo_session_storage.rst index fd088a4dec7..0e2c923d5d9 100644 --- a/doctrine/pdo_session_storage.rst +++ b/doctrine/pdo_session_storage.rst @@ -4,12 +4,6 @@ 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 @@ -122,10 +116,6 @@ a second array argument to ``PdoSessionHandler``: )); $container->setDefinition('session.handler.pdo', $storageDefinition); -.. versionadded:: 2.6 - The ``db_lifetime_col`` was introduced in Symfony 2.6. Prior to 2.6, - this column did not exist. - These are parameters that you must configure: ``db_table`` (default ``sessions``): @@ -193,24 +183,6 @@ 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 ~~~~~ diff --git a/doctrine/registration_form.rst b/doctrine/registration_form.rst index a8483bc31a4..628c1df426a 100644 --- a/doctrine/registration_form.rst +++ b/doctrine/registration_form.rst @@ -168,16 +168,20 @@ 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', 'email') - ->add('username', 'text') - ->add('plainPassword', 'repeated', array( - 'type' => 'password', + ->add('email', EmailType::class) + ->add('username', TextType::class) + ->add('plainPassword', RepeatedType::class, array( + 'type' => PasswordType::class, 'first_options' => array('label' => 'Password'), 'second_options' => array('label' => 'Repeat Password'), ) @@ -190,11 +194,6 @@ 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`` @@ -230,7 +229,7 @@ into the database:: { // 1) build the form $user = new User(); - $form = $this->createForm(new UserType(), $user); + $form = $this->createForm(UserType::class, $user); // 2) handle the submit (will only happen on POST) $form->handleRequest($request); @@ -379,7 +378,7 @@ your database schema using this command: .. code-block:: bash - $ php app/console doctrine:schema:update --force + $ php bin/console doctrine:schema:update --force That's it! Head to ``/register`` to try things out! @@ -425,15 +424,17 @@ 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', 'email'); + ->add('email', EmailType::class); // ... - ->add('termsAccepted', 'checkbox', array( + ->add('termsAccepted', CheckboxType::class, array( 'mapped' => false, 'constraints' => new IsTrue(), )) diff --git a/doctrine/repository.rst b/doctrine/repository.rst index 32e0bcf94bf..be1f9bd2512 100644 --- a/doctrine/repository.rst +++ b/doctrine/repository.rst @@ -59,7 +59,7 @@ and setter methods: .. code-block:: bash - $ php app/console doctrine:generate:entities AppBundle + $ php bin/console doctrine:generate:entities AppBundle .. tip:: diff --git a/doctrine/reverse_engineering.rst b/doctrine/reverse_engineering.rst index 9cf9eb51d85..ba64d4fdb29 100644 --- a/doctrine/reverse_engineering.rst +++ b/doctrine/reverse_engineering.rst @@ -59,7 +59,7 @@ table fields. .. code-block:: bash - $ php app/console doctrine:mapping:import --force AcmeBlogBundle xml + $ php bin/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 app/console doctrine:mapping:convert annotation ./src - $ php app/console doctrine:generate:entities AcmeBlogBundle + $ php bin/console doctrine:mapping:convert annotation ./src + $ php bin/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/email.rst b/email.rst index b3191e77ea9..831f0006bbe 100644 --- a/email.rst +++ b/email.rst @@ -143,11 +143,6 @@ template might look something like this: {# 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 of `Creating Messages`_ in great detail in its documentation. diff --git a/email/spool.rst b/email/spool.rst index 923c2b8afe0..8c3f63c6b75 100644 --- a/email/spool.rst +++ b/email/spool.rst @@ -124,19 +124,19 @@ There is a console command to send the messages in the spool: .. code-block:: bash - $ php app/console swiftmailer:spool:send --env=prod + $ php bin/console swiftmailer:spool:send --env=prod It has an option to limit the number of messages to be sent: .. code-block:: bash - $ php app/console swiftmailer:spool:send --message-limit=10 --env=prod + $ php bin/console swiftmailer:spool:send --message-limit=10 --env=prod You can also set the time limit in seconds: .. code-block:: bash - $ php app/console swiftmailer:spool:send --time-limit=10 --env=prod + $ php bin/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/email/testing.rst b/email/testing.rst index 45b45350d77..b7402f7dc01 100644 --- a/email/testing.rst +++ b/email/testing.rst @@ -33,7 +33,9 @@ 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:: - // src/AppBundle/Tests/Controller/MailControllerTest.php + // tests/AppBundle/Controller/MailControllerTest.php + namespace Tests\AppBundle\Controller; + use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class MailControllerTest extends WebTestCase diff --git a/event_dispatcher.rst b/event_dispatcher.rst index 853c4ff946d..69e530a0585 100644 --- a/event_dispatcher.rst +++ b/event_dispatcher.rst @@ -265,22 +265,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 app/console debug:event-dispatcher + $ php bin/console debug:event-dispatcher You can get registered listeners for a particular event by specifying its name: .. code-block:: bash - $ php app/console debug:event-dispatcher kernel.exception + $ php bin/console debug:event-dispatcher kernel.exception Learn more ---------- diff --git a/event_dispatcher/before_after_filters.rst b/event_dispatcher/before_after_filters.rst index eb171b4e9ca..29d284d131a 100644 --- a/event_dispatcher/before_after_filters.rst +++ b/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. -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 `. +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 `. Token Validation Example ------------------------ diff --git a/expressions.rst b/expressions.rst index 2b70e21dfe1..a8c90e40850 100644 --- a/expressions.rst +++ b/expressions.rst @@ -4,9 +4,9 @@ How to use Expressions in Security, Routing, Services, and Validation ===================================================================== -In Symfony 2.4, a powerful :doc:`ExpressionLanguage ` -component was added to Symfony. This allows us to add highly customized -logic inside configuration. +Symfony comes with a powerful +:doc:`ExpressionLanguage ` +component. It allows you to add highly customized logic inside configuration. The Symfony Framework leverages expressions out of the box in the following ways: diff --git a/form/action_method.rst b/form/action_method.rst index 27fdddfb1ac..64098cfc647 100644 --- a/form/action_method.rst +++ b/form/action_method.rst @@ -14,9 +14,9 @@ form, you can use ``setAction()`` and ``setMethod()``:: $form = $this->createFormBuilder($task) ->setAction($this->generateUrl('target_route')) ->setMethod('GET') - ->add('task', 'text') - ->add('dueDate', 'date') - ->add('save', 'submit') + ->add('task', TextType::class) + ->add('dueDate', DateType::class) + ->add('save', SubmitType::class) ->getForm(); .. note:: @@ -30,7 +30,7 @@ options:: use AppBundle\Form\TaskType; // ... - $form = $this->createForm(new TaskType(), $task, array( + $form = $this->createForm(TaskType::class, $task, array( 'action' => $this->generateUrl('target_route'), 'method' => 'GET', )); @@ -49,7 +49,9 @@ to the ``form()`` or the ``form_start()`` helper functions: start($form, array( - 'action' => $view['router']->generate('target_route'), + // The path() method was introduced in Symfony 2.8. Prior to 2.8, + // you had to use generate(). + 'action' => $view['router']->path('target_route'), 'method' => 'GET', )) ?> diff --git a/form/button_based_validation.rst b/form/button_based_validation.rst index 0afbc535451..4a28aaad405 100644 --- a/form/button_based_validation.rst +++ b/form/button_based_validation.rst @@ -4,9 +4,6 @@ How to Choose Validation Groups Based on the Clicked Button =========================================================== -.. versionadded:: 2.3 - Support for buttons in forms was introduced in Symfony 2.3. - When your form contains multiple submit buttons, you can change the validation group depending on which button is used to submit the form. For example, consider a form in a wizard that lets you advance to the next step or go back @@ -17,8 +14,8 @@ First, we need to add the two buttons to the form:: $form = $this->createFormBuilder($task) // ... - ->add('nextStep', 'submit') - ->add('previousStep', 'submit') + ->add('nextStep', SubmitType::class) + ->add('previousStep', SubmitType::class) ->getForm(); Then, we configure the button for returning to the previous step to run @@ -27,7 +24,7 @@ so we set its ``validation_groups`` option to false:: $form = $this->createFormBuilder($task) // ... - ->add('previousStep', 'submit', array( + ->add('previousStep', SubmitType::class, array( 'validation_groups' => false, )) ->getForm(); diff --git a/form/create_custom_field_type.rst b/form/create_custom_field_type.rst index c1cd9c6c30e..762845610e9 100644 --- a/form/create_custom_field_type.rst +++ b/form/create_custom_field_type.rst @@ -25,6 +25,7 @@ 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 { @@ -40,12 +41,7 @@ for form fields, which is ``\Form\Type``. Make sure the field extend public function getParent() { - return 'choice'; - } - - public function getName() - { - return 'app_gender'; + return ChoiceType::class; } } @@ -55,7 +51,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 ``choice`` field type. This means that, by default, you inherit +extending the ``ChoiceType`` field. 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: @@ -72,10 +68,6 @@ 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 @@ -89,10 +81,6 @@ 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. @@ -100,13 +88,27 @@ genders. Creating a Template for the Field --------------------------------- -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:`form-customization-form-themes`. +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 :ref:`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 ``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" +.. caution:: + + When the name of your form class matches any of the built-in field types, + your form might not be rendered correctly. A form type named + ``AppBundle\Form\PasswordType`` will have the same block name as the + built-in ``PasswordType`` and won't be rendered correctly. Override the + ``getBlockPrefix()`` method to return a unique block prefix (e.g. + ``app_password``) to avoid collisions. + +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" (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: @@ -154,7 +156,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``, according to the value returned by ``getName``. + be ``gender_widget`` (see :ref:`form-customization-form-themes`). Further, the main config file should point to the custom form template so that it's used when rendering all forms. @@ -241,25 +243,22 @@ 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', new GenderType(), array( + $builder->add('gender_code', GenderType::class, 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-field-service: Creating your Field Type as a Service @@ -311,14 +310,14 @@ the ``genders`` parameter value as the first argument to its to-be-created arguments: - '%genders%' tags: - - { name: form.type, alias: app_gender } + - { name: form.type } .. code-block:: xml %genders% - + .. code-block:: php @@ -331,9 +330,7 @@ the ``genders`` parameter value as the first argument to its to-be-created 'AppBundle\Form\Type\GenderType', array('%genders%') )) - ->addTag('form.type', array( - 'alias' => 'app_gender', - )) + ->addTag('form.type') ; .. tip:: @@ -341,10 +338,8 @@ 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. -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:: +First, add a ``__construct`` method to ``GenderType``, which receives the gender +configuration:: // src/AppBundle/Form/Type/GenderType.php namespace AppBundle\Form\Type; @@ -374,28 +369,28 @@ method to ``GenderType``, which receives the gender configuration:: } Great! The ``GenderType`` is now fueled by the configuration parameters and -registered as a service. Additionally, because you used the ``form.type`` alias in its -configuration, using the field is now much easier:: +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:: // 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', 'gender', array( + $builder->add('gender_code', GenderType::class, array( 'placeholder' => 'Choose a gender', )); } } -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! +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/form/create_form_type_extension.rst b/form/create_form_type_extension.rst index f57d3347020..e0bcb69a7fd 100644 --- a/form/create_form_type_extension.rst +++ b/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 "file" field type); + as adding a "download" feature to the ``FileType`` 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,6 +51,7 @@ 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 { @@ -61,7 +62,7 @@ class. In most cases, it's easier to extend the abstract class:: */ public function getExtendedType() { - return 'file'; + return FileType::class; } } @@ -72,8 +73,8 @@ by your extension. .. tip:: The value you return in the ``getExtendedType`` method corresponds - to the value returned by the ``getName`` method in the form type class - you wish to extend. + to the fully qualified class name of 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: @@ -104,14 +105,14 @@ tag: app.image_type_extension: class: AppBundle\Form\Extension\ImageTypeExtension tags: - - { name: form.type_extension, alias: file } + - { name: form.type_extension, extended_type: Symfony\Component\Form\Extension\Core\Type\FileType } .. code-block:: xml - + .. code-block:: php @@ -121,11 +122,11 @@ tag: 'app.image_type_extension', 'AppBundle\Form\Extension\ImageTypeExtension' ) - ->addTag('form.type_extension', array('alias' => 'file')); + ->addTag('form.type_extension', array('extended_type' => 'Symfony\Component\Form\Extension\Core\Type\FileType')); -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. +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``. Adding the extension Business Logic ----------------------------------- @@ -167,14 +168,14 @@ the database:: } Your form type extension class will need to do two things in order to extend -the ``file`` form type: +the ``FileType::class`` form type: #. Override the ``configureOptions`` method in order to add an ``image_path`` option; #. Override the ``buildView`` methods in order to pass the image URL to the view. -The logic is the following: when adding a form field of type ``file``, +The logic is the following: when adding a form field of type ``FileType::class``, 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:: @@ -187,6 +188,7 @@ 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 { @@ -197,7 +199,7 @@ it in the view:: */ public function getExtendedType() { - return 'file'; + return FileType::class; } /** @@ -282,7 +284,7 @@ Specifically, you need to override the ``file_widget`` block: Using the Form Type Extension ----------------------------- -From now on, when adding a field of type ``file`` in your form, you can +From now on, when adding a field of type ``FileType::class`` 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:: @@ -291,19 +293,16 @@ 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', 'text') - ->add('file', 'file', array('image_path' => 'webPath')); - } - - public function getName() - { - return 'app_media'; + ->add('name', TextType::class) + ->add('file', FileType::class, array('image_path' => 'webPath')); } } @@ -315,13 +314,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 ``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. +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. In the same way, since **most** form types natively available in Symfony inherit -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. +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. diff --git a/form/data_transformers.rst b/form/data_transformers.rst index 381e21bdfa0..28e1a9c2b5c 100644 --- a/form/data_transformers.rst +++ b/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:`date field type ` +many field types. For example, the :doc:`DateType ` field 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. @@ -28,13 +28,14 @@ Suppose you have a Task form with a tags ``text`` type:: use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; + use Symfony\Component\Form\Extension\Core\Type\TextType; // ... class TaskType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->add('tags', 'text') + $builder->add('tags', TextType::class) } public function configureOptions(OptionsResolver $resolver) @@ -59,13 +60,14 @@ class:: use Symfony\Component\Form\CallbackTransformer; use Symfony\Component\Form\FormBuilderInterface; + use Symfony\Component\Form\Extension\Core\Type\TextType; // ... class TaskType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->add('tags', 'text'); + $builder->add('tags', TextType::class); $builder->get('tags') ->addModelTransformer(new CallbackTransformer( @@ -98,9 +100,11 @@ the format you'll use 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\TextType; + $builder->add( $builder - ->create('tags', 'text') + ->create('tags', TextType::class) ->addModelTransformer(...) ); @@ -118,14 +122,17 @@ 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', 'textarea') - ->add('issue', 'text') + ->add('description', TextareaType::class) + ->add('issue', TextType::class) ; } @@ -242,13 +249,15 @@ 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. Then, you can easily create and add the transformer:: +to be passed in by registering ``TaskType`` as a service:: // 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 @@ -263,8 +272,8 @@ to be passed in. Then, you can easily create and add the transformer:: public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('description', 'textarea') - ->add('issue', 'text', array( + ->add('description', TextareaType::class) + ->add('issue', TextType::class, array( // validation message if the data transformer fails 'invalid_message' => 'That is not a valid issue number', )); @@ -278,18 +287,62 @@ to be passed in. Then, you can easily create and add the transformer:: // ... } -Now, when you create your ``TaskType``, you'll need to pass in the entity manager:: +Define the form type as a service in your configuration files. - // e.g. in a controller somewhere - $manager = $this->getDoctrine()->getManager(); - $form = $this->createForm(new TaskType($manager), $task); +.. configuration-block:: - // ... + .. code-block:: yaml -.. note:: + # 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 + :doc:`register your form type as a service `. - To make this step easier (especially if ``TaskType`` is embedded into other - form type classes), you might choose to :doc:`register your form type as a service `. +Now, you can easily use your ``TaskType``:: + + // e.g. in a controller somewhere + $form = $this->createForm(TaskType::class, $task); + + // ... 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 @@ -307,7 +360,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', 'text') + $builder->add('issue', TextType::class) ->addModelTransformer($transformer); .. _using-transformers-in-a-custom-field-type: @@ -355,12 +408,7 @@ First, create the custom field type class:: public function getParent() { - return 'text'; - } - - public function getName() - { - return 'issue_selector'; + return TextType::class; } } @@ -380,7 +428,7 @@ it's recognized as a custom field type: class: AppBundle\Form\IssueSelectorType arguments: ['@doctrine.orm.entity_manager'] tags: - - { name: form.type, alias: issue_selector } + - { name: form.type } .. code-block:: xml @@ -396,7 +444,7 @@ it's recognized as a custom field type: - + @@ -416,9 +464,7 @@ it's recognized as a custom field type: new Reference('doctrine.orm.entity_manager'), ) ) - ->addTag('form.type', array( - 'alias' => 'issue_selector', - )) + ->addTag('form.type') ; Now, whenever you need to use your special ``issue_selector`` field type, @@ -428,6 +474,7 @@ 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 @@ -435,8 +482,8 @@ it's quite easy:: public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('description', 'textarea') - ->add('issue', 'issue_selector') + ->add('description', TextareaType::class) + ->add('issue', IssueSelectorType::class) ; } diff --git a/form/direct_submit.rst b/form/direct_submit.rst index b5ba66f631a..1108047ce8d 100644 --- a/form/direct_submit.rst +++ b/form/direct_submit.rst @@ -4,10 +4,6 @@ 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:: @@ -42,9 +38,6 @@ 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` @@ -90,44 +83,3 @@ 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``. - -.. _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/form/disabling_validation.rst b/form/disabling_validation.rst index 06acfdbac6e..55c18a51dc2 100644 --- a/form/disabling_validation.rst +++ b/form/disabling_validation.rst @@ -4,9 +4,6 @@ How to Disable the Validation of Submitted Data =============================================== -.. 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``:: diff --git a/form/dynamic_form_modification.rst b/form/dynamic_form_modification.rst index cacacc993e2..3ee725dee1d 100644 --- a/form/dynamic_form_modification.rst +++ b/form/dynamic_form_modification.rst @@ -56,11 +56,6 @@ a bare form class looks like:: 'data_class' => 'AppBundle\Entity\Product' )); } - - public function getName() - { - return 'product'; - } } .. note:: @@ -125,7 +120,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', 'text'); + $form->add('name', TextType::class); } }); } @@ -173,6 +168,7 @@ 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 { @@ -189,7 +185,7 @@ class:: $form = $event->getForm(); if (!$product || null === $product->getId()) { - $form->add('name', 'text'); + $form->add('name', TextType::class); } } } @@ -219,24 +215,21 @@ 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', 'text') - ->add('body', 'textarea') + ->add('subject', TextType::class) + ->add('body', TextareaType::class) ; $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 @@ -272,6 +265,10 @@ 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 @@ -286,8 +283,8 @@ and fill in the listener logic:: public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('subject', 'text') - ->add('body', 'textarea') + ->add('subject', TextType::class) + ->add('body', TextareaType::class) ; // grab the user, do a quick sanity check that one exists @@ -318,7 +315,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', 'entity', $formOptions); + $form->add('friend', EntityType::class, $formOptions); } ); } @@ -326,52 +323,16 @@ 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 ``entity``. + because the type of the friend field is ``EntityType::class``. Using the Form ~~~~~~~~~~~~~~ -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`. +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 `: .. configuration-block:: @@ -383,7 +344,7 @@ it with :ref:`dic-tags-form-type`. class: AppBundle\Form\Type\FriendMessageFormType arguments: ['@security.token_storage'] tags: - - { name: form.type, alias: app_friend_message } + - { name: form.type } .. code-block:: xml @@ -391,7 +352,7 @@ it with :ref:`dic-tags-form-type`. - + @@ -404,15 +365,10 @@ it with :ref:`dic-tags-form-type`. 'AppBundle\Form\Type\FriendMessageFormType', array(new Reference('security.token_storage')) ); - $definition->addTag('form.type', array('alias' => 'app_friend_message')); + $definition->addTag('form.type'); $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:: @@ -422,7 +378,7 @@ class, you can simply call:: { public function newAction(Request $request) { - $form = $this->createForm('app_friend_message'); + $form = $this->createForm(FriendMessageFormType::class); // ... } @@ -433,7 +389,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', 'app_friend_message'); + $builder->add('message', FriendMessageFormType::class); } .. _form-events-submitted-data: @@ -459,6 +415,7 @@ 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 @@ -466,7 +423,7 @@ sport like this:: public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('sport', 'entity', array( + ->add('sport', EntityType::class, array( 'class' => 'AppBundle:Sport', 'placeholder' => '', )) @@ -483,7 +440,7 @@ sport like this:: $sport = $data->getSport(); $positions = null === $sport ? array() : $sport->getAvailablePositions(); - $form->add('position', 'entity', array( + $form->add('position', EntityType::class, array( 'class' => 'AppBundle:Position', 'placeholder' => '', 'choices' => $positions, @@ -495,10 +452,6 @@ 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. @@ -514,10 +467,6 @@ 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 @@ -530,6 +479,7 @@ 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 @@ -537,7 +487,7 @@ The type would now look like:: public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('sport', 'entity', array( + ->add('sport', EntityType::class, array( 'class' => 'AppBundle:Sport', 'placeholder' => '', )); @@ -546,7 +496,7 @@ The type would now look like:: $formModifier = function (FormInterface $form, Sport $sport = null) { $positions = null === $sport ? array() : $sport->getAvailablePositions(); - $form->add('position', 'entity', array( + $form->add('position', EntityType::class, array( 'class' => 'AppBundle:Position', 'placeholder' => '', 'choices' => $positions, @@ -603,7 +553,7 @@ your application. Assume that you have a sport meetup creation controller:: public function createAction(Request $request) { $meetup = new SportMeetup(); - $form = $this->createForm(new SportMeetupType(), $meetup); + $form = $this->createForm(SportMeetupType::class, $meetup); $form->handleRequest($request); if ($form->isValid()) { // ... save the meetup, redirect etc. diff --git a/form/embedded.rst b/form/embedded.rst index 10b628d7a1b..4cdd7cc0ca8 100644 --- a/form/embedded.rst +++ b/form/embedded.rst @@ -86,11 +86,6 @@ 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 @@ -105,7 +100,7 @@ class:: { // ... - $builder->add('category', new CategoryType()); + $builder->add('category', CategoryType::class); } The fields from ``CategoryType`` can now be rendered alongside those from @@ -152,4 +147,4 @@ form with many ``Product`` sub-forms). This is done by using the ``collection`` field type. For more information see the :doc:`/form/form_collections` article and the -:doc:`collection ` field type reference. +:doc:`CollectionType ` reference. diff --git a/form/events.rst b/form/events.rst index c736ac9b336..566e65463db 100644 --- a/form/events.rst +++ b/form/events.rst @@ -257,19 +257,6 @@ 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 ~~~~~~~~~~~~~~~ @@ -281,10 +268,13 @@ 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', 'text') - ->add('show_email', 'checkbox') + ->add('username', TextType::class) + ->add('show_email', CheckboxType::class) ->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) { $user = $event->getData(); $form = $event->getForm(); @@ -297,7 +287,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', 'email'); + $form->add('email', EmailType::class); } else { unset($user['email']); $event->setData($user); @@ -313,14 +303,18 @@ callback for better readability:: // src/AppBundle/Form/SubscriptionType.php namespace AppBundle\Form; + use Symfony\Component\Form\Extension\Core\Type\TextType; + use Symfony\Component\Form\Extension\Core\Type\CheckboxType; + use Symfony\Component\Form\FormEvents; + // ... class SubscriptionType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('username', 'text') - ->add('show_email', 'checkbox') + ->add('username', TextType::class) + ->add('show_email', CheckboxType::class) ->addEventListener( FormEvents::PRE_SET_DATA, array($this, 'onPreSetData') @@ -351,6 +345,7 @@ 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 { @@ -370,7 +365,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', 'email'); + $form->add('email', EmailType::class); } } @@ -387,7 +382,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', 'email'); + $form->add('email', EmailType::class); } else { unset($user['email']); $event->setData($user); @@ -397,12 +392,15 @@ Event subscribers have different uses: To register the event subscriber, use the ``addEventSubscriber()`` method:: - use AppBundle\Form\EventListener\AddEmailFieldListener; + use Symfony\Component\Form\Extension\Core\Type\TextType; + use Symfony\Component\Form\Extension\Core\Type\CheckboxType; + use AppBundle\Form\EventListener\AddEmailFieldListener; + // ... $form = $formFactory->createBuilder() - ->add('username', 'text') - ->add('show_email', 'checkbox') + ->add('username', TextType::class) + ->add('show_email', CheckboxType::class) ->addEventSubscriber(new AddEmailFieldListener()) ->getForm(); diff --git a/form/form_collections.rst b/form/form_collections.rst index 5f300241e1e..8ba09456094 100644 --- a/form/form_collections.rst +++ b/form/form_collections.rst @@ -104,11 +104,6 @@ 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 @@ -116,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:`collection ` field type:: +:doc:`CollectionType ` field:: // src/AppBundle/Form/Type/TaskType.php namespace AppBundle\Form\Type; @@ -124,6 +119,7 @@ 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 { @@ -131,7 +127,9 @@ Notice that you embed a collection of ``TagType`` forms using the { $builder->add('description'); - $builder->add('tags', 'collection', array('type' => new TagType())); + $builder->add('tags', CollectionType::class, array( + 'entry_type' => TagType::class + )); } public function configureOptions(OptionsResolver $resolver) @@ -140,14 +138,9 @@ 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 now initialize a new instance of ``TaskType``:: +In your controller, you'll create a new form from the ``TaskType``:: // src/AppBundle/Controller/TaskController.php namespace AppBundle\Controller; @@ -174,7 +167,7 @@ In your controller, you'll now initialize a new instance of ``TaskType``:: $task->getTags()->add($tag2); // end dummy code - $form = $this->createForm(new TaskType(), $task); + $form = $this->createForm(TaskType::class, $task); $form->handleRequest($request); @@ -289,8 +282,8 @@ add the ``allow_add`` option to your collection field:: { $builder->add('description'); - $builder->add('tags', 'collection', array( - 'type' => new TagType(), + $builder->add('tags', CollectionType::class, array( + 'entry_type' => TagType::class, 'allow_add' => true, )); } @@ -458,7 +451,7 @@ Next, add a ``by_reference`` option to the ``tags`` field and set it to ``false` { // ... - $builder->add('tags', 'collection', array( + $builder->add('tags', CollectionType::class, array( // ... 'by_reference' => false, )); @@ -574,7 +567,7 @@ you will learn about next!). .. _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. @@ -588,7 +581,7 @@ Start by adding the ``allow_delete`` option in the form Type:: { // ... - $builder->add('tags', 'collection', array( + $builder->add('tags', CollectionType::class, array( // ... 'allow_delete' => true, )); @@ -701,7 +694,7 @@ the relationship between the removed ``Tag`` and ``Task`` object. $originalTags->add($tag); } - $editForm = $this->createForm(new TaskType(), $task); + $editForm = $this->createForm(TaskType::class, $task); $editForm->handleRequest($request); diff --git a/form/form_customization.rst b/form/form_customization.rst index 5a206616473..5d1a2232c4d 100644 --- a/form/form_customization.rst +++ b/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 four **built-in form themes** that define each and every +Symfony comes with some **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,6 +113,9 @@ 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:: @@ -208,6 +211,9 @@ 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``, @@ -689,12 +695,13 @@ 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', 'text', array( + $builder->add('name', TextType::class, array( 'block_name' => 'custom_name', )); } @@ -1124,3 +1131,5 @@ 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/form/form_dependencies.rst b/form/form_dependencies.rst index 35b4be594a8..5e727039797 100644 --- a/form/form_dependencies.rst +++ b/form/form_dependencies.rst @@ -31,12 +31,13 @@ Now that you've done this, you *must* pass an ``entity_manager`` option when you create your form:: // src/AppBundle/Controller/DefaultController.php - // ... + use AppBundle\Form\TaskType; + // ... public function newAction() { $task = ...; - $form = $this->createForm(new TaskType(), $task, array( + $form = $this->createForm(TaskType::class, $task, array( 'entity_manager' => $this->get('doctrine.orm.entity_manager') )); @@ -101,7 +102,7 @@ Next, register this as a service and tag it with ``form.type``: app.form.type.task: class: AppBundle\Form\TaskType tags: - - { name: form.type, alias: app_task } + - { name: form.type } .. code-block:: xml @@ -113,7 +114,7 @@ Next, register this as a service and tag it with ``form.type``: - + @@ -126,37 +127,10 @@ Next, register this as a service and tag it with ``form.type``: 'app.form.type.task', 'AppBundle\Form\TaskType' ) - ->addTag('form.type', array( - 'alias' => 'app_task', - )) + ->addTag('form.type') ; -That's it! Use the ``alias`` key from the tag to reference your form:: - - // src/AppBundle/Controller/DefaultController.php - // ... - - public function newAction() - { - $task = ...; - $form = $this->createForm('app_task', $task); - - // ... - } - -Or, use the from within another form:: - - // src/AppBundle/Form/Type/ListType.php - // ... - - class ListType extends AbstractType - { - public function buildForm(FormBuilderInterface $builder, array $options) - { - // ... - - $builder->add('someTask', 'app_task'); - } - } +That's it! Your controller - where you create the form - doesn't need to change +at all: Symfony is smart enough to load the ``TaskType`` from the container. Read :ref:`form-field-service` for more information. diff --git a/form/form_themes.rst b/form/form_themes.rst index 621ddb952f6..aed32ac79fc 100644 --- a/form/form_themes.rst +++ b/form/form_themes.rst @@ -95,7 +95,7 @@ the next section. For a more extensive discussion, see :doc:`/form/form_customization`. .. index:: - single: Forms; Template fragment naming + single: Forms; Template fragment naming .. _form-template-blocks: @@ -148,7 +148,7 @@ customize (e.g. ``widget``), you can construct the fragment name that needs to be overridden (e.g. ``textarea_widget``). .. index:: - single: Forms; Template fragment inheritance + single: Forms; Template fragment inheritance Template Fragment Inheritance ----------------------------- @@ -175,7 +175,7 @@ override the default error rendering for *all* fields, copy and customize the :doc:`form type reference ` for each field type. .. index:: - single: Forms; Global Theming + single: Forms; Global Theming .. _forms-theming-global: @@ -189,7 +189,7 @@ to import form customizations across your entire project. .. _forms-theming-twig: Twig -~~~ +.... To automatically include the customized blocks from the ``fields.html.twig`` template created earlier in *all* templates, modify your application configuration @@ -269,7 +269,7 @@ to define form output. must point ``form_theme`` to a separate template. PHP -~~~ +... To automatically include the customized templates from the ``app/Resources/views/form`` directory created earlier in *all* templates, modify your application configuration diff --git a/form/inherit_data_option.rst b/form/inherit_data_option.rst index 7429baae325..4f0ff9a6839 100644 --- a/form/inherit_data_option.rst +++ b/form/inherit_data_option.rst @@ -4,10 +4,6 @@ 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``:: @@ -52,14 +48,15 @@ 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', 'text') - ->add('website', 'text'); + ->add('name', TextType::class) + ->add('website', TextType::class); } } @@ -70,14 +67,15 @@ 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', 'text') - ->add('lastName', 'text'); + ->add('firstName', TextType::class) + ->add('lastName', TextType::class); } } @@ -91,16 +89,18 @@ 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', 'textarea') - ->add('zipcode', 'text') - ->add('city', 'text') - ->add('country', 'text'); + ->add('address', TextareaType::class) + ->add('zipcode', TextType::class) + ->add('city', TextType::class) + ->add('country', TextType::class); } public function configureOptions(OptionsResolver $resolver) @@ -109,11 +109,6 @@ for that:: 'inherit_data' => true )); } - - public function getName() - { - return 'location'; - } } The location form has an interesting option set, namely ``inherit_data``. This @@ -135,7 +130,7 @@ Finally, make this work by adding the location form to your two original forms:: { // ... - $builder->add('foo', new LocationType(), array( + $builder->add('foo', LocationType::class, array( 'data_class' => 'AppBundle\Entity\Company' )); } @@ -147,7 +142,7 @@ Finally, make this work by adding the location form to your two original forms:: { // ... - $builder->add('bar', new LocationType(), array( + $builder->add('bar', LocationType::class, array( 'data_class' => 'AppBundle\Entity\Customer' )); } diff --git a/form/multiple_buttons.rst b/form/multiple_buttons.rst index 8baac65f18f..712a7a220a6 100644 --- a/form/multiple_buttons.rst +++ b/form/multiple_buttons.rst @@ -4,18 +4,15 @@ How to Submit a Form 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', 'text') - ->add('dueDate', 'date') - ->add('save', 'submit', array('label' => 'Create Task')) - ->add('saveAndAdd', 'submit', array('label' => 'Save and Add')) + ->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')) ->getForm(); In your controller, use the button's diff --git a/form/rendering.rst b/form/rendering.rst index 9dc978903dc..c0f0449ad2b 100644 --- a/form/rendering.rst +++ b/form/rendering.rst @@ -60,7 +60,7 @@ output can be customized on many different levels. vars['value']->getTask() ?> .. index:: - single: Forms; Rendering each field by hand + single: Forms; Rendering each field by hand Rendering each Field by Hand ---------------------------- diff --git a/form/type_guesser.rst b/form/type_guesser.rst index f1173660ddf..52dd1ac64a4 100644 --- a/form/type_guesser.rst +++ b/form/type_guesser.rst @@ -32,11 +32,9 @@ This interface requires four methods: Tries to guess the value of the :ref:`required ` option; :method:`Symfony\\Component\\Form\\FormTypeGuesserInterface::guessMaxLength` - Tries to guess the value of the :ref:`max_length ` - option; + Tries to guess the value of the ``maxlength`` input attribute; :method:`Symfony\\Component\\Form\\FormTypeGuesserInterface::guessPattern` - Tries to guess the value of the :ref:`pattern ` - option. + Tries to guess the value of the ``pattern`` input attribute. Start by creating the class and these methods. Next, you'll learn how to fill each on. @@ -92,6 +90,10 @@ 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 { @@ -108,25 +110,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('text', array(), Guess::HIGH_CONFIDENCE); + return new TypeGuess(TextType::class, 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('integer', array(), Guess::MEDIUM_CONFIDENCE); + return new TypeGuess(IntegerType::class, array(), Guess::MEDIUM_CONFIDENCE); case 'float': case 'double': case 'real': - return new TypeGuess('number', array(), Guess::MEDIUM_CONFIDENCE); + return new TypeGuess(NumberType::class, array(), Guess::MEDIUM_CONFIDENCE); case 'boolean': case 'bool': - return new TypeGuess('checkbox', array(), Guess::HIGH_CONFIDENCE); + return new TypeGuess(CheckboxType::class, array(), Guess::HIGH_CONFIDENCE); default: // there is a very low confidence that this one is correct - return new TypeGuess('text', array(), Guess::LOW_CONFIDENCE); + return new TypeGuess(TextType::class, array(), Guess::LOW_CONFIDENCE); } } diff --git a/form/unit_testing.rst b/form/unit_testing.rst index 3638a9f7cac..dca8f7d643c 100644 --- a/form/unit_testing.rst +++ b/form/unit_testing.rst @@ -20,11 +20,6 @@ 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 @@ -36,8 +31,8 @@ The Basics The simplest ``TypeTestCase`` implementation looks like the following:: - // src/AppBundle/Tests/Form/Type/TestedTypeTest.php - namespace AppBundle\Tests\Form\Type; + // tests/AppBundle/Form/Type/TestedTypeTest.php + namespace Tests\AppBundle\Form\Type; use AppBundle\Form\Type\TestedType; use AppBundle\Model\TestObject; @@ -52,8 +47,7 @@ The simplest ``TypeTestCase`` implementation looks like the following:: 'test2' => 'test2', ); - $type = new TestedType(); - $form = $this->factory->create($type); + $form = $this->factory->create(TestedType::class); $object = TestObject::fromArray($formData); @@ -78,8 +72,7 @@ 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:: - $type = new TestedType(); - $form = $this->factory->create($type); + $form = $this->factory->create(TestedType::class); This test checks that none of your data transformers used by the form failed. The :method:`Symfony\\Component\\Form\\FormInterface::isSynchronized` @@ -109,55 +102,57 @@ widgets you want to display are available in the children property:: $this->assertArrayHasKey($key, $children); } -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 +Testings Types from the Service Container +----------------------------------------- - // ... the buildForm method - $builder->add('app_test_child_type'); +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. -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:: +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:: - // src/AppBundle/Tests/Form/Type/TestedTypeTests.php - namespace AppBundle\Tests\Form\Type; + // tests/AppBundle/Form/Type/TestedTypeTests.php + namespace Tests\AppBundle\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() { - $childType = new TestChildType(); + // create a type instance with the mocked dependencies + $type = new TestedType($this->entityManager); - return array(new PreloadedExtension(array( - $childType->getName() => $childType, - ), array())); + return array( + // register the type instances with the PreloadedExtension + new PreloadedExtension(array($type), array()), + ); } public function testSubmitValidData() { - $type = new TestedType(); - $form = $this->factory->create($type); + // Instead of creating a new instance, the one created in + // getExtensions() will be used. + $form = $this->factory->create(TestedType::class); // ... 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 ------------------------ @@ -170,26 +165,28 @@ 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:: - // src/AppBundle/Tests/Form/Type/TestedTypeTests.php - namespace AppBundle\Tests\Form\Type; + // tests/AppBundle/Form/Type/TestedTypeTests.php + namespace Tests\AppBundle\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() { - $validator = $this->getMock('\Symfony\Component\Validator\Validator\ValidatorInterface'); - $validator->method('validate')->will($this->returnValue(new ConstraintViolationList())); + $this->validator = $this->getMock( + 'Symfony\Component\Validator\Validator\ValidatorInterface' + ); + $this->validator + ->method('validate') + ->will($this->returnValue(new ConstraintViolationList())); return array( - new ValidatorExtension($validator), + new ValidatorExtension($this->validator), ); } @@ -202,8 +199,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:: - // src/AppBundle/Tests/Form/Type/TestedTypeTests.php - namespace AppBundle\Tests\Form\Type; + // tests/AppBundle/Form/Type/TestedTypeTests.php + namespace Tests\AppBundle\Form\Type; use AppBundle\Form\Type\TestedType; use AppBundle\Model\TestObject; @@ -211,7 +208,6 @@ a good opportunity to use them:: class TestedTypeTest extends TypeTestCase { - /** * @dataProvider getValidTestData */ diff --git a/form/use_empty_data.rst b/form/use_empty_data.rst index 342341e5b7a..80d740940d2 100644 --- a/form/use_empty_data.rst +++ b/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(new BlogType(), $blog); + $form = $this->createForm(BlogType::class, $blog); // no data is passed in, so empty_data is // used to get the "starting data" - $form = $this->createForm(new BlogType()); + $form = $this->createForm(BlogType::class); } By default, ``empty_data`` is set to ``null``. Or, if you have specified @@ -61,10 +61,14 @@ that constructor with no arguments:: } } -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. +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 + :doc:`register it as a service and tag with form.type `. Option 2: Provide a Closure --------------------------- diff --git a/form/use_virtuals_forms.rst b/form/use_virtuals_forms.rst index 33b11c5eb2f..6e09d09e383 100644 --- a/form/use_virtuals_forms.rst +++ b/form/use_virtuals_forms.rst @@ -1,5 +1,8 @@ How to Use the virtual Form Field Option ======================================== -As of Symfony 2.3, the ``virtual`` option is renamed to ``inherit_data``. You -can read everything about the new option in ":doc:`/form/inherit_data_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:`/form/inherit_data_option`". diff --git a/form/validation_groups.rst b/form/validation_groups.rst index baec42abab4..62567052557 100644 --- a/form/validation_groups.rst +++ b/form/validation_groups.rst @@ -4,6 +4,9 @@ How to Define the Validation Groups to Use ========================================== +Validation Groups +----------------- + If your object takes advantage of :doc:`validation groups `, you'll need to specify which validation group(s) your form should use:: @@ -11,10 +14,6 @@ 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:: diff --git a/form/without_class.rst b/form/without_class.rst index 3f2e99b7851..b23edfab4ed 100644 --- a/form/without_class.rst +++ b/form/without_class.rst @@ -19,10 +19,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', 'text') - ->add('email', 'email') - ->add('message', 'textarea') - ->add('send', 'submit') + ->add('name', TextType::class) + ->add('email', EmailType::class) + ->add('message', TextareaType::class) + ->add('send', SubmitType::class) ->getForm(); $form->handleRequest($request); @@ -61,7 +61,7 @@ an array. it's been transformed by the Form component. Adding Validation -~~~~~~~~~~~~~~~~~ +----------------- The only missing piece is validation. Usually, when you call ``$form->isValid()``, the object is validated by reading the constraints that you applied to that @@ -83,12 +83,13 @@ 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', 'text', array( + ->add('firstName', TextType::class, array( 'constraints' => new Length(array('min' => 3)), )) - ->add('lastName', 'text', array( + ->add('lastName', TextType::class, array( 'constraints' => array( new NotBlank(), new Length(array('min' => 3)), diff --git a/forms.rst b/forms.rst index fa48db276d1..6c1ebd9e6a3 100644 --- a/forms.rst +++ b/forms.rst @@ -80,6 +80,9 @@ 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 { @@ -91,9 +94,9 @@ from inside a controller:: $task->setDueDate(new \DateTime('tomorrow')); $form = $this->createFormBuilder($task) - ->add('task', 'text') - ->add('dueDate', 'date') - ->add('save', 'submit', array('label' => 'Create Task')) + ->add('task', TextType::class) + ->add('dueDate', DateType::class) + ->add('save', SubmitType::class, array('label' => 'Create Task')) ->getForm(); return $this->render('default/new.html.twig', array( @@ -116,16 +119,13 @@ 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. ``text``, ``date``), which, among -other things, determines which HTML form tag(s) is rendered for that field. +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. 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:`forms-type-reference`). @@ -227,9 +227,9 @@ your controller:: $task = new Task(); $form = $this->createFormBuilder($task) - ->add('task', 'text') - ->add('dueDate', 'date') - ->add('save', 'submit', array('label' => 'Create Task')) + ->add('task', TextType::class) + ->add('dueDate', DateType::class) + ->add('save', SubmitType::class, array('label' => 'Create Task')) ->getForm(); $form->handleRequest($request); @@ -252,19 +252,13 @@ 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:`form-submit-request`. - This controller follows a common pattern for handling forms, and has three possible paths: @@ -458,11 +452,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:`date field ` can be +boxes. However, the :doc:`DateType ` 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', 'date', array('widget' => 'single_text')) + ->add('dueDate', DateType::class, array('widget' => 'single_text')) .. image:: /_images/form/simple-form-2.png :align: center @@ -479,7 +473,7 @@ the documentation for each type. is left blank. If you don't want this behavior, either :ref:`disable HTML5 validation ` or set the ``required`` option on your field to ``false``:: - + ->add('dueDate', 'date', array( 'widget' => 'single_text', 'required' => false @@ -499,7 +493,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', 'date', array( + ->add('dueDate', DateType::class, array( 'widget' => 'single_text', 'label' => 'Due Date', )) @@ -520,7 +514,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 -``text`` field and the ``dueDate`` field is a ``date`` field:: +``TextType`` field and the ``dueDate`` field is a ``DateType`` field:: public function newAction() { @@ -529,7 +523,7 @@ guess from the validation rules that both the ``task`` field is a normal $form = $this->createFormBuilder($task) ->add('task') ->add('dueDate', null, array('widget' => 'single_text')) - ->add('save', 'submit') + ->add('save', SubmitType::class) ->getForm(); } @@ -601,6 +595,7 @@ 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 { @@ -609,36 +604,21 @@ that will house the logic for building the task form:: $builder ->add('task') ->add('dueDate', null, array('widget' => 'single_text')) - ->add('save', 'submit') + ->add('save', SubmitType::class) ; } - - 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\TaskType; public function newAction() { $task = ...; - $form = $this->createForm(new TaskType(), $task); + $form = $this->createForm(TaskType::class, $task); // ... } @@ -685,7 +665,7 @@ the choice is ultimately up to you. $builder ->add('task') ->add('dueDate', null, array('mapped' => false)) - ->add('save', 'submit') + ->add('save', SubmitType::class) ; } @@ -730,3 +710,4 @@ Learn more .. _`Symfony Form component`: https://github.com/symfony/form .. _`DateTime`: http://php.net/manual/en/class.datetime.php +.. _`2.8 UPGRADE Log`: https://github.com/symfony/symfony/blob/2.8/UPGRADE-2.8.md#form diff --git a/http_cache.rst b/http_cache.rst index 6179978a8c3..f7319c16fb6 100644 --- a/http_cache.rst +++ b/http_cache.rst @@ -86,8 +86,9 @@ To enable caching, modify the code of your front controller. You can also make t changes to ``app_dev.php`` to add caching to the ``dev`` environment:: // web/app.php - // ... + use Symfony\Component\HttpFoundation\Request; + // ... $kernel = new AppKernel('prod', false); $kernel->loadClassCache(); diff --git a/http_cache/esi.rst b/http_cache/esi.rst index 55fe74434d3..4e21007813e 100644 --- a/http_cache/esi.rst +++ b/http_cache/esi.rst @@ -138,23 +138,20 @@ 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 ControllerReference( + new Symfony\Component\HttpKernel\Controller\ControllerReference( 'AppBundle:News:latest', array('maxPerPage' => 5) ), array('strategy' => 'esi') ) ?> - // ... or a URL - use Symfony\Component\Routing\Generator\UrlGeneratorInterface; + render( - $view['router']->generate( + $view['router']->path( 'latest_news', - array('maxPerPage' => 5), - UrlGeneratorInterface::ABSOLUTE_URL + array('maxPerPage' => 5) ), array('strategy' => 'esi'), ) ?> diff --git a/introduction/from_flat_php_to_symfony2.rst b/introduction/from_flat_php_to_symfony2.rst index cf11b68df65..dd8c41c1e07 100644 --- a/introduction/from_flat_php_to_symfony2.rst +++ b/introduction/from_flat_php_to_symfony2.rst @@ -431,7 +431,7 @@ content: { "require": { - "symfony/symfony": "2.6.*" + "symfony/symfony": "3.0.*" }, "autoload": { "files": ["model.php","controllers.php"] @@ -594,7 +594,7 @@ database and the Templating component to render a template and return a