Passed
Push — master ( 743cc2...6ffec3 )
by Oleg
02:50
created

AbstractTest::getColumnValue()   C

Complexity

Conditions 7
Paths 12

Size

Total Lines 28
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
cc 7
eloc 21
nc 12
nop 3
dl 0
loc 28
rs 6.7272
c 0
b 0
f 0
ccs 0
cts 21
cp 0
crap 56
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\Id;
9
use Doctrine\ORM\Mapping\ManyToMany;
10
use Doctrine\ORM\Mapping\ManyToOne;
11
use Doctrine\ORM\Mapping\OneToOne;
12
use Faker\Factory;
13
use SlayerBirden\DFCodeGeneration\Generator\NamingTrait;
14
15
abstract class AbstractTest
16
{
17
    use NamingTrait;
18
    /**
19
     * @var string
20
     */
21
    protected $entityClassName;
22
    protected $ids = [];
23
    protected $relations = [
24
        ManyToOne::class,
25
        ManyToMany::class,
26
        OneToOne::class,
27
    ];
28
    protected $haveInRepoParams = [];
29
    protected $unique = [];
30
    protected $existingRelations = [];
31
    /**
32
     * @var string
33
     */
34
    protected $shortName;
35
36
    public function __construct(string $entityClassName)
37
    {
38
        $this->entityClassName = $entityClassName;
39
        $this->shortName = strtolower($this->getBaseName($this->entityClassName));
40
    }
41
42
    abstract public function generate(): string;
43
44
    /**
45
     * @param int $count
46
     * @return string
47
     * @throws \Doctrine\Common\Annotations\AnnotationException
48
     * @throws \ReflectionException
49
     */
50
    protected function getBefore(int $count = 1): string
51
    {
52
        $parts = [];
53
        for ($i = 0; $i < $count; ++$i) {
54
            $parts[] = $this->getHaveInRepoPhrase($this->entityClassName);
55
        }
56
57
        return implode(PHP_EOL, $parts);
58
    }
59
60
    /**
61
     * @param string $entityClassName
62
     * @return string
63
     * @throws \Doctrine\Common\Annotations\AnnotationException
64
     * @throws \ReflectionException
65
     */
66
    protected function getHaveInRepoPhrase(string $entityClassName): string
67
    {
68
        $body = '$I->haveInRepository(%s, %s);';
69
70
        $params = [];
71
        $reflectionClassName = new \ReflectionClass($entityClassName);
72
        foreach ($reflectionClassName->getProperties() as $property) {
73
            $isId = false;
74
            $key = $property->getName();
75
            /** @var Id $id */
76
            $id = (new AnnotationReader())
77
                ->getPropertyAnnotation($property, Id::class);
78
            if ($id) {
79
                $isId = true;
80
            }
81
            foreach ($this->relations as $type) {
82
                $annotation = (new AnnotationReader())
83
                    ->getPropertyAnnotation($property, $type);
84
                if ($annotation) {
85
                    $body = $this->getRelationBody($body, $annotation->targetEntity, $key, $params, $type);
86
                    continue 2;
87
                }
88
            }
89
            $params[$key] = $this->getColumnValue($property, $entityClassName, $isId);
90
        }
91
        $this->haveInRepoParams[$entityClassName][] = $params;
92
93
        return sprintf($body, $entityClassName, var_export($params, true));
94
    }
95
96
    protected function getHaveInRepoParams(string $entityClassName, int $idx = 0): array
97
    {
98
        if (isset($this->haveInRepoParams[$entityClassName]) && isset($this->haveInRepoParams[$entityClassName][$idx])) {
99
            return $this->haveInRepoParams[$entityClassName][$idx];
100
        }
101
        return [];
102
    }
103
104
    /**
105
     * @param \ReflectionProperty $property
106
     * @param string $entityClassName
107
     * @param bool $isId
108
     * @return \DateTime|int|string|null
109
     * @throws \Doctrine\Common\Annotations\AnnotationException
110
     */
111
    protected function getColumnValue(\ReflectionProperty $property, string $entityClassName, bool $isId)
112
    {
113
        $faker = Factory::create();
114
        /** @var Column $column */
115
        $column = (new AnnotationReader())
116
            ->getPropertyAnnotation($property, Column::class);
117
        $value = null;
118
        if (!$column->nullable) {
119
            switch ($column->type) {
120
                case 'string':
121
                    $value = $faker->word;
122
                    break;
123
                case 'integer':
124
                    if ($isId) {
125
                        $value = $this->getIncrId($entityClassName);
126
                    } else {
127
                        $value = $faker->numberBetween(1, 10);
128
                    }
129
                    break;
130
                case 'datetime':
131
                    $value = $faker->dateTime();
132
                    break;
133
            }
134
        }
135
        if ($column->unique) {
136
            $this->addUnique($entityClassName, $property->getName());
137
        }
138
        return $value;
139
    }
140
141
    protected function addUnique(string $entityClassName, string $column): void
142
    {
143
        if (isset($this->unique[$entityClassName])) {
144
            $this->unique[$entityClassName][] = $column;
145
        } else {
146
            $this->unique[$entityClassName] = [$column];
147
        }
148
    }
149
150
    /**
151
     * @param string $body
152
     * @param string $entityClassName
153
     * @param string $key
154
     * @param array $params
155
     * @param string $type
156
     * @return string
157
     * @throws \Doctrine\Common\Annotations\AnnotationException
158
     * @throws \ReflectionException
159
     */
160
    protected function getRelationBody(
161
        string $body,
162
        string $entityClassName,
163
        string $key,
164
        array &$params,
165
        string $type
166
    ): string {
167
        $shortName = strtolower($this->getBaseName($entityClassName));
168
        if (!in_array($shortName, $this->existingRelations, true) || $type !== OneToOne::class) {
169
            $oldBody = $body;
170
            $body = $this->getHaveInRepoPhrase($entityClassName);
171
            $body .= PHP_EOL . $this->getUsagePhrase($shortName, $entityClassName, $this->getId($entityClassName));
172
            $body .= PHP_EOL . $oldBody;
173
            $this->existingRelations[] = $shortName;
174
        }
175
        $params[$key] = '$' . $shortName;
176
177
        return $body;
178
    }
179
180
    protected function getIncrId(string $entityClassName): int
181
    {
182
        if (isset($this->ids[$entityClassName])) {
183
            return ++$this->ids[$entityClassName];
184
        } else {
185
            return $this->ids[$entityClassName] = 1;
186
        }
187
    }
188
189
    protected function getId(string $entityClassName): ?int
190
    {
191
        if (isset($this->ids[$entityClassName])) {
192
            return $this->ids[$entityClassName];
193
        }
194
        return null;
195
    }
196
197
    protected function getUsagePhrase(string $shortName, string $entityClassName, int $id): string
198
    {
199
        $body = '$%s = $I->grabEntityFromRepository(%s, [\'id\' => %d]);';
200
201
        return sprintf($body, $shortName, $entityClassName, $id);
202
    }
203
204
    /**
205
     * @return array
206
     * @throws \Doctrine\Common\Annotations\AnnotationException
207
     * @throws \ReflectionException
208
     */
209
    protected function getPostParams(): array
210
    {
211
        $params = [];
212
        $reflectionClassName = new \ReflectionClass($this->entityClassName);
213
        foreach ($reflectionClassName->getProperties() as $property) {
214
            $key = $property->getName();
215
            /** @var Id $id */
216
            $id = (new AnnotationReader())
217
                ->getPropertyAnnotation($property, Id::class);
218
            if ($id) {
219
                continue;
220
            }
221
            foreach ($this->relations as $type) {
222
                $annotation = (new AnnotationReader())
223
                    ->getPropertyAnnotation($property, $type);
224
                if ($annotation) {
225
                    $params[$key] = $this->getId($annotation->targetEntity);
226
                    continue;
227
                }
228
            }
229
            $params[$key] = $this->getColumnValue($property, $this->entityClassName, false);
230
        }
231
232
        return $params;
233
    }
234
}
235