1 | <?php |
||||
2 | /* |
||||
3 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
4 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
5 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
6 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
7 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
8 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
9 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
10 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
11 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
12 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
13 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
14 | * |
||||
15 | * This software consists of voluntary contributions made by many individuals |
||||
16 | * and is licensed under the MIT license. For more information, see |
||||
17 | * <http://www.doctrine-project.org>. |
||||
18 | */ |
||||
19 | |||||
20 | namespace Bdf\Prime\Entity; |
||||
21 | |||||
22 | use Bdf\Prime\Mapper\Info\InfoInterface; |
||||
23 | use Bdf\Prime\Mapper\Info\ObjectPropertyInfo; |
||||
24 | use Bdf\Prime\Mapper\Info\PropertyInfo; |
||||
25 | use Bdf\Prime\Mapper\Mapper; |
||||
26 | use Bdf\Prime\Mapper\Info\MapperInfo; |
||||
27 | use Bdf\Prime\ServiceLocator; |
||||
28 | use Bdf\Prime\Types\PhpTypeInterface; |
||||
29 | use Bdf\Prime\Types\TypeInterface; |
||||
30 | use Doctrine\Common\Inflector\Inflector; |
||||
31 | use Doctrine\Inflector\Inflector as InflectorObject; |
||||
32 | use Doctrine\Inflector\InflectorFactory; |
||||
33 | |||||
34 | /** |
||||
35 | * Generic class used to generate PHP5 entity classes from Mapper. |
||||
36 | * |
||||
37 | * [php] |
||||
38 | * $mapper = $service->mappers()->build('Entity); |
||||
39 | * |
||||
40 | * $generator = new EntityGenerator(); |
||||
41 | * $generator->setGenerateStubMethods(true); |
||||
42 | * $generator->setRegenerateEntityIfExists(false); |
||||
43 | * $generator->setUpdateEntityIfExists(true); |
||||
44 | * $generator->generate($mapper, '/path/to/generate/entities'); |
||||
45 | * |
||||
46 | * |
||||
47 | * @link www.doctrine-project.org |
||||
48 | * @since 2.0 |
||||
49 | * @author Benjamin Eberlei <[email protected]> |
||||
50 | * @author Guilherme Blanco <[email protected]> |
||||
51 | * @author Jonathan Wage <[email protected]> |
||||
52 | * @author Roman Borschel <[email protected]> |
||||
53 | */ |
||||
54 | class EntityGenerator |
||||
55 | { |
||||
56 | // @todo should not be there : should be on PhpTypeInterface |
||||
57 | /** |
||||
58 | * Map prime types to php 7.4 property type |
||||
59 | */ |
||||
60 | public const PROPERTY_TYPE_MAP = [ |
||||
61 | PhpTypeInterface::BOOLEAN => 'bool', |
||||
62 | PhpTypeInterface::DOUBLE => 'float', |
||||
63 | PhpTypeInterface::INTEGER => 'int', |
||||
64 | ]; |
||||
65 | |||||
66 | /** |
||||
67 | * Specifies class fields should be protected. |
||||
68 | */ |
||||
69 | public const FIELD_VISIBLE_PROTECTED = 'protected'; |
||||
70 | |||||
71 | /** |
||||
72 | * Specifies class fields should be private. |
||||
73 | */ |
||||
74 | public const FIELD_VISIBLE_PRIVATE = 'private'; |
||||
75 | |||||
76 | /** |
||||
77 | * The prime service locator |
||||
78 | * |
||||
79 | * @var ServiceLocator |
||||
80 | */ |
||||
81 | private $prime; |
||||
82 | |||||
83 | /** |
||||
84 | * The inflector instance |
||||
85 | * |
||||
86 | * @var InflectorObject |
||||
87 | */ |
||||
88 | private $inflector; |
||||
89 | |||||
90 | /** |
||||
91 | * The mapper info |
||||
92 | * |
||||
93 | * @var MapperInfo |
||||
94 | */ |
||||
95 | private $mapperInfo; |
||||
96 | |||||
97 | /** |
||||
98 | * The extension to use for written php files. |
||||
99 | * |
||||
100 | * @var string |
||||
101 | */ |
||||
102 | private $extension = '.php'; |
||||
103 | |||||
104 | /** |
||||
105 | * Whether or not the current Mapper instance is new or old. |
||||
106 | * |
||||
107 | * @var boolean |
||||
108 | */ |
||||
109 | private $isNew = true; |
||||
110 | |||||
111 | /** |
||||
112 | * @var array |
||||
113 | */ |
||||
114 | private $staticReflection = []; |
||||
115 | |||||
116 | /** |
||||
117 | * Number of spaces to use for indention in generated code. |
||||
118 | */ |
||||
119 | private $numSpaces = 4; |
||||
120 | |||||
121 | /** |
||||
122 | * The actual spaces to use for indention. |
||||
123 | * |
||||
124 | * @var string |
||||
125 | */ |
||||
126 | private $spaces = ' '; |
||||
127 | |||||
128 | /** |
||||
129 | * The class all generated entities should extend. |
||||
130 | * |
||||
131 | * @var string |
||||
132 | */ |
||||
133 | private $classToExtend; |
||||
134 | |||||
135 | /** |
||||
136 | * The interfaces all generated entities should implement. |
||||
137 | * |
||||
138 | * @var array |
||||
139 | */ |
||||
140 | private $interfaces = []; |
||||
141 | |||||
142 | /** |
||||
143 | * The traits |
||||
144 | * |
||||
145 | * @var array |
||||
146 | */ |
||||
147 | private $traits = []; |
||||
148 | |||||
149 | /** |
||||
150 | * Whether or not to generate sub methods. |
||||
151 | * |
||||
152 | * @var boolean |
||||
153 | */ |
||||
154 | private $generateEntityStubMethods = true; |
||||
155 | |||||
156 | /** |
||||
157 | * Whether or not to update the entity class if it exists already. |
||||
158 | * |
||||
159 | * @var boolean |
||||
160 | */ |
||||
161 | private $updateEntityIfExists = false; |
||||
162 | |||||
163 | /** |
||||
164 | * Whether or not to re-generate entity class if it exists already. |
||||
165 | * |
||||
166 | * @var boolean |
||||
167 | */ |
||||
168 | private $regenerateEntityIfExists = false; |
||||
169 | |||||
170 | /** |
||||
171 | * The name of get methods will not contains the 'get' prefix |
||||
172 | * |
||||
173 | * @var boolean |
||||
174 | */ |
||||
175 | private $useGetShortcutMethod = true; |
||||
176 | |||||
177 | /** |
||||
178 | * Visibility of the field |
||||
179 | * |
||||
180 | * @var string |
||||
181 | */ |
||||
182 | private $fieldVisibility = self::FIELD_VISIBLE_PROTECTED; |
||||
183 | |||||
184 | /** |
||||
185 | * Use type on generated properties |
||||
186 | * Note: only compatible with PHP >= 7.4 |
||||
187 | * |
||||
188 | * @var bool |
||||
189 | */ |
||||
190 | private $useTypedProperties = false; |
||||
191 | |||||
192 | /** |
||||
193 | * Enable generation of PHP 8 constructor with promoted properties |
||||
194 | * If used, the constructor will not call import for filling the entity |
||||
195 | * |
||||
196 | * Note: only compatible with PHP >= 8.0 |
||||
197 | * |
||||
198 | * @var bool |
||||
199 | */ |
||||
200 | private $useConstructorPropertyPromotion = false; |
||||
201 | |||||
202 | /** |
||||
203 | * @var string |
||||
204 | */ |
||||
205 | private static $classTemplate = |
||||
206 | '<?php |
||||
207 | |||||
208 | <namespace><useStatement><entityAnnotation> |
||||
209 | <entityClassName> |
||||
210 | { |
||||
211 | <entityTraits><entityBody> |
||||
212 | } |
||||
213 | '; |
||||
214 | |||||
215 | /** |
||||
216 | * @var string |
||||
217 | */ |
||||
218 | private static $getMethodTemplate = |
||||
219 | '/** |
||||
220 | * <description> |
||||
221 | * |
||||
222 | * @return <variableType> |
||||
223 | */ |
||||
224 | public function <methodName>(): <methodTypeHint> |
||||
225 | { |
||||
226 | <spaces>return $this-><fieldName>; |
||||
227 | } |
||||
228 | '; |
||||
229 | |||||
230 | /** |
||||
231 | * @var string |
||||
232 | */ |
||||
233 | private static $setMethodTemplate = |
||||
234 | '/** |
||||
235 | * <description> |
||||
236 | * |
||||
237 | * @param <variableType> $<variableName> |
||||
238 | * |
||||
239 | * @return $this |
||||
240 | */ |
||||
241 | public function <methodName>(<methodTypeHint> $<variableName><variableDefault>): self |
||||
242 | { |
||||
243 | <spaces>$this-><fieldName> = $<variableName>; |
||||
244 | |||||
245 | <spaces>return $this; |
||||
246 | } |
||||
247 | '; |
||||
248 | |||||
249 | /** |
||||
250 | * @var string |
||||
251 | */ |
||||
252 | private static $addMethodTemplate = |
||||
253 | '/** |
||||
254 | * <description> |
||||
255 | * |
||||
256 | * @param <variableType> $<variableName> |
||||
257 | * |
||||
258 | * @return $this |
||||
259 | */ |
||||
260 | public function <methodName>(<methodTypeHint> $<variableName>): self |
||||
261 | { |
||||
262 | <spaces>$this-><fieldName>[] = $<variableName>; |
||||
263 | |||||
264 | <spaces>return $this; |
||||
265 | } |
||||
266 | '; |
||||
267 | |||||
268 | /** |
||||
269 | * @var string |
||||
270 | */ |
||||
271 | private static $methodTemplate = |
||||
272 | '/** |
||||
273 | * <description> |
||||
274 | */ |
||||
275 | public function <methodName>()<return> |
||||
276 | { |
||||
277 | <spaces><content> |
||||
278 | } |
||||
279 | '; |
||||
280 | |||||
281 | /** |
||||
282 | * @var string |
||||
283 | */ |
||||
284 | private static $constructorMethodTemplate = |
||||
285 | '/** |
||||
286 | * Constructor |
||||
287 | */ |
||||
288 | public function __construct() |
||||
289 | { |
||||
290 | <spaces><collections> |
||||
291 | } |
||||
292 | '; |
||||
293 | |||||
294 | /** |
||||
295 | * @var string |
||||
296 | */ |
||||
297 | private static $importableConstructorMethodTemplate = |
||||
298 | '/** |
||||
299 | * Constructor |
||||
300 | * |
||||
301 | * @param array $data |
||||
302 | */ |
||||
303 | public function __construct(array $data = []) |
||||
304 | { |
||||
305 | <spaces><initialize>$this->import($data); |
||||
306 | } |
||||
307 | '; |
||||
308 | |||||
309 | /** |
||||
310 | * @var string |
||||
311 | */ |
||||
312 | private static $constructorWithPromotedPropertiesMethodTemplate = |
||||
313 | 'public function __construct( |
||||
314 | <properties> |
||||
315 | ) { |
||||
316 | <spaces><body> |
||||
317 | } |
||||
318 | '; |
||||
319 | |||||
320 | /** |
||||
321 | * Set prime service locator |
||||
322 | */ |
||||
323 | 35 | public function __construct(ServiceLocator $prime, ?InflectorObject $inflector = null) |
|||
324 | { |
||||
325 | 35 | $this->prime = $prime; |
|||
326 | 35 | $this->inflector = $inflector ?? InflectorFactory::create()->build(); |
|||
327 | } |
||||
328 | |||||
329 | /** |
||||
330 | * Generates and writes entity classes |
||||
331 | * |
||||
332 | * @param Mapper $mapper |
||||
333 | * @param string $file Entity file name |
||||
334 | * |
||||
335 | * @return string|false If no generation |
||||
336 | * |
||||
337 | * @api |
||||
338 | */ |
||||
339 | 34 | public function generate($mapper, $file = null) |
|||
340 | { |
||||
341 | 34 | $this->isNew = !$file || !file_exists($file) || $this->regenerateEntityIfExists; |
|||
342 | |||||
343 | // If entity doesn't exist or we're re-generating the entities entirely |
||||
344 | 34 | if ($this->isNew || !$file) { |
|||
345 | 31 | return $this->generateEntityClass($mapper); |
|||
346 | // If entity exists and we're allowed to update the entity class |
||||
347 | 3 | } elseif ($this->updateEntityIfExists && $file) { |
|||
348 | 3 | return $this->generateUpdatedEntityClass($mapper, $file); |
|||
349 | } |
||||
350 | |||||
351 | return false; |
||||
352 | } |
||||
353 | |||||
354 | /** |
||||
355 | * Generates a PHP5 Doctrine 2 entity class from the given Mapper instance. |
||||
356 | * |
||||
357 | * @param Mapper $mapper |
||||
358 | * |
||||
359 | * @return string |
||||
360 | */ |
||||
361 | 31 | public function generateEntityClass(Mapper $mapper) |
|||
362 | { |
||||
363 | 31 | $this->mapperInfo = $mapper->info(); |
|||
364 | |||||
365 | 31 | $this->staticReflection[$this->mapperInfo->className()] = ['properties' => [], 'methods' => []]; |
|||
366 | |||||
367 | 31 | $placeHolders = [ |
|||
368 | 31 | '<namespace>', |
|||
369 | 31 | '<useStatement>', |
|||
370 | 31 | '<entityAnnotation>', |
|||
371 | 31 | '<entityClassName>', |
|||
372 | 31 | '<entityTraits>', |
|||
373 | 31 | '<entityBody>' |
|||
374 | 31 | ]; |
|||
375 | |||||
376 | 31 | $replacements = [ |
|||
377 | 31 | $this->generateEntityNamespace(), |
|||
378 | 31 | $this->generateEntityUse(), |
|||
379 | 31 | $this->generateEntityDocBlock(), |
|||
380 | 31 | $this->generateEntityClassName(), |
|||
381 | 31 | $this->generateEntityTraits(), |
|||
382 | 31 | $this->generateEntityBody() |
|||
383 | 31 | ]; |
|||
384 | |||||
385 | 31 | $code = str_replace($placeHolders, $replacements, static::$classTemplate); |
|||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||
386 | |||||
387 | 31 | return str_replace('<spaces>', $this->spaces, $code); |
|||
388 | } |
||||
389 | |||||
390 | /** |
||||
391 | * Generates the updated code for the given Mapper and entity at path. |
||||
392 | * |
||||
393 | * @param Mapper $mapper |
||||
394 | * @param string $file |
||||
395 | * |
||||
396 | * @return string |
||||
397 | */ |
||||
398 | 3 | public function generateUpdatedEntityClass(Mapper $mapper, $file) |
|||
399 | { |
||||
400 | 3 | $this->mapperInfo = $mapper->info(); |
|||
401 | |||||
402 | 3 | $currentCode = file_get_contents($file); |
|||
403 | |||||
404 | 3 | $this->parseTokensInEntityFile($currentCode); |
|||
405 | |||||
406 | 3 | $body = $this->generateEntityBody(); |
|||
407 | 3 | $body = str_replace('<spaces>', $this->spaces, $body); |
|||
408 | 3 | $last = strrpos($currentCode, '}'); |
|||
409 | |||||
410 | 3 | return substr($currentCode, 0, $last) . $body . (strlen($body) > 0 ? "\n" : '') . "}\n"; |
|||
411 | } |
||||
412 | |||||
413 | /** |
||||
414 | * @return string |
||||
415 | */ |
||||
416 | 31 | protected function generateEntityNamespace(): string |
|||
417 | { |
||||
418 | 31 | if ($this->hasNamespace($this->mapperInfo->className())) { |
|||
419 | 31 | return 'namespace ' . $this->getNamespace($this->mapperInfo->className()) .';' . "\n\n"; |
|||
420 | } |
||||
421 | |||||
422 | return ''; |
||||
423 | } |
||||
424 | |||||
425 | /** |
||||
426 | * Generate use part |
||||
427 | * |
||||
428 | * @return string |
||||
429 | */ |
||||
430 | 31 | protected function generateEntityUse() |
|||
431 | { |
||||
432 | 31 | $use = []; |
|||
433 | |||||
434 | 31 | if (($parentClass = $this->getClassToExtend()) && $this->hasNamespace($parentClass)) { |
|||
435 | 2 | $use[$parentClass] = 'use ' . $parentClass . ';'; |
|||
436 | } |
||||
437 | |||||
438 | 31 | foreach ($this->interfaces as $interface) { |
|||
439 | 3 | if ($this->hasNamespace($interface)) { |
|||
440 | 3 | $use[$interface] = 'use ' . $interface . ';'; |
|||
441 | } |
||||
442 | } |
||||
443 | |||||
444 | 31 | foreach ($this->traits as $trait) { |
|||
445 | 2 | if ($this->hasNamespace($trait)) { |
|||
446 | $use[$trait] = 'use ' . $trait . ';'; |
||||
447 | } |
||||
448 | } |
||||
449 | |||||
450 | 31 | foreach ($this->mapperInfo->objects() as $info) { |
|||
451 | 27 | $className = $info->className(); |
|||
452 | 27 | if (!$info->belongsToRoot()) { |
|||
453 | 5 | continue; |
|||
454 | } |
||||
455 | |||||
456 | 27 | if ($this->hasNamespace($className)) { |
|||
457 | 27 | $use[$className] = 'use '.$className.';'; |
|||
458 | } |
||||
459 | |||||
460 | 27 | if ($info->wrapper() !== null) { |
|||
461 | 1 | $repository = $this->prime->repository($className); |
|||
462 | 1 | $wrapperClass = $repository->collectionFactory()->wrapperClass($info->wrapper()); |
|||
0 ignored issues
–
show
It seems like
$info->wrapper() can also be of type callable ; however, parameter $wrapper of Bdf\Prime\Collection\Col...Factory::wrapperClass() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
463 | |||||
464 | 1 | if ($this->hasNamespace($wrapperClass)) { |
|||
465 | 1 | $use[$wrapperClass] = 'use '.$wrapperClass.';'; |
|||
466 | } |
||||
467 | } |
||||
468 | } |
||||
469 | |||||
470 | 31 | if (!$use) { |
|||
471 | 5 | return ''; |
|||
472 | } |
||||
473 | |||||
474 | 27 | sort($use); |
|||
475 | |||||
476 | 27 | return implode("\n", $use) . "\n\n"; |
|||
477 | } |
||||
478 | |||||
479 | /** |
||||
480 | * @return string |
||||
481 | */ |
||||
482 | 31 | protected function generateEntityClassName() |
|||
483 | { |
||||
484 | 31 | return 'class ' . $this->getClassName($this->mapperInfo->className()) . |
|||
485 | 31 | ($this->classToExtend ? ' extends ' . $this->getClassToExtendName() : null) . |
|||
486 | 31 | ($this->interfaces ? ' implements ' . $this->getInterfacesToImplement() : null); |
|||
487 | } |
||||
488 | |||||
489 | /** |
||||
490 | * @return string |
||||
491 | */ |
||||
492 | 31 | protected function generateEntityTraits() |
|||
493 | { |
||||
494 | 31 | if (!$this->traits) { |
|||
0 ignored issues
–
show
The expression
$this->traits of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||
495 | 29 | return ''; |
|||
496 | } |
||||
497 | |||||
498 | 2 | $traits = ''; |
|||
499 | |||||
500 | 2 | foreach ($this->traits as $trait) { |
|||
501 | 2 | $traits .= $this->spaces . 'use ' . $this->getRelativeClassName($trait) . ';' . "\n"; |
|||
502 | } |
||||
503 | |||||
504 | 2 | return $traits . "\n"; |
|||
505 | } |
||||
506 | |||||
507 | /** |
||||
508 | * @return string |
||||
509 | */ |
||||
510 | 34 | protected function generateEntityBody() |
|||
511 | { |
||||
512 | 34 | $fieldMappingProperties = $this->generateEntityFieldMappingProperties($this->useConstructorPropertyPromotion); |
|||
513 | 34 | $embeddedProperties = $this->generateEntityEmbeddedProperties($this->useConstructorPropertyPromotion); |
|||
514 | 34 | $stubMethods = $this->generateEntityStubMethods ? $this->generateEntityStubMethods() : null; |
|||
515 | |||||
516 | 34 | $code = []; |
|||
517 | |||||
518 | 34 | if (!$this->useConstructorPropertyPromotion) { |
|||
519 | 31 | if ($fieldMappingProperties) { |
|||
520 | 29 | $code[] = $fieldMappingProperties; |
|||
521 | } |
||||
522 | |||||
523 | 31 | if ($embeddedProperties) { |
|||
524 | 25 | $code[] = $embeddedProperties; |
|||
525 | } |
||||
526 | } |
||||
527 | |||||
528 | 34 | $code[] = $this->generateEntityConstructor( |
|||
529 | 34 | $this->useConstructorPropertyPromotion, |
|||
530 | 34 | $fieldMappingProperties, |
|||
531 | 34 | $embeddedProperties |
|||
532 | 34 | ); |
|||
533 | |||||
534 | 34 | if ($stubMethods) { |
|||
535 | 32 | $code[] = $stubMethods; |
|||
536 | } |
||||
537 | |||||
538 | 34 | return implode("\n", $code); |
|||
539 | } |
||||
540 | |||||
541 | /** |
||||
542 | * @param bool $propertyPromotion Generate constructor with property promotion |
||||
543 | * @param string $fieldMappingProperties Entity properties |
||||
544 | * @param string $embeddedProperties Relations and embedded properties |
||||
545 | * |
||||
546 | * @return string |
||||
547 | */ |
||||
548 | 34 | protected function generateEntityConstructor(bool $propertyPromotion, string $fieldMappingProperties, string $embeddedProperties) |
|||
549 | { |
||||
550 | 34 | $initializable = in_array(InitializableInterface::class, $this->interfaces); |
|||
551 | 34 | $isImportable = in_array(ImportableInterface::class, $this->interfaces) |
|||
552 | 34 | || is_subclass_of($this->classToExtend, ImportableInterface::class); |
|||
553 | |||||
554 | 34 | $collections = []; |
|||
555 | |||||
556 | // Assignment operator : use null coalesce assignment with property promotion |
||||
557 | // because assignation is performed before initializing default value |
||||
558 | 34 | $assign = $propertyPromotion ? '??=' : '='; |
|||
559 | |||||
560 | 34 | foreach ($this->mapperInfo->objects() as $property) { |
|||
561 | 27 | if (!$property->belongsToRoot()) { |
|||
562 | 5 | continue; |
|||
563 | } |
||||
564 | |||||
565 | 27 | if ($property->isRelation()) { |
|||
566 | 26 | if (!$property->isArray()) { |
|||
567 | 26 | $collections[$property->name()] = '$this->'.$property->name().' '.$assign.' new '.$this->getRelativeClassName($property->className()).'();'; |
|||
568 | 21 | } elseif ($property->wrapper() === 'collection') { // @todo handle other wrapper types |
|||
569 | 26 | $collections[$property->name()] = '$this->'.$property->name().' '.$assign.' '.$this->getRelativeClassName($property->className()).'::collection();'; |
|||
570 | } |
||||
571 | } else { |
||||
572 | 5 | $collections[$property->name()] = '$this->'.$property->name().' '.$assign.' new '.$this->getRelativeClassName($property->className()).'();'; |
|||
573 | } |
||||
574 | } |
||||
575 | 34 | foreach ($this->mapperInfo->properties() as $property) { |
|||
576 | 34 | if ($property->isDateTime() && $property->hasDefault()) { |
|||
577 | 4 | $constructorArgs = ''; |
|||
578 | // Add the default timezone from the property type. |
||||
579 | 4 | if ($timezone = $property->getTimezone()) { |
|||
580 | 4 | $constructorArgs = "'now', new \DateTimeZone('$timezone')"; |
|||
581 | } |
||||
582 | |||||
583 | 4 | $collections[$property->name()] = '$this->'.$property->name().' '.$assign.' new '.$property->phpType().'('.$constructorArgs.');'; |
|||
584 | } |
||||
585 | } |
||||
586 | |||||
587 | 34 | $methods = []; |
|||
588 | |||||
589 | 34 | if (!$this->hasMethod('__construct')) { |
|||
590 | 29 | if ($propertyPromotion) { |
|||
591 | 3 | $methods[] = $this->generateConstructorWithPromotedProperties($initializable, $collections, $fieldMappingProperties, $embeddedProperties); |
|||
592 | 26 | } elseif ($constructor = $this->generateClassicConstructor($isImportable, $initializable, $collections)) { |
|||
593 | 25 | $methods[] = $constructor; |
|||
594 | } |
||||
595 | } |
||||
596 | |||||
597 | 34 | if (!$this->hasMethod('initialize') && $initializable) { |
|||
598 | 1 | $methods[] = $this->generateMethod('{@inheritdoc}', 'initialize', implode("\n".$this->spaces, $collections), 'void'); |
|||
599 | } |
||||
600 | |||||
601 | 34 | return implode("\n", $methods); |
|||
602 | } |
||||
603 | |||||
604 | /** |
||||
605 | * Generate PHP 8 constructor |
||||
606 | * |
||||
607 | * @param bool $initializable Does the entity class implements InitializableInterface ? |
||||
608 | * @param string[] $collections Initialisation method instructions |
||||
609 | * @param string $fieldMappingProperties Entity properties |
||||
610 | * @param string $embeddedProperties Relations and embedded properties |
||||
611 | * |
||||
612 | * @return string |
||||
613 | */ |
||||
614 | 3 | private function generateConstructorWithPromotedProperties(bool $initializable, array $collections, string $fieldMappingProperties, string $embeddedProperties): string |
|||
615 | { |
||||
616 | 3 | if ($initializable) { |
|||
617 | $buffer = '$this->initialize();'."\n".$this->spaces; |
||||
618 | 3 | } elseif ($collections) { |
|||
0 ignored issues
–
show
The expression
$collections of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||
619 | 3 | $buffer = implode("\n".$this->spaces, $collections)."\n".$this->spaces; |
|||
620 | } else { |
||||
621 | $buffer = ''; |
||||
622 | } |
||||
623 | |||||
624 | 3 | $properties = rtrim($fieldMappingProperties."\n".$embeddedProperties); |
|||
625 | 3 | $properties = str_replace(';', ',', $properties); |
|||
626 | |||||
627 | 3 | return $this->prefixCodeWithSpaces(str_replace( |
|||
628 | 3 | ['<body>', '<properties>'], |
|||
629 | 3 | [rtrim($buffer), $properties], |
|||
630 | 3 | static::$constructorWithPromotedPropertiesMethodTemplate |
|||
0 ignored issues
–
show
|
|||||
631 | 3 | )); |
|||
632 | } |
||||
633 | |||||
634 | /** |
||||
635 | * Generate classic constructor |
||||
636 | * |
||||
637 | * @param bool $isImportable Does the entity class implements InitializableInterface ? |
||||
638 | * @param bool $initializable Does the entity class implements ImportableInterface ? |
||||
639 | * @param string[] $collections Initialisation method instructions |
||||
640 | * |
||||
641 | * @return string|null |
||||
642 | */ |
||||
643 | 26 | private function generateClassicConstructor(bool $isImportable, bool $initializable, array $collections): ?string |
|||
644 | { |
||||
645 | 26 | if ($isImportable) { |
|||
646 | 2 | $buffer = ''; |
|||
647 | |||||
648 | 2 | if ($initializable) { |
|||
649 | 1 | $buffer = '$this->initialize();'."\n".$this->spaces; |
|||
650 | 1 | } elseif ($collections) { |
|||
0 ignored issues
–
show
The expression
$collections of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||
651 | 1 | $buffer = implode("\n".$this->spaces, $collections)."\n".$this->spaces; |
|||
652 | } |
||||
653 | |||||
654 | 2 | return $this->prefixCodeWithSpaces(str_replace("<initialize>", $buffer, static::$importableConstructorMethodTemplate)); |
|||
0 ignored issues
–
show
|
|||||
655 | 24 | } elseif ($collections && !$initializable) { |
|||
0 ignored issues
–
show
The expression
$collections of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||
656 | 23 | return $this->prefixCodeWithSpaces(str_replace("<collections>", implode("\n".$this->spaces, $collections), static::$constructorMethodTemplate)); |
|||
0 ignored issues
–
show
|
|||||
657 | } |
||||
658 | |||||
659 | 2 | return null; |
|||
660 | } |
||||
661 | |||||
662 | /** |
||||
663 | * @param Mapper $mapper |
||||
664 | * |
||||
665 | * @return string |
||||
666 | */ |
||||
667 | 31 | protected function generateEntityDocBlock() |
|||
668 | { |
||||
669 | 31 | $lines = []; |
|||
670 | 31 | $lines[] = '/**'; |
|||
671 | 31 | $lines[] = ' * ' . $this->getClassName($this->mapperInfo->className()); |
|||
672 | 31 | $lines[] = ' */'; |
|||
673 | |||||
674 | 31 | return implode("\n", $lines); |
|||
675 | } |
||||
676 | |||||
677 | /** |
||||
678 | * @return string |
||||
679 | */ |
||||
680 | 33 | protected function generateEntityStubMethods() |
|||
681 | { |
||||
682 | 33 | $methods = []; |
|||
683 | |||||
684 | 33 | foreach ($this->mapperInfo->properties() as $property) { |
|||
685 | 33 | if ($code = $this->generateEntityStubMethod('set', $property)) { |
|||
686 | 32 | $methods[] = $code; |
|||
687 | } |
||||
688 | |||||
689 | 33 | if ($code = $this->generateEntityStubMethod('get', $property)) { |
|||
690 | 32 | $methods[] = $code; |
|||
691 | } |
||||
692 | } |
||||
693 | |||||
694 | 33 | foreach ($this->mapperInfo->objects() as $property) { |
|||
695 | 26 | if (!$property->belongsToRoot()) { |
|||
696 | 5 | continue; |
|||
697 | } |
||||
698 | |||||
699 | 26 | if (!$property->isArray() || $property->wrapper() !== null) { |
|||
700 | 26 | if ($code = $this->generateEntityStubMethod('set', $property)) { |
|||
701 | 26 | $methods[] = $code; |
|||
702 | } |
||||
703 | 26 | if ($code = $this->generateEntityStubMethod('get', $property)) { |
|||
704 | 26 | $methods[] = $code; |
|||
705 | } |
||||
706 | } else { |
||||
707 | 19 | if ($code = $this->generateEntityStubMethod('add', $property)) { |
|||
708 | 19 | $methods[] = $code; |
|||
709 | } |
||||
710 | 19 | if ($code = $this->generateEntityStubMethod('set', $property)) { |
|||
711 | 19 | $methods[] = $code; |
|||
712 | } |
||||
713 | 19 | if ($code = $this->generateEntityStubMethod('get', $property)) { |
|||
714 | 19 | $methods[] = $code; |
|||
715 | } |
||||
716 | } |
||||
717 | } |
||||
718 | |||||
719 | 33 | return implode("\n", $methods); |
|||
720 | } |
||||
721 | |||||
722 | /** |
||||
723 | * @return string |
||||
724 | */ |
||||
725 | 34 | protected function generateEntityFieldMappingProperties(bool $forceNullable = false) |
|||
726 | { |
||||
727 | 34 | $lines = []; |
|||
728 | |||||
729 | 34 | foreach ($this->mapperInfo->properties() as $property) { |
|||
730 | 34 | if ($this->hasProperty($property->name())) { |
|||
731 | 5 | continue; |
|||
732 | } |
||||
733 | |||||
734 | 32 | $default = ''; |
|||
735 | |||||
736 | 32 | if ($property->hasDefault() && !$property->isDateTime()) { |
|||
737 | 5 | $default = ' = '.$this->stringfyValue( |
|||
738 | 5 | $property->convert($property->getDefault()) |
|||
739 | 5 | ); |
|||
740 | 32 | } elseif ($property->isArray()) { |
|||
741 | 17 | $default = ' = []'; |
|||
742 | } |
||||
743 | |||||
744 | // A nullable property should be defined as null by default |
||||
745 | // A property is considered as nullable if it's explicitly defined on mapper or if the field is auto-generated |
||||
746 | 32 | if (!$default && ($forceNullable || ($this->useTypedProperties && $property->isNullable()))) { |
|||
747 | 14 | $default = ' = null'; |
|||
748 | } |
||||
749 | |||||
750 | 32 | $lines[] = $this->generateFieldMappingPropertyDocBlock($property); |
|||
751 | 32 | $lines[] = $this->spaces.$this->fieldVisibility.$this->getPropertyTypeHintForSimpleProperty($property, $forceNullable).' $'.$property->name().$default.";\n"; |
|||
752 | } |
||||
753 | |||||
754 | 34 | return implode("\n", $lines); |
|||
755 | } |
||||
756 | |||||
757 | /** |
||||
758 | * @param bool $forceNullable Force typehint to be nullable. Useful property promotion |
||||
759 | * @return string |
||||
760 | */ |
||||
761 | 34 | protected function generateEntityEmbeddedProperties(bool $forceNullable = false) |
|||
762 | { |
||||
763 | 34 | $lines = []; |
|||
764 | |||||
765 | 34 | foreach ($this->mapperInfo->objects() as $property) { |
|||
766 | 27 | if (!$property->belongsToRoot() || $this->hasProperty($property->name())) { |
|||
767 | 7 | continue; |
|||
768 | } |
||||
769 | |||||
770 | 27 | if (!$property->isRelation()) { |
|||
771 | // Always add a default value with use property promotion |
||||
772 | 5 | $default = $this->useConstructorPropertyPromotion ? ' = null' : ''; |
|||
773 | |||||
774 | 5 | $lines[] = $this->generateEmbeddedPropertyDocBlock($property); |
|||
775 | 5 | $lines[] = $this->spaces . $this->fieldVisibility . $this->getPropertyTypeHintForObject($property, $forceNullable) . ' $'.$property->name().$default.";\n"; |
|||
776 | } else { |
||||
777 | 26 | $name = $property->name(); |
|||
778 | 26 | $default = ''; |
|||
779 | |||||
780 | // Do not initialize the property if it's a wrapper |
||||
781 | 26 | if ($property->isArray() && $property->wrapper() === null) { |
|||
782 | 18 | $default = ' = []'; |
|||
783 | } |
||||
784 | |||||
785 | // If property is typed, always define a default value |
||||
786 | 26 | if (($forceNullable || $this->useTypedProperties) && !$default) { |
|||
787 | 13 | $default = ' = null'; |
|||
788 | } |
||||
789 | |||||
790 | 26 | $lines[] = $this->generateEmbeddedPropertyDocBlock($property); |
|||
791 | 26 | $lines[] = $this->spaces . $this->fieldVisibility . $this->getPropertyTypeHintForObject($property, $forceNullable) . ' $' . $name . $default .";\n"; |
|||
792 | } |
||||
793 | } |
||||
794 | |||||
795 | 34 | return implode("\n", $lines); |
|||
796 | } |
||||
797 | |||||
798 | /** |
||||
799 | * @param string $type |
||||
800 | * @param InfoInterface $propertyInfo |
||||
801 | * @param string|null $defaultValue |
||||
802 | * |
||||
803 | * @return string |
||||
804 | */ |
||||
805 | 33 | protected function generateEntityStubMethod($type, InfoInterface $propertyInfo, $defaultValue = null) |
|||
806 | { |
||||
807 | 33 | $fieldName = $propertyInfo->name(); |
|||
808 | |||||
809 | // The hint flag help algorithm to determine the hint info for object parameter. |
||||
810 | // It should be 'array' for collection but the add method need the object hint. |
||||
811 | // setItems(array $items) |
||||
812 | // addItem(Item $item) |
||||
813 | 33 | $hintOne = false; |
|||
814 | |||||
815 | 33 | if ($type === 'get' && $this->useGetShortcutMethod === true) { |
|||
816 | 32 | $variableName = $this->inflector->camelize($fieldName); |
|||
817 | 32 | $methodName = $variableName; |
|||
818 | } else { |
||||
819 | 33 | $methodName = $type . $this->inflector->classify($fieldName); |
|||
820 | 33 | $variableName = $this->inflector->camelize($fieldName); |
|||
821 | } |
||||
822 | |||||
823 | 33 | if ($type === 'add') { |
|||
824 | 19 | $methodName = $this->inflector->singularize($methodName); |
|||
825 | 19 | $variableName = $this->inflector->singularize($variableName); |
|||
826 | 19 | $hintOne = true; |
|||
827 | } |
||||
828 | |||||
829 | 33 | if ($this->hasMethod($methodName)) { |
|||
830 | 2 | return ''; |
|||
831 | } |
||||
832 | 32 | $this->staticReflection[$this->mapperInfo->className()]['methods'][] = strtolower($methodName); |
|||
833 | |||||
834 | 32 | if ($propertyInfo->isObject()) { |
|||
835 | /** @var ObjectPropertyInfo $propertyInfo */ |
||||
836 | 26 | $variableType = $this->getRelativeClassName($propertyInfo->className()); |
|||
837 | // Only makes nullable for single relation |
||||
838 | 26 | $methodTypeHint = $this->getPropertyTypeHint($propertyInfo->className(), !$hintOne && !$propertyInfo->isEmbedded()); |
|||
0 ignored issues
–
show
It seems like
$propertyInfo->className() can also be of type null ; however, parameter $type of Bdf\Prime\Entity\EntityG...::getPropertyTypeHint() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
839 | } else { |
||||
840 | /** @var PropertyInfo $propertyInfo */ |
||||
841 | 32 | $variableType = $propertyInfo->phpType(); |
|||
842 | 32 | $methodTypeHint = $this->getPropertyTypeHint($variableType, $propertyInfo->isNullable()); |
|||
843 | } |
||||
844 | |||||
845 | 32 | if ($propertyInfo->isArray() && $hintOne === false) { |
|||
846 | 20 | if ($propertyInfo->isObject() && $propertyInfo->wrapper() !== null) { |
|||
0 ignored issues
–
show
The method
wrapper() does not exist on Bdf\Prime\Mapper\Info\PropertyInfo .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||
847 | /** @var ObjectPropertyInfo $propertyInfo */ |
||||
848 | 1 | $repository = $this->prime->repository($propertyInfo->className()); |
|||
849 | 1 | $wrapperClass = $this->getRelativeClassName($repository->collectionFactory()->wrapperClass($propertyInfo->wrapper())); |
|||
0 ignored issues
–
show
It seems like
$propertyInfo->wrapper() can also be of type callable ; however, parameter $wrapper of Bdf\Prime\Collection\Col...Factory::wrapperClass() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
850 | |||||
851 | 1 | $methodTypeHint = $wrapperClass; |
|||
852 | 1 | $variableType .= '[]|'.$wrapperClass; |
|||
853 | } else { |
||||
854 | 19 | $methodTypeHint = 'array'; |
|||
855 | |||||
856 | 19 | if ($variableType !== 'array') { |
|||
857 | 19 | $variableType .= '[]'; |
|||
858 | } |
||||
859 | } |
||||
860 | } |
||||
861 | |||||
862 | 32 | $replacements = [ |
|||
863 | 32 | '<description>' => ucfirst($type).' '.$variableName, |
|||
864 | 32 | '<methodTypeHint>' => $methodTypeHint, |
|||
865 | 32 | '<variableType>' => $variableType, |
|||
866 | 32 | '<variableName>' => $variableName, |
|||
867 | 32 | '<methodName>' => $methodName, |
|||
868 | 32 | '<fieldName>' => $fieldName, |
|||
869 | 32 | '<variableDefault>' => ($defaultValue !== null) ? (' = '.$defaultValue) : '' |
|||
870 | 32 | ]; |
|||
871 | |||||
872 | 32 | $method = str_replace( |
|||
873 | 32 | array_keys($replacements), |
|||
874 | 32 | array_values($replacements), |
|||
875 | 32 | $this->getMethodTemplate($type) |
|||
876 | 32 | ); |
|||
877 | |||||
878 | 32 | return $this->prefixCodeWithSpaces($method); |
|||
879 | } |
||||
880 | |||||
881 | /** |
||||
882 | * Get the template of the method |
||||
883 | * |
||||
884 | * @param string $prefix |
||||
885 | * |
||||
886 | * @return string |
||||
887 | * |
||||
888 | * @throws \LogicException |
||||
889 | */ |
||||
890 | 32 | private function getMethodTemplate($prefix) |
|||
891 | { |
||||
892 | switch ($prefix) { |
||||
893 | 32 | case 'get': |
|||
894 | 32 | return static::$getMethodTemplate; |
|||
0 ignored issues
–
show
|
|||||
895 | |||||
896 | 32 | case 'add': |
|||
897 | 19 | return static::$addMethodTemplate; |
|||
0 ignored issues
–
show
|
|||||
898 | |||||
899 | 32 | case 'set': |
|||
900 | 32 | return static::$setMethodTemplate; |
|||
0 ignored issues
–
show
|
|||||
901 | } |
||||
902 | |||||
903 | throw new \LogicException('No template found for method "'.$prefix.'"'); |
||||
904 | } |
||||
905 | |||||
906 | /** |
||||
907 | * @param string $description |
||||
908 | * @param string $methodName |
||||
909 | * @param string $content |
||||
910 | * |
||||
911 | * @return string |
||||
912 | */ |
||||
913 | 1 | protected function generateMethod(string $description, string $methodName, string $content, ?string $return = null) |
|||
914 | { |
||||
915 | 1 | if ($this->hasMethod($methodName)) { |
|||
916 | return ''; |
||||
917 | } |
||||
918 | |||||
919 | 1 | $this->staticReflection[$this->mapperInfo->className()]['methods'][] = $methodName; |
|||
920 | |||||
921 | 1 | $replacements = [ |
|||
922 | 1 | '<description>' => $description, |
|||
923 | 1 | '<methodName>' => $methodName, |
|||
924 | 1 | '<content>' => $content, |
|||
925 | 1 | '<return>' => $return ? ": $return" : '', |
|||
926 | 1 | ]; |
|||
927 | |||||
928 | 1 | $method = str_replace( |
|||
929 | 1 | array_keys($replacements), |
|||
930 | 1 | array_values($replacements), |
|||
931 | 1 | static::$methodTemplate |
|||
0 ignored issues
–
show
|
|||||
932 | 1 | ); |
|||
933 | |||||
934 | 1 | return $this->prefixCodeWithSpaces($method); |
|||
935 | } |
||||
936 | |||||
937 | /** |
||||
938 | * @param PropertyInfo $property |
||||
939 | * |
||||
940 | * @return string |
||||
941 | */ |
||||
942 | 32 | protected function generateFieldMappingPropertyDocBlock($property) |
|||
943 | { |
||||
944 | 32 | $lines = []; |
|||
945 | 32 | $lines[] = $this->spaces . '/**'; |
|||
946 | 32 | $lines[] = $this->spaces . ' * @var '.$property->phpType(); |
|||
947 | 32 | $lines[] = $this->spaces . ' */'; |
|||
948 | |||||
949 | 32 | return implode("\n", $lines); |
|||
950 | } |
||||
951 | |||||
952 | /** |
||||
953 | * @param ObjectPropertyInfo $property |
||||
954 | * |
||||
955 | * @return string |
||||
956 | */ |
||||
957 | 27 | protected function generateEmbeddedPropertyDocBlock($property) |
|||
958 | { |
||||
959 | 27 | $className = $property->className(); |
|||
960 | 27 | if ($className) { |
|||
961 | 27 | $className = $this->getRelativeClassName($className); |
|||
962 | |||||
963 | 27 | if ($property->isArray()) { |
|||
964 | 19 | if ($property->wrapper() !== null) { |
|||
965 | 1 | $repository = $this->prime->repository($property->className()); |
|||
966 | 1 | $className = $this->getRelativeClassName($repository->collectionFactory()->wrapperClass($property->wrapper())).'|'.$className.'[]'; |
|||
0 ignored issues
–
show
It seems like
$property->wrapper() can also be of type callable ; however, parameter $wrapper of Bdf\Prime\Collection\Col...Factory::wrapperClass() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
967 | } else { |
||||
968 | 27 | $className .= '[]'; |
|||
969 | } |
||||
970 | } |
||||
971 | } else { |
||||
972 | $className = '{type}'; |
||||
973 | } |
||||
974 | |||||
975 | 27 | $lines = []; |
|||
976 | 27 | $lines[] = $this->spaces . '/**'; |
|||
977 | 27 | $lines[] = $this->spaces . ' * @var '.$className; |
|||
978 | 27 | $lines[] = $this->spaces . ' */'; |
|||
979 | |||||
980 | 27 | return implode("\n", $lines); |
|||
981 | } |
||||
982 | |||||
983 | // |
||||
984 | //---------- tools methods |
||||
985 | // |
||||
986 | |||||
987 | /** |
||||
988 | * @todo this won't work if there is a namespace in brackets and a class outside of it. |
||||
989 | * |
||||
990 | * @param string $src |
||||
991 | * |
||||
992 | * @return void |
||||
993 | */ |
||||
994 | 3 | protected function parseTokensInEntityFile($src) |
|||
995 | { |
||||
996 | 3 | $tokens = token_get_all($src); |
|||
997 | 3 | $lastSeenNamespace = ""; |
|||
998 | 3 | $lastSeenClass = false; |
|||
999 | |||||
1000 | 3 | $inNamespace = false; |
|||
1001 | 3 | $inClass = false; |
|||
1002 | |||||
1003 | 3 | for ($i = 0; $i < count($tokens); $i++) { |
|||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||||
1004 | 3 | $token = $tokens[$i]; |
|||
1005 | 3 | if (in_array($token[0], [T_WHITESPACE, T_COMMENT, T_DOC_COMMENT])) { |
|||
1006 | 3 | continue; |
|||
1007 | } |
||||
1008 | |||||
1009 | 3 | if ($inNamespace) { |
|||
1010 | 3 | if ($token[0] == T_NS_SEPARATOR || $token[0] == T_STRING || (defined('T_NAME_QUALIFIED') && $token[0] == T_NAME_QUALIFIED)) { |
|||
1011 | 3 | $lastSeenNamespace .= $token[1]; |
|||
1012 | 3 | } elseif (is_string($token) && in_array($token, [';', '{'])) { |
|||
1013 | 3 | $inNamespace = false; |
|||
1014 | } |
||||
1015 | } |
||||
1016 | |||||
1017 | 3 | if ($inClass) { |
|||
1018 | 3 | $inClass = false; |
|||
1019 | 3 | $lastSeenClass = $lastSeenNamespace . ($lastSeenNamespace ? '\\' : '') . $token[1]; |
|||
1020 | 3 | $this->staticReflection[$lastSeenClass]['properties'] = []; |
|||
1021 | 3 | $this->staticReflection[$lastSeenClass]['methods'] = []; |
|||
1022 | } |
||||
1023 | |||||
1024 | 3 | if ($token[0] == T_NAMESPACE) { |
|||
1025 | 3 | $lastSeenNamespace = ""; |
|||
1026 | 3 | $inNamespace = true; |
|||
1027 | 3 | } elseif ($token[0] == T_CLASS && $tokens[$i-1][0] != T_DOUBLE_COLON) { |
|||
1028 | 3 | $inClass = true; |
|||
1029 | 3 | } elseif ($token[0] == T_FUNCTION) { |
|||
1030 | 3 | if ($tokens[$i+2][0] == T_STRING) { |
|||
1031 | 3 | $this->staticReflection[$lastSeenClass]['methods'][] = strtolower($tokens[$i+2][1]); |
|||
1032 | } elseif ($tokens[$i+2] == "&" && $tokens[$i+3][0] == T_STRING) { |
||||
1033 | 3 | $this->staticReflection[$lastSeenClass]['methods'][] = strtolower($tokens[$i+3][1]); |
|||
1034 | } |
||||
1035 | 3 | } elseif (in_array($token[0], [T_VAR, T_PUBLIC, T_PRIVATE, T_PROTECTED]) && $tokens[$i+2][0] != T_FUNCTION) { |
|||
1036 | 3 | $this->staticReflection[$lastSeenClass]['properties'][] = substr($tokens[$i+2][1], 1); |
|||
1037 | } |
||||
1038 | } |
||||
1039 | } |
||||
1040 | |||||
1041 | /** |
||||
1042 | * @param string $property |
||||
1043 | * |
||||
1044 | * @return bool |
||||
1045 | */ |
||||
1046 | 34 | protected function hasProperty($property) |
|||
1047 | { |
||||
1048 | 34 | if ($this->classToExtend || (!$this->isNew && class_exists($this->mapperInfo->className()))) { |
|||
1049 | // don't generate property if its already on the base class. |
||||
1050 | 5 | $reflClass = new \ReflectionClass($this->getClassToExtend() ?: $this->mapperInfo->className()); |
|||
1051 | 5 | if ($reflClass->hasProperty($property)) { |
|||
1052 | 2 | return true; |
|||
1053 | } |
||||
1054 | } |
||||
1055 | |||||
1056 | // check traits for existing property |
||||
1057 | 34 | foreach ($this->getTraitsReflections() as $trait) { |
|||
1058 | if ($trait->hasProperty($property)) { |
||||
1059 | return true; |
||||
1060 | } |
||||
1061 | } |
||||
1062 | |||||
1063 | 34 | return ( |
|||
1064 | 34 | isset($this->staticReflection[$this->mapperInfo->className()]) && |
|||
1065 | 34 | in_array($property, $this->staticReflection[$this->mapperInfo->className()]['properties']) |
|||
1066 | 34 | ); |
|||
1067 | } |
||||
1068 | |||||
1069 | /** |
||||
1070 | * @param string $method |
||||
1071 | * |
||||
1072 | * @return bool |
||||
1073 | */ |
||||
1074 | 34 | protected function hasMethod($method) |
|||
1075 | { |
||||
1076 | 34 | if ($this->classToExtend || (!$this->isNew && class_exists($this->mapperInfo->className()))) { |
|||
1077 | // don't generate method if its already on the base class. |
||||
1078 | 5 | $reflClass = new \ReflectionClass($this->getClassToExtend() ?: $this->mapperInfo->className()); |
|||
1079 | |||||
1080 | 5 | if ($reflClass->hasMethod($method)) { |
|||
1081 | 2 | return true; |
|||
1082 | } |
||||
1083 | } |
||||
1084 | |||||
1085 | // check traits for existing method |
||||
1086 | 34 | foreach ($this->getTraitsReflections() as $trait) { |
|||
1087 | if ($trait->hasMethod($method)) { |
||||
1088 | return true; |
||||
1089 | } |
||||
1090 | } |
||||
1091 | |||||
1092 | 34 | return ( |
|||
1093 | 34 | isset($this->staticReflection[$this->mapperInfo->className()]) && |
|||
1094 | 34 | in_array(strtolower($method), $this->staticReflection[$this->mapperInfo->className()]['methods']) |
|||
1095 | 34 | ); |
|||
1096 | } |
||||
1097 | |||||
1098 | /** |
||||
1099 | * Get class name relative to use |
||||
1100 | * |
||||
1101 | * @param string $className |
||||
1102 | * @return string |
||||
1103 | */ |
||||
1104 | 30 | protected function getRelativeClassName($className) |
|||
1105 | { |
||||
1106 | 30 | $className = ltrim($className, '\\'); |
|||
1107 | |||||
1108 | 30 | if ($this->hasNamespace($className)) { |
|||
1109 | 27 | return $this->getClassName($className); |
|||
1110 | } else { |
||||
1111 | 7 | return '\\' . $className; |
|||
1112 | } |
||||
1113 | } |
||||
1114 | |||||
1115 | /** |
||||
1116 | * Get the class short name |
||||
1117 | * |
||||
1118 | * @param string $className |
||||
1119 | * |
||||
1120 | * @return string |
||||
1121 | */ |
||||
1122 | 31 | protected function getClassName($className) |
|||
1123 | { |
||||
1124 | 31 | $parts = explode('\\', $className); |
|||
1125 | 31 | return array_pop($parts); |
|||
1126 | } |
||||
1127 | |||||
1128 | /** |
||||
1129 | * @param string $className |
||||
1130 | * |
||||
1131 | * @return string |
||||
1132 | */ |
||||
1133 | 31 | protected function getNamespace($className) |
|||
1134 | { |
||||
1135 | 31 | $parts = explode('\\', $className); |
|||
1136 | 31 | array_pop($parts); |
|||
1137 | |||||
1138 | 31 | return implode('\\', $parts); |
|||
1139 | } |
||||
1140 | |||||
1141 | /** |
||||
1142 | * @param string $className |
||||
1143 | * |
||||
1144 | * @return bool |
||||
1145 | */ |
||||
1146 | 31 | protected function hasNamespace($className) |
|||
1147 | { |
||||
1148 | 31 | return strrpos($className, '\\') != 0; |
|||
1149 | } |
||||
1150 | |||||
1151 | /** |
||||
1152 | * @return string |
||||
1153 | */ |
||||
1154 | 2 | protected function getClassToExtendName() |
|||
1155 | { |
||||
1156 | 2 | $refl = new \ReflectionClass($this->getClassToExtend()); |
|||
1157 | |||||
1158 | 2 | return $this->getRelativeClassName($refl->getName()); |
|||
1159 | } |
||||
1160 | |||||
1161 | /** |
||||
1162 | * @return string |
||||
1163 | */ |
||||
1164 | 3 | protected function getInterfacesToImplement() |
|||
1165 | { |
||||
1166 | 3 | $interfaces = []; |
|||
1167 | |||||
1168 | 3 | foreach ($this->interfaces as $interface) { |
|||
1169 | 3 | $refl = new \ReflectionClass($interface); |
|||
1170 | |||||
1171 | 3 | $interfaces[] = $this->getRelativeClassName($refl->getName()); |
|||
1172 | } |
||||
1173 | |||||
1174 | 3 | return implode(', ', $interfaces); |
|||
1175 | } |
||||
1176 | |||||
1177 | /** |
||||
1178 | * @param Mapper $mapper |
||||
1179 | * |
||||
1180 | * @return \ReflectionClass[] |
||||
1181 | */ |
||||
1182 | 34 | protected function getTraitsReflections() |
|||
1183 | { |
||||
1184 | 34 | if ($this->isNew) { |
|||
1185 | 31 | return []; |
|||
1186 | } |
||||
1187 | |||||
1188 | 3 | $reflClass = new \ReflectionClass($this->mapperInfo->className()); |
|||
1189 | |||||
1190 | 3 | $traits = []; |
|||
1191 | |||||
1192 | 3 | while ($reflClass !== false) { |
|||
1193 | 3 | $traits = array_merge($traits, $reflClass->getTraits()); |
|||
1194 | |||||
1195 | 3 | $reflClass = $reflClass->getParentClass(); |
|||
1196 | } |
||||
1197 | |||||
1198 | 3 | return $traits; |
|||
1199 | } |
||||
1200 | |||||
1201 | /** |
||||
1202 | * @param string $code |
||||
1203 | * @param int $num |
||||
1204 | * |
||||
1205 | * @return string |
||||
1206 | */ |
||||
1207 | 33 | protected function prefixCodeWithSpaces($code, $num = 1) |
|||
1208 | { |
||||
1209 | 33 | $lines = explode("\n", $code); |
|||
1210 | |||||
1211 | 33 | foreach ($lines as $key => $value) { |
|||
1212 | 33 | if (! empty($value)) { |
|||
1213 | 33 | $lines[$key] = str_repeat($this->spaces, $num) . $lines[$key]; |
|||
1214 | } |
||||
1215 | } |
||||
1216 | |||||
1217 | 33 | return implode("\n", $lines); |
|||
1218 | } |
||||
1219 | |||||
1220 | /** |
||||
1221 | * Get string representation of a value |
||||
1222 | * |
||||
1223 | * @param mixed $value |
||||
1224 | * |
||||
1225 | * @return string |
||||
1226 | */ |
||||
1227 | 5 | protected function stringfyValue($value) |
|||
1228 | { |
||||
1229 | 5 | if (is_array($value)) { |
|||
1230 | if (empty($value)) { |
||||
1231 | return '[]'; |
||||
1232 | } |
||||
1233 | |||||
1234 | return var_export($value, true); |
||||
1235 | } |
||||
1236 | |||||
1237 | 5 | if (null === $value) { |
|||
1238 | return 'null'; |
||||
1239 | } |
||||
1240 | |||||
1241 | 5 | if (is_string($value)) { |
|||
1242 | 4 | return "'" . $value . "'"; |
|||
1243 | } |
||||
1244 | |||||
1245 | 2 | if (is_bool($value)) { |
|||
1246 | 2 | return $value ? 'true' : 'false'; |
|||
1247 | } |
||||
1248 | |||||
1249 | return $value; |
||||
1250 | } |
||||
1251 | |||||
1252 | /** |
||||
1253 | * Get the php 7.4 property type hint |
||||
1254 | * |
||||
1255 | * This method will map invalid type hint to value one (ex: double -> float) |
||||
1256 | * It will also resolve the relative class name if the type is a class |
||||
1257 | * |
||||
1258 | * @param string $type The property type declared by field phpType() |
||||
1259 | * @param bool $nullable Does the property should be nullable |
||||
1260 | * |
||||
1261 | * @return string |
||||
1262 | * |
||||
1263 | * @see TypeInterface::phpType() |
||||
1264 | * |
||||
1265 | * @todo use directly the property info object ? |
||||
1266 | */ |
||||
1267 | 32 | protected function getPropertyTypeHint(string $type, bool $nullable): string |
|||
1268 | { |
||||
1269 | 32 | if (class_exists($type)) { |
|||
1270 | 29 | $type = $this->getRelativeClassName($type); |
|||
1271 | } else { |
||||
1272 | 32 | $type = self::PROPERTY_TYPE_MAP[$type] ?? $type; |
|||
1273 | } |
||||
1274 | |||||
1275 | 32 | return ($nullable ? '?' : '') . $type; |
|||
1276 | } |
||||
1277 | |||||
1278 | /** |
||||
1279 | * Get the php 7.4 property type hint for a simple property |
||||
1280 | * |
||||
1281 | * If typed properties are disabled, this method will return an empty string |
||||
1282 | * The returned type hint will be prefixed by a single space |
||||
1283 | * |
||||
1284 | * @param PropertyInfo $property |
||||
1285 | * @param bool $forceNullable Force typehint to be nullable. Useful property promotion |
||||
1286 | * |
||||
1287 | * @return string |
||||
1288 | */ |
||||
1289 | 32 | protected function getPropertyTypeHintForSimpleProperty(PropertyInfo $property, bool $forceNullable = false): string |
|||
1290 | { |
||||
1291 | 32 | if (!$this->useTypedProperties) { |
|||
1292 | 27 | return ''; |
|||
1293 | } |
||||
1294 | |||||
1295 | 16 | return ' ' . $this->getPropertyTypeHint($property->phpType(), $forceNullable || $property->isNullable()); |
|||
1296 | } |
||||
1297 | |||||
1298 | /** |
||||
1299 | * Get the php 7.4 property type hint for a object property (i.e. relation or embedded) |
||||
1300 | * |
||||
1301 | * If typed properties are disabled, this method will return an empty string |
||||
1302 | * The returned type hint will be prefixed by a single space |
||||
1303 | * |
||||
1304 | * - Embedded properties will not be marked as nullable |
||||
1305 | * - Relations will always be nullable |
||||
1306 | * - This method will also resolve collection relations and the wrapper class if provided |
||||
1307 | * |
||||
1308 | * @param ObjectPropertyInfo $property |
||||
1309 | * @param bool $forceNullable Force typehint to be nullable. Useful property promotion |
||||
1310 | * |
||||
1311 | * @return string |
||||
1312 | */ |
||||
1313 | 27 | protected function getPropertyTypeHintForObject(ObjectPropertyInfo $property, bool $forceNullable = false): string |
|||
1314 | { |
||||
1315 | 27 | if (!$this->useTypedProperties) { |
|||
1316 | 23 | return ''; |
|||
1317 | } |
||||
1318 | |||||
1319 | 13 | $type = $property->className(); |
|||
1320 | |||||
1321 | 13 | if ($property->isArray()) { |
|||
1322 | 8 | if ($property->wrapper() === null) { |
|||
1323 | 7 | $type = 'array'; |
|||
1324 | } else { |
||||
1325 | 1 | $repository = $this->prime->repository($type); |
|||
1326 | 1 | $type = $repository->collectionFactory()->wrapperClass($property->wrapper()); |
|||
0 ignored issues
–
show
It seems like
$property->wrapper() can also be of type callable ; however, parameter $wrapper of Bdf\Prime\Collection\Col...Factory::wrapperClass() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
1327 | } |
||||
1328 | } |
||||
1329 | |||||
1330 | 13 | return ' ' . $this->getPropertyTypeHint($type, $forceNullable || $property->isRelation()); |
|||
0 ignored issues
–
show
It seems like
$type can also be of type null ; however, parameter $type of Bdf\Prime\Entity\EntityG...::getPropertyTypeHint() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
1331 | } |
||||
1332 | |||||
1333 | //---------------------- mutators |
||||
1334 | |||||
1335 | /** |
||||
1336 | * Sets the number of spaces the exported class should have. |
||||
1337 | * |
||||
1338 | * @api |
||||
1339 | */ |
||||
1340 | 1 | public function setNumSpaces(int $numSpaces): void |
|||
1341 | { |
||||
1342 | 1 | $this->spaces = str_repeat(' ', $numSpaces); |
|||
1343 | 1 | $this->numSpaces = $numSpaces; |
|||
1344 | } |
||||
1345 | |||||
1346 | /** |
||||
1347 | * Gets the indentation spaces |
||||
1348 | */ |
||||
1349 | 1 | public function getNumSpaces(): int |
|||
1350 | { |
||||
1351 | 1 | return $this->numSpaces; |
|||
1352 | } |
||||
1353 | |||||
1354 | /** |
||||
1355 | * Sets the extension to use when writing php files to disk. |
||||
1356 | * |
||||
1357 | * @api |
||||
1358 | */ |
||||
1359 | 1 | public function setExtension(string $extension): void |
|||
1360 | { |
||||
1361 | 1 | $this->extension = $extension; |
|||
1362 | } |
||||
1363 | |||||
1364 | /** |
||||
1365 | * Get the file extension |
||||
1366 | */ |
||||
1367 | 1 | public function getExtension(): string |
|||
1368 | { |
||||
1369 | 1 | return $this->extension; |
|||
1370 | } |
||||
1371 | |||||
1372 | /** |
||||
1373 | * Sets the name of the class the generated classes should extend from. |
||||
1374 | * |
||||
1375 | * @api |
||||
1376 | */ |
||||
1377 | 6 | public function setClassToExtend(string $classToExtend): void |
|||
1378 | { |
||||
1379 | 6 | $this->classToExtend = $classToExtend; |
|||
1380 | } |
||||
1381 | |||||
1382 | /** |
||||
1383 | * Get the class to extend |
||||
1384 | */ |
||||
1385 | 35 | public function getClassToExtend(): ?string |
|||
1386 | { |
||||
1387 | 35 | return $this->classToExtend; |
|||
1388 | } |
||||
1389 | |||||
1390 | /** |
||||
1391 | * Add interface to implement |
||||
1392 | * |
||||
1393 | * @api |
||||
1394 | * |
||||
1395 | * @return void |
||||
1396 | */ |
||||
1397 | 2 | public function addInterface(string $interface): void |
|||
1398 | { |
||||
1399 | 2 | $this->interfaces[$interface] = $interface; |
|||
1400 | } |
||||
1401 | |||||
1402 | /** |
||||
1403 | * Sets the interfaces |
||||
1404 | * |
||||
1405 | * @param string[] $interfaces |
||||
1406 | * |
||||
1407 | * @api |
||||
1408 | */ |
||||
1409 | 2 | public function setInterfaces(array $interfaces): void |
|||
1410 | { |
||||
1411 | 2 | $this->interfaces = $interfaces; |
|||
1412 | } |
||||
1413 | |||||
1414 | /** |
||||
1415 | * Get the registered interfaces |
||||
1416 | */ |
||||
1417 | 1 | public function getInterfaces(): array |
|||
1418 | { |
||||
1419 | 1 | return $this->interfaces; |
|||
1420 | } |
||||
1421 | |||||
1422 | /** |
||||
1423 | * Add trait |
||||
1424 | * |
||||
1425 | * @api |
||||
1426 | * |
||||
1427 | * @return void |
||||
1428 | */ |
||||
1429 | 2 | public function addTrait(string $trait): void |
|||
1430 | { |
||||
1431 | 2 | $this->traits[$trait] = $trait; |
|||
1432 | } |
||||
1433 | |||||
1434 | /** |
||||
1435 | * Sets the traits |
||||
1436 | * |
||||
1437 | * @param string[] $traits |
||||
1438 | * |
||||
1439 | * @api |
||||
1440 | */ |
||||
1441 | 1 | public function setTraits(array $traits): void |
|||
1442 | { |
||||
1443 | 1 | $this->traits = $traits; |
|||
1444 | } |
||||
1445 | |||||
1446 | /** |
||||
1447 | * Get the registered traits |
||||
1448 | */ |
||||
1449 | 1 | public function getTraits(): array |
|||
1450 | { |
||||
1451 | 1 | return $this->traits; |
|||
1452 | } |
||||
1453 | |||||
1454 | /** |
||||
1455 | * Sets the class fields visibility for the entity (can either be private or protected). |
||||
1456 | * |
||||
1457 | * @throws \InvalidArgumentException |
||||
1458 | * |
||||
1459 | * @api |
||||
1460 | */ |
||||
1461 | 2 | public function setFieldVisibility(string $visibility): void |
|||
1462 | { |
||||
1463 | 2 | if ($visibility !== static::FIELD_VISIBLE_PRIVATE && $visibility !== static::FIELD_VISIBLE_PROTECTED) { |
|||
1464 | throw new \InvalidArgumentException('Invalid provided visibility (only private and protected are allowed): ' . $visibility); |
||||
1465 | } |
||||
1466 | |||||
1467 | 2 | $this->fieldVisibility = $visibility; |
|||
1468 | } |
||||
1469 | |||||
1470 | /** |
||||
1471 | * Get the field visibility |
||||
1472 | */ |
||||
1473 | 1 | public function getFieldVisibility(): string |
|||
1474 | { |
||||
1475 | 1 | return $this->fieldVisibility; |
|||
1476 | } |
||||
1477 | |||||
1478 | /** |
||||
1479 | * Sets whether or not to try and update the entity if it already exists. |
||||
1480 | * |
||||
1481 | * @api |
||||
1482 | */ |
||||
1483 | 4 | public function setUpdateEntityIfExists(bool $bool): void |
|||
1484 | { |
||||
1485 | 4 | $this->updateEntityIfExists = $bool; |
|||
1486 | } |
||||
1487 | |||||
1488 | /** |
||||
1489 | * Get the flag for updating the entity |
||||
1490 | */ |
||||
1491 | 1 | public function getUpdateEntityIfExists(): bool |
|||
1492 | { |
||||
1493 | 1 | return $this->updateEntityIfExists; |
|||
1494 | } |
||||
1495 | |||||
1496 | /** |
||||
1497 | * Sets whether or not to regenerate the entity if it exists. |
||||
1498 | * |
||||
1499 | * @api |
||||
1500 | */ |
||||
1501 | 1 | public function setRegenerateEntityIfExists(bool $bool): void |
|||
1502 | { |
||||
1503 | 1 | $this->regenerateEntityIfExists = $bool; |
|||
1504 | } |
||||
1505 | |||||
1506 | /** |
||||
1507 | * Get the flag for regenerating entity |
||||
1508 | */ |
||||
1509 | 1 | public function getRegenerateEntityIfExists(): bool |
|||
1510 | { |
||||
1511 | 1 | return $this->regenerateEntityIfExists; |
|||
1512 | } |
||||
1513 | |||||
1514 | /** |
||||
1515 | * Sets whether or not to generate stub methods for the entity. |
||||
1516 | * |
||||
1517 | * @api |
||||
1518 | */ |
||||
1519 | 2 | public function setGenerateStubMethods(bool $bool): void |
|||
1520 | { |
||||
1521 | 2 | $this->generateEntityStubMethods = $bool; |
|||
1522 | } |
||||
1523 | |||||
1524 | /** |
||||
1525 | * Get the flag for generating stub methods |
||||
1526 | */ |
||||
1527 | 1 | public function getGenerateStubMethods(): bool |
|||
1528 | { |
||||
1529 | 1 | return $this->generateEntityStubMethods; |
|||
1530 | } |
||||
1531 | |||||
1532 | /** |
||||
1533 | * Sets whether or not the get mehtod will be suffixed by 'get'. |
||||
1534 | * |
||||
1535 | * @param bool $bool |
||||
1536 | * |
||||
1537 | * @return void |
||||
1538 | * |
||||
1539 | * @api |
||||
1540 | */ |
||||
1541 | 2 | public function useGetShortcutMethod($bool = true) |
|||
1542 | { |
||||
1543 | 2 | $this->useGetShortcutMethod = $bool; |
|||
1544 | } |
||||
1545 | |||||
1546 | /** |
||||
1547 | * Get the flag for get mehtod name. |
||||
1548 | */ |
||||
1549 | 1 | public function getUseGetShortcutMethod(): bool |
|||
1550 | { |
||||
1551 | 1 | return $this->useGetShortcutMethod; |
|||
1552 | } |
||||
1553 | |||||
1554 | /** |
||||
1555 | * @return bool |
||||
1556 | */ |
||||
1557 | public function getUseTypedProperties(): bool |
||||
1558 | { |
||||
1559 | return $this->useTypedProperties; |
||||
1560 | } |
||||
1561 | |||||
1562 | /** |
||||
1563 | * Enable usage of php 7.4 type properties |
||||
1564 | * |
||||
1565 | * @param bool $useTypedProperties |
||||
1566 | */ |
||||
1567 | 16 | public function useTypedProperties(bool $useTypedProperties = true): void |
|||
1568 | { |
||||
1569 | 16 | $this->useTypedProperties = $useTypedProperties; |
|||
1570 | } |
||||
1571 | |||||
1572 | /** |
||||
1573 | * @return bool |
||||
1574 | */ |
||||
1575 | public function getUseConstructorPropertyPromotion(): bool |
||||
1576 | { |
||||
1577 | return $this->useConstructorPropertyPromotion; |
||||
1578 | } |
||||
1579 | |||||
1580 | /** |
||||
1581 | * Enable usage of PHP 8 promoted properties on constructor instead of array import |
||||
1582 | * |
||||
1583 | * @param bool $useConstructorPropertyPromotion |
||||
1584 | */ |
||||
1585 | 3 | public function useConstructorPropertyPromotion(bool $useConstructorPropertyPromotion = true): void |
|||
1586 | { |
||||
1587 | 3 | $this->useConstructorPropertyPromotion = $useConstructorPropertyPromotion; |
|||
1588 | } |
||||
1589 | } |
||||
1590 |