Skip to content

Commit 0b78495

Browse files
committed
Merge branch '2.7' into 2.8
* 2.7: [#7907] add some use statements Updating Doctrine syntax for getRepository method Updating doctrine class use [#7909] fix some typos Explained the locateResource() method of HttpKernel Reworded the note about dump() not being available in prod Symfony Installer Instructions for Windows Typo Fixing a typo in the Final Thoughts section Stop recommending the use of "doctrine:generate:entities" Added a help note about translating routes Use a safer code sample for Twig best practices Use the Twig namespaced syntax for all templates
2 parents 9c85e79 + 517f386 commit 0b78495

32 files changed

+186
-189
lines changed

best_practices/controllers.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ for the homepage of our app:
9595
9696
namespace AppBundle\Controller;
9797
98+
use AppBundle\Entity\Post;
9899
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
99100
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
100101
@@ -106,7 +107,7 @@ for the homepage of our app:
106107
public function indexAction()
107108
{
108109
$posts = $this->getDoctrine()
109-
->getRepository('AppBundle:Post')
110+
->getRepository(Post::class)
110111
->findLatest();
111112
112113
return $this->render('default/index.html.twig', array(
@@ -170,7 +171,7 @@ manually. In our application, we have this situation in ``CommentController``:
170171
public function newAction(Request $request, $postSlug)
171172
{
172173
$post = $this->getDoctrine()
173-
->getRepository('AppBundle:Post')
174+
->getRepository(Post::class)
174175
->findOneBy(array('slug' => $postSlug));
175176
176177
if (!$post) {

best_practices/security.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ more advanced use-case, you can always do the same security check in PHP:
226226
*/
227227
public function editAction($id)
228228
{
229-
$post = $this->getDoctrine()->getRepository('AppBundle:Post')
229+
$post = $this->getDoctrine()->getRepository(Post::class)
230230
->find($id);
231231
232232
if (!$post) {

best_practices/templates.rst

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,20 @@ Template Locations
3030
Store all your application's templates in ``app/Resources/views/`` directory.
3131

3232
Traditionally, Symfony developers stored the application templates in the
33-
``Resources/views/`` directory of each bundle. Then they used the logical name
34-
to refer to them (e.g. ``AcmeDemoBundle:Default:index.html.twig``).
33+
``Resources/views/`` directory of each bundle. Then they used the Twig namespaced
34+
path to refer to them (e.g. ``@AcmeDemo/Default/index.html.twig``).
3535

3636
But for the templates used in your application, it's much more convenient
3737
to store them in the ``app/Resources/views/`` directory. For starters, this
3838
drastically simplifies their logical names:
3939

40-
================================================= ==================================
41-
Templates Stored inside Bundles Templates Stored in ``app/``
42-
================================================= ==================================
43-
``AcmeDemoBundle:Default:index.html.twig`` ``default/index.html.twig``
44-
``::layout.html.twig`` ``layout.html.twig``
45-
``AcmeDemoBundle::index.html.twig`` ``index.html.twig``
46-
``AcmeDemoBundle:Default:subdir/index.html.twig`` ``default/subdir/index.html.twig``
47-
``AcmeDemoBundle:Default/subdir:index.html.twig`` ``default/subdir/index.html.twig``
48-
================================================= ==================================
40+
============================================ ==================================
41+
Templates Stored inside Bundles Templates Stored in ``app/``
42+
============================================ ==================================
43+
``@AcmeDemo/index.html.twig`` ``index.html.twig``
44+
``@AcmeDemo/Default/index.html.twig`` ``default/index.html.twig``
45+
``@AcmeDemo/Default/subdir/index.html.twig`` ``default/subdir/index.html.twig``
46+
============================================ ==================================
4947

5048
Another advantage is that centralizing your templates simplifies the work
5149
of your designers. They don't need to look for templates in lots of directories
@@ -131,7 +129,7 @@ service in the constructor of the Twig extension:
131129
new \Twig_SimpleFilter(
132130
'md2html',
133131
array($this, 'markdownToHtml'),
134-
array('is_safe' => array('html'))
132+
array('is_safe' => array('html'), 'pre_escape' => 'html')
135133
),
136134
);
137135
}

bundles/best_practices.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,21 @@ API is being used. The following code, would work for *all* users::
471471
}
472472
}
473473

474+
Resources
475+
---------
476+
477+
If the bundle references any resources (config files, translation files, etc.),
478+
don't use physical paths (e.g. ``__DIR__/config/services.xml``) but logical
479+
paths (e.g. ``@AppBundle/Resources/config/services.xml``).
480+
481+
The logical paths are required because of the bundle overriding mechanism that
482+
lets you override any resource/file of any bundle. See :ref:`http-kernel-resource-locator`
483+
for more details about transforming physical paths into logical paths.
484+
485+
Beware that templates use a simplified version of the logical path shown above.
486+
For example, an ``index.html.twig`` template located in the ``Resources/views/Default/``
487+
directory of the AppBundle, is referenced as ``@App/Default/index.html.twig``.
488+
474489
Learn more
475490
----------
476491

bundles/override.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ How to Override any Part of a Bundle
77
This document is a quick reference for how to override different parts of
88
third-party bundles.
99

10+
.. tip::
11+
12+
The bundle overriding mechanism means that you cannot use physical paths to
13+
refer to bundle's resources (e.g. ``__DIR__/config/services.xml``). Always
14+
use logical paths in your bundles (e.g. ``@AppBundle/Resources/config/services.xml``)
15+
and call the :ref:`locateResource() method <http-kernel-resource-locator>`
16+
to turn them into physical paths when needed.
17+
1018
Templates
1119
---------
1220

components/form.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ is created from the form factory.
420420
->add('dueDate', DateType::class)
421421
->getForm();
422422
423-
return $this->render('AcmeTaskBundle:Default:new.html.twig', array(
423+
return $this->render('@AcmeTask/Default/new.html.twig', array(
424424
'form' => $form->createView(),
425425
));
426426
}

components/http_kernel.rst

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ each event has their own event object:
592592
===================== ================================ ===================================================================================
593593
Name ``KernelEvents`` Constant Argument passed to the listener
594594
===================== ================================ ===================================================================================
595-
kernel.request ``KernelEvents::REQUEST`` :class:`Symfony\\Component\\HttpKernel\\Event\\GetResponseEvent`
595+
kernel.request ``KernelEvents::REQUEST`` :class:`Symfony\\Component\\HttpKernel\\Event\\GetResponseEvent`
596596
kernel.controller ``KernelEvents::CONTROLLER`` :class:`Symfony\\Component\\HttpKernel\\Event\\FilterControllerEvent`
597597
kernel.view ``KernelEvents::VIEW`` :class:`Symfony\\Component\\HttpKernel\\Event\\GetResponseForControllerResultEvent`
598598
kernel.response ``KernelEvents::RESPONSE`` :class:`Symfony\\Component\\HttpKernel\\Event\\FilterResponseEvent`
@@ -702,6 +702,32 @@ look like this::
702702
// ...
703703
}
704704

705+
.. _http-kernel-resource-locator:
706+
707+
Locating Resources
708+
------------------
709+
710+
The HttpKernel component is responsible of the bundle mechanism used in Symfony
711+
applications. The key feature of the bundles is that they allow to override any
712+
resource used by the application (config files, templates, controllers,
713+
translation files, etc.)
714+
715+
This overriding mechanism works because resources are referenced not by their
716+
physical path but by their logical path. For example, the ``services.xml`` file
717+
stored in the ``Resources/config/`` directory of a bundle called AppBundle is
718+
referenced as ``@AppBundle/Resources/config/services.xml``. This logical path
719+
will work when the application overrides that file and even if you change the
720+
directory of AppBundle.
721+
722+
The HttpKernel component provides a method called :method:`Symfony\\Component\\HttpKernel\\Kernel::locateResource`
723+
which can be used to transform logical paths into physical paths::
724+
725+
use Symfony\Component\HttpKernel\HttpKernel;
726+
727+
// ...
728+
$kernel = new HttpKernel($dispatcher, $resolver);
729+
$path = $kernel->locateResource('@AppBundle/Resources/config/services.xml');
730+
705731
Learn more
706732
----------
707733

components/security/authorization.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ on a "remember-me" cookie, or even authenticated anonymously?
123123
use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
124124
125125
$anonymousClass = AnonymousToken::class;
126-
$rememberMeClass = RememberMeToken::Class;
126+
$rememberMeClass = RememberMeToken::class;
127127
128128
$trustResolver = new AuthenticationTrustResolver($anonymousClass, $rememberMeClass);
129129

controller/service.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ Symfony's base controller::
174174
public function indexAction($name)
175175
{
176176
return $this->render(
177-
'AppBundle:Hello:index.html.twig',
177+
'@App/Hello/index.html.twig',
178178
array('name' => $name)
179179
);
180180
}
@@ -210,7 +210,7 @@ service and use it directly::
210210
public function indexAction($name)
211211
{
212212
return $this->templating->renderResponse(
213-
'AppBundle:Hello:index.html.twig',
213+
'@App/Hello/index.html.twig',
214214
array('name' => $name)
215215
);
216216
}

doctrine.rst

Lines changed: 13 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -400,56 +400,8 @@ Even though Doctrine now knows how to persist a ``Product`` object to the
400400
database, the class itself isn't really useful yet. Since ``Product`` is just
401401
a regular PHP class with ``private`` properties, you need to create ``public``
402402
getter and setter methods (e.g. ``getName()``, ``setName($name)``) in order
403-
to access its properties in the rest of your application's code. Fortunately,
404-
the following command can generate these boilerplate methods automatically:
405-
406-
.. code-block:: terminal
407-
408-
$ php app/console doctrine:generate:entities AppBundle/Entity/Product
409-
410-
This command makes sure that all the getters and setters are generated
411-
for the ``Product`` class. This is a safe command - you can run it over and
412-
over again: it only generates getters and setters that don't exist (i.e. it
413-
doesn't replace your existing methods).
414-
415-
.. caution::
416-
417-
Keep in mind that Doctrine's entity generator produces simple getters/setters.
418-
You should review the generated methods and add any logic, if necessary,
419-
to suit the needs of your application.
420-
421-
.. sidebar:: More about ``doctrine:generate:entities``
422-
423-
With the ``doctrine:generate:entities`` command you can:
424-
425-
* generate getter and setter methods in entity classes;
426-
427-
* generate repository classes on behalf of entities configured with the
428-
``@ORM\Entity(repositoryClass="...")`` annotation;
429-
430-
* generate the appropriate constructor for 1:n and n:m relations.
431-
432-
The ``doctrine:generate:entities`` command saves a backup of the original
433-
``Product.php`` named ``Product.php~``. In some cases, the presence of
434-
this file can cause a "Cannot redeclare class" error. It can be safely
435-
removed. You can also use the ``--no-backup`` option to prevent generating
436-
these backup files.
437-
438-
Note that you don't *need* to use this command. You could also write the
439-
necessary getters and setters by hand. This option simply exists to save
440-
you time, since creating these methods is often a common task during
441-
development.
442-
443-
You can also generate all known entities (i.e. any PHP class with Doctrine
444-
mapping information) of a bundle or an entire namespace:
445-
446-
.. code-block:: terminal
447-
448-
# generates all entities in the AppBundle
449-
$ php app/console doctrine:generate:entities AppBundle
450-
451-
# generates all entities of bundles in the Acme namespace
452-
$ php app/console doctrine:generate:entities Acme
403+
to access its properties in the rest of your application's code. Add these
404+
methods manually or with your own IDE.
453405

454406
.. _doctrine-creating-the-database-tables-schema:
455407

@@ -589,7 +541,7 @@ on its ``id`` value::
589541
public function showAction($productId)
590542
{
591543
$product = $this->getDoctrine()
592-
->getRepository('AppBundle:Product')
544+
->getRepository(Product::class)
593545
->find($productId);
594546

595547
if (!$product) {
@@ -613,18 +565,18 @@ job is to help you fetch entities of a certain class. You can access the
613565
repository object for an entity class via::
614566

615567
$repository = $this->getDoctrine()
616-
->getRepository('AppBundle:Product');
568+
->getRepository(Product::class);
617569

618570
.. note::
619571

620-
The ``AppBundle:Product`` string is a shortcut you can use anywhere
572+
You can also use ``AppBundle:Product`` syntax. This string is a shortcut you can use anywhere
621573
in Doctrine instead of the full class name of the entity (i.e. ``AppBundle\Entity\Product``).
622574
As long as your entity lives under the ``Entity`` namespace of your bundle,
623575
this will work.
624576

625577
Once you have a repository object, you can access all sorts of helpful methods::
626578

627-
$repository = $this->getDoctrine()->getRepository('AppBundle:Product');
579+
$repository = $this->getDoctrine()->getRepository(Product::class);
628580

629581
// query for a single product by its primary key (usually "id")
630582
$product = $repository->find($productId);
@@ -647,7 +599,7 @@ Once you have a repository object, you can access all sorts of helpful methods::
647599
You can also take advantage of the useful ``findBy()`` and ``findOneBy()`` methods
648600
to easily fetch objects based on multiple conditions::
649601

650-
$repository = $this->getDoctrine()->getRepository('AppBundle:Product');
602+
$repository = $this->getDoctrine()->getRepository(Product::class);
651603

652604
// query for a single product matching the given name and price
653605
$product = $repository->findOneBy(
@@ -680,10 +632,13 @@ Updating an Object
680632
Once you've fetched an object from Doctrine, updating it is easy. Suppose
681633
you have a route that maps a product id to an update action in a controller::
682634

635+
use AppBundle\Entity\Post;
636+
// ...
637+
683638
public function updateAction($productId)
684639
{
685640
$em = $this->getDoctrine()->getManager();
686-
$product = $em->getRepository('AppBundle:Product')->find($productId);
641+
$product = $em->getRepository(Product::class)->find($productId);
687642

688643
if (!$product) {
689644
throw $this->createNotFoundException(
@@ -729,7 +684,7 @@ Querying for Objects
729684
You've already seen how the repository object allows you to run basic queries
730685
without any work::
731686

732-
$repository = $this->getDoctrine()->getRepository('AppBundle:Product');
687+
$repository = $this->getDoctrine()->getRepository(Product::class);
733688

734689
$product = $repository->find($productId);
735690
$product = $repository->findOneByName('Keyboard');
@@ -790,7 +745,7 @@ depends on dynamic conditions, as your code soon becomes hard to read with
790745
DQL as you start to concatenate strings::
791746

792747
$repository = $this->getDoctrine()
793-
->getRepository('AppBundle:Product');
748+
->getRepository(Product::class);
794749

795750
// createQueryBuilder() automatically selects FROM AppBundle:Product
796751
// and aliases it to "p"

doctrine/associations.rst

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,8 @@ own a collection of its related ``Product`` objects.
189189
namespace as the targetEntity.
190190

191191
Now that you've added new properties to both the ``Product`` and ``Category``
192-
classes, tell Doctrine to generate the missing getter and setter methods for you:
193-
194-
.. code-block:: terminal
195-
196-
$ php app/console doctrine:generate:entities AppBundle
192+
classes, you must generate the missing getter and setter methods manually or
193+
using your own IDE.
197194

198195
Ignore the Doctrine metadata for a moment. You now have two classes - ``Product``
199196
and ``Category``, with a natural many-to-one relationship. The ``Product``
@@ -276,10 +273,13 @@ When you need to fetch associated objects, your workflow looks just like it
276273
did before. First, fetch a ``$product`` object and then access its related
277274
``Category`` object::
278275

276+
use AppBundle\Entity\Post;
277+
// ...
278+
279279
public function showAction($productId)
280280
{
281281
$product = $this->getDoctrine()
282-
->getRepository('AppBundle:Product')
282+
->getRepository(Product::class)
283283
->find($productId);
284284

285285
$categoryName = $product->getCategory()->getName();
@@ -306,7 +306,7 @@ You can also query in the other direction::
306306
public function showProductsAction($categoryId)
307307
{
308308
$category = $this->getDoctrine()
309-
->getRepository('AppBundle:Category')
309+
->getRepository(Category::class)
310310
->find($categoryId);
311311

312312
$products = $category->getProducts();
@@ -327,7 +327,7 @@ to the given ``Category`` object via their ``category_id`` value.
327327
example::
328328

329329
$product = $this->getDoctrine()
330-
->getRepository('AppBundle:Product')
330+
->getRepository(Product::class)
331331
->find($productId);
332332

333333
$category = $product->getCategory();
@@ -388,7 +388,7 @@ object and its related ``Category`` with just one query::
388388
public function showAction($productId)
389389
{
390390
$product = $this->getDoctrine()
391-
->getRepository('AppBundle:Product')
391+
->getRepository(Product::class)
392392
->findOneByIdJoinedToCategory($productId);
393393

394394
$category = $product->getCategory();

0 commit comments

Comments
 (0)