Symfony best practices
Here is a digest of the best practices that are commonly followed for Symfony2 projects. They are given as is, in no particular order and are far from being exhaustive.
Naming things
- find a common naming scheme for your team and stick to it
- be explicit
- be consistent
- same for routes and services naming
- use service alias:
mailer
is better thanswiftmailer.mailer.default
- use service alias:
- prefer
Vendor/Bundle/CoolBundle
overVendor/CoolBundle
for bundles namespace- for an application, you can even skip the vendor part
Config
Which configuration format should you use?
- bundles config: YAML
- routes: YAML
- entities: YAML/XML
- validation, serializer: YAML
- services: YAML (XML for some use cases)
Create a routing.yml
file per bundle and import it in app/config/routing.yml
.
Nest your routing files using prefixes.
Split vendor bundles configurations and import them in app/config/config.yml
.
Split validation configuration files.
Bundles
- should be self-contained
- should provide a feature, not an app (examples: Forum, Admin, …)
- should follow bundles structure standards
Controllers
- should be lightweight
- do not put logic in them, write handlers/services instead
- avoid extending FrameworkBundle/Controller (especially if your controller is meant to be distributed)
- see http://richardmiller.co.uk/2011/06/14/symfony2-moving-away-from-the-base-controller/
- define them as services
- inject the request into controller actions parameters
- do not hesitate to dispatch events for “add-on actions”
- use Form handlers/persistence handlers
DependencyInjection
- do not inject the Container (except for some scope-related use cases)
- see RequestStack
- see synchronized services
- split services definition into several files
- bonus: easy dynamic loading of services (per env for instance)
- use a semantic configuration
- inject configuration parameters in your services
- environment variables (defined in apache/nginx) can be used!
- know how tagged services and compiler passes work
Dependencies management
- (learn how-to) use composer
- group you dependencies by “theme” in your composer.json
- do not commit your
vendor
directory or composer.phar, only commit composer.json and composer.lock - use
composer.phar install --no-dev --optimize-autoloader --prefer-dist
in prod - do not require
dev-master
unless you absolutely have to - use bounded versions constraints
- BAD :
>=1.2.0
- GOOD:
>=1.2.0,<2.0.0
- BETTER:
~1.2
- BAD :
- know about composer stability flags
- avoid optional dependencies
Forms
- use Type classes
- always set a default
data_class
- define types as services
- do not disable CSRF (except for API)
- set the
intention
option
Doctrine
- activate caches: metadata cache, query cache, result cache
- and don’t forget to clear these caches when you deploy
- register repositories as services and inject them
- do not write queries outside repositories
- only flush from the controller
Tools
- PHP-CS-Fixer
- use static analysis tools
- XHProf + XHProf.io
- xdebug + kcachegrind
- sismo
- Travis-CI
- Scrutinizer
- Vagrant
- capifony
Useful bundles
- FOS
- StofDoctrineExtensionsBundle
- e-commerce
- Sonata
- Admin, User
- SEO, media, news, …
- i18n, cache, …
- http://sonata-project.org/bundles/
- GenemuFormBundle
- WebProfilerExtraBundle
- LexikMaintenanceBundle
- BazingaFakerBundle
- BazingaJsTranslationBundle
- LiipFunctionalTestBundle
- VichUploaderBundle
Miscellaneous
- add a .gitignore: only commit your own code
- PHP The right way
- PSR-0, PSR-1, PSR-2 and be aware of PSR-3
- use APC
- use xdebug (in dev env)
- store sessions in the database or in memcached
- translations
- work with translation keys instead of sentences
- check for missing translations with tools (like https://github.com/maisonsdumonde/MDMTranslatorCheckerBundle)
- be pragmatic!