Я нашел много вопросов о частичном ответе API с помощью FOSRest, и все ответы основаны на опциях сериализатора JMS (исключить, включить, группы и т. Д.). Это работает нормально, но я пытаюсь добиться чего-то менее «статичного».
Допустим, у меня есть пользователь со следующими атрибутами: id
username
firstname
lastname
age
sex
Я получаю этого пользователя с конечной точки 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
}
Вы можете сделать это так через группы, как вы показали. Может быть, немного более элегантным решением было бы реализовать свой собственный ExclusionStrategy. @Groups и другие тоже являются реализациями ExclusionStrategyInterface.
Итак, скажем, вы назвали свою стратегию SelectFieldsStrategy. Как только вы реализуете его, вы можете очень легко добавить его в контекст сериализации:
$context = new SerializationContext();
$context->addExclusionStrategy(new SelectFieldsStrategy(['id', 'name', 'someotherfield']));
Моя реализация основана на Игорь ответ:
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));
}
Конечная точка:
GET /users/{id}?fields=id,username,sex