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 ( 0d82f1...4042bf )
by joseph
20s queued 14s
created

CreateDtoBodyProcess::updateFileContents()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 1.0046

Importance

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