Relation D'entité de sérialisation seulement avec L'Id avec le Serializer JMS
j'essaie de sérialiser une relation d'entité avec le sérialiseur JMS.
Ici est l'Entité:
class Ad
{
/**
* @Type("string")
* @Groups({"manage"})
*
* @var string
*/
private $description;
/**
* @Type("AcmeSearchBundleEntityCountry")
* @Groups({"manage"})
*
* @var AcmeSearchBundleEntityCountry
*/
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 AcmeSearchBundleEntityCountry $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;
}
}
Et l'Entité de la relation:
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;
}
}
Je sérialise l'entity mais je ne sais pas comment convertir l'attribut country en un simple champ.
- je obtenir ce résultat en json:
{"description":"foo", "title":"bar", "country":{"id":"en"} }
Mais je veux obtenir le champ id du pays, comme ceci:
{"description":"foo", "title":"bar", "country": "en" }
c'est possible avec JMS Sérialiseur?
je vous Remercie.
[EDIT]
@VirtualProperty ne fonctionne pas.
5 réponses
Oui, vous pouvez utiliser @VirtualProperty
note:
/**
* @VirtualProperty
* @SerializedName("foo")
*/
public function bar()
{
return $this->country->getCode();
}
mais attention quand il s'agit de la desérialisation:
@VirtualProperty cette annotation peut être définie sur une méthode pour indiquer que les données retournées par la méthode doit apparaître comme un propriété de l'objet.
> Remarque: Cela ne fonctionne que pour la sérialisation et est complètement ignorée pendant la désérialisation.
J'espère que cela vous aidera...
Juste à suivre répondu à la question:
Si vous n'aimez pas écrire une méthode pour chaque relation que vous avez - il suffit d'écrire votre propre gestionnaire. C'est facile comme
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;
}
}
Enregistrer le Handler
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}
cela vous permet de remplacer les méthodes virtual getter par `Type("Relation").
si vous ne voulez pas non plus désérialiser la relation - vous devriez le dire à chacun @Type("Relation")
le nom de la classe (@Type("Relation<FQCN>")
) qu'il devrait désérialiser ou envelopper le pilote de métadonnées avec qui le faire pour vous.
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;
}
je sais que cela a déjà été répondu, mais vous pouvez également utiliser @Accesseur. Cela fonctionne probablement (peut-être, Je ne peux pas en être sûr) avec la desérialisation aussi.
/**
* @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;
}
Vous pouvez utiliser @Type
et @Accessor
notes:
/**
* @Type("string")
* @Accessor(getter="serializeType",setter="setType")
*/
protected $type;
public function serializeType()
{
return $this->type->getId();
}
l'auteur veut conserver le nom de la propriété, qui ne s'applique pas à la réponse acceptée. Pour autant que j'ai compris, la réponse de ScayTrase conserverait le nom de propriété original mais aurait un autre inconvénient selon les commentaires: L'objet lié sera récupéré si vous utilisez la Doctrine ORM @ManyToOne
, diminuant ainsi la performance.
si vous voulez conserver le nom de propriété original, vous devez définir le @VirtualProperty
au niveau de la classe et @Exclude
la propriété originale. Sinon, le nom de la propriété sérialisée sera dérivé de la méthode getter (countryId
dans ce cas):
/**
* @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();
}
}