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 (#191)
by joseph
16:39 queued 23s
created

CreateDtoBodyProcess::run()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1.0156

Importance

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