@@ -20,10 +20,75 @@ practices and methodologies. Symfony is flexible enough to adapt to your needs.
20
20
Creating the Project
21
21
--------------------
22
22
23
+ Use the Symfony Binary to Create Symfony Applications
24
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23
25
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:
24
29
30
+ .. code-block :: terminal
25
31
32
+ $ symfony new my_project_name
26
33
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/
27
92
28
93
Configuration
29
94
-------------
@@ -97,12 +162,61 @@ values is that it's complicated to redefine their values in your tests.
97
162
Business Logic
98
163
--------------
99
164
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.
100
175
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.
101
179
180
+ Use Autowiring to Automate the Configuration of Application Services
181
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
102
182
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.
103
187
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.
104
191
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.
105
198
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.
106
220
107
221
Controllers
108
222
-----------
@@ -120,6 +234,8 @@ controllers shouldn't contain any business logic. Controllers should contain
120
234
nothing more than a few lines of *glue-code *, so you are not coupling the
121
235
important parts of your application.
122
236
237
+ .. _best-practice-controller-annotations :
238
+
123
239
Use Annotations to Configure Routing, Caching and Security
124
240
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
125
241
@@ -157,7 +273,7 @@ to your controller. It will also show a 404 page if no entity can be found.
157
273
158
274
If the logic to get an entity from a route variable is more complex, instead of
159
275
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 >`).
161
277
162
278
Templates
163
279
---------
@@ -187,12 +303,41 @@ with an underscore to better differentiate them from complete templates (e.g.
187
303
Forms
188
304
-----
189
305
306
+ Define your Forms as PHP Classes
307
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
190
308
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.
191
312
313
+ Add Form Buttons in Templates
314
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
192
315
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.
193
319
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.
194
324
325
+ Define Validation Constraints on the Underlying Object
326
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
195
327
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.
196
341
197
342
Internationalization
198
343
--------------------
@@ -223,11 +368,30 @@ would be ``label.username``, *not* ``edit_form.label.username``.
223
368
Security
224
369
--------
225
370
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.
226
377
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.
227
381
382
+ Use the ``auto `` Password Hasher
383
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
228
384
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 ``.
229
388
389
+ Use Voters to Implement Fine-grained Security Restrictions
390
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
230
391
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.
231
395
232
396
Web Assets
233
397
----------
@@ -301,6 +465,8 @@ from routes. Whenever a route changes, tests will break and you'll know that
301
465
you must set up a redirection.
302
466
303
467
.. _`Symfony Demo` : https://github.com/symfony/demo
468
+ .. _`download Symfony` : https://symfony.com/download
469
+ .. _`Composer` : https://getcomposer.org/
304
470
.. _`ParamConverter` : https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
305
471
.. _`feature toggles` : https://en.wikipedia.org/wiki/Feature_toggle
306
472
.. _`smoke testing` : https://en.wikipedia.org/wiki/Smoke_testing_(software)
0 commit comments