2014-12-11 6 views
5

Kontext gefragt

ich eine Menge Fragen über Teil API-Antwort mit FOSRest gefunden und alle Antworten basieren auf den JMS-Serializer-Optionen (exlude, umfassen Gruppen, etc). Es funktioniert gut, aber ich versuche, etwas weniger "statisch" zu erreichen.FOSRestBundle: partielles Ansprechen in Abhängigkeit von Attributen in der Anfrage

Sagen wir, ich habe einen Benutzer mit den folgenden Attributen: idusernamefirstnamelastnameagesex

ich abrufen diesen Benutzer mit dem Endpunkt GET /users/{id} und die folgende Methode:

/** 
* @View 
* 
* GET /users/{id} 
* @param integer $user (uses ParamConverter) 
*/ 
public function getUserAction(User $user) { 
    return $user; 
} 

Die Methode liefert der Benutzer mit all seinen Attributen.

Jetzt möchte ich, so etwas erlauben: GET /users/{id}?attributes=id,username,sex

Frage

Habe ich eine Funktionalität von FOSRestBUndle, JMSserializer oder SensioFrameworkExtraBundle verpassten es automatisch zu erreichen? Eine Annotation, eine Methode, ein Schlüsselwort in der Anfrage oder etwas anderes?

Oder, was ist der beste Weg, um es zu erreichen?

-Code

Ich dachte, so etwas zu tun:

/** 
* @View 
* @QueryParam(name="attributes") 
* 
* GET /users/{id} 
* 
* @param integer $user (uses ParamConverter) 
*/ 
public function getUserAction(User $user, $attributes) { 
    $groups = $attributes ? explode(",", $attributes) : array("Default"); 

    $view = $this->view($user, 200) 
     ->setSerializationContext(SerializationContext::create()->setGroups($groups)); 

    return $this->handleView($view); 
} 

und eine Gruppe für jedes Attribut erstellen:

use JMS\Serializer\Annotation\Groups; 

class User { 

    /** @Groups({"id"}) */ 
    protected $id; 

    /** @Groups({"username"}) */ 
    protected $username; 

    /** @Groups({"firstname"}) */ 
    protected $firstname; 

    //etc 
} 

Antwort

3

Sie es so, dass durch Gruppen tun können, wie Sie habe gezeigt. Vielleicht wäre eine etwas elegantere Lösung, Ihre eigene ExclusionStrategy zu implementieren. @Groups und andere sind auch Implementierungen von ExclusionStrategyInterface.

Also, sagen Sie, Sie haben Ihre Strategie SelectFieldsStrategy aufgerufen. Sobald Sie es implementieren, können Sie es zu Ihrem Serialisierungskontext hinzufügen sehr einfach:

$context = new SerializationContext(); 
$context->addExclusionStrategy(new SelectFieldsStrategy(['id', 'name', 'someotherfield'])); 
+0

Wissen Sie, ob es einen Weg gibt all diese Logik in einer Anmerkung zu setzen (direkt in @View oder in eine neue Anmerkung)?Eigentlich benötige ich Felderausschlüsse überall und der Code wird in jedem Endpunkt streng identisch sein. Ich bin ziemlich neu in PHP und Symfony, also wenn Sie einige Links haben, werde ich es zu schätzen wissen. :) –

+0

Es ist definitiv möglich, aber ich habe nie benutzerdefinierte Annotation gemacht, so kann ich Ihnen nicht wirklich mit Implementierungsrichtlinien helfen, müssen Sie diesen Teil selbst recherchieren :) –

4

Meine Implementierung basiert auf Igor's answer:

ExlusionStrategy:

use JMS\Serializer\Exclusion\ExclusionStrategyInterface; 
use JMS\Serializer\Metadata\ClassMetadata; 
use JMS\Serializer\Metadata\PropertyMetadata; 
use JMS\Serializer\Context; 

class FieldsExclusionStrategy implements ExclusionStrategyInterface { 
    private $fields = array(); 

    public function __construct(array $fields) { 
     $this->fields = $fields; 
    } 

    public function shouldSkipClass(ClassMetadata $metadata, Context $navigatorContext) { 
     return false; 
    } 

    public function shouldSkipProperty(PropertyMetadata $property, Context $navigatorContext) { 
     if (empty($this->fields)) { 
      return false; 
     } 

     if (in_array($property->name, $this->fields)) { 
      return false; 
     } 

     return true; 
    } 
} 

Controller:

/** 
* @View 
* @QueryParam(name="fields") 
* 
* GET /users/{id} 
* 
* @param integer $user (uses ParamConverter) 
*/ 
public function getUserAction(User $user, $fields) { 
    $context = new SerializationContext(); 
    $context->addExclusionStrategy(new FieldsExclusionStrategy($fields ? explode(',', $fields) : array())); 

    return $this->handleView($this->view($user)->setSerializationContext($context)); 
} 

Endpunkt:

GET /users/{id}?fields=id,username,sex 
+0

Irgendwelche Ideen zum Umgang mit verbundenen Entitäten mit diesem Ansatz? Im PropertyMetadata scheint keine Information zu sein, die anzeigen könnte, dass das angegebene Feld ein Objekt ist. – Nicolas

+0

Ich habe es herausgefunden: '$ context-> getDepth()' könnte dafür verwendet werden. In meinem Fall überprüfe ich, ob es mehr als 1 ist. – Nicolas