L'Entity API implementa il Typed Data API
Miglioramento significativo
- L'Entity API ora implementa l'API Typed Data
In questa nuova implementazione di Entity API tutto è un campo basato sulla stessa API, quindi le entità risultano prevedibili e coerenti.
Comprendere il modello dati di Drupal
Prima di addentrarci nell’API Typed Data, dobbiamo capire come il modello dati di Drupal (Entity API) veniva percepito in passato. Questo è importante perché l’API dei dati tipizzati nasce da lì, ed Entity API è uno dei sistemi per i quali è stata progettata.
Un’entità è un insieme complesso di dati, costituito da altre parti di dati, come campi con liste di elementi. Anche un elemento di campo è complesso – è composto da più frammenti di dati, come il valore di testo e il formato di input. Tuttavia, questa complessità si ferma a un punto in cui qualcosa può essere descritto come un tipo di dato primitivo, come una stringa o un intero.
Esempio semplificato da Drupal 7 (senza chiave di lingua, poiché Drupal 8 lo gestisce in modo diverso):
Esempio 1
// Le entità sono complesse, contengono altri pezzi di dati. $entity; // I campi non sono complessi, contengono solo una lista di elementi. $entity->image; // Gli elementi sono complessi, contengono altri pezzi di dati. // Sono anche traducibili e accessibili (con permessi). $entity->image[0]; // L’ID del file è un intero primitivo. $entity->image[0]['fid']; // Il testo alternativo è una stringa primitiva. $entity->image[0]['alt'];
Mettere tutto insieme
Segue un esempio semplificato di come Entity API implementa interfacce diverse dall’API Typed Data. In realtà, Entity API estende queste interfacce aggiungendo metodi aggiuntivi richiesti. Tuttavia, tutte le affermazioni sottostanti risultano vere:
Esempio 2
// Le entità sono complesse.
$entity instanceof ComplexDataInterface;
// Le proprietà non sono complesse, sono solo una lista di elementi.
$entity->get('image') instanceof ListInterface;
// Gli elementi sono complessi.
$entity->get('image')->offsetGet(0) instanceof ComplexDataInterface;
// L’oggetto typed data che rappresenta il valore alt.
$entity->get('image')->offsetGet(0)->get('alt') instanceof TypedDataInterface;
// Il valore alt è una stringa primitiva.
is_string($entity->get('image')->offsetGet(0)->get('alt')->getValue());
Segue una panoramica di come Entity API estende l’API Typed Data per soddisfare esigenze aggiuntive:
Esempio 3
interface EntityInterface extends ComplexDataInterface, TranslatableInterface, AccessibleInterface {
// ...
}
interface FielditemListInterface extends ListInterface {
// ...
}
// Nota che estende due interfacce. Spiegazione sotto.
interface FieldItemInterface extends ComplexDataInterface, TypedDataInterface {
// ...
}
// Di seguito alcune implementazioni reali.
// Estende una classe astratta con logica comune.
class ImageItem extends FieldItemBase {
// ...
}
// Estende una classe astratta con logica comune.
class String extends TypedData {
// ...
}
[I due paragrafi seguenti richiedono ulteriore lavoro]
Due cose notevoli sopra:
1. EntityInterface estende alcune interfacce di servizio per funzionalità come traduzione e controllo accessi. Questo dovrebbe essere abbastanza ovvio.
2. FieldItemInterface estende sia ComplexDataInterface che TypedDataInterface. Come spiegato in precedenza, gli elementi sono complessi perché contengono più frammenti di dati (es. valore testuale e formato per un campo testo). Ma allo stesso tempo l’elemento è esso stesso parte dei dati tipizzati, quindi ha la sua definizione e il proprio tipo di dato.
Riassumendo, in aggiunta all’esempio 2, anche tutte le affermazioni sottostanti sono vere:
Esempio 4
$entity instanceof EntityInterface;
$entity->get('image') instanceof FieldItemListInterface;
$entity->get('image')->offsetGet(0) instanceof FieldItemInterface;
$entity->get('image')->offsetGet(0)->get('alt') instanceof String;
is_string($entity->get('image')->offsetGet(0)->get('alt')->getValue());
Uso dell’API
[In questa sezione servono altri esempi]
L’Entity API definisce alcuni metodi magici, come __get(), per fornire un accesso rapido e semplice ai valori dei campi. In questo modo l’uso dell’API è molto semplice e la sintassi ricorda i tempi prima di Drupal 8.
Recuperare il valore effettivo del testo alternativo dell’immagine si fa così:
Esempio 5
// Il modo più dettagliato.
$string = $entity->get('image')->offsetGet(0)->get('alt')->getValue();
// Con la “magia” aggiunta da Entity API.
$string = $entity->image[0]->alt;
// Con ulteriore “magia” per ottenere di default il primo elemento della lista.
$string = $entity->image->alt;
L’esempio sopra aggiunge solo una sintassi più comoda al vecchio API. I seguenti esempi mostrano il vero valore di questo API: la validazione dei dati.
Esempio 6
// Restituisce un array con chiavi nominali per tutti i campi e le loro definizioni.
// Ad esempio il campo ‘image’.
$property_definitions = $entity->getFieldDefinitions();
// Restituisce un array con chiavi nominali per tutte le proprietà e le loro definizioni.
// Ad esempio le proprietà ‘file_id’ e ‘alt’.
$property_definitions = $entity->image
->getFieldDefinition()
->getFieldStorageDefinition()
->getPropertyDefinitions();
// Restituisce solo la definizione della proprietà ‘alt’.
$string_definition = $entity->image
->getFieldDefinition()
->getFieldStorageDefinition()
->getPropertyDefinition('alt');
Sulla base di queste definizioni possiamo fare cose intelligenti, come serializzare o esportare in altri array di dati. Possiamo anche fornire questi dati tramite API semanticamente ricche, come un endpoint JSON-LD, così che altri sistemi possano comprendere la struttura dei nostri dati.
Vedi https://drupal.org/node/2078241 per ulteriori informazioni su come definire e utilizzare le definizioni dei campi di tipo entità.