Symfony 4 is the newest version of one of the most famous PHP frameworks. It was released November 30, 2017, and is having great success! One of the biggest differences between this version and older ones is the presence of very small dependencies installed when you init your Symfony 4 project. Symfony 4 is so tiny that the Silex project has been dismissed.
In order to create a new Symfony 4 application, you need to have PHP 7.1 (or higher) and Composer installed. With Composer installed, you can create the project by launching this command into your console:
composer create-project Symfony/website-skeleton my-project
This is the command used for traditional web applications that download a Symfony project’s base skeleton with a ready-to-start default configuration. If you are building microservices, console applications, or APIs, consider using the much simpler skeleton project:
composer create-project symfony/skeleton my-project
In this version, there are no bundles installed, so it’s smaller.
Symfony 4 has changed its directory structure quite a bit in accordance with frameworks and community requests. Now, the new directory structure is:
app/ – The application configuration, templates, and translations where you can find the AppKernel file (the main entry point of an application’s configuration).
bin/ – Executable files (e.g., bin/console).
src/ – The project’s PHP code where you have controllers, templates, and entity directories. There isn’t a main bundle in this folder because Symfony 4’s idea was to have a single project instead of many packages within a project.
tests/ – Automatic tests (e.g., unit tests with PHPUnit, Behat, etc.)
var/ – Generated files (cache, logs, etc.)
vendor/ – External libraries installed by the composer.
public/ – The webroot directory where public and static files are stored like images, stylesheets, and JavaScript files – this folder is the old “web” folder.
When designing your system, you may want to have different variables that are not the same in other environments. In previous Symfony versions, you would put that variable into a file called parameters.yml in parameters.yml.yourenv
. In Symfony 4, that file doesn’t exist (you can change your code to use it, but it’s a little complex), so you have to write those variables in a file called .env
in the project root. You can have different .env
files, but that will depend on how many environments you have in your application. Here is a sample .env
file:
DB_USER=root
DB_PASS=pass
You can also use variables inside it, like this:
DB_USER=root
DB_PASS=${DB_USER}pass
The component reading those files is the Dotenv component that parses .env
files to make environment variables stored in them accessible (via getenv(), $_ENV, or $_SERVER). If you don’t already have the Dotenv component in your project, you can launch the following command to form your CLI:
composer require symfony/dotenv
To get the value of an environment variable, use the following syntax inside your code:
$dbUser = getenv('DB_USER');
Remember, Symfony Dotenv never overwrites existing environment variables.
Autowiring is one of the most powerful features in Symfony 4 (you’ve been able to use it since the Symfony 3.3 version). It allows you to manage services in the container with minimal configuration, without specifying, for example, all the arguments that have to be passed to your service (now controllers are also
services). So, if you have a service class where you need to pass into the __construct
method, know that, with some other services, you’ll only need to enable auto wiring and Symfony will do it for you!
Example:
namespace App\Service;
use App\Util\Bar;
use Psr\Log\LoggerInterface;
class Foo
{
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
}
In the older method, you needed to do this into your services.yml,
app.foo:
class:AppBundle\Services\Foo
arguments:['@logger']
In this new version you can do this:
app.foo:
class:AppBundle\Services\Foo
public: true
So, you’ll only need to specify public as true. Since you have plenty of arguments to declare many services, you will gain save time!
Services aren’t public, so you’ll need to render it true into services.yml:
services:
_defaults:
autowire: true
autoconfigure: true
public: true
This is the default configuration of your services and, as you can see, it’s under _defaults
. If you want to have a different configuration for your service, for example, a private service, you can write this:
services:
_defaults:
autowire: true
autoconfigure: true
public: true
App\Services\YourService:
class:App\Services\YourService
public: false
So, the Autowire option indicates to Symfony to automatically inject dependencies in your services. The Autoconfigure option indicates that Symfony should automatically register your services as commands, event subscribers, etc.
Controllers are also services, so it’s easy to make unit tests on them instead of using slow integration tests. Now, you can inject services inside your controller, like this:
public function index(LoggerInterface $logger)
{
$logger->info('This is a injected service!');
//code
}
With this action, you can inject LoggerInterface directly without having to instantiate it inside the action!
Symfony Flex is a Composer plugin called when you run the require composer
, update composer
, or remove composer
commands. When you run those flex search commands inside Symfony Flex, the server will take it, install it and configure it for you if the package is on there. The power of Flex is that you don’t have to watch all the libraries’ readme files to configure your package because there is a recipe that does it for you. You don’t need to add your new bundle into AppKernel.php because flex already did it when you install it. If your package doesn’t exist, the server will fallback on Composer standard behavior.
Flex keeps track of the recipes it installed in a symfony.lock file that must be committed to your code repository. Recipes are stored in two different GitHub repositories:
Recipe is a curated list of recipes for maintained, high quality packages. Symfony Flex looks into this repository by default.
Recipes-Contrib contains all the recipes created by the community. All of them are guaranteed to work, but their associated packages could be unmaintained. Symfony Flex ignores these recipes by default, but you can execute the following command to start using them in your project:
composer config extra.symfony.allow-contrib true
Sometimes, there is an alias you can use (like the one below) to be faster and remember the command easier:
composer require logger
A recipe contains a manifest.json
file where the package configuration is stored. When Flex installs this package, it gets the manifest.json file and applies the default configuration to your project. This way, you can immediately use the new library without writing any configuration.
The messenger component helps applications send and receive messages to/from other applications or message queues. In order to install the component, you need to launch the following from your console:
composer require symfony/messenger
The sender serializes and sends a message to
LoggingMiddleware: logs the processing of your messages
SendMessageMiddleware: enables asynchronous processing
HandleMessageMiddleware: calls the registered handle
Once the message is dispatched to the bus, it will be handled by a “message handler”. A message handler is a PHP
Free Resources