Skip to content

Commit adadb5a

Browse files
committed
updating best practices for DI 3.3 changes
1 parent 66f8383 commit adadb5a

File tree

3 files changed

+56
-20
lines changed

3 files changed

+56
-20
lines changed

best_practices/business-logic.rst

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -84,30 +84,41 @@ Next, define a new service for that class.
8484
8585
# app/config/services.yml
8686
services:
87-
# keep your service names short
88-
app.slugger:
89-
class: AppBundle\Utils\Slugger
87+
# ...
88+
89+
# use the class name as the service id
90+
AppBundle\Utils\Slugger:
91+
public: false
92+
93+
.. note::
9094

91-
Traditionally, the naming convention for a service involved following the
92-
class name and location to avoid name collisions. Thus, the service
93-
*would have been* called ``app.utils.slugger``. But by using short service names,
94-
your code will be easier to read and use.
95+
If you're using the :ref:`default services.yml configuration <service-container-services-load-example>`,
96+
the class is auto-registered as a service.
97+
98+
Traditionally, the naming convention for a service was a short, but unique
99+
snake case key - e.g. ``app.utils.slugger``. But for most services, you should now
100+
use the class name.
95101

96102
.. best-practice::
97103

98-
The name of your application's services should be as short as possible,
99-
but unique enough that you can search your project for the service if
100-
you ever need to.
104+
The id of your application's services should be equal to their class name,
105+
except when you have multiple services configured for the same class (in that
106+
case, use a snake case id).
101107

102108
Now you can use the custom slugger in any controller class, such as the
103109
``AdminController``:
104110

105111
.. code-block:: php
106112
107-
public function createAction(Request $request)
113+
use AppBundle\Utils\Slugger;
114+
115+
public function createAction(Request $request, Slugger $slugger)
108116
{
109117
// ...
110118
119+
// you can also fetch a public service like this, but is not the best-practice
120+
// $slugger = $this->get('app.slugger');
121+
111122
if ($form->isSubmitted() && $form->isValid()) {
112123
$slug = $this->get('app.slugger')->slugify($post->getTitle());
113124
$post->setSlug($slug);
@@ -116,6 +127,16 @@ Now you can use the custom slugger in any controller class, such as the
116127
}
117128
}
118129
130+
Services can also be :ref:`public or private <container-public>`. If you use the
131+
:ref:`default services.yml configuration <service-container-services-load-example>`,
132+
all services are private by default.
133+
134+
.. best-practice::
135+
136+
Services should be ``private`` whenever possible. This will prevent you from
137+
accessing that service via ``$container->get()``. Instead, you will need to use
138+
dependency injection.
139+
119140
Service Format: YAML
120141
--------------------
121142

best_practices/controllers.rst

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,16 +97,16 @@ for the homepage of our app:
9797
9898
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
9999
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
100+
use Doctrine\ORM\EntityManagerInterface;
100101
101102
class DefaultController extends Controller
102103
{
103104
/**
104105
* @Route("/", name="homepage")
105106
*/
106-
public function indexAction()
107+
public function indexAction(EntityManagerInterface $em)
107108
{
108-
$posts = $this->getDoctrine()
109-
->getRepository('AppBundle:Post')
109+
$posts = $em->getRepository('AppBundle:Post')
110110
->findLatest();
111111
112112
return $this->render('default/index.html.twig', array(
@@ -115,6 +115,19 @@ for the homepage of our app:
115115
}
116116
}
117117
118+
Fetching Services
119+
-----------------
120+
121+
If you extend the base ``Controller`` class, you can access services directly from
122+
the container via ``$this->container->get()`` or ``$this->get()``. Instead, you
123+
should use dependency injection to fetch services: most easily done by
124+
:ref:`type-hinting action method arguments <controller-accessing-services>`:
125+
126+
.. best-practice::
127+
128+
Don't use ``$this->get()`` or ``$this->container->get()`` to fetch services
129+
from the container. Instead, use dependency injection.
130+
118131
.. _best-practices-paramconverter:
119132

120133
Using the ParamConverter
@@ -164,13 +177,14 @@ manually. In our application, we have this situation in ``CommentController``:
164177

165178
.. code-block:: php
166179
180+
use Doctrine\ORM\EntityManagerInterface;
181+
167182
/**
168183
* @Route("/comment/{postSlug}/new", name = "comment_new")
169184
*/
170-
public function newAction(Request $request, $postSlug)
185+
public function newAction(Request $request, $postSlug, EntityManagerInterface $em)
171186
{
172-
$post = $this->getDoctrine()
173-
->getRepository('AppBundle:Post')
187+
$post = $em->getRepository('AppBundle:Post')
174188
->findOneBy(array('slug' => $postSlug));
175189
176190
if (!$post) {

best_practices/security.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,9 @@ more advanced use-case, you can always do the same security check in PHP:
224224
/**
225225
* @Route("/{id}/edit", name="admin_post_edit")
226226
*/
227-
public function editAction($id)
227+
public function editAction($id, EntityManagerInterface $em)
228228
{
229-
$post = $this->getDoctrine()->getRepository('AppBundle:Post')
229+
$post = $em->getRepository('AppBundle:Post')
230230
->find($id);
231231
232232
if (!$post) {
@@ -328,7 +328,8 @@ the same ``getAuthorEmail()`` logic you used above:
328328
}
329329
}
330330
331-
Your application will :ref:`autoconfigure <services-autoconfigure>` your security
331+
If you're using the :ref:`default services.yml configuration <service-container-services-load-example>`,
332+
your application will :ref:`autoconfigure <services-autoconfigure>` your security
332333
voter and inject a ``AccessDecisionManagerInterface`` instance in it thanks to
333334
:doc:`autowiring </service_container/autowiring>`.
334335

0 commit comments

Comments
 (0)