Skip to content
  • About
    • What is Symfony?
    • Community
    • News
    • Contributing
    • Support
  • Documentation
    • Symfony Docs
    • Symfony Book
    • Screencasts
    • Symfony Bundles
    • Symfony Cloud
    • Training
  • Services
    • Platform.sh for Symfony Best platform to deploy Symfony apps
    • SymfonyInsight Automatic quality checks for your apps
    • Symfony Certification Prove your knowledge and boost your career
    • SensioLabs Professional services to help you with Symfony
    • Blackfire Profile and monitor performance of your apps
  • Other
  • Blog
  • Download
sponsored by
  1. Home
  2. Documentation
  3. Symfony: The Fast Track
  4. English
  5. Branching the Code

Branching the Code

There are many ways to organize the workflow of code changes in a project. But working directly on the Git master branch and deploying directly to production without testing is probably not the best one.

Testing is not just about unit or functional tests, it is also about checking the application behavior with production data. If you or your stakeholders can browse the application exactly as it will be deployed to end users, this becomes a huge advantage and allows you to deploy with confidence. It is especially powerful when non-technical people can validate new features.

We will continue doing all the work in the Git master branch in the next steps for simplicity sake and to avoid repeating ourselves, but let's see how this could work better.

Adopting a Git Workflow

One possible workflow is to create one branch per new feature or bug fix. It is simple and efficient.

Creating Branches

The workflow starts with the creation of a Git branch:

1
$ git branch -D sessions-in-db || true
1
$ git checkout -b sessions-in-db

This command creates a sessions-in-db branch from the master branch. It "forks" the code and the infrastructure configuration.

Storing Sessions in the Database

As you might have guessed from the branch name, we want to switch session storage from the filesystem to a database store (our PostgreSQL database here).

The needed steps to make it a reality are typical:

  1. Create a Git branch;
  2. Update the Symfony configuration if needed;
  3. Write and/or update some code if needed;
  4. Update the PHP configuration if needed (like adding the PostgreSQL PHP extension);
  5. Update the infrastructure on Docker and Platform.sh if needed (add the PostgreSQL service);
  6. Test locally;
  7. Test remotely;
  8. Merge the branch to master;
  9. Deploy to production;
  10. Delete the branch.

To store sessions in the database, change the session.handler_id configuration to point to the database DSN:

1
2
3
4
5
6
7
8
9
10
11
--- a/config/packages/framework.yaml
+++ b/config/packages/framework.yaml
@@ -7,7 +7,7 @@ framework:
     # Enables session support. Note that the session will ONLY be started if you read or write from it.
     # Remove or comment this section to explicitly disable session support.
     session:
-        handler_id: null
+        handler_id: '%env(DATABASE_URL)%'
         cookie_secure: auto
         cookie_samesite: lax
         storage_factory_id: session.storage.factory.native

To store sessions in the database, we need to create the sessions table. Do so with a Doctrine migration:

1
$ symfony console make:migration

Edit the file to add the table creation in the up() method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
--- a/migrations/Version00000000000000.php
+++ b/migrations/Version00000000000000.php
@@ -21,6 +21,14 @@ final class Version00000000000000 extends AbstractMigration
     {
         // this up() migration is auto-generated, please modify it to your needs

+        $this->addSql('
+            CREATE TABLE sessions (
+                sess_id VARCHAR(128) NOT NULL PRIMARY KEY,
+                sess_data BYTEA NOT NULL,
+                sess_lifetime INTEGER NOT NULL,
+                sess_time INTEGER NOT NULL
+            )
+        ');
     }

     public function down(Schema $schema): void

Migrate the database:

1
$ symfony console doctrine:migrations:migrate

Test locally by browsing the website. As there are no visual changes and because we are not using sessions yet, everything should still work as before.

Note

We don't need steps 3 to 5 here as we are re-using the database as the session storage, but the chapter about using Redis shows how straightforward it is to add, test, and deploy a new service in both Docker and Platform.sh.

As the new table is not "managed" by Doctrine, we must configure Doctrine to not remove it in the next database migration:

1
2
3
4
5
6
7
8
9
10
11
--- a/config/packages/doctrine.yaml
+++ b/config/packages/doctrine.yaml
@@ -5,6 +5,8 @@ doctrine:
         # IMPORTANT: You MUST configure your server version,
         # either here or in the DATABASE_URL env var (see .env file)
         #server_version: '13'
+
+        schema_filter: ~^(?!session)~
     orm:
         auto_generate_proxy_classes: true
         naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware

Commit your changes to the new branch:

1
2
$ git add .
$ git commit -m'Configure database sessions'

Deploying a Branch

Before deploying to production, we should test the branch on the same infrastructure as the production one. We should also validate that everything works fine for the Symfony prod environment (the local website used the Symfony dev environment).

Now, let's create a Platform.sh environment based on the Git branch:

1
$ symfony cloud:env:delete sessions-in-db
1
$ symfony cloud:deploy

This command creates a new environment as follows:

  • The branch inherits the code and infrastructure from the current Git branch (sessions-in-db);
  • The data come from the master (aka production) environment by taking a consistent snapshot of all service data, including files (user uploaded files for instance) and databases;
  • A new dedicated cluster is created to deploy the code, the data, and the infrastructure.

As the deployment follows the same steps as deploying to production, database migrations will also be executed. This is a great way to validate that the migrations work with production data.

The non-master environments are very similar to the master one except for some small differences: for instance, emails are not sent by default.

Once the deployment is finished, open the new branch in a browser:

1
$ symfony cloud:url -1

Note that all Platform.sh commands work on the current Git branch. This command opens the deployed URL for the sessions-in-db branch; the URL will look like https://sessions-in-db-xxx.eu-5.platformsh.site/.

Test the website on this new environment, you should see all the data that you created in the master environment.

If you add more conferences on the master environment, they won't show up in the sessions-in-db environment and vice-versa. The environments are independent and isolated.

If the code evolves on master, you can always rebase the Git branch and deploy the updated version, resolving the conflicts for both the code and the infrastructure.

You can even synchronize the data from master back to the sessions-in-db environment:

1
$ symfony cloud:env:sync

Debugging Production Deployments before Deploying

By default, all Platform.sh environments use the same settings as the master/prod environment (aka the Symfony prod environment). This allows you to test the application in real-life conditions. It gives you the feeling of developing and testing directly on production servers, but without the risks associated with it. This reminds me of the good old days when we were deploying via FTP.

In case of a problem, you might want to switch to the dev Symfony environment:

1
$ symfony cloud:env:debug

When done, move back to production settings:

1
$ symfony cloud:env:debug --off

Warning

Never enable the dev environment and never enable the Symfony Profiler on the master branch; it would make your application really slow and open a lot of serious security vulnerabilities.

Testing Production Deployments before Deploying

Having access to the upcoming version of the website with production data opens up a lot of opportunities: from visual regression testing to performance testing. Blackfire is the perfect tool for the job.

Refer to the step about Performance to learn more about how you can use Blackfire to test your code before deploying.

Merging to Production

When you are satisfied with the branch changes, merge the code and the infrastructure back to the Git master branch:

1
2
$ git checkout master
$ git merge sessions-in-db

And deploy:

1
$ symfony cloud:deploy

When deploying, only the code and infrastructure changes are pushed to Platform.sh; the data are not affected in any way.

Cleaning up

Finally, clean up by removing the Git branch and the Platform.sh environment:

1
2
$ git branch -d sessions-in-db
$ symfony cloud:env:delete -e sessions-in-db

Going Further

  • Git branching;
Previous page Building the User Interface
Next page Listening to Events
This work, including the code samples, is licensed under a Creative Commons BY-NC-SA 4.0 license.
TOC
    Version

    Symfony 5.4 is backed by

    Online exam, become Symfony certified today

    Online exam, become Symfony certified today

    The life jacket for your team and your project

    The life jacket for your team and your project

    Version:
    Locale:
    ebook

    This book is backed by:

    see all backers

    Symfony footer

    Avatar of Vlad Gregurco, a Symfony contributor

    Thanks Vlad Gregurco (@vgregurco) for being a Symfony contributor

    10 commits • 290 lines changed

    View all contributors that help us make Symfony

    Become a Symfony contributor

    Be an active part of the community and contribute ideas, code and bug fixes. Both experts and newcomers are welcome.

    Learn how to contribute

    Symfony™ is a trademark of Symfony SAS. All rights reserved.

    • What is Symfony?

      • What is Symfony?
      • Symfony at a Glance
      • Symfony Components
      • Symfony Releases
      • Security Policy
      • Logo & Screenshots
      • Trademark & Licenses
      • symfony1 Legacy
    • Learn Symfony

      • Symfony Docs
      • Symfony Book
      • Reference
      • Bundles
      • Best Practices
      • Training
      • eLearning Platform
      • Certification
    • Screencasts

      • Learn Symfony
      • Learn PHP
      • Learn JavaScript
      • Learn Drupal
      • Learn RESTful APIs
    • Community

      • Symfony Community
      • SymfonyConnect
      • Events & Meetups
      • Projects using Symfony
      • Contributors
      • Symfony Jobs
      • Backers
      • Code of Conduct
      • Downloads Stats
      • Support
    • Blog

      • All Blog Posts
      • A Week of Symfony
      • Case Studies
      • Cloud
      • Community
      • Conferences
      • Diversity
      • Living on the edge
      • Releases
      • Security Advisories
      • Symfony Insight
      • Twig
      • SensioLabs Blog
    • Services

      • SensioLabs services
      • Train developers
      • Manage your project quality
      • Improve your project performance
      • Host Symfony projects

      Powered by

    Follow Symfony