2016-03-25 15 views
5

Attualmente sto imparando come implementare un'API relativamente semplice utilizzando Symfony 3 (con FOSRestBundle) e JMS Serializer. Recentemente ho cercato di implementare la capacità di specificare, come client che consuma, quali campi devono essere restituiti all'interno di una risposta (entrambi i campi all'interno dell'entità e delle relazioni richieste). Per esempio;Consigli per l'implementazione di whitelist di campo con Symfony/FosRestBundle/JMS Serializer

  • /posts senza comprendono stringa di query restituirebbe tutti Post proprietà di entità (ad esempio titolo, corpo, posted_at ecc) ma non relazioni.
  • /posts?fields[]=id&fields[]=title sarebbe restituire solo l'id e il titolo per i post (ma ancora una volta, nessuna relazione)
  • /posts?include[]=comment dovrebbe includere quanto sopra, ma con il rapporto Comment (e tutte le sue proprietà)
  • /posts?include[]=comment&include[]=comment.author sarebbe tornato come sopra , ma includere anche l'autore in ogni commento

È una cosa sensata da provare e implementare? Recentemente ho fatto molte ricerche su questo aspetto e non riesco a vedere che posso 1) limitare il recupero dei singoli campi e 2) restituire le entità correlate solo se sono state esplicitamente richieste.

Ho avuto alcuni giochi iniziali con questo concetto, tuttavia, anche assicurando che il mio repository restituisca solo l'entità Post (cioè nessun commento), JMS Serializer sembra attivare il caricamento lento di tutte le entità correlate e non riesco a sembrare per fermare questo. Ho visto un paio di link, come this example però le correzioni non sembrano funzionare (per esempio in quel link, il commentate $object->__load() chiamata non viene mai raggiunto in ogni caso nel codice originale.

ho implementato un relationship-based example of this using JMSSerializer's Group functionality ma mi sembra strano doverlo fare, quando sarei idealmente in grado di creare un'istanza di Querybuilder di Doctrine, aggiungere dinamicamente le chiamate andWhere() e fare in modo che il serializzatore restituisca solo i dati esatti senza caricare nelle relazioni

Mi scuso per aver vagato con questo ma Sono rimasto bloccato per un po 'di tempo e apprezzerei qualsiasi input! Grazie

risposta

2

Dovresti essere in grado di ottenere ciò che desideri con la strategia di esclusione Groups.

Ad esempio, l'entità Post potrebbe essere la seguente:

use JMS\Serializer\Annotation as JMS; 

/** 
* @JMS\ExclusionPolicy("all") 
*/ 
class Post 
{ 
    /** 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="IDENTITY") 
    * @ORM\Column(type="integer") 
    * 
    * @JMS\Expose 
    * @JMS\Groups({"all", "withFooAssociation", "withoutAssociations"}) 
    */ 
    private $id; 

    /** 
    * @ORM\Column(type="string") 
    * 
    * @JMS\Expose 
    * @JMS\Groups({"all", "withFooAssociation", "withoutAssociations"}) 
    */ 
    private $title; 

    /** 
    * @JMS\Expose 
    * @JMS\Groups({"all", "withFooAssociation"}) 
    * 
    * @ORM\OneToMany(targetEntity="Foo", mappedBy="post") 
    */ 
    private $foos; 
} 

In questo modo, se la vostra azione di controllo restituisce un View utilizzando serializerGroups={"all"}, la volontà di risposta contiene tutti i campi della vostra entità.

se utilizza serializerGroups={"withFooAssociation"}, la risposta sarà contiene le voci foos[] di associazione e relativi esposti campi.

E, se utilizza serializerGroups={"withoutAssociation"}, l'associazione foos verrà esclusa dal serializzatore e pertanto non verrà renderizzata.

Per escludere le proprietà dall'entità di destinazione dell'associazione (entità), utilizzare lo stesso Groups sulle proprietà dell'entità di destinazione per ottenere una strategia di serializzazione concatenata.

Quando la struttura di serializzazione è buono, è possibile impostare la dinamicamente serializerGroups nel controller, al fine di utilizzare i gruppi diversi a seconda delle include e fields params (vale a dire /posts?fields[]=id&fields[]=title). Esempio:

// PostController::getAction 

use JMS\Serializer\SerializationContext; 
use JMS\Serializer\SerializerBuilder; 

$serializer = SerializerBuilder::create()->build(); 
$context = SerializationContext::create(); 
$groups = []; 

// Assuming $request contains the "fields" param 
$fields = $request->query->get('fields'); 

// Do this kind of check for all fields in $fields 
if (in_array('foos', $fields)) { 
    $groups[] = 'withFooAssociation'; 
} 

// Tell the serializer to use the groups previously defined 
$context->setGroups($groups); 

// Serialize the data 
$data = $serializer->serialize($posts, 'json', $context); 

// Create the view 
$view = View::create()->setData($data); 

return $this->handleView($view); 

Spero correttamente capito la tua domanda e che questo sarà sufficiente per aiutarvi.

+0

Sì, questo ha senso! Questo significa che, assumendo che volevo applicare lo stesso principio ai singoli campi (non-relazioni come 'title' nel tuo esempio) avrei bisogno di gruppi per ogni campo? Immagino che questo sia l'unico modo per ottenere questo risultato, mi sembra un po 'strano che non sia possibile definire le relazioni quando si costruisce un'istanza di Doctrine QueryBuilder (aggiungendo condizionalmente join) e il serializzatore serializza semplicemente tali dati, senza. Grazie per la risposta però, accetterò questa risposta per ora :) –

+0

Inoltre, mi dispiace di aggiungere ulteriori domande, ma sai come gestiresti i campi annidati? (cioè stai recuperando i post, ma vuoi includere/escludere di dire una relazione 'Utente' all'interno di una entità' Foo' sopra)? –

+1

Vedere [l'annotazione '@ MaxDepth'] (http://jmsyst.com/libs/serializer/master/cookbook/exclusion_strategies#limiting-serialization-depth-of-some-properties) per limitare la profondità delle associazioni. Se hai bisogno di escludere/esporre totalmente alcuni campi, avrai sicuramente bisogno di trattare anche con i Gruppi. Se vuoi veramente usare un QueryBuilder personalizzato, non utilizzare affatto il serializzatore e idratare il risultato come array (cioè '$ qb-> getQuery-> getArrayResult()'), dovresti ottenere solo i campi aggiunti da una selezione dichiarazione. – chalasr