Sonata DataMapper e Autowiring

Se hai una necessità specifica di trasformare i dati tra il modulo e la registrazione della tua entità e pensi che questo codice di trasformazione debba essere situato in un servizio perché ha più senso, puoi utilizzare il dataMapper utilizzando l'iniezione delle dipendenze fornita da Symfony.

Ma come implementarlo?

Un piccolo promemoria riguardo al DataMapper. Se siamo d'accordo con la documentazione ufficiale di Symfony riguardo il DataMapper e DataTransformer, un dataMapper ha la responsabilità di leggere e scrivere un oggetto (un'entità) per passarlo a un formulario. In breve, fa da collegamento tra un formulario e la sua entità.

Riassumendo: Il data transformer modifica un elemento dell'entità, il dataMapper è responsabile per l'intero oggetto.

DataMapperInterface impone logicamente due metodi:

Uno prende i dati dal formulario per darci la possibilità di trasformarli nell'entità di destinazione (mapFormsToData()). L'altro, al contrario, prende i dati dall'entità per trasformarli per il formulario (mapDataToForms()).

Attenzione, questa trasformazione avviene prima della registrazione dell'entità, quindi prima delle validazioni.
Se hai una necessità più complessa, puoi utilizzare gli eventi di Symfony definiti nella classe Symfony\Component\Form\FormEvents. Questo è, tra l'altro, raccomandato.
FormEvents::PRE_SUBMIT, FormEvents::SUBMIT, FormEvents::POST_SUBMIT, FormEvents::PRE_SET_DATA, FormEvents::POST_SET_DATA. Ne parleremo sicuramente di nuovo in un futuro articolo.

Per ora, torniamo al nostro formulario. Vi mostreremo come potete facilmente utilizzare le dichiarazioni di servizio e l'autowiring di Symfony per utilizzare un servizio direttamente in un dataMapper con Sonata. Il nostro esempio non è molto rilevante, poiché esiste già in Symfony un meccanismo molto più avanzato. Useremo un campo di testo "Title" per scrivere la sua versione "slug" in un campo "slug" automaticamente. Per formattare lo Slug, utilizzeremo il servizio che Symfony ci offre: Symfony\Component\String\Slugger\SluggerInterface.

Sonata_esempio_slug

Quindi, implementeremo un formulario con il singolo campo 'title'. Al momento della presentazione di questo formulario, passeremo attraverso il DataMapper che chiamerà il servizio Slug, e questo servizio avrà un metodo slugify() che andrà a prendere il servizio Symfony SluggerInterface. Ecco lo schema della tabella:

{{placeholder_codice_0}}

Ecco la definizione dei nostri servizi:

{{placeholder_codice_1}}

In ordine, abbiamo il formulario, il servizio Slug e il nostro DataMapper che ci consente di fare il collegamento tra i due. Il trucco è considerare il dataMapper come un servizio. L'iniezione delle dipendenze sarà eseguita naturalmente da Symfony. Il dataMapper sarà applicato al Formulario che a sua volta avrà naturalmente il suo servizio impostato perché è dichiarato nel suo costruttore.

Abbiamo ora bisogno di aggiungere la dichiarazione del nostro formulario in sonata_admin.yaml.

{{placeholder_codice_2}}

Ecco il formulario in questione:

{{placeholder_codice_3}}

Come potete vedere, title è un campo di testo standard. Abbiamo aggiunto il campo slug per poterlo accedere nel nostro DataMapper (ma non lo visualizziamo) e abbiamo aggiunto un campo template solo per avere la visualizzazione del nostro campo slug informato.

Notare il servizio DataMapper passato nel costruttore che riutilizziamo direttamente nel formBuilder tramite setDataMapper().

{{placeholder_codice_4}}

Riempiamo l'array $form nel primo metodo \App\Form\DataMapper\SlugDataMapper::mapDataToForms. Nel secondo metodo \App\Form\DataMapper\SlugDataMapper::mapFormsToData, creiamo un'entità con le nostre nuove informazioni per passare la validazione e la registrazione. Il costruttore ci fornisce automaticamente il nostro servizio Slug che a sua volta avrà il servizio Symfony Slug nel suo costruttore.

{{placeholder_codice_5}}

Per finire l'esempio, il codice del nostro campo "template" che ci permette di visualizzare il risultato:

{{placeholder_codice_6}}

Ecco fatto!