2014-12-11 3 views
5

Контекст

я нашел много вопросов о частичном ответе API с FOSRest и все ответы основаны на параметрах JMS Serializer (Exlude, включают в себя группы, и т.д). Он отлично работает, но я пытаюсь достичь чего-то менее «статического».FOSRestBundle: частичный ответ в зависимости от атрибутов задаются в запрос

Скажем, у меня есть пользователь со следующими атрибутами: idusernamefirstnamelastnameagesex

Я восстановить этот пользователь с конечной GET /users/{id} и следующий метод:

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

метод возвращает пользователь со всеми его атрибутами.

Теперь я хочу, чтобы что-то вроде этого: GET /users/{id}?attributes=id,username,sex

Вопрос

я пропустил функциональность FOSRestBUndle, JMSserializer или SensioFrameworkExtraBundle добиться его автоматически? Аннотации, метод, ключевое слово в запросе или что-то еще?

В противном случае, что является лучшим способом его достижения?

Код

Я думал сделать что-то вроде этого:

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

И создать группу для каждого атрибута:

use JMS\Serializer\Annotation\Groups; 

class User { 

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

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

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

    //etc 
} 

ответ

3

Вы можете сделать это так через группы, как вы - сказал он. Возможно, немного более элегантным решением было бы реализовать свой собственный ExclusionStrategy. @Groups, а также другие реализации ExclusionStrategyInterface.

Итак, предположим, что вы назвали свою стратегию SelectFieldsStrategy. После того, как вы реализуете его, вы можете добавить его в контекст сериализации очень легко:

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

Вы знаете, если есть способ поставить всю эту логику в аннотации (непосредственно внутри @View или внутри новой аннотации)?На самом деле мне нужно исключать поля везде, и код будет строго одинаковым в каждой конечной точке. Я довольно новичок в php и symfony, поэтому, если у вас есть ссылки, я буду признателен. :) –

+0

Это определенно возможно, но я никогда не делал пользовательскую аннотацию, поэтому я не могу реально помочь вам с рекомендациями по внедрению, вам придется самостоятельно изучить эту часть :) –

4

Моя реализация на основе 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; 
    } 
} 

Контроллер:

/** 
* @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

Любые идеи о том, как обрабатывать связанные объекты с помощью этого подхода? В PropertyMetadata нет никакой информации, которая могла бы указывать, что данное поле является объектом. – Nicolas

+0

Я понял: '$ context-> getDepth()' можно использовать для этого. В моем случае я проверяю, если это больше, чем 1. – Nicolas