Skip to content

Commit 47aab81

Browse files
committed
Finished moving the best practices
1 parent 7dd787b commit 47aab81

File tree

9 files changed

+177
-995
lines changed

9 files changed

+177
-995
lines changed

best_practices.rst

Lines changed: 167 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,75 @@ practices and methodologies. Symfony is flexible enough to adapt to your needs.
2020
Creating the Project
2121
--------------------
2222

23+
Use the Symfony Binary to Create Symfony Applications
24+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2325

26+
The Symfony binary is an executable command created in your machine when you
27+
`download Symfony`_. It provides multiple utilities, including the simplest way
28+
to create new Symfony applications:
2429

30+
.. code-block:: terminal
2531
32+
$ symfony new my_project_name
2633
34+
Under the hood, this Symfony binary command executes the needed `Composer`_
35+
command to create a new Symfony application based on the current stable version.
36+
37+
Use the Symfony Skeleton to Create New Symfony-based Projects
38+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
39+
40+
Symfony provides two "skeletons" (or "project templates") to
41+
:ref:`create new Symfony projects <creating-symfony-applications>`. Use the
42+
minimal "skeleton" to start small and get the best performance and grow your
43+
application later as needed.
44+
45+
Use Composer and Symfony Flex to Manage Symfony Applications
46+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
47+
48+
`Composer`_ is the package manager used by modern PHP applications to manage
49+
their dependencies. :ref:`Symfony Flex <symfony-flex>` is a Composer plugin
50+
designed to automate some of the most common tasks performed in Symfony
51+
applications. Using Flex is optional but recommended because it improves your
52+
productivity significantly.
53+
54+
Use the Directory Structure Proposed by Flex
55+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
56+
57+
Unless your project follows a development practice that imposes a certain
58+
directory structure, follow the structure proposed by Symfony Flex. It's flat,
59+
self-explanatory and not coupled to Symfony:
60+
61+
.. code-block:: text
62+
63+
your_project/
64+
├─ assets/
65+
├─ bin/
66+
│ └─ console
67+
├─ config/
68+
│ ├─ packages/
69+
│ └─ services.yaml
70+
└─ public/
71+
│ ├─ build/
72+
│ └─ index.php
73+
├─ src/
74+
│ ├─ Kernel.php
75+
│ ├─ Command/
76+
│ ├─ Controller/
77+
│ ├─ DataFixtures/
78+
│ ├─ Entity/
79+
│ ├─ EventSubscriber/
80+
│ ├─ Form/
81+
│ ├─ Migrations/
82+
│ ├─ Repository/
83+
│ ├─ Security/
84+
│ └─ Twig/
85+
├─ templates/
86+
├─ tests/
87+
├─ translations/
88+
├─ var/
89+
│ ├─ cache/
90+
│ └─ log/
91+
└─ vendor/
2792
2893
Configuration
2994
-------------
@@ -97,12 +162,61 @@ values is that it's complicated to redefine their values in your tests.
97162
Business Logic
98163
--------------
99164

165+
Don't Create any Bundle to Organize your Application Logic
166+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
167+
168+
When Symfony 2.0 was released, Symfony applications used bundles to divide their
169+
code into logical features: UserBundle, ProductBundle, InvoiceBundle, etc.
170+
171+
However, a bundle is meant to be something that can be reused as a stand-alone
172+
piece of software. If UserBundle cannot be used "as is" in other Symfony
173+
applications, then it shouldn't be its own bundle. Moreover, if InvoiceBundle
174+
depends on ProductBundle, then there's no advantage to having two separate bundles.
100175

176+
Symfony applications can still use third-party bundles (installed in ``vendor/``)
177+
to add features, but you should use PHP namespaces instead of bundles to organize
178+
your own code.
101179

180+
Use Autowiring to Automate the Configuration of Application Services
181+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
102182

183+
:doc:`Service autowiring </service_container/autowiring>` is a feature that
184+
reads the type-hints on your constructor (or other methods) and automatically
185+
passes the correct services to each method, making unnecessary to configure
186+
services explicitly and simplifying the application maintenance.
103187

188+
Use it in combination with :ref:`service autoconfiguration <services-autoconfigure>`
189+
to also add :doc:`service tags </service_container/tags>` to the services
190+
needing them, such as Twig extensions, event subscribers, etc.
104191

192+
Services Should be Private Whenever Possible
193+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
194+
195+
:ref:`Make services private <container-public>` to prevent you from accessing
196+
those services via ``$container->get()``. Instead, you will need to use proper
197+
dependency injection.
105198

199+
Use the YAML Format to Configure your Own Services
200+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
201+
202+
If you use the :ref:`default services.yaml configuration <service-container-services-load-example>`,
203+
most services will be configured automatically. However, in some edge cases
204+
you'll need to configure services (or parts of them) manually.
205+
206+
YAML is the format recommended to configure services because it's friendly to
207+
newcomers and concise, but Symfony also supports XML and PHP configuration, so
208+
you can use whatever format you like.
209+
210+
Use Annotations to Define the Doctrine Entity Mapping
211+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
212+
213+
Doctrine entities are plain PHP objects that you store in some "database".
214+
Doctrine only knows about your entities through the mapping metadata configured
215+
for your model classes.
216+
217+
Doctrine supports several metadata formats, but it's recommended to use
218+
annotations because they are by far the most convenient and agile way of setting
219+
up and looking for mapping information.
106220

107221
Controllers
108222
-----------
@@ -120,6 +234,8 @@ controllers shouldn't contain any business logic. Controllers should contain
120234
nothing more than a few lines of *glue-code*, so you are not coupling the
121235
important parts of your application.
122236

237+
.. _best-practice-controller-annotations:
238+
123239
Use Annotations to Configure Routing, Caching and Security
124240
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
125241

@@ -157,7 +273,7 @@ to your controller. It will also show a 404 page if no entity can be found.
157273

158274
If the logic to get an entity from a route variable is more complex, instead of
159275
configuring the ParamConverter, it's better to make the Doctrine query inside
160-
the controller (e.g. by calling to a :ref:`Doctrine repository method </doctrine>`).
276+
the controller (e.g. by calling to a :doc:`Doctrine repository method </doctrine>`).
161277

162278
Templates
163279
---------
@@ -187,12 +303,41 @@ with an underscore to better differentiate them from complete templates (e.g.
187303
Forms
188304
-----
189305

306+
Define your Forms as PHP Classes
307+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
190308

309+
Creating :ref:`forms in classes <creating-forms-in-classes>` allows to reuse
310+
them in different parts of the application. Besides, not creating forms in
311+
controllers simplify the code and maintenance of the controllers.
191312

313+
Add Form Buttons in Templates
314+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
192315

316+
Form classes should be agnostic to where they will be used. For example, the
317+
button of a form used to both create and edit items should change from "Add new"
318+
to "Save changes" depending on where it's used.
193319

320+
Instead of adding buttons in form classes or the controllers, it's recommended
321+
to add buttons in the templates. This also improves the separation of concerns,
322+
because the button styling (CSS class and other attributes) is defined in the
323+
template instead of in a PHP class.
194324

325+
Define Validation Constraints on the Underlying Object
326+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
195327

328+
Attaching :doc:`validation constraints </reference/constraints>` to form fields
329+
instead of to the mapped object prevents the validation from being reused in
330+
other forms or other places where the object is used.
331+
332+
.. _best-practice-handle-form:
333+
334+
Use a Single Action to Render and Process the Form
335+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
336+
337+
:ref:`Rendering forms <rendering-forms>` and :ref:`processing forms <processing-forms>`
338+
are two of the main tasks when handling forms. Both are too similar (most of the
339+
times, almost identical), so it's much simpler to let a single controller action
340+
handle everything.
196341

197342
Internationalization
198343
--------------------
@@ -223,11 +368,30 @@ would be ``label.username``, *not* ``edit_form.label.username``.
223368
Security
224369
--------
225370

371+
Define a Single Firewall
372+
~~~~~~~~~~~~~~~~~~~~~~~~
373+
374+
Unless you have two legitimately different authentication systems and users
375+
(e.g. form login for the main site and a token system for your API only), it's
376+
recommended to have only one firewall to keep things simple.
226377

378+
Additionally, you should use the ``anonymous`` key under your firewall. If you
379+
require users to be logged in for different sections of your site, use the
380+
:doc:`access_control </security/access_control>` option.
227381

382+
Use the ``auto`` Password Hasher
383+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
228384

385+
The :ref:`auto password hasher <reference-security-encoder-auto>` automatically
386+
selects the best possible encoder/hasher depending on your PHP installation.
387+
Currently, it tries to use ``sodium`` by default and falls back to ``bcrypt``.
229388

389+
Use Voters to Implement Fine-grained Security Restrictions
390+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
230391

392+
If your security logic is complex, you should create custom
393+
:doc:`security voters </security/voters>` instead of defining long expressions
394+
inside the ``@Security`` annotation.
231395

232396
Web Assets
233397
----------
@@ -301,6 +465,8 @@ from routes. Whenever a route changes, tests will break and you'll know that
301465
you must set up a redirection.
302466

303467
.. _`Symfony Demo`: https://github.com/symfony/demo
468+
.. _`download Symfony`: https://symfony.com/download
469+
.. _`Composer`: https://getcomposer.org/
304470
.. _`ParamConverter`: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
305471
.. _`feature toggles`: https://en.wikipedia.org/wiki/Feature_toggle
306472
.. _`smoke testing`: https://en.wikipedia.org/wiki/Smoke_testing_(software)

0 commit comments

Comments
 (0)