Symfony 4 Installation and new features

minompi

AlessandroMinoccheri

Posted on May 18, 2018

Symfony 4 Installation and new features

Symfony 4 is the newest version of the one of the most famous PHP frameworks.
It has been released on the 30th of November 2017 and it's having a great success!
One of the biggest difference with the older versions is the presence of very small dependencies installed when you init your Symfony 4 project.
Symfony 4 is so tiny that Silex project has been dismissed.

How to Install Symfony 4

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 launching this command into your console:

composer create-project symfony/website-skeleton my-project
Enter fullscreen mode Exit fullscreen mode

This is the command for traditional web applications that downloads a base skeleton of a Symfony project 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
Enter fullscreen mode Exit fullscreen mode

In this version there aren't bundles installed so it's smaller.

Directory Structure

Symfony 4 has changed a bit its directory structure according to other frameworks and community requests, so now the new directory structure is:

Directory Structure Image

app/
The application configuration, templates and translations, where you can find the AppKernel file, the main entry point of the application configuration.

bin/
Executable files (e.g. bin/console).

src/
The project's PHP code, where you have controllers, templates and entities directories.
In this folder there isn't a main bundle because Symfony 4's idea is to have a single project instead of more packages in a project.

tests/
Automatic tests (e.g. Unit tests with PHPUnit or Behat or others).

var/
Generated files (cache, logs, etc.).

vendor/
External libraries installed by composer.

public/
The web root directory where are stored public and static files like images, stylesheets and JavaScript files, this folder is the old "web" folder.

Environment Variables

When designing your system, you may wish to have different variables that can be not the same as in other environments.
In previous Symfony versions you put that variables into a file called parameters.yml and in parameters.yml.yourenv. Now that file doesn't exist (you can obviously change your code to use it but it's a little bit complex) and you need to write those variables in a file called .env in the project root.
Obviously you can have different .env files but it depends on how many environments you have into your application.
Here is a simple .env file:

DB_USER=root
DB_PASS=pass
Enter fullscreen mode Exit fullscreen mode

You can also use variables inside it like this:

DB_USER=root
DB_PASS=${DB_USER}pass
Enter fullscreen mode Exit fullscreen mode

The component that reads 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 it in your project you can launch this command to form your CLI to use it:

composer require symfony/dotenv
Enter fullscreen mode Exit fullscreen mode

To get the value of an environment variable you can use this syntax inside your code:

$dbUser = getenv('DB_USER');
Enter fullscreen mode Exit fullscreen mode

Remember that Symfony Dotenv never overwrites existing environment variables.

Autowiring

Autowiring is one of the most powerful feature in Symfony 4 (you can use it since 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 also controllers are services!).
So if you have a service class where you need to pass into __construct method some other services you only need to enable autowiring 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;
    }
}
Enter fullscreen mode Exit fullscreen mode

In the older method you needed to do this into your services.yml

app.foo:
    class:     AppBundle\Services\Foo
    arguments: ['@logger']
Enter fullscreen mode Exit fullscreen mode

In this new version you can do like this:

app.foo:
    class: AppBundle\Services\Foo
    public: true
Enter fullscreen mode Exit fullscreen mode

So you need to specify only public as true. Imagine having plenty arguments to declare for many services, in this way you will gain spare time!
Basically, services aren't public so you need to render it true into services.yml if you want also in this way:

services:
    _defaults:
        autowire: true
        autoconfigure: true
        public: true
Enter fullscreen mode Exit fullscreen mode

This is the default configuration of your services and as you can see it's under _defaults.
If you want to have 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
Enter fullscreen mode Exit fullscreen mode

So the Autowire option indicates to Symfony to automatically inject dependencies in your services.
Autoconfigure option indicates to Symfony to automatically register your services as commands, event subscribers, etc.

Now also controllers are services so it's easy to make unit tests on it instead of using integration tests that are slower.
So now you can also inject services inside your controller like this:

public function index(LoggerInterface $logger) 
{
    $logger->info('This is a injected service!');
    //code
}
Enter fullscreen mode Exit fullscreen mode

In this action you inject LoggerInterface directly and you don't need to instantiate it inside the action!

Flex and Recipes

Symfony Flex is a Composer plugin and it's called when you run require, update, and 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 since 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, it fallbacks on Composer standard behaviour.

Flex keeps track of the recipes it installed in a symfony.lock file, which must be committed to your code repository.
Recipes are stored in two different github repositories:

  • Recipe, is a curated list of recipes for high quality and maintained 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 this command to start using them in your project:

composer config extra.symfony.allow-contrib true
Enter fullscreen mode Exit fullscreen mode

Inside this site Symfony you can view the recipes complete list where you can find how to install them into your project.
Sometimes there is an alias so you can use it like this one to be faster and to remember the command easier:

composer require logger
Enter fullscreen mode Exit fullscreen mode

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 default configuration to your project, so you can use the new library immediately without writing any configuration.

The Messenger Component

The Messenger component helps applications send and receive messages to/from other applications or via message queues.
In order to install the component, you need to launch from your console:

composer require symfony/messenger
Enter fullscreen mode Exit fullscreen mode

Messenger Component

How does it work?

Sender serializes and sends a message to something. For example this something can be a message broker or a third party API.
The bus dispatches the message. The behaviour of the bus is in its ordered middleware stack. The component comes with a set of middleware that you can use.
When using the message bus with Symfony's FrameworkBundle, the following middleware are configured for you:

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 callable (i.e. a function or an instance of a class) that will do the required processing for your message.
In order to send and receive messages, you will have to configure the adapter. The adapter will be responsible for communicating with your message broker or 3rd parties.
Then the receiver Receiver deserializes and forwards the message to the handler(s). This can be a message queue puller or an API endpoint.

For further information contact me or follow me on:

Twitter
GitHub

đź’– đź’Ş đź™… đźš©
minompi
AlessandroMinoccheri

Posted on May 18, 2018

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related