From e1d36e6b84821267cf312f07ed56369883572153 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Sat, 6 May 2017 11:03:29 -0400 Subject: [PATCH] Going through more chapters to use types and autowiring --- controller/argument_value_resolver.rst | 37 +++++----- controller/error_pages.rst | 34 ++++----- controller/soap_web_service.rst | 66 +++++++++++------- controller/upload_file.rst | 81 ++++++++++++--------- doctrine/associations.rst | 41 ++++++----- doctrine/dbal.rst | 5 +- doctrine/event_listeners_subscribers.rst | 57 ++++----------- doctrine/multiple_entity_managers.rst | 28 ++++---- doctrine/pdo_session_storage.rst | 89 +++++++++++++++--------- doctrine/registration_form.rst | 8 +-- doctrine/repository.rst | 11 ++- doctrine/reverse_engineering.rst | 18 ++--- email/dev_environment.rst | 4 +- email/testing.rst | 4 +- event_dispatcher.rst | 45 ++---------- forms.rst | 3 +- quick_tour/the_architecture.rst | 1 - quick_tour/the_controller.rst | 1 - serializer.rst | 10 ++- service_container.rst | 4 ++ 20 files changed, 276 insertions(+), 271 deletions(-) diff --git a/controller/argument_value_resolver.rst b/controller/argument_value_resolver.rst index 1f02d43e968..202497ebea8 100644 --- a/controller/argument_value_resolver.rst +++ b/controller/argument_value_resolver.rst @@ -16,7 +16,7 @@ Functionality Shipped with the HttpKernel ----------------------------------------- .. versionadded:: 3.3 - The ``SessionValueResolver`` was introduced in Symfony 3.3. + The ``SessionValueResolver`` and ``ServiceValueResolver`` were both added in Symfony 3.3. Symfony ships with five value resolvers in the HttpKernel component: @@ -27,6 +27,10 @@ Symfony ships with five value resolvers in the HttpKernel component: Injects the current ``Request`` if type-hinted with ``Request`` or a class extending ``Request``. +:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\ServiceValueResolver` + Injects a service if type-hinted with a valid service class or interface. This + works like :doc:`autowiring `. + :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\SessionValueResolver` Injects the configured session class extending ``SessionInterface`` if type-hinted with ``SessionInterface`` or a class extending @@ -146,10 +150,12 @@ and adding a priority. # app/config/services.yml services: - app.value_resolver.user: - class: AppBundle\ArgumentResolver\UserValueResolver - arguments: - - '@security.token_storage' + _defaults: + # ... be sure autowiring is enabled + autowire: true + # ... + + AppBundle\ArgumentResolver\UserValueResolver: tags: - { name: controller.argument_value_resolver, priority: 50 } @@ -162,10 +168,11 @@ and adding a priority. xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - - + + + + + @@ -175,14 +182,10 @@ and adding a priority. .. code-block:: php // app/config/services.php - use Symfony\Component\DependencyInjection\Definition; - - $definition = new Definition( - 'AppBundle\ArgumentResolver\UserValueResolver', - array(new Reference('security.token_storage')) - ); - $definition->addTag('controller.argument_value_resolver', array('priority' => 50)); - $container->setDefinition('app.value_resolver.user', $definition); + use AppBundle\ArgumentResolver\UserValueResolver; + + $container->autowire(UserValueResolver::class) + ->addTag('controller.argument_value_resolver', array('priority' => 50)); While adding a priority is optional, it's recommended to add one to make sure the expected value is injected. The ``RequestAttributeValueResolver`` has a diff --git a/controller/error_pages.rst b/controller/error_pages.rst index e42997404ab..dc831737574 100644 --- a/controller/error_pages.rst +++ b/controller/error_pages.rst @@ -269,9 +269,15 @@ In that case, you might want to override one or both of the ``showAction()`` and # app/config/services.yml services: - app.exception_controller: - class: AppBundle\Controller\CustomExceptionController - arguments: ['@twig', '%kernel.debug%'] + _defaults: + # ... be sure autowiring is enabled + autowire: true + # ... + + AppBundle\Controller\CustomExceptionController: + public: true + arguments: + $debug: '%kernel.debug%' .. code-block:: xml @@ -282,11 +288,12 @@ In that case, you might want to override one or both of the ``showAction()`` and xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd" > - - - %kernel.debug% + + + + + + %kernel.debug% @@ -295,16 +302,9 @@ In that case, you might want to override one or both of the ``showAction()`` and // app/config/services.php use AppBundle\Controller\CustomExceptionController; - use Symfony\Component\DependencyInjection\Reference; - - $container->register('app.exception_controller', CustomExceptionController::class) - ->setArguments(array( - new Reference('twig'), - '%kernel.debug%', - )); - And then configure ``twig.exception_controller`` using the controller as - services syntax (e.g. ``app.exception_controller:showAction``). + $container->autowire(CustomExceptionController::class) + ->setArgument('$debug', '%kernel.debug%'); .. tip:: diff --git a/controller/soap_web_service.rst b/controller/soap_web_service.rst index 6a2fe21940e..47412c0fd8f 100644 --- a/controller/soap_web_service.rst +++ b/controller/soap_web_service.rst @@ -24,8 +24,8 @@ which represents the functionality that you'll expose in your SOAP service. In this case, the SOAP service will allow the client to call a method called ``hello``, which happens to send an email:: - // src/Acme/SoapBundle/Services/HelloService.php - namespace Acme\SoapBundle\Services; + // src/AppBundle/Service/HelloService.php + namespace AppBundle\Service; class HelloService { @@ -50,10 +50,9 @@ In this case, the SOAP service will allow the client to call a method called } } -Next, you can train Symfony to be able to create an instance of this class. -Since the class sends an email, it's been designed to accept a ``Swift_Mailer`` -instance. Using the Service Container, you can configure Symfony to construct -a ``HelloService`` object properly: +Next, make sure that your new class is registered as a service. If you use +:doc:`autowiring ` (enabled by default in the Symfony +Standard Edition), this is easy: .. configuration-block:: @@ -61,45 +60,62 @@ a ``HelloService`` object properly: # app/config/services.yml services: - hello_service: - class: Acme\SoapBundle\Services\HelloService - arguments: ['@mailer'] + _defaults: + # ... be sure autowiring is enabled + autowire: true + # ... + + # add Service/ to the list of directories to load services from + AppBundle\: + resource: '../../src/AppBundle/{Service,Updates,Command,Form,EventSubscriber,Twig,Security}' .. code-block:: xml - - - - - + + + + + + + + + + + + .. code-block:: php // app/config/services.php - use Acme\SoapBundle\Services\HelloService; + use AppBundle\Service\HelloService; - $container - ->register('hello_service', HelloService::class) - ->addArgument(new Reference('mailer')); + $container->autowire(HelloService::class) + ->setPublic(false); Below is an example of a controller that is capable of handling a SOAP -request. If ``indexAction()`` is accessible via the route ``/soap``, then the -WSDL document can be retrieved via ``/soap?wsdl``. - -.. code-block:: php +request. Because ``indexAction()`` is accessible via ``/soap``, the WSDL document +can be retrieved via ``/soap?wsdl``:: - namespace Acme\SoapBundle\Controller; + namespace AppBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Response; + use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; + use AppBundle\Service\HelloService; class HelloServiceController extends Controller { - public function indexAction() + /** + * @Route("/soap") + */ + public function indexAction(HelloService $helloService) { $server = new \SoapServer('/path/to/hello.wsdl'); - $server->setObject($this->get('hello_service')); + $server->setObject($helloService); $response = new Response(); $response->headers->set('Content-Type', 'text/xml; charset=ISO-8859-1'); diff --git a/controller/upload_file.rst b/controller/upload_file.rst index 7ffe7503d97..fb351d8bf8c 100644 --- a/controller/upload_file.rst +++ b/controller/upload_file.rst @@ -221,8 +221,8 @@ Creating an Uploader Service To avoid logic in controllers, making them big, you can extract the upload logic to a separate service:: - // src/AppBundle/FileUploader.php - namespace AppBundle; + // src/AppBundle/Service/FileUploader.php + namespace AppBundle\Service; use Symfony\Component\HttpFoundation\File\UploadedFile; @@ -259,47 +259,51 @@ Then, define a service for this class: # app/config/services.yml services: # ... - app.brochure_uploader: - class: AppBundle\FileUploader - arguments: ['%brochures_directory%'] + + AppBundle\Service\FileUploader: + arguments: + $targetDir: '%brochures_directory%' .. code-block:: xml - + - + http://symfony.com/schema/dic/services/services-1.0.xsd"> - - %brochures_directory% - + + + + + %brochures_directory% + + .. code-block:: php // app/config/services.php - use AppBundle\FileUploader; + use AppBundle\Service\FileUploader; - // ... - $container->register('app.brochure_uploader', FileUploader::class) - ->addArgument('%brochures_directory%'); + $container->autowire(FileUploader::class) + ->setArgument('$targetDir', '%brochures_directory%'); Now you're ready to use this service in the controller:: // src/AppBundle/Controller/ProductController.php + use Symfony\Component\HttpFoundation\Request; + use AppBundle\Service\FileUploader; // ... - public function newAction(Request $request) + public function newAction(Request $request, FileUploader $fileUploader) { // ... if ($form->isSubmitted() && $form->isValid()) { $file = $product->getBrochure(); - $fileName = $this->get('app.brochure_uploader')->upload($file); + $fileName = $fileUploader->upload($file); $product->setBrochure($fileName); @@ -323,7 +327,7 @@ automatically upload the file when persisting the entity:: use Doctrine\ORM\Event\LifecycleEventArgs; use Doctrine\ORM\Event\PreUpdateEventArgs; use AppBundle\Entity\Product; - use AppBundle\FileUploader; + use AppBundle\Service\FileUploader; class BrochureUploadListener { @@ -375,10 +379,12 @@ Now, register this class as a Doctrine listener: # app/config/services.yml services: + _defaults: + # ... be sure autowiring is enabled + autowire: true # ... - app.doctrine_brochure_listener: - class: AppBundle\EventListener\BrochureUploadListener - arguments: ['@app.brochure_uploader'] + + AppBundle\EventListener\BrochureUploadListener: tags: - { name: doctrine.event_listener, event: prePersist } - { name: doctrine.event_listener, event: preUpdate } @@ -392,33 +398,44 @@ Now, register this class as a Doctrine listener: xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd" > - - - - - - - - + + + + + + + + + + .. code-block:: php // app/config/services.php use AppBundle\EventListener\BrochureUploaderListener; +<<<<<<< HEAD use Symfony\Component\DependencyInjection\Reference; // ... $container->register('app.doctrine_brochure_listener', BrochureUploaderListener::class) ->addArgument(new Reference('brochures_directory')) +======= + + $container->autowire(BrochureUploaderListener::class) +>>>>>>> 8974c4842... Going through more chapters to use types and autowiring ->addTag('doctrine.event_listener', array( 'event' => 'prePersist', )) ->addTag('doctrine.event_listener', array( +<<<<<<< HEAD 'event' => 'prePersist', )); +======= + 'event' => 'preUpdate', + )) + ; +>>>>>>> 8974c4842... Going through more chapters to use types and autowiring This listener is now automatically executed when persisting a new Product entity. This way, you can remove everything related to uploading from the diff --git a/doctrine/associations.rst b/doctrine/associations.rst index f91e3c2a603..6ccdbeae6ec 100644 --- a/doctrine/associations.rst +++ b/doctrine/associations.rst @@ -236,10 +236,11 @@ Now you can see this new code in action! Imagine you're inside a controller:: use AppBundle\Entity\Category; use AppBundle\Entity\Product; use Symfony\Component\HttpFoundation\Response; + use Doctrine\ORM\EntityManagerInterface; class DefaultController extends Controller { - public function createProductAction() + public function createProductAction(EntityManagerInterface $em) { $category = new Category(); $category->setName('Computer Peripherals'); @@ -252,7 +253,6 @@ Now you can see this new code in action! Imagine you're inside a controller:: // relate this product to the category $product->setCategory($category); - $em = $this->getDoctrine()->getManager(); $em->persist($category); $em->persist($product); $em->flush(); @@ -276,10 +276,11 @@ When you need to fetch associated objects, your workflow looks just like it did before. First, fetch a ``$product`` object and then access its related ``Category`` object:: - public function showAction($productId) + use Doctrine\ORM\EntityManagerInterface; + + public function showAction($productId, EntityManagerInterface $em) { - $product = $this->getDoctrine() - ->getRepository('AppBundle:Product') + $product = $em->getRepository('AppBundle:Product') ->find($productId); $categoryName = $product->getCategory()->getName(); @@ -303,10 +304,11 @@ the category (i.e. it's "lazily loaded"). You can also query in the other direction:: - public function showProductsAction($categoryId) + use Doctrine\ORM\EntityManagerInterface; + + public function showProductsAction($categoryId, EntityManagerInterface $em) { - $category = $this->getDoctrine() - ->getRepository('AppBundle:Category') + $category = $em->getRepository('AppBundle:Category') ->find($categoryId); $products = $category->getProducts(); @@ -326,8 +328,7 @@ to the given ``Category`` object via their ``category_id`` value. a "proxy" object in place of the true object. Look again at the above example:: - $product = $this->getDoctrine() - ->getRepository('AppBundle:Product') + $product = $em->getRepository('AppBundle:Product') ->find($productId); $category = $product->getCategory(); @@ -366,14 +367,15 @@ can avoid the second query by issuing a join in the original query. Add the following method to the ``ProductRepository`` class:: // src/AppBundle/Repository/ProductRepository.php + use Doctrine\ORM\EntityManagerInterface; + public function findOneByIdJoinedToCategory($productId) { - $query = $this->getEntityManager() - ->createQuery( - 'SELECT p, c FROM AppBundle:Product p - JOIN p.category c - WHERE p.id = :id' - )->setParameter('id', $productId); + $query = $em->createQuery( + 'SELECT p, c FROM AppBundle:Product p + JOIN p.category c + WHERE p.id = :id' + )->setParameter('id', $productId); try { return $query->getSingleResult(); @@ -385,10 +387,11 @@ following method to the ``ProductRepository`` class:: Now, you can use this method in your controller to query for a ``Product`` object and its related ``Category`` with just one query:: - public function showAction($productId) + use Doctrine\ORM\EntityManagerInterface; + + public function showAction($productId, EntityManagerInterface $em) { - $product = $this->getDoctrine() - ->getRepository('AppBundle:Product') + $product = $em->getRepository('AppBundle:Product') ->findOneByIdJoinedToCategory($productId); $category = $product->getCategory(); diff --git a/doctrine/dbal.rst b/doctrine/dbal.rst index 70e183d84c5..9e876c2f4b1 100644 --- a/doctrine/dbal.rst +++ b/doctrine/dbal.rst @@ -72,11 +72,12 @@ connections, see :ref:`reference-dbal-configuration`. You can then access the Doctrine DBAL connection by accessing the ``database_connection`` service:: + use Doctrine\DBAL\Driver\Connection; + class UserController extends Controller { - public function indexAction() + public function indexAction(Connection $conn) { - $conn = $this->get('database_connection'); $users = $conn->fetchAll('SELECT * FROM users'); // ... diff --git a/doctrine/event_listeners_subscribers.rst b/doctrine/event_listeners_subscribers.rst index 911b3cb6b4a..5893a93345f 100644 --- a/doctrine/event_listeners_subscribers.rst +++ b/doctrine/event_listeners_subscribers.rst @@ -32,25 +32,16 @@ managers that use this connection. .. code-block:: yaml - doctrine: - dbal: - default_connection: default - connections: - default: - driver: pdo_sqlite - memory: true - services: - my.listener: - class: AppBundle\EventListener\SearchIndexer + # ... + + AppBundle\EventListener\SearchIndexer: tags: - { name: doctrine.event_listener, event: postPersist } - my.listener2: - class: AppBundle\EventListener\SearchIndexer2 + AppBundle\EventListener\SearchIndexer2: tags: - { name: doctrine.event_listener, event: postPersist, connection: default } - my.subscriber: - class: AppBundle\EventListener\SearchIndexerSubscriber + AppBundle\EventListener\SearchIndexerSubscriber: tags: - { name: doctrine.event_subscriber, connection: default } @@ -59,21 +50,16 @@ managers that use this connection. - - - - - - - - + + + - + - + @@ -85,38 +71,23 @@ managers that use this connection. use AppBundle\EventListener\SearchIndexer2; use AppBundle\EventListener\SearchIndexerSubscriber; - $container->loadFromExtension('doctrine', array( - 'dbal' => array( - 'default_connection' => 'default', - 'connections' => array( - 'default' => array( - 'driver' => 'pdo_sqlite', - 'memory' => true, - ), - ), - ), - )); - - $container - ->register('my.listener', SearchIndexer::class) + $container->autowire(SearchIndexer::class) ->addTag('doctrine.event_listener', array('event' => 'postPersist')) ; - $container - ->register('my.listener2', SearchIndexer2::class) + $container->autowire(SearchIndexer2::class) ->addTag('doctrine.event_listener', array( 'event' => 'postPersist', 'connection' => 'default' )) ; - $container - ->register('my.subscriber', SearchIndexerSubscriber::class) + $container->autowire(SearchIndexerSubscriber::class) ->addTag('doctrine.event_subscriber', array('connection' => 'default')) ; Creating the Listener Class --------------------------- -In the previous example, a service ``my.listener`` was configured as a Doctrine +In the previous example, a ``SearchIndexer`` service was configured as a Doctrine listener on the event ``postPersist``. The class behind that service must have a ``postPersist()`` method, which will be called when the event is dispatched:: diff --git a/doctrine/multiple_entity_managers.rst b/doctrine/multiple_entity_managers.rst index a574bd437d0..8f9e4ed6899 100644 --- a/doctrine/multiple_entity_managers.rst +++ b/doctrine/multiple_entity_managers.rst @@ -183,17 +183,21 @@ When working with multiple entity managers to update your schema: If you *do* omit the entity manager's name when asking for it, the default entity manager (i.e. ``default``) is returned:: + use Doctrine\ORM\EntityManagerInterface; + use Doctrine\Common\Persistence\ManagerRegistry; + class UserController extends Controller { - public function indexAction() + public function indexAction(EntityManagerInterface $em, ManagerRegistry $doctrine) { - // All three return the "default" entity manager - $em = $this->get('doctrine')->getManager(); - $em = $this->get('doctrine')->getManager('default'); + // All 4 return the "default" entity manager + // $em from the EntityManagerInterface + $em = $doctrine->getManager(); + $em = $doctrine->getManager('default'); $em = $this->get('doctrine.orm.default_entity_manager'); // Both of these return the "customer" entity manager - $customerEm = $this->get('doctrine')->getManager('customer'); + $customerEm = $doctrine->getManager('customer'); $customerEm = $this->get('doctrine.orm.customer_entity_manager'); } } @@ -204,27 +208,25 @@ entity manager to persist and fetch its entities. The same applies to repository calls:: + use Doctrine\Common\Persistence\ManagerRegistry; + class UserController extends Controller { - public function indexAction() + public function indexAction(ManagerRegistry $doctrine) { // Retrieves a repository managed by the "default" em - $products = $this->get('doctrine') - ->getRepository('AcmeStoreBundle:Product') + $products = $doctrine->getRepository('AcmeStoreBundle:Product') ->findAll() ; // Explicit way to deal with the "default" em - $products = $this->get('doctrine') - ->getRepository('AcmeStoreBundle:Product', 'default') + $products = $doctrine->getRepository('AcmeStoreBundle:Product', 'default') ->findAll() ; // Retrieves a repository managed by the "customer" em - $customers = $this->get('doctrine') - ->getRepository('AcmeCustomerBundle:Customer', 'customer') + $customers = $doctrine->getRepository('AcmeCustomerBundle:Customer', 'customer') ->findAll() ; } } - diff --git a/doctrine/pdo_session_storage.rst b/doctrine/pdo_session_storage.rst index f318d4ccda1..631a052ef92 100644 --- a/doctrine/pdo_session_storage.rst +++ b/doctrine/pdo_session_storage.rst @@ -11,21 +11,17 @@ multiple web server environment. Symfony has a built-in solution for database session storage called :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\PdoSessionHandler`. -To use it, you just need to change some parameters in the main configuration file: +To use it, first register a new handler service: .. configuration-block:: .. code-block:: yaml # app/config/config.yml - framework: - session: - # ... - handler_id: session.handler.pdo - services: - session.handler.pdo: - class: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler + # ... + + Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler: public: false arguments: - 'mysql:dbname=mydatabase' @@ -34,12 +30,10 @@ To use it, you just need to change some parameters in the main configuration fil .. code-block:: xml - - - - - + + + mysql:dbname=mydatabase myuser @@ -51,7 +45,38 @@ To use it, you just need to change some parameters in the main configuration fil .. code-block:: php // app/config/config.php + use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; + $storageDefinition = $container->register(PdoSessionHandler::class) + ->setArguments(array( + 'mysql:dbname=mydatabase', + array('db_username' => 'myuser', 'db_password' => 'mypassword') + )) + ; + +Next, tell Symfony to use your service as the session handler: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + framework: + session: + # ... + handler_id: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler + + .. code-block:: xml + + + + + + + + .. code-block:: php + + // app/config/config.php use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; // ... @@ -59,16 +84,10 @@ To use it, you just need to change some parameters in the main configuration fil // ... 'session' => array( // ... - 'handler_id' => 'session.handler.pdo', + 'handler_id' => PdoSessionHandler::class, ), )); - $container->register('session.handler.pdo', PdoSessionHandler::class) - ->setArguments(array( - 'mysql:dbname=mydatabase', - array('db_username' => 'myuser', 'db_password' => 'mypassword'), - )); - Configuring the Table and Column Names -------------------------------------- @@ -83,8 +102,8 @@ a second array argument to ``PdoSessionHandler``: # app/config/config.yml services: # ... - session.handler.pdo: - class: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler + + Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler: public: false arguments: - 'mysql:dbname=mydatabase' @@ -94,7 +113,7 @@ a second array argument to ``PdoSessionHandler``: - + mysql:dbname=mydatabase sessions @@ -111,11 +130,12 @@ a second array argument to ``PdoSessionHandler``: use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; // ... - $container->register('session.handler.pdo', PdoSessionHandler::class) + $container->register(PdoSessionHandler::class) ->setArguments(array( 'mysql:dbname=mydatabase', - array('db_table' => 'sessions', 'db_username' => 'myuser', 'db_password' => 'mypassword'), - )); + array('db_table' => 'sessions', 'db_username' => 'myuser', 'db_password' => 'mypassword') + )) + ; These are parameters that you must configure: @@ -151,8 +171,9 @@ of your project's data, you can use the connection settings from the .. code-block:: yaml services: - session.handler.pdo: - class: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler + # ... + + Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler: public: false arguments: - 'mysql:host=%database_host%;port=%database_port%;dbname=%database_name%' @@ -160,7 +181,7 @@ of your project's data, you can use the connection settings from the .. code-block:: xml - + mysql:host=%database_host%;port=%database_port%;dbname=%database_name% %database_user% @@ -171,10 +192,12 @@ of your project's data, you can use the connection settings from the .. code-block:: php // ... - $storageDefinition = new Definition(PdoSessionHandler::class, array( - 'mysql:host=%database_host%;port=%database_port%;dbname=%database_name%', - array('db_username' => '%database_user%', 'db_password' => '%database_password%') - )); + $container->register(PdoSessionHandler::class) + ->setArguments(array( + 'mysql:host=%database_host%;port=%database_port%;dbname=%database_name%', + array('db_username' => '%database_user%', 'db_password' => '%database_password%') + )) + ; .. _example-sql-statements: diff --git a/doctrine/registration_form.rst b/doctrine/registration_form.rst index 2f3b13a7d34..1fbdf9d50c4 100644 --- a/doctrine/registration_form.rst +++ b/doctrine/registration_form.rst @@ -225,13 +225,15 @@ into the database:: use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; + use Doctrine\ORM\EntityManagerInterface; class RegistrationController extends Controller { /** * @Route("/register", name="user_registration") */ - public function registerAction(Request $request) + public function registerAction(Request $request, UserPasswordEncoderInterface $passwordEncoder, EntityManagerInterface $em) { // 1) build the form $user = new User(); @@ -242,12 +244,10 @@ into the database:: if ($form->isSubmitted() && $form->isValid()) { // 3) Encode the password (you could also do this via Doctrine listener) - $password = $this->get('security.password_encoder') - ->encodePassword($user, $user->getPlainPassword()); + $password = $passwordEncoder->encodePassword($user, $user->getPlainPassword()); $user->setPassword($password); // 4) save the User! - $em = $this->getDoctrine()->getManager(); $em->persist($user); $em->flush(); diff --git a/doctrine/repository.rst b/doctrine/repository.rst index 8a10c01346b..acc80431f22 100644 --- a/doctrine/repository.rst +++ b/doctrine/repository.rst @@ -96,9 +96,14 @@ entities, ordered alphabetically by name. You can use this new method just like the default finder methods of the repository:: - $em = $this->getDoctrine()->getManager(); - $products = $em->getRepository('AppBundle:Product') - ->findAllOrderedByName(); + use Doctrine\ORM\EntityManagerInterface; + // ... + + public function listAction(EntityManagerInterface $em) + { + $products = $em->getRepository('AppBundle:Product') + ->findAllOrderedByName(); + } .. note:: diff --git a/doctrine/reverse_engineering.rst b/doctrine/reverse_engineering.rst index eb195a62ce0..45b34bddc72 100644 --- a/doctrine/reverse_engineering.rst +++ b/doctrine/reverse_engineering.rst @@ -48,9 +48,7 @@ to a post record thanks to a foreign key constraint. Before diving into the recipe, be sure your database connection parameters are correctly setup in the ``app/config/parameters.yml`` file (or wherever your -database configuration is kept) and that you have initialized a bundle that -will host your future entity class. In this tutorial it's assumed that an -AcmeBlogBundle exists and is located under the ``src/Acme/BlogBundle`` folder. +database configuration is kept). The first step towards building entity classes from an existing database is to ask Doctrine to introspect the database and generate the corresponding @@ -59,10 +57,10 @@ table fields. .. code-block:: terminal - $ php bin/console doctrine:mapping:import --force AcmeBlogBundle xml + $ php bin/console doctrine:mapping:import --force AppBundle 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`` +the XML metadata files under the ``src/AppBundle/Resources/config/doctrine`` folder of your bundle. This generates two files: ``BlogPost.orm.xml`` and ``BlogComment.orm.xml``. @@ -77,7 +75,7 @@ The generated ``BlogPost.orm.xml`` metadata file looks as follows: - + @@ -93,7 +91,7 @@ entity classes by executing the following two commands. .. code-block:: terminal $ php bin/console doctrine:mapping:convert annotation ./src - $ php bin/console doctrine:generate:entities AcmeBlogBundle + $ php bin/console doctrine:generate:entities AppBundle The first command generates entity classes with annotation mappings. But if you want to use YAML or XML mapping instead of annotations, you should @@ -107,14 +105,12 @@ execute the second command only. For example, the newly created ``BlogComment`` entity class looks as follow:: - // src/Acme/BlogBundle/Entity/BlogComment.php - namespace Acme\BlogBundle\Entity; + // src/AppBundle/Entity/BlogComment.php + namespace AppBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** - * Acme\BlogBundle\Entity\BlogComment - * * @ORM\Table(name="blog_comment") * @ORM\Entity */ diff --git a/email/dev_environment.rst b/email/dev_environment.rst index 42ba08ed9bb..8e0eba07666 100644 --- a/email/dev_environment.rst +++ b/email/dev_environment.rst @@ -96,7 +96,7 @@ Now, suppose you're sending an email to ``recipient@example.com``. .. code-block:: php - public function indexAction($name) + public function indexAction($name, \Swift_Mailer $mailer) { $message = \Swift_Message::newInstance() ->setSubject('Hello Email') @@ -109,7 +109,7 @@ Now, suppose you're sending an email to ``recipient@example.com``. ) ) ; - $this->get('mailer')->send($message); + $mailer->send($message); return $this->render(...); } diff --git a/email/testing.rst b/email/testing.rst index d5835e915df..de3b4532e70 100644 --- a/email/testing.rst +++ b/email/testing.rst @@ -12,7 +12,7 @@ content or any other headers, you can use :doc:`the Symfony Profiler Start with an easy controller action that sends an email:: - public function sendEmailAction($name) + public function sendEmailAction($name, \Swift_Mailer $mailer) { $message = \Swift_Message::newInstance() ->setSubject('Hello Email') @@ -21,7 +21,7 @@ Start with an easy controller action that sends an email:: ->setBody('You should see me from the profiler!') ; - $this->get('mailer')->send($message); + $mailer->send($message); return $this->render(...); } diff --git a/event_dispatcher.rst b/event_dispatcher.rst index 925e89e0fd4..34ad82502e1 100644 --- a/event_dispatcher.rst +++ b/event_dispatcher.rst @@ -176,46 +176,15 @@ listen to the same ``kernel.exception`` event:: } } -Now, you just need to register the class as a service and add the -``kernel.event_subscriber`` tag to tell Symfony that this is an event subscriber: +That's it! Your ``services.yml`` file should already be setup to load services from +the ``EventSubscriber`` directory. Symfony takes care of the rest. -.. configuration-block:: - - .. code-block:: yaml - - # app/config/services.yml - services: - app.exception_subscriber: - class: AppBundle\EventSubscriber\ExceptionSubscriber - tags: - - { name: kernel.event_subscriber } - - .. code-block:: xml - - - - - - - - - - - - - - .. code-block:: php - - // app/config/services.php - use AppBundle\EventSubscriber\ExceptionSubscriber; +.. tip:: - $container - ->register('app.exception_subscriber', ExceptionSubscriber::class) - ->addTag('kernel.event_subscriber') - ; + If your methods are *not* called when an exception is thrown, double-check that + you're :ref:`loading services ` from + the ``EventSubscriber`` directory and have :ref:`autoconfigure ` + enabled. You can also manually add the ``kernel.event_subscriber`` tag. Request Events, Checking Types ------------------------------ diff --git a/forms.rst b/forms.rst index 084aaa63030..168025bad91 100644 --- a/forms.rst +++ b/forms.rst @@ -221,7 +221,7 @@ your controller:: // ... use Symfony\Component\HttpFoundation\Request; - public function newAction(Request $request) + public function newAction(Request $request, EntityManagerInterface $em) { // just setup a fresh $task object (remove the dummy data) $task = new Task(); @@ -241,7 +241,6 @@ your controller:: // ... perform some action, such as saving the task to the database // for example, if Task is a Doctrine entity, save it! - // $em = $this->getDoctrine()->getManager(); // $em->persist($task); // $em->flush(); diff --git a/quick_tour/the_architecture.rst b/quick_tour/the_architecture.rst index ea0713def34..4130cd063ae 100644 --- a/quick_tour/the_architecture.rst +++ b/quick_tour/the_architecture.rst @@ -43,7 +43,6 @@ production controller shown here:: use Symfony\Component\HttpFoundation\Request; $kernel = new AppKernel('prod', false); - $kernel->loadClassCache(); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send(); diff --git a/quick_tour/the_controller.rst b/quick_tour/the_controller.rst index 1bc9412e015..513aa8b3e0b 100644 --- a/quick_tour/the_controller.rst +++ b/quick_tour/the_controller.rst @@ -115,7 +115,6 @@ as its default value:: // src/AppBundle/Controller/DefaultController.php use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; - use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; // ... diff --git a/serializer.rst b/serializer.rst index f032f0aa4e5..4c31e45eaf0 100644 --- a/serializer.rst +++ b/serializer.rst @@ -69,20 +69,19 @@ Using the Serializer Service ---------------------------- Once enabled, the ``serializer`` service can be injected in any service where -you need it or it can be used in a controller like the following:: +you need it or it can be used in a controller:: // src/AppBundle/Controller/DefaultController.php namespace AppBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; + use Symfony\Component\Serializer\SerializerInterface; class DefaultController extends Controller { - public function indexAction() + public function indexAction(SerializerInterface $serializer) { - $serializer = $this->get('serializer'); - - // ... + // keep reading for usage examples } } @@ -172,7 +171,6 @@ with the following configuration: Next, add the :ref:`@Groups annotations ` to your class and choose which groups to use when serializing:: - $serializer = $this->get('serializer'); $json = $serializer->serialize( $someObject, 'json', array('groups' => array('group1')) diff --git a/service_container.rst b/service_container.rst index 5fb39ddab8d..b702ef0a223 100644 --- a/service_container.rst +++ b/service_container.rst @@ -141,6 +141,8 @@ it can't be re-used. Instead, you decide to create a new class:: Congratulations! You've just created your first service class. Next, you can *teach* the service container *how* to instantiate it: +.. _service-container-services-load-example: + .. configuration-block:: .. code-block:: yaml @@ -285,6 +287,8 @@ suggestion. Be sure to read more about :doc:`autowiring `. +.. _services-debug-container-types: + .. tip:: How should you know to use ``LoggerInterface`` for the type-hint? The best way