czydojade/api/src/Service/SerializerContextFactory.php
2020-11-01 17:57:06 +01:00

82 lines
2.7 KiB
PHP

<?php
namespace App\Service;
use App\Serialization\SerializeAs;
use Doctrine\Common\Annotations\Reader;
use JMS\Serializer\Metadata\PropertyMetadata;
use JMS\Serializer\SerializationContext;
use Metadata\AdvancedMetadataFactoryInterface;
use Metadata\ClassHierarchyMetadata;
use function Kadet\Functional\Transforms\property;
final class SerializerContextFactory
{
private $factory;
private $reader;
public function __construct(AdvancedMetadataFactoryInterface $factory, Reader $reader)
{
$this->factory = $factory;
$this->reader = $reader;
}
public function create($subject, array $groups = ['Default'])
{
return SerializationContext::create()->setSerializeNull(true)->setGroups($this->groups($subject, $groups));
}
private function groups($subject, array $groups)
{
$metadata = $this->factory->getMetadataForClass(is_object($subject) ? get_class($subject) : $subject);
$properties = $metadata instanceof ClassHierarchyMetadata
? collect($metadata->classMetadata)->flatMap(property('propertyMetadata'))
: $metadata->propertyMetadata;
$fields = [];
/** @var PropertyMetadata $property */
foreach ($properties as $property) {
try {
$annotation = $this->getAnnotationForProperty($property);
if ($annotation && !empty($fieldGroups = $this->map($annotation, $groups))) {
$type = $property->type;
$class = $type['name'] !== 'array' ? $type['name'] : $type['params'][0];
$fields[$property->name] = $this->groups($class, $fieldGroups);
}
} catch (\ReflectionException $e) { }
}
return array_merge($groups, $fields);
}
private function getAnnotationForProperty(PropertyMetadata $metadata)
{
$reflection = new \ReflectionClass($metadata->class);
try {
$property = $reflection->getProperty($metadata->name);
/** @var SerializeAs $annotation */
return $this->reader->getPropertyAnnotation($property, SerializeAs::class);
} catch (\ReflectionException $exception) {
$method = $reflection->getMethod($metadata->getter);
return $this->reader->getMethodAnnotation($method, SerializeAs::class);
}
}
private function map(SerializeAs $annotation, array $groups)
{
$result = [];
foreach ($groups as $group) {
if (array_key_exists($group, $annotation->map)) {
$result[] = $annotation->map[$group];
} else {
$result[] = $groups;
}
}
return $result;
}
}