Issues (39)

src/Metadata/Driver/JMSAnnotationDriver.php (2 issues)

1
<?php
2
3
namespace Bdf\Serializer\Metadata\Driver;
4
5
use Bdf\Serializer\Metadata\Builder\ClassMetadataBuilder;
6
use Bdf\Serializer\Metadata\ClassMetadata;
7
use JMS\Serializer\Metadata\ClassMetadata as JMSClassMetadata;
8
use JMS\Serializer\Metadata\PropertyMetadata as JMSPropertyMetadata;
9
use Metadata\ClassMetadata as JMSBaseClassMetadata;
10
use Metadata\Driver\DriverInterface as JMSDriverInterface;
11
use Metadata\MergeableInterface;
12
use ReflectionClass;
13
14
/**
15
 * The annotation driver use JMS annotation
16
 *
17
 * Works only with php 7.2
18
 */
19
class JMSAnnotationDriver implements DriverInterface
20
{
21
    /**
22
     * @var JMSDriverInterface
23
     */
24
    private $driver;
25
26
    /**
27
     * AnnotationDriver constructor.
28
     *
29
     * @param JMSDriverInterface $driver
30
     */
31 4
    public function __construct(JMSDriverInterface $driver)
32
    {
33 4
        $this->driver = $driver;
34
    }
35
36
    /**
37
     * {@inheritDoc}
38
     */
39 4
    public function getMetadataForClass(ReflectionClass $class): ?ClassMetadata
40
    {
41 4
        $builder = new ClassMetadataBuilder($class);
42 4
        $jmsMetadata = $this->getJmsMetadata($class);
43
44 4
        if ($this->isJmsMetadataEmpty($jmsMetadata)) {
45 2
            return null;
46
        }
47
48 2
        if ($jmsMetadata instanceof JMSClassMetadata) {
49 2
            if (isset($jmsMetadata->postSerializeMethods[0])) {
50
                $builder->postDenormalization($jmsMetadata->postSerializeMethods[0]->name);
51
            }
52
        }
53
54
        /** @var JMSPropertyMetadata $metadata */
55 2
        foreach ($jmsMetadata->propertyMetadata as $property => $metadata) {
56 2
            if ($this->isPropertyStatic($metadata)) {
57 2
                continue;
58
            }
59
60 2
            $propertyBuilder = $builder->add($property);
61 2
            $propertyBuilder->alias($metadata->serializedName);
62 2
            $propertyBuilder->readOnly($metadata->readOnly);
63 2
            $propertyBuilder->inline($metadata->inline);
64
65 2
            if ($metadata->sinceVersion) {
66 2
                $propertyBuilder->since($metadata->sinceVersion);
67
            }
68 2
            if ($metadata->untilVersion) {
69 2
                $propertyBuilder->until($metadata->untilVersion);
70
            }
71 2
            if ($metadata->getter) {
72
                $propertyBuilder->readWith($metadata->getter);
73
            }
74 2
            if ($metadata->setter) {
75
                $propertyBuilder->writeWith($metadata->setter);
76
            }
77 2
            if ($metadata->groups) {
78 2
                $propertyBuilder->groups($metadata->groups);
79
            }
80 2
            if ($metadata->type) {
81 2
                if (JMSPropertyMetadata::isCollectionList($metadata->type)) {
82 2
                    $propertyBuilder->type($metadata->type['params'][0]['name'])->collection();
83 2
                } elseif (JMSPropertyMetadata::isCollectionMap($metadata->type)) {
84
                    $propertyBuilder->type($metadata->type['params'][1]['name'])->collection();
85
                } else {
86 2
                    $propertyBuilder->type($metadata->type['name']);
87
                }
88
            }
89
        }
90
91 2
        return $builder->build();
92
    }
93
94
    /**
95
     * Gets all the annotations from this class
96
     *
97
     * @param ReflectionClass $reflection
98
     *
99
     * @return JMSBaseClassMetadata|null
100
     */
101 4
    private function getJmsMetadata(ReflectionClass $reflection): ?JMSBaseClassMetadata
102
    {
103 4
        $metadata = null;
104
105
        do {
106 4
            $current = $this->driver->loadMetadataForClass($reflection);
107
108 4
            if ($metadata instanceof MergeableInterface && $current instanceof MergeableInterface) {
109 2
                $current->merge($metadata);
110
            }
111
112 4
            $metadata = $current;
113 4
            $reflection = $reflection->getParentClass();
114 4
        } while ($reflection);
115
116 4
        return $metadata;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $metadata could return the type Metadata\MergeableInterface which is incompatible with the type-hinted return Metadata\ClassMetadata|null. Consider adding an additional type-check to rule them out.
Loading history...
117
    }
118
119
    /**
120
     * Checks whether the property of this metadata is static.
121
     *
122
     * @param JMSPropertyMetadata $metadata
123
     *
124
     * @return bool
125
     */
126 2
    private function isPropertyStatic(JMSPropertyMetadata $metadata): bool
127
    {
128
        try {
129 2
            $reflection = new \ReflectionProperty($metadata->class, $metadata->name);
130
131 2
            return $reflection->isStatic();
132
        } catch (\ReflectionException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
133
        }
134
135
        return false;
136
    }
137
138
    /**
139
     * Check whether the jms metadata has been loaded by default
140
     *
141
     * @param JMSBaseClassMetadata|null $jmsMetadata
142
     *
143
     * @return bool
144
     * @psalm-assert-if-false !null $jmsMetadata
145
     */
146 4
    private function isJmsMetadataEmpty(?JMSBaseClassMetadata $jmsMetadata): bool
147
    {
148 4
        if (!$jmsMetadata) {
149
            return true;
150
        }
151
152 4
        foreach ($jmsMetadata->propertyMetadata as $metadata) {
153 4
            $class = get_class($metadata);
154 4
            $default = new $class($metadata->class, $metadata->name);
155 4
            $attributes = (array)$metadata;
156
157 4
            unset($attributes['serializedName']);
158
159 4
            foreach ($attributes as $attribute => $value) {
160 4
                if ($default->$attribute !== $value) {
161 2
                    return false;
162
                }
163
            }
164
        }
165
166 2
        return true;
167
    }
168
}
169