Symfony 2 Checklist for Development and Deployment

Taylor Ren

In my Building a Personal Web App Head To Toe With Symfony 2 series published on Sitepoint, I have covered some basics in bootstrapping, development and finalizing (on some advanced techniques) to use Symfony 2 to develop a web application. However, due to the length limitation of the series, we have not covered much on the “final” step: To deploy a Symfony 2 application to the production environment.

When we do development, most likely we are in a “root” role; but in a production environment, we may be deprived of this privilege. Also, the settings may be different. To make things worse, sometimes we are not able to change these settings as we do in our own machines.

Thus, it is of great importance to check the “compatibility” of our production server BEFORE any real development is done in our own server. This will avoid such horrible situations like: a library that Symfony depends on is missing, some global settings which the app relies on are unchangeable, etc.

Testing the “compatibility” of our production server should really be something we do at the very beginning. There are also some other aspects to be addressed during deployment – such as templates for various error messages, etc.

In the following sections, we’ll be assuming you don’t have full control over your production server. If you do, most of the compatibility issues probably don’t apply, as you should be able to resolve them yourself quite easily.

An empty Symfony framework on the production server

Please follow the instructions in my first article on Symfony 2 to set up an empty Symfony framework on the production server.

This is also useful to test if the server has cURL enabled, not only installed on the server but also as a PHP extension, making sure we can grab external resources. In my particular case, this is very important – composer.org is blocked in my country and I need to use a proxy to fetch and install the Symfony Framework.

This empty framework can later be checked into version control.

The config file

Symfony 2 comes with a config.php file which resides in the web directory. This is the script to test most of the “readiness” issue. To visit that page, we need to tweak it a bit:

<?php

if (!isset($_SERVER['HTTP_HOST'])) {
    exit('This script cannot be run from the CLI. Run it from a browser.');
}

if (!in_array(@$_SERVER['REMOTE_ADDR'], array(
    '127.0.0.1',
    '::1',
))) {
    header('HTTP/1.0 403 Forbidden');
    exit('This script is only accessible from localhost.');
}
...

This file is meant to be called from a local browser only. We need to comment out the second if block so that we can visit it remotely.

My server is configured correctly and does not have any critical issues:

This file tests the readiness issues which I summarize in the table below. The actual testing is done in app/SymfonyRequirements.php so we can also take a look at that file.

Settings/Modules Requirement Seriousness Actions
PHP version
= 5.3.3

Required but must NOT be 5.3.16 Upgrade to latest version. Suggest to use at least PHP 5.4.8 and above.
Vendor libraries Installed by composer.phar Required Update using composer.phar
cache, logs directory Writable Required By issuing chmod to grant permissions. Normally, the privilege should be 755 or 777.
Timezone Something like 'Asia/Shanghai' or your timezone Required Change php.ini.
json_encode, session_start, ctype_alpha, token_get_all, simplexml_import_dom Enabled Required Enable respective PHP libraries. Most PHP servers have these enabled.
APC Enabled/Disabled Enabled if APC is used Enable APC or disable APC if you are using another cache/accelerator.
xdebug Various settings Required, Recommended Change xdebug settings accordingly.
DomDocument, mb_strlen, icony, utf8_decode, intl, etc Various modules Recommended Enable if you wish.
Accelerators Various settings Recommended Install and enable per your request.
<? short open tag, magic_quotes_gpc, register_globals, session.auto_start Disabled Recommended Suggest to follow the suggestions. PHP latest versions have some of them disabled by default.
PDO Database driver Recommended Please do install and enable it. It is mandatory if you are using Doctrine ORM.

A seriousness level of “Required” means we have to change our server settings to meet the requirement. Otherwise, Symfony 2 won’t be running and thus should not be the right choice for our application development. A “Recommended” item can be safely ignored but I do suggest we fulfill those recommendations as much as we can. In my case (shown above), my production server only has one warning. That establishes a solid and reliable ground for further development.

Using git to sync files

During development, you may, instead of copying the files to the production server, want to use version control to sync local changes to the remote site.

In that case, a proper .gitignore (or equivalent in other version control systems) will become handy. The below excerpt from my .gitignore file is for reference:

# Composer
vendor
vendor/*
!public/assets/js/vendor
!public/assets/js/vendor/*
!public/assets/css/vendor
!public/assets/css/vendor/*
composer.phar
composer.lock

# Symfony
app/cache/*
app/logs/*

# Logs
error.log
access.log

# Netbeans
nbproject
.nbproject
.nbproject/*
nbproject/*
nbproject/private/
build/
nbbuild/
dist/
nbdist/
nbactions.xml
nb-configuration.xml

This is never an exhaustive or fit-all-purposes list. For example, if you use PhpStorm but not Netbeans, you can delete the Netbeans section and replace with filters fit for PhpStorm:

# IntelliJ - PhpStorm and PyCharm
.idea
.idea/
.idea/*
*.iml
*.ipr
*.iws 

Or just leave them both in, so you automatically accommodate other devs who may be using other IDEs. It is recommended to always include the first 3 sections (Composer, Symfony, Logs).

Clearing cache

The first time a Symfony app runs on a remote server, it will create a compiled version of our app in the app/cache/prod directory. When our files, especially our controllers and routes, are updated, we need to refresh the cache, or the output may be incorrect and often causes 500 errors.

To clear the cache, I will normally SSH to my production server and do a rm -rf cache command under app directory. The console cache:clear or console cache:warmup command may not be the cleanest way to do so.

Remote dev mode

Use this with caution and only when absolutely necessary!

In some cases, a local functioning site may just crash when it is deployed to the production server. The reasons causing this may be complex and not related to the coding process itself. In these circumstances, we can consider enabling the remote dev mode.

To do this, we take the similar approach to disable the localhost check by commenting the below code block in app_dev.php:

// This check prevents access to debug front controllers that are deployed by accident to production servers.
// Feel free to remove this, extend it, or make something more sophisticated.
if (isset($_SERVER['HTTP_CLIENT_IP'])
    || isset($_SERVER['HTTP_X_FORWARDED_FOR'])
    || !in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', 'fe80::1', '::1'))
) {
    header('HTTP/1.0 403 Forbidden');
    exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
} 

We can then visit the domain and pages with something like: http://rsywx_remote/app_dev.php. When something goes wrong, this dev mode displays more useful debug information and can help us a lot to find some deep rooted issues. For added security during this debug period, add a check that only allows visits from your own IP to the above file – this will keep the dev mode off for everyone else. Most of the issues will be related to database setup (wrong database and/or credentials), wrong API URIs (local and remote URIs may be different), outdated cache, missing libraries used locally but not enabled remotely, etc.

When the problems have been fixed, please do remember to un-comment those lines to restore full access control. Regular users shall only be allowed to use app.php as our app’s entry point.

Customize the error pages

Symfony 2’s default Twig template engine does provide some error pages (404, 500, etc). But the design of these pages will usually not fit our application. The official site has the detailed explanation on how to do this. We can develop our own error pages based on our own layout and theme.

We can customize the error pages and put them under app/Resources/TwigBundle/views/Exception. The files can be named error404.html.twig for 404 errors, error403.html.twig for 403 errors, etc, or just error.html.twig for general purposes.

It’s important to note that in Symfony 2, error message pages do not support the Twig template extension. This means we cannot have an error page extended from a existing layout designed for other pages. We have to design the error pages from scratch. This is a bit inconvenient but still worth doing for a serious site.

Conclusion

In this article, we have covered some Symfony deployment related topics: the server readiness, version control, remote dev mode, cache update, error pages customization, etc.

Deployment is usually the final step in our development. I do hope this article helped you avoid some common pitfals and made your deployment process more smooth.

Please reshare this article if you’ve found it interesting or useful, and leave a comment below if you have feedback, it’s much appreciated!

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Taylor Ren

    One more thing:

    One of the reasons to customize the error pages in production environment is that in dev mode, any error prompted will be handled by app_dev.php with helpful debug messages. Only in prod environment, the customized error pages will be displayed.

  • Taylor Ren

    Another one more thing:

    Re-test the template including/extending in error pages. It seems working. Could be because of recent Symfony 2/Twig update. Welcome trials and feedbacks on this.

  • sebastiaan hilbers

    My tip: clear and warm cache when you have deployed on production because the DIC container file will have absolute positions of where to find files

  • Taylor Ren

    I choose to ignore composer.lock is because you may want to update the Symfony 2 and related stuffs on your production site. The lock file is more useful when you distribute your app to another one and want to restrict, maintain the consistency.

    • Kuba Turek

      I don’t agree. Because of few reasons:
      * testing application. When you run CI, you’d like to have the same dependencies you’ve been working on while developing the code. Then you test application with dependencies with different version than you’ve been working on.
      * deploying application. You also want to have your dependencies on production server in the same version as in your local developer machine.
      * team work. You want your coworker to have EXACTLY the same version as you already have.

      I read many pros and cons about keeping composer.lock in VCS. But there are so many advantages to keep composer.lock versioned.. because it’s worth it! :)

  • https://www.peternijssen.nl/ Peter Nijssen

    Instead of opening up the config.php file to the outside world, I prefer to run “php app/check.php” in the console. Only problem could be that you are using a different php.ini for CLI.

    • Taylor Ren

      Yes Peter. That is my point too. CLI ini may not be the same as the Apache used ini.

  • http://www.bitfalls.com/ Bruno Skvorc

    Excellent feedback, thanks!

  • Taylor Ren

    Thanks for the heads up!

    I explained below on composer.lock ignorance.

    On exposing the app_dev.php, the log file is not omnipotent.

    Thanks for the tip on the cache side.