GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 0b4676...ecfcbd )
by joseph
17s queued 14s
created

CreateDtoBodyProcess   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 298
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
eloc 153
dl 0
loc 298
rs 9.68
c 0
b 0
f 0
ccs 0
cts 224
cp 0
wmc 34

15 Methods

Rating   Name   Duplication   Size   Complexity  
A buildArraysOfCode() 0 17 3
A getDefaultValueCodeForProperty() 0 10 2
A setDtoGetterAndSetterForEntityProperty() 0 34 2
A getPropertyVarType() 0 16 3
A updateFileContents() 0 14 1
A __construct() 0 8 1
A getPropertyTypeFromSetter() 0 18 4
A setGetterFromPropertyAndType() 0 12 2
A setSetterFromPropertyAndType() 0 14 2
A setEntityFqn() 0 11 2
A makeIdTypesNullable() 0 7 3
A run() 0 4 1
A addIssetMethodsForProperty() 0 20 2
A setProperty() 0 13 2
A getGetterBody() 0 26 4
1
<?php declare(strict_types=1);
2
3
namespace EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Creation\Process\Src\Entity\DataTransferObjects;
4
5
use Doctrine\Common\Collections\Collection;
6
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\CodeHelper;
7
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Creation\Process\ProcessInterface;
8
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Filesystem\File;
9
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\NamespaceHelper;
10
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\ReflectionHelper;
11
use EdmondsCommerce\DoctrineStaticMeta\DoctrineStaticMeta;
12
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Interfaces\PrimaryKey\IdFieldInterface;
13
use ts\Reflection\ReflectionMethod;
14
15
class CreateDtoBodyProcess implements ProcessInterface
16
{
17
    /**
18
     * @var DoctrineStaticMeta
19
     */
20
    private $dsm;
21
    /**
22
     * @var ReflectionHelper
23
     */
24
    private $reflectionHelper;
25
26
    /**
27
     * @var array
28
     */
29
    private $properties = [];
30
31
    /**
32
     * @var array
33
     */
34
    private $setters = [];
35
36
    /**
37
     * @var array
38
     */
39
    private $getters = [];
40
    /**
41
     * @var CodeHelper
42
     */
43
    private $codeHelper;
44
    /**
45
     * @var string
46
     */
47
    private $entityFqn;
48
    /**
49
     * @var NamespaceHelper
50
     */
51
    private $namespaceHelper;
52
53
    public function __construct(
54
        ReflectionHelper $reflectionHelper,
55
        CodeHelper $codeHelper,
56
        NamespaceHelper $namespaceHelper
57
    ) {
58
        $this->reflectionHelper = $reflectionHelper;
59
        $this->codeHelper       = $codeHelper;
60
        $this->namespaceHelper  = $namespaceHelper;
61
    }
62
63
    public function setEntityFqn(string $entityFqn)
64
    {
65
        $this->entityFqn = $entityFqn;
66
        if (false === \ts\stringContains($entityFqn, '\\Entities\\')) {
0 ignored issues
show
introduced by
The condition false === stringContains...ntityFqn, '\Entities\') is always false.
Loading history...
67
            throw new \RuntimeException(
68
                'This does not look like an Entity FQN: ' . $entityFqn
69
            );
70
        }
71
        $this->dsm = new DoctrineStaticMeta($entityFqn);
72
73
        return $this;
74
    }
75
76
    public function run(File\FindReplace $findReplace): void
77
    {
78
        $this->buildArraysOfCode();
79
        $this->updateFileContents($findReplace);
80
    }
81
82
    private function buildArraysOfCode()
83
    {
84
        foreach ($this->dsm->getSetters() as $getterName => $setterName) {
85
            if ('getId' === $getterName) {
86
                continue;
87
            }
88
            $trait    = $this->reflectionHelper->getTraitImplementingMethod(
89
                $this->dsm->getReflectionClass(),
90
                $setterName
91
            );
92
            $setter   = $trait->getMethod($setterName);
93
            $property = $trait->getProperties(\ReflectionProperty::IS_PRIVATE)[0]->getName();
94
            $type     = $this->getPropertyTypeFromSetter($setter);
95
            $this->setProperty($property, $type);
96
            $this->setGetterFromPropertyAndType($getterName, $property, $type);
97
            $this->setSetterFromPropertyAndType($setterName, $property, $type);
98
            $this->addIssetMethodsForProperty($property, $type);
99
        }
100
    }
101
102
    private function getPropertyTypeFromSetter(ReflectionMethod $setter): string
103
    {
104
        /**
105
         * @var \ReflectionParameter $param
106
         */
107
        $param = current($setter->getParameters());
108
        $type  = $param->getType();
109
        if (null !== $type) {
110
            $type = $type->getName();
111
            if (!\in_array($type, ['string', 'bool', 'int', 'float'], true)) {
112
                $type = "\\$type";
113
            }
114
            if ($param->allowsNull()) {
115
                $type = "?$type";
116
            }
117
        }
118
119
        return (string)$type;
120
    }
121
122
    private function setProperty(string $property, string $type): void
123
    {
124
        $defaultValue = $this->getDefaultValueCodeForProperty($property);
125
        $type         = $this->getPropertyVarType($type);
126
        $type         = $this->makeIdTypesNullable($property, $type);
127
128
        $code = '';
129
        $code .= "\n" . '    /**';
130
        $code .= ('' !== $type) ? "\n" . '     * @var ' . $type : '';
131
        $code .= "\n" . '     */';
132
        $code .= "\n" . '    private $' . $property . ' = ' . $defaultValue . ';';
133
134
        $this->properties[] = $code;
135
    }
136
137
    private function getDefaultValueCodeForProperty(
138
        string $property
139
    ) {
140
        $defaultValueConst = 'DEFAULT_' . $this->codeHelper->consty($property);
141
        $fullValueString   = $this->entityFqn . '::' . $defaultValueConst;
142
        if (\defined($fullValueString)) {
143
            return $this->dsm->getShortName() . '::' . $defaultValueConst;
144
        }
145
146
        return 'null';
147
    }
148
149
    private function getPropertyVarType(string $type): string
150
    {
151
        if (false === \ts\stringContains($type, '\\Entity\\Interfaces\\')) {
0 ignored issues
show
introduced by
The condition false === stringContains... '\Entity\Interfaces\') is always false.
Loading history...
152
            return $type;
153
        }
154
        $types = [];
155
        if (0 === strpos($type, '?')) {
156
            $types[] = 'null';
157
            $type    = substr($type, 1);
158
        }
159
        $types[] = $type;
160
        $types[] = $this->namespaceHelper->getEntityDtoFqnFromEntityFqn(
161
            $this->namespaceHelper->getEntityFqnFromEntityInterfaceFqn($type)
162
        );
163
164
        return implode('|', $types);
165
    }
166
167
    private function makeIdTypesNullable(string $property, string $type): string
168
    {
169
        if (IdFieldInterface::PROP_ID === $property && 0 !== strpos($type, '?')) {
170
            $type = "?$type";
171
        }
172
173
        return $type;
174
    }
175
176
    /**
177
     * @SuppressWarnings(PHPMD.ElseExpression)
178
     * @param string $getterName
179
     * @param string $property
180
     * @param string $type
181
     */
182
    private function setGetterFromPropertyAndType(
183
        string $getterName,
184
        string $property,
185
        string $type
186
    ) {
187
        $type            = $this->makeIdTypesNullable($property, $type);
188
        $code            = '';
189
        $code            .= "\n    public function $getterName()" . (('' !== $type) ? ": $type" : '');
190
        $code            .= "\n    {";
191
        $code            .= $this->getGetterBody($property, $type);
192
        $code            .= "\n    }\n";
193
        $this->getters[] = $code;
194
    }
195
196
    private function getGetterBody(
197
        string $property,
198
        string $type
199
    ) {
200
        if ('\\' . Collection::class === $type) {
201
            return "\n        return \$this->$property ?? \$this->$property = new ArrayCollection();";
202
        }
203
        if (\ts\stringContains($type, '\\Entity\\Interfaces\\')) {
204
            $getterCode = '';
205
            $getterCode .= "\n        if(null === \$this->$property){";
206
            $getterCode .= "\n            return \$this->$property;";
207
            $getterCode .= "\n        }";
208
            if (0 === strpos($type, '?')) {
209
                $type = substr($type, 1);
210
            }
211
            $getterCode .= "\n        if(\$this->$property instanceof $type){";
212
            $getterCode .= "\n            return \$this->$property;";
213
            $getterCode .= "\n        }";
214
            $getterCode .= "\n        throw new \RuntimeException(";
215
            $getterCode .= "\n            '\$this->$property is not an Entity, but is '. \get_class(\$this->$property)";
216
            $getterCode .= "\n        );";
217
218
            return $getterCode;
219
        }
220
221
        return "\n        return \$this->$property;";
222
    }
223
224
    private function setSetterFromPropertyAndType(
225
        string $setterName,
226
        string $property,
227
        string $type
228
    ) {
229
        $code            = '';
230
        $code            .= "\n    public function $setterName($type \$$property): self ";
231
        $code            .= "\n    {";
232
        $code            .= "\n        \$this->$property = \$$property;";
233
        $code            .= "\n        return \$this;";
234
        $code            .= "\n    }\n";
235
        $this->setters[] = $code;
236
        if (\ts\stringContains($type, '\\Entity\\Interfaces\\')) {
237
            $this->setDtoGetterAndSetterForEntityProperty($setterName, $property, $type);
238
        }
239
    }
240
241
    private function setDtoGetterAndSetterForEntityProperty(
242
        string $setterName,
243
        string $property,
244
        string $entityInterfaceFqn
245
    ) {
246
        $dtoFqn          = $this->namespaceHelper->getEntityDtoFqnFromEntityFqn(
247
            $this->namespaceHelper->getEntityFqnFromEntityInterfaceFqn($entityInterfaceFqn)
248
        );
249
        $setterCode      = '';
250
        $setterCode      .= "\n    public function ${setterName}Dto($dtoFqn \$$property): self ";
251
        $setterCode      .= "\n    {";
252
        $setterCode      .= "\n        \$this->$property = \$$property;";
253
        $setterCode      .= "\n        return \$this;";
254
        $setterCode      .= "\n    }\n";
255
        $this->setters[] = $setterCode;
256
257
        $getterName = 'get' . substr($setterName, 3);
258
        $getterCode = '';
259
        $getterCode .= "\n    public function $getterName" . "Dto(): $dtoFqn";
260
        $getterCode .= "\n    {";
261
        $getterCode .= "\n        if(null === \$this->$property){";
262
        $getterCode .= "\n            return \$this->$property;";
263
        $getterCode .= "\n        }";
264
        if (0 === strpos($dtoFqn, '?')) {
265
            $dtoFqn = substr($dtoFqn, 1);
266
        }
267
        $getterCode      .= "\n        if(\$this->$property instanceof $dtoFqn){";
268
        $getterCode      .= "\n            return \$this->$property;";
269
        $getterCode      .= "\n        }";
270
        $getterCode      .= "\n        throw new \RuntimeException(";
271
        $getterCode      .= "\n            '\$this->$property is not a DTO, but is '. \get_class(\$this->$property)";
272
        $getterCode      .= "\n        );";
273
        $getterCode      .= "\n    }\n";
274
        $this->getters[] = $getterCode;
275
    }
276
277
    private function addIssetMethodsForProperty(string $property, string $type): void
278
    {
279
        if (false === \ts\stringContains($type, '\\Entity\\Interfaces\\')) {
0 ignored issues
show
introduced by
The condition false === stringContains... '\Entity\Interfaces\') is always false.
Loading history...
280
            return;
281
        }
282
        $methodName      = 'isset' . ucfirst($property) . 'AsDto';
283
        $getterCodeDto   = '';
284
        $getterCodeDto   .= "\n    public function $methodName(): bool";
285
        $getterCodeDto   .= "\n    {";
286
        $getterCodeDto   .= "\n        return \$this->$property instanceof DataTransferObjectInterface;";
287
        $getterCodeDto   .= "\n    }\n";
288
        $this->getters[] = $getterCodeDto;
289
290
        $methodName       = 'isset' . ucfirst($property) . 'AsEntity';
291
        $getterCodeEntity = '';
292
        $getterCodeEntity .= "\n    public function $methodName(): bool";
293
        $getterCodeEntity .= "\n    {";
294
        $getterCodeEntity .= "\n        return \$this->$property instanceof EntityInterface;";
295
        $getterCodeEntity .= "\n    }\n";
296
        $this->getters[]  = $getterCodeEntity;
297
    }
298
299
    private function updateFileContents(
300
        File\FindReplace $findReplace
301
    ) {
302
        sort($this->properties, SORT_STRING);
303
        sort($this->getters, SORT_STRING);
304
        sort($this->setters, SORT_STRING);
305
306
        $body = implode("\n", $this->properties) .
307
                "\n\n" .
308
                implode("\n", $this->getters) .
309
                "\n" .
310
                implode("\n", $this->setters);
311
312
        $findReplace->findReplaceRegex('%{(.+)}%s', "{\n\$1\n$body\n}");
313
    }
314
}
315