Completed
Push — master ( 6ffec3...6f905d )
by Oleg
06:32
created

ReflectionProvider::getParams()   B

Complexity

Conditions 5
Paths 2

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

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