Сериализация отношения сущности только к идентификатору с помощью JMS-сериализатора

Я пытаюсь сериализовать отношение сущности с JMS Serializer.

Вот объект:

class Ad { /** * @Type("string") * @Groups({"manage"}) * * @var string */ private $description; /** * @Type("Acme\SearchBundle\Entity\Country") * @Groups({"manage"}) * * @var \Acme\SearchBundle\Entity\Country */ private $country; /** * @Type("string") * @Groups({"manage"}) * * @var string */ private $title; /** * Set description * * @param string $description * @return Ad */ public function setDescription($description) { $this->description = $description; return $this; } /** * Get description * * @return string */ public function getDescription() { return $this->description; } /** * Set country * * @param \Acme\SearchBundle\Entity\Country $country * @return Ad */ public function setCountry($country) { $this->country= $country; return $this; } /** * Get country * * @return string */ public function getCountry() { return $this->country; } /** * Set title * * @param string $title * @return Ad */ public function setTituloanuncio($title) { $this->title = $title; return $this; } /** * Get title * * @return string */ public function getTitle() { return $this->title; } } 

И Сущность отношений:

 class Country { /** * @Type("string") * @Groups("manage") * * @var string */ private $id; /** * @Type("string") * @Groups("admin") * * @var string */ private $description; /** * Set description * @Groups("") * * @param string $description * @return Country */ public function setDescripcionpais($description) { $this->description = $description; return $this; } /** * Get description * * @return string */ public function getDescription() { return $this->description; } } /** * Get id * * @return string */ public function getId() { return $this->id; } } 

Я сериализую объект, но я не знаю, как преобразовать атрибут страны в простое поле.

Я получаю этот результат в json:

 {"description":"foo", "title":"bar", "country":{"id":"en"} } 

Но я хочу получить поле id страны следующим образом:

 {"description":"foo", "title":"bar", "country": "en" } 

Это возможно с помощью JMS Serializer?

Спасибо.

[РЕДАКТИРОВАТЬ]

@VirtualProperty не работает.

Related of "Сериализация отношения сущности только к идентификатору с помощью JMS-сериализатора"

Да, вы можете использовать аннотацию @VirtualProperty :

 /** * @VirtualProperty * @SerializedName("foo") */ public function bar() { return $this->country->getCode(); } 

Но имейте в виду, когда дело доходит до десериализации:

@VirtualProperty Эта аннотация может быть определена в методе, чтобы указать, что данные, возвращаемые методом, должны отображаться как свойство объекта.

> Примечание. Это работает только для сериализации и полностью игнорируется во время десериализации.

Надеюсь это поможет…

Просто чтобы ответить на вопрос:

Если вам не нравится писать один метод для каждого вашего отношения – просто напишите свой собственный обработчик. Это легко, как

 final class RelationsHandler { /** * @var EntityManagerInterface */ private $manager; /** * RelationsHandler constructor. * * @param EntityManagerInterface $manager */ public function __construct(EntityManagerInterface $manager) { $this->manager = $manager; } public function serializeRelation(JsonSerializationVisitor $visitor, $relation, array $type, Context $context) { if ($relation instanceof \Traversable) { $relation = iterator_to_array($relation); } if (is_array($relation)) { return array_map([$this, 'getSingleEntityRelation'], $relation); } return $this->getSingleEntityRelation($relation); } /** * @param $relation * * @return array|mixed */ protected function getSingleEntityRelation($relation) { $metadata = $this->manager->getClassMetadata(get_class($relation)); $ids = $metadata->getIdentifierValues($relation); if (!$metadata->isIdentifierComposite) { $ids = array_shift($ids); } return $ids; } } 

Зарегистрировать обработчик

  jms_serializer.handler.relation: class: MyBundle\RelationsHandler arguments: - "@doctrine.orm.entity_manager" tags: - { name: jms_serializer.handler, type: Relation, direction: serialization, format: json, method: serializeRelation} - { name: jms_serializer.handler, type: Relation, direction: deserialization, format: json, method: deserializeRelation} - { name: jms_serializer.handler, type: Relation<?>, direction: serialization, format: json, method: serializeRelation} - { name: jms_serializer.handler, type: Relation<?>, direction: deserialization, format: json, method: deserializeRelation} 

Это позволяет заменить виртуальные методы getter на «Type (« Relation »).

Если вы также не хотите десериализовать отношение, вы должны указать каждому @Type("Relation") имя класса ( @Type("Relation<FQCN>") ), который он должен десериализовать или обернуть драйвер метаданных тем, кто это делает для тебя.

  public function deserializeRelation(JsonDeserializationVisitor $visitor, $relation, array $type, Context $context) { $className = isset($type['params'][0]['name']) ? $type['params'][0]['name'] : null; if (!class_exists($className, false)) { throw new \InvalidArgumentException('Class name should be explicitly set for deserialization'); } $metadata = $this->manager->getClassMetadata($className); if (!is_array($relation)) { return $this->manager->getReference($className, $relation); } $single = false; if ($metadata->isIdentifierComposite) { $single = true; foreach ($metadata->getIdentifierFieldNames() as $idName) { $single = $single && array_key_exists($idName, $relation); } } if ($single) { return $this->manager->getReference($className, $relation); } $objects = []; foreach ($relation as $idSet) { $objects[] = $this->manager->getReference($className, $idSet); } return $objects; } 

Я знаю, что это уже ответили, но вы также можете использовать @Accessor. Это возможно (возможно, я не могу быть уверенным) работать с десериализацией тоже.

 /** * @Type("Acme\SearchBundle\Entity\Country") * @Groups({"manage"}) * * @var \Acme\SearchBundle\Entity\Country * * @Serializer\Accessor(getter="getCountryMinusId",setter="setCountryWithId") */ private $country; /** * @return string|null */ public function getCountryMinusId() { if (is_array($this->country) && isset($this->country['id'])) { return $this->country['id']; } return null; } /** * @param string $country * @return $this */ public function setCountryWithId($country) { if (!is_array($this->country)) { $this->country = array(); ) $this->country['id'] = $country; return $this; } 

Вы можете использовать аннотации @Type и @Accessor :

 /** * @Type("string") * @Accessor(getter="serializeType",setter="setType") */ protected $type; public function serializeType() { return $this->type->getId(); } 

Автор хочет сохранить имя свойства, которое не относится к принятому ответу. Насколько я понял, ответ ScayTrase сохранил исходное имя свойства, но имеет еще один недостаток в соответствии с комментариями: связанный объект будет извлечен, если вы используете Doctrine ORM @ManyToOne , тем самым снижая производительность.

Если вы хотите сохранить исходное имя свойства, вы должны определить @VirtualProperty на уровне класса и @Exclude исходное свойство. В противном случае имя сериализованного свойства будет получено из метода getter ( countryId в этом случае):

 /** * @Serializer\VirtualProperty( * "country", * exp="object.getCountryId()", * options={@Serializer\SerializedName("country")} * ) */ class Ad { /** * @Serializer\Exclude */ private $country; public function getCountryId() { return $this->country === null ? null : $this->country->getId(); } }