Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Autowiring delle dipendenze

Autowiring: una delle componenti fondamentali di un framework è la gestione delle dipendenze tra le classi, vediamo come ciò accade in Symfony
Autowiring: una delle componenti fondamentali di un framework è la gestione delle dipendenze tra le classi, vediamo come ciò accade in Symfony
Link copiato negli appunti

Dependency Injection

La Dependency Injection (DI) è un design pattern che rende le classi indipendenti dalle proprie dipendenze. Questo ci consente di avere il codice isolato e mantenibile, potendo sostituire le singole dipendenze in ogni momento senza dover cambiare il codice della classe.

Per implementare la DI abbiamo bisogno di quattro ruoli:

  1. Il servizio che si vuole usare.
  2. Il client che usa questo servizio e l'oggetto che stiamo implementando.
  3. Un'interfaccia - che funge da “contratto” - implementata dal servizio ed usata dal client.
  4. L'injector che si occupa di creare un'istanza del servizio e la inietta al client.

Service Container ed autowiring

Su Symfony il container si occupa di gestire le dipendenze e di istanziarle. Grazie all'autowiring la gestione delle dipendenze viene ulteriormente semplificata riducendo al minimo la configurazione necessaria. L'autowiring si occupa di identificare ed iniettare i servizi necessari leggendo i type-hint nel costruttore della classe.

Se usiamo la configurazione di default di Symfony l'autowire è abilitato di default. Infatti all'interno del file app/config/services.yml abbiamo:

services:
    # default configuration for services in *this* file
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.

    # makes classes in src/ available to be used as services
    # this creates a service per class whose id is the fully-qualified class name
    App\:
        resource: '../src/*'
        exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'

Questa impostazione di default permette a Symfony di considerare come servizi tutte le classi definite nella directory src ad eccezione di quelle presenti nell'impostazione exclude.

Ora che abbiamo visto come l'autowiring viene definito proviamo a creare un nostro servizio e ad utilizzarlo all'interno di un controller. Questo infatti è un caso d'uso comune che permette di iniettare nel singolo controller solo i servizi necessari.

Supponiamo di dover creare, ad esempio, un servizio che data una stringa effettui operazioni sulla stessa. Potremmo effettuare ad esempio lo shuffle dei caratteri contenuti. Sicuramente non è un caso d'uso molto utile ma, per ora, serve solo a prendere dimestichezza con la creazione di un servizio.

La prima cosa da fare è definire la classe che permetterà di eseguire l'operazione:

<?php  
  
namespace App\Service;  
  
class StringShuffler  
{  
   public function shuffle(string $string): string  
   {  
        return str_shuffle($string);  
   }
}

Il codice è molto semplice e non introduce nessun nuovo concetto. A questo punto, grazie all'autowiring che abbiamo introdotto non dobbiamo fare altro che "iniettare" il servizio all'interno del controller in cui lo vogliamo usare. Per fare ciò abbiamo due possibilità:

  1. all'interno del metodo __constuct() del Controller dichiariamo il servizio come dipendenza. public function __construct(StringShuffler $shuffler);
  2. all'interno della action in cui vogliamo usarlo passiamo il servizio come parametro. public function index(StringShuffler $shuffler): Response.

In entrambi i casi sarà l'autowiring a recuperare il servizio e istanziarlo in modo da essere pronto all'uso. Non ci resta che utilizzarlo nel controller:

public function index(StringShuffler $shuffler): Response  
{  
    $shuffler->shuffle('this is an example of service injected thanks to the Autowiring');  
  
	//...  
}

Abbiamo visto come sia semplice definire ed utilizzare i servizi all'interno dell'applicazione. Nella realtà, però, è abbastanza difficile che un servizio non abbia la necessità di altre dipendenze per funzionare correttamente.

Molto spesso infatti si ha la necessità di utilizzare diversi servizi insieme per raggiungere il nostro scopo. Pensiamo ad esempio al servizio che si occupa di effettuare l'autenticazione visto nelle precedenti lezioni. Il suo scopo è quello di autenticare un utente ma, per farlo, ha bisogno almeno di: un servizio per generare URL di redirezione dopo l'avvenuto login, un servizio per verificare che il CSFR token fosse valido ed un altro servizio per verificare che l'utente sia già registrato e che la password è corretta.

Anche in casi come questi non abbiamo alcuna necessità di istanziare e recuperare i singoli servizi manualmente per utilizzare l'autenticatore, ci è sufficienti dichiararli nel costruttore del servizio e Symfony si occuperà di tutto il resto.

Possiamo vedere in azione quanto detto aprendo il file app/src/Security/LoginFormAuthenticator.php. Questo file è stato creato automaticamente dal MakerBundle quando abbiamo creato il form di login. Se notiamo, all'interno del costruttore abbiamo definito i servizi sovracitati ma non abbiamo dovuto definirli né richiamarli in nessuna maniera.

Un altro esempio di come abbiamo già usato l'autowiring senza esserne consapevoli è l'action di registrazione (app/src/Controller/RegistrationController.php). Aprendo il file infatti noteremo che oltre alla Request sono stati iniettati diversi altri servizi e anche in questo caso Symfony si è occupato di fornirci tutto quello di cui avevamo bisogno.

Ti consigliamo anche