2014-12-11 12 views
5

kontekście

Znalazłem wiele pytań o częściowej odpowiedzi API z FOSRest i wszystkie odpowiedzi są oparte na opcjach JMS serializer (exlude, obejmują grupy, itp). Działa dobrze, ale staram się osiągnąć coś mniej "statycznego".FOSRestBundle: częściowa odpowiedź w zależności od atrybutów zapytał żądania

Powiedzmy mam użytkownikowi następujące atrybuty: idusernamefirstnamelastnameagesex

odzyskać to użytkownikowi końcowym GET /users/{id} i następujący sposób:

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

metoda zwraca użytkownik ze wszystkimi swoimi atrybutami.

Teraz chcę, aby umożliwić coś takiego: GET /users/{id}?attributes=id,username,sex

Pytanie

ja brakowało funkcjonalności FOSRestBUndle, JMSserializer lub SensioFrameworkExtraBundle osiągnąć to automatycznie? Adnotacja, metoda, słowo kluczowe w żądaniu lub coś innego?

W przeciwnym razie, jaki jest najlepszy sposób, aby to osiągnąć?

Kod

myślałem zrobić coś takiego:

/** 
* @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); 
} 

i utworzyć grupę dla każdego atrybutu:

use JMS\Serializer\Annotation\Groups; 

class User { 

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

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

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

    //etc 
} 

Odpowiedz

3

można to zrobić tak przez grupy, jak ty "pokazano. Być może nieco bardziej eleganckim rozwiązaniem byłoby zaimplementowanie własnego ExclusionStrategy. @Groups i inne są również implementacjami ExclusionStrategyInterface.

Załóżmy, że nazwałaś swoją strategię: SelectFieldsStrategy. Kiedy wdrożyć go, możesz dodać go do swojej kontekście serializacji bardzo proste:

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

Wiesz, czy istnieje sposób, aby umieścić całą tę logikę w adnotacji (bezpośrednio wewnątrz @View lub wewnątrz nowej adnotacji)?Właściwie, potrzebuję wszędzie wykluczenia pól, a kod będzie ściśle identyczny w każdym punkcie końcowym. Jestem całkiem nowym użytkownikiem php i symfony, więc jeśli masz jakieś linki, to doceniam to. :) –

+0

Jest to zdecydowanie możliwe, ale nigdy nie napisałem adnotacji, więc nie mogę ci pomóc z wytycznymi dotyczącymi implementacji, będziesz musiał sam to zbadać :) –

4

Moje wykonanie na podstawie 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; 
    } 
} 

Kontroler:

/** 
* @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)); 
} 

Endpoint:

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

Jakieś pomysły na to, jak radzić sobie z podobnymi podmiotami w tym podejściu? W PropertyMetadata nie ma żadnych informacji, które mogłyby wskazywać, że dane pole jest obiektem. – Nicolas

+0

Zrozumiałem to: '$ context-> getDepth()' może być użyte do tego. W moim przypadku sprawdzam, czy jest więcej niż 1. – Nicolas

Powiązane problemy