php - serialize - Relación de la entidad de serialización solo con el identificador con el serializador JMS
strip_tags wordpress (5)
El autor quiere conservar el nombre de la propiedad, que no se aplica a la respuesta aceptada. Por lo que yo entiendo, la respuesta de ScayTrase mantendría el nombre original de la propiedad, pero tiene otra desventaja de acuerdo con los comentarios: el objeto relacionado se buscará si está utilizando Doctrine ORM @ManyToOne
, disminuyendo así el rendimiento.
Si desea conservar el nombre de la propiedad original, debe definir @VirtualProperty
en el nivel de clase y @Exclude
la propiedad original. De lo contrario, el nombre de la propiedad serializada se derivará del método getter ( countryId
en este caso):
/**
* @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();
}
}
Estoy tratando de serializar una relación de entidad con el Serializador JMS.
Aquí está la Entidad:
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;
}
}
Y la Entidad de la relación:
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;
}
}
Yo serializo la entidad pero no sé cómo convertir el atributo de país en un campo simple.
Obtengo este resultado en json:
{"description":"foo", "title":"bar", "country":{"id":"en"} }
Pero quiero obtener el campo de identificación del país de esta manera:
{"description":"foo", "title":"bar", "country": "en" }
¿Es posible con el serializador JMS?
Gracias.
[EDITAR]
@VirtualProperty no funciona.
Puedes usar las anotaciones @Type
y @Accessor
:
/**
* @Type("string")
* @Accessor(getter="serializeType",setter="setType")
*/
protected $type;
public function serializeType()
{
return $this->type->getId();
}
Sé que esto ya ha sido respondido, pero también puedes usar @Accessor. Esto probablemente (puede, no estoy seguro) también funciona con la deserialización.
/**
* @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;
}
Sí, puedes usar la anotación @VirtualProperty
:
/**
* @VirtualProperty
* @SerializedName("foo")
*/
public function bar()
{
return $this->country->getCode();
}
Pero ten cuidado cuando se trata de deserialización:
@VirtualProperty Esta anotación se puede definir en un método para indicar que los datos devueltos por el método deben aparecer como una propiedad del objeto.
> Nota: Esto solo funciona para la serialización y se ignora por completo durante la deserialización.
Espero que esto ayude...
Solo para seguir la pregunta respondida:
Si no le gusta escribir un método para cada relación que tiene, simplemente escriba su propio controlador. Es fácil como
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;
}
}
Registre el controlador
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}
Esto le permite reemplazar métodos getter virtuales con `Type (" Relation ").
Si no desea deserializar la relación, debe indicar a cada @Type("Relation")
el nombre de clase ( @Type("Relation<FQCN>")
) que debe deserializar o ajustar el controlador de metadatos con uno que lo haga para ti.
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;
}