Passed
Push — master ( 6f905d...2edd34 )
by Oleg
02:55
created

ReflectionProvider::getEntityClassName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace SlayerBirden\DFCodeGeneration\Generator\Tests;
5
6
use Doctrine\Common\Annotations\AnnotationReader;
7
use Doctrine\ORM\Mapping\Column;
8
use Doctrine\ORM\Mapping\GeneratedValue;
9
use Doctrine\ORM\Mapping\Id;
10
use Doctrine\ORM\Mapping\JoinColumn;
11
use Doctrine\ORM\Mapping\ManyToMany;
12
use Doctrine\ORM\Mapping\ManyToOne;
13
use Doctrine\ORM\Mapping\OneToOne;
14
use SlayerBirden\DFCodeGeneration\Generator\BaseNameTrait;
15
use Zend\Code\Reflection\ClassReflection;
16
17
class ReflectionProvider implements EntityProviderInterface
18
{
19
    use BaseNameTrait;
20
    /**
21
     * @var string
22
     */
23
    private $entityClassName;
24
    private $relations = [
25
        ManyToOne::class,
26
        ManyToMany::class,
27
        OneToOne::class,
28
    ];
29
    /**
30
     * @var ValueProviderInterface
31
     */
32
    private $valueProvider;
33
    /**
34
     * @var array
35
     */
36
    private $spec = [];
37
    /**
38
     * @var array
39
     */
40
    private $params = [];
41
    /**
42
     * @var IdHandlerInterface
43
     */
44
    private $idHandler;
45
    /**
46
     * @var bool|null
47
     */
48
    private $hasUnique;
49
    /**
50
     * @var string|null
51
     */
52
    private $idName;
53
54
    public function __construct(
55
        string $entityClassName,
56
        ValueProviderInterface $valueProvider,
57
        IdHandlerInterface $idHandler
58
    ) {
59
        $this->entityClassName = $entityClassName;
60
        $this->valueProvider = $valueProvider;
61
        $this->idHandler = $idHandler;
62
    }
63
64
    /**
65
     * @return array
66
     * @throws \Doctrine\Common\Annotations\AnnotationException
67
     * @throws \ReflectionException
68
     */
69
    public function getEntitySpec(): array
70
    {
71
        if (empty($this->spec)) {
72
            $reflectionClassName = new ClassReflection($this->entityClassName);
73
            foreach ($reflectionClassName->getProperties() as $property) {
74
                foreach ($this->relations as $type) {
75
                    /** @var ManyToMany|OneToOne|ManyToOne $annotation */
76
                    $annotation = (new AnnotationReader())
77
                        ->getPropertyAnnotation($property, $type);
78
                    if ($annotation) {
79
                        $ref = new ClassReflection($annotation);
80
                        $columnType = strtolower($ref->getShortName());
81
                        $target = $annotation->targetEntity;
82
                        /** @var JoinColumn $joinColumn */
83
                        $joinColumn = (new AnnotationReader())
84
                            ->getPropertyAnnotation($property, JoinColumn::class);
85
                        if ($joinColumn) {
86
                            $nullable = $joinColumn->nullable;
87
                            $referenceColumn = $joinColumn->referencedColumnName;
88
                        }
89
                        break;
90
                    }
91
                }
92
93
                if (empty($columnType)) {
94
                    /** @var Column $column */
95
                    $column = (new AnnotationReader())
96
                        ->getPropertyAnnotation($property, Column::class);
97
                    $columnType = $column->type;
98
                }
99
100
                $this->spec[] = [
101
                    'name' => $property->getName(),
102
                    'type' => $columnType,
103
                    'entity' => $target ?? null,
104
                    'nullable' => $nullable ?? false,
105
                    'ref_column_key' => $referenceColumn ?? 'id',
106
                ];
107
            }
108
        }
109
110
        return $this->spec;
111
    }
112
113
    /**
114
     * @return array
115
     * @throws \Doctrine\Common\Annotations\AnnotationException
116
     * @throws \ReflectionException
117
     */
118
    public function getPostParams(): array
119
    {
120
        $params = $this->getParams();
121
122
        $postParams = [];
123
124
        $reflectionClassName = new ClassReflection($this->entityClassName);
125
        foreach ($reflectionClassName->getProperties() as $property) {
126
            $key = $property->getName();
127
            /** @var GeneratedValue $generated */
128
            $generated = (new AnnotationReader())
129
                ->getPropertyAnnotation($property, GeneratedValue::class);
130
            if (!empty($generated)) {
131
                continue;
132
            }
133
            $postParams[$key] = $params[$key];
134
        }
135
136
        return $postParams;
137
    }
138
139
    /**
140
     * @return string
141
     * @throws \ReflectionException
142
     */
143
    public function getShortName(): string
144
    {
145
        return strtolower($this->getBaseName());
146
    }
147
148
    /**
149
     * Immutable
150
     * @return mixed
151
     * @throws \Doctrine\Common\Annotations\AnnotationException
152
     * @throws \ReflectionException
153
     */
154
    public function getId()
155
    {
156
        return $this->params[$this->getIdName()];
157
    }
158
159
    /**
160
     * Immutable
161
     * @return string
162
     */
163
    public function getEntityClassName(): string
164
    {
165
        return $this->entityClassName;
166
    }
167
168
    /**
169
     * Immutable
170
     * @return bool
171
     * @throws \Doctrine\Common\Annotations\AnnotationException
172
     * @throws \ReflectionException
173
     */
174
    public function hasUnique(): bool
175
    {
176
        if ($this->hasUnique === null) {
177
            $reflectionClassName = new ClassReflection($this->entityClassName);
178
            foreach ($reflectionClassName->getProperties() as $property) {
179
                /** @var Column $column */
180
                $column = (new AnnotationReader())
181
                    ->getPropertyAnnotation($property, Column::class);
182
                if ($column->unique) {
183
                    $this->hasUnique = true;
184
                    break;
185
                }
186
            }
187
        }
188
189
        return $this->hasUnique;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->hasUnique could return the type null which is incompatible with the type-hinted return boolean. Consider adding an additional type-check to rule them out.
Loading history...
190
    }
191
192
    /**
193
     * Immutable
194
     * @return array
195
     * @throws \Doctrine\Common\Annotations\AnnotationException
196
     * @throws \ReflectionException
197
     */
198
    public function getParams(): array
199
    {
200
        if (empty($this->params)) {
201
            $reflectionClassName = new ClassReflection($this->entityClassName);
202
            foreach ($reflectionClassName->getProperties() as $property) {
203
                $key = $property->getName();
204
                /** @var GeneratedValue $generated */
205
                $generated = (new AnnotationReader())
206
                    ->getPropertyAnnotation($property, GeneratedValue::class);
207
                foreach ($this->relations as $type) {
208
                    /** @var ManyToMany|OneToOne|ManyToOne $annotation */
209
                    $annotation = (new AnnotationReader())
210
                        ->getPropertyAnnotation($property, $type);
211
                    if ($annotation) {
212
                        $target = $annotation->targetEntity;
213
                        $this->params[$key] = $this->idHandler->getId($target);
214
                        continue 2;
215
                    }
216
                }
217
                /** @var Column $column */
218
                $column = (new AnnotationReader())
219
                    ->getPropertyAnnotation($property, Column::class);
220
                $this->params[$key] = $this->valueProvider->getValue($column->type, !empty($generated));
221
            }
222
        }
223
224
        return $this->params;
225
    }
226
227
    /**
228
     * @return string
229
     * @throws \Doctrine\Common\Annotations\AnnotationException
230
     * @throws \ReflectionException
231
     */
232
    public function getIdName(): string
233
    {
234
        if ($this->idName === null) {
235
            $reflectionClassName = new ClassReflection($this->entityClassName);
236
            foreach ($reflectionClassName->getProperties() as $property) {
237
                /** @var Id $id */
238
                $id = (new AnnotationReader())
239
                    ->getPropertyAnnotation($property, Id::class);
240
                if (!empty($id)) {
241
                    $this->idName = $property->getName();
242
                    break;
243
                }
244
            }
245
        }
246
247
        return $this->idName;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->idName could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
248
    }
249
}
250