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