Symfony 4 è la nuova versione di uno dei più famosi framework di php.
È stato rilasciato il 30 Novembre 2017 e sta avendo un gran successo!
Una delle più grandi differenze con le vecchie versioni sono le poche dipendenze installate quando si inizializza un progetto in Symfony 4.
Il framework è così piccolo che il progetto Silex è stato dismesso in quanto il suo scopo era di avere una versione ristretta di Symfony, ma dal momento che Symfony 4 richiede cosi poche dipendenze alla sua installazione, risulta essere inutile.

Come installare Symfony 4

Per creare una nuova applicazione con Symfony 4 è necessario avere una versione di PHP uguale o superiore alla 7.1 e Composer installato.
Con Composer installato puoi creare un progetto lanciando il seguente comando dal terminale:
composer create-project symfony/website-skeleton my-project

Questo è il comando tradizionale per le applicazioni web, il quale scarica uno scheletro base di Symfony 4 pronto ad essere usato con una configurazione di default.

Se stai invece creando micro-servizi, console application o API, potresti considerare l’uso di uno scheletro di un progetto ancora più semplificato.
composer create-project symfony/skeleton my-project

In questa versione non ci sono bundle installati, rendendo il progetto davvero piccolo.

Struttura delle cartelle

Symfony 4 ha cambiato un po’ la sua struttura delle cartelle adattandosi ad altri framework e alle richieste della comunità. La struttura base risulta la seguente:

app/
La configurazione dell’applicazione, template e traduzioni, dove puoi trovare il file AppKernel.

bin/
File eseguibili (esempio: bin/console).

src/
Il codice php del progetto, dove si possono trovare i controller, viste e cartelle delle entità.
In questa cartella non c’è un bundle principale perché l’idea di Symfony 4 è di avere un singolo progetto piuttosto che più pacchetti dentro di esso.

tests/
Test automatici (esempio: test unitari con PHPUnit o Behat o altri).

var/
File generati (cache, logs, etc.).

vendor/
Librerie esterne installate tramite Composer.

public/
La cartella dove sono immagazzinati i file statici come le immagini, fogli di stile e file javascript. Questa è la vecchia cartella “web”.

Variabili d’ambiente

Quando progetti la tua applicazione, potresti aver bisogno di diverse variabili d’ambiente che potrebbero differire tra di loro a seconda dell’ambiente.
Nelle versioni precedenti di Symfony si creavano queste variabili dentro un file chiamato parameters.yml e volendo anche nel parameters.yml.ambiente. Ora quel file non esiste (ovviamente si può cambiare il codice per riutilizzarlo, ma complica un po’ il codice) e il file adatto per queste variabili è chiamato .env nella root del progetto.
Si possono avere diverse .env a seconda di quanti ambienti sono presenti nella applicazione.
Ecco un semplice esempio di un file .env:

DB_USER=root
DB_PASS=pass

È possibile usare anche delle variabili al suo interno in questo modo:
DB_USER=root
DB_PASS=${DB_USER}pass

Il componente che legge questi file è Dotenv che analizza i file .env per poter rendere accessibili le variabili d’ambiente tramite getenv(), $_ENV or $_SERVER.
Se non è installato nel progetto è possibile aggiungerlo tramite questo comando dal terminale:

composer require symfony/dotenv

Per leggere il valore delle variabili d’ambiente si può usare la seguente sintassi all’interno del codice:

$dbUser = getenv('DB_USER');

È importante sapere che il componente Dotenv non sovrascrive mai le variabili d’ambiente esistenti.

Autowiring

L’Autowiring è una delle funzionalità più potenti di Symfony 4 (si può usare questa funzionalità già dalla versione 3.3).
Questa funzionalità consente di gestire i servizi nel container con una configurazione minima senza specificare, ad esempio, tutti gli argomenti che dovrebbero essere passati al servizio (ora anche i controller sono servizi!).
Così, se in un servizio è necessario passare altri servizi al metodo __construct, è possibile abilitare l’autowiring e Symfony penserà a tutto!

Esempio:

namespace App\Service;
use App\Util\Bar;
use Psr\Log\LoggerInterface;
class Foo
{
    private $logger;
    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }
}

Senza autowiring bisognerebbe scrivere nel file services.yml

app.foo:
class: AppBundle\Services\Foo
arguments: ['@logger']

Con l’autowiring è possibile scrivere ciò:

app.foo:
class: AppBundle\Services\Foo
public: true

Bisogna solo specificare public con valore true. Immagina di avere molti argomenti da dichiarare per altrettanti servizi, in questo modo guadagnerai tempo prezioso!
Fondamentalmente, i servizi non sono pubblici quindi è necessario renderli tali nel file services.yml, se lo si desidera, anche in questo modo:


services:
_defaults:
autowire: true
autoconfigure: true
public: true

Questa è la configurazione dei servizi, infatti è al di sotto di _defaults.
Se c’è la necessità di una configurazione differente solo per un servizio, per esempio che deve essere privato, si può scrivere la seguente configurazione:


services:
_defaults:
autowire: true
autoconfigure: true
public: true


App\Services\YourService:
class: App\Services\YourService
public: false

L’opzione autowire indica a Symfony di iniettare automaticamente le dipendenze nei servizi.
L’opzione autoconfigure indica a Symfony di registrare automaticamente i servizi come i comandi, event subscribers, etc.

Quindi ora è possibile iniettare i servizi direttamente al controller, esempio:

public function index(LoggerInterface $logger)
{
    $logger->info('Questo è un servizio iniettato!');
    //code
}

In questa action si inietta il servizio LoggerInterface direttamente senza doverlo instanziare al suo interno!

Flex e ricette

Symfony Flex è un plugin di Composer e viene chiamato quando viene eseguito un comando di composer tra i seguenti: require, update e remove.
Quando esegui i comandi di ricerca flex all’interno di Symfony Flex, il server lo prenderà, lo installerà e configurerà per te se il pacchetto se è presente.
Il vantaggio di Flex è che non devi guardare nei file readme delle librerie e configurare il bundle perché la ricetta farà già questo al tuo posto.
Non bisogna più aggiungere il nuovo bundle nel AppKernel.php perchè Flex lo fa al momento dell’installazione.
Se il pacchetto non esiste, verrà eseguito il normale comportamento di Composer.

Flex tiene traccia delle ricette installate nel file symfony.lock, che deve essere committato nel repository.
Le ricette sono presenti in due repository github differenti:
https://github.com/symfony/recipes, è una curata lista di alta qualità di ricette e pacchetti. Symfony Flex guarda di default all’interno di questo repository.
https://github.com/symfony/recipes-contrib, contiene le ricette create dalla community. Tutti sono garantiti per funzionare, ma i pacchetti associati potrebbero essere non mantenuti. Symfony Flex ignora queste ricette di default, ma puoi eseguire questo comando per iniziare a usarle nel tuo progetto:

composer config extra.symfony.allow-contrib true

All’interno del sito https://symfony.sh/ puoi controllare la lista completa delle ricette dove puoi trovare come installarle all’interno del progetto.
A volte c’è un alias che può essere usato come segue per rendere più veloce e ricordare meglio il comando:

composere require logger

Una ricetta contiene un file manifest.json che contiene la configurazione del pacchetto.
Quando Flex installa il pacchetto, prende il manifest.json e applica la configurazione di default nel tuo progetto, così potrai usare la libreria immediatamente senza scrivere nessuna configurazione.

Il componente Messenger

Il componente Messenger aiuta le applicazioni a mandare e ricevere messaggi da/a altre applicazioni oppure usa una coda di messaggi.
Per installare il componente, bisogna lanciare dal terminale il seguente comando:
composer require symfony/messenger

Come funziona?

Il Sender serializza e spedisce messaggi a qualcosa. Per esempio questo qualcosa potrebbe essere un broker di messaggi o un API di terze parti.
Il bus invia i messaggi. Il comportamento del bus è nel suo stack middleware ordinato. Il componente contiene un set di middleware che puoi usare.
Quando il bus viene utilizzato con il FrameworkBundle di Symfony, i seguenti middleware sono già configurati:
LoggingMiddleware (registra l’elaborazione dei tuoi messaggi)
SendMessageMiddleware (abilita i processi asincroni)
HandleMessageMiddleware (chiama l’handle registrato)

Una volta che il messaggio è stato inviato al bus sarà gestito tramite un “gestore di messaggi”.
Un gestore di messaggi è una funzione di PHP richiamabile (come ad esempio una funzione o un’istanza di una classe) che eseguirà i procedimenti necessari per elaborare i messaggi per te.
Per mandare e ricevere i messaggi, bisogna configurare un adapter. L’adapter sarà responsabile della comunicazione con il broker dei messaggi o di terze parti.
Quindi il ricevente Recevier deserializza e inoltra i messaggi ad uno o più handler. Può trattarsi di una queue puller di messaggi o di un endpoint di un API.

Alessandro Minoccheri
Written by Alessandro Minoccheri