Serializing Entity Relation only to Id with JMS Serializer
I know this has already been answered but you could also use @Accessor. This probably (may, I can't be sure) work with deserialization too.
/**
* @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;
}
Yes, you could use @VirtualProperty
annotation:
/**
* @VirtualProperty
* @SerializedName("foo")
*/
public function bar()
{
return $this->country->getCode();
}
But be aware when it comes to deserialization:
@VirtualProperty This annotation can be defined on a method to indicate that the data returned by the method should appear like a property of the object.
> Note: This only works for serialization and is completely ignored during deserialization.
Hope this helps...
Just to follow answered question:
If you don't like writing one method for each relation you have - just write your own handler. It's easy like
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;
}
}
Register the 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}
This allows you to replace virtual getter methods with `Type("Relation").
If you also want't to deserialize relation - you should tell each @Type("Relation")
the classname (@Type("Relation<FQCN>")
) which it should deserialize to or wrap the metadata driver with one which do it for you.
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;
}