• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ipublikuj / doctrine-crud / 10244968780

05 Aug 2024 08:03AM UTC coverage: 31.907% (-22.9%) from 54.777%
10244968780

push

github

web-flow
Merge pull request #8 from ipublikuj/feature/throw-exception

Throw dbal exception

0 of 2 new or added lines in 2 files covered. (0.0%)

277 existing lines in 8 files now uncovered.

164 of 514 relevant lines covered (31.91%)

2.13 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

16.56
/src/Mapping/EntityMapper.php
1
<?php declare(strict_types = 1);
2

3
/**
4
 * EntityMapper.php
5
 *
6
 * @copyright      More in LICENSE.md
7
 * @license        https://www.ipublikuj.eu
8
 * @author         Adam Kadlec <adam.kadlec@ipublikuj.eu>
9
 * @package        iPublikuj:DoctrineCrud!
10
 * @subpackage     Mapping
11
 * @since          1.0.0
12
 *
13
 * @date           29.01.14
14
 */
15

16
namespace IPub\DoctrineCrud\Mapping;
17

18
use Doctrine\Common;
19
use Doctrine\ORM;
20
use Doctrine\Persistence;
21
use IPub\DoctrineCrud\Entities;
22
use IPub\DoctrineCrud\Exceptions;
23
use IPub\DoctrineCrud\Helpers;
24
use IPub\DoctrineCrud\Mapping;
25
use Nette;
26
use Nette\Utils;
27
use phpDocumentor;
28
use ReflectionAttribute;
29
use ReflectionClass;
30
use ReflectionException;
31
use ReflectionMethod;
32
use ReflectionProperty;
33
use Reflector;
34
use function array_key_exists;
35
use function array_map;
36
use function array_merge;
37
use function array_reduce;
38
use function array_unique;
39
use function assert;
40
use function call_user_func;
41
use function call_user_func_array;
42
use function class_exists;
43
use function explode;
44
use function in_array;
45
use function is_array;
46
use function is_callable;
47
use function is_string;
48
use function method_exists;
49
use function sprintf;
50
use function strpos;
51
use function trim;
52
use function ucfirst;
53

54
/**
55
 * Doctrine CRUD entity mapper
56
 *
57
 * @package        iPublikuj:DoctrineCrud!
58
 * @subpackage     Mapping
59
 *
60
 * @author         Adam Kadlec <adam.kadlec@ipublikuj.eu>
61
 */
62
final class EntityMapper implements IEntityMapper
63
{
64

65
        use Nette\SmartObject;
66

67
        public function __construct(
68
                private readonly Persistence\ManagerRegistry $managerRegistry,
69
        )
70
        {
71
        }
12✔
72

73
        /**
74
         * @throws Exceptions\EntityCreation
75
         * @throws Exceptions\InvalidState
76
         * @throws ReflectionException
77
         */
78
        public function fillEntity(Utils\ArrayHash $values, Entities\IEntity $entity, bool $isNew = false): Entities\IEntity
79
        {
80
                $reflectionClass = new ReflectionClass($entity::class);
9✔
81

82
                // Hack for proxy classes...
83
                if ($reflectionClass->implementsInterface(Common\Proxy\Proxy::class)) {
9✔
84
                        // ... we need to extract entity class name from proxy class
UNCOV
85
                        $parentClass = $reflectionClass->getParentClass();
×
86

UNCOV
87
                        $entityClass = $parentClass !== false ? $parentClass->getName() : $entity::class;
×
88

89
                } else {
90
                        $entityClass = $entity::class;
9✔
91
                }
92

93
                $entityClassManager = $this->managerRegistry->getManagerForClass($entityClass);
9✔
94

95
                if ($entityClassManager === null) {
9✔
UNCOV
96
                        throw new Exceptions\InvalidState(
×
UNCOV
97
                                sprintf('Entity manager for entity %s could not be loaded', $entityClass),
×
UNCOV
98
                        );
×
99
                }
100

101
                /** @var ORM\Mapping\ClassMetadataInfo<object> $classMetadata */
102
                $classMetadata = $entityClassManager->getClassMetadata($entityClass);
9✔
103

104
                $reflectionProperties = [];
9✔
105

106
                try {
107
                        $ref = new ReflectionClass($entityClass);
9✔
108

109
                        foreach ($ref->getProperties() as $reflectionProperty) {
9✔
110
                                $reflectionProperties[] = $reflectionProperty->getName();
9✔
111
                        }
UNCOV
112
                } catch (ReflectionException) {
×
113
                        // Nothing to do here
114
                }
115

116
                foreach (array_unique(
9✔
117
                        array_merge($reflectionProperties, $classMetadata->getFieldNames(), $classMetadata->getAssociationNames()),
9✔
118
                ) as $fieldName) {
9✔
119
                        try {
120
                                $propertyReflection = new ReflectionProperty($entityClass, $fieldName);
9✔
121

UNCOV
122
                        } catch (ReflectionException) {
×
123
                                // Entity property is readonly
UNCOV
124
                                continue;
×
125
                        }
126

127
                        $crudAttribute = array_reduce(
9✔
128
                                $propertyReflection->getAttributes(),
9✔
129
                                static function (ReflectionAttribute|null $carry, ReflectionAttribute $attribute): ReflectionAttribute|null {
9✔
130
                                        if ($carry === null && $attribute->getName() === Mapping\Attribute\Crud::class) {
9✔
131
                                                return $attribute;
9✔
132
                                        }
133

134
                                        return $carry;
9✔
135
                                },
9✔
136
                        );
9✔
137

138
                        if ($crudAttribute === null) {
9✔
139
                                continue;
9✔
140
                        }
141

142
                        $crud = $crudAttribute->newInstance();
9✔
143
                        assert($crud instanceof Mapping\Attribute\Crud);
144

145
                        if ($isNew && $crud->isRequired() && !$values->offsetExists($fieldName)) {
9✔
UNCOV
146
                                throw new Exceptions\MissingRequiredField(
×
147
                                        $entity,
×
148
                                        $fieldName,
×
UNCOV
149
                                        sprintf('Missing required key "%s"', $fieldName),
×
150
                                );
×
151
                        }
152

153
                        if (!array_key_exists($fieldName, (array) $values) || (!$isNew && !$crud->isWritable())) {
9✔
154
                                continue;
3✔
155
                        }
156

157
                        $value = $values->offsetGet($fieldName);
9✔
158

159
                        if (
160
                                (
161
                                        $value instanceof Utils\ArrayHash
9✔
162
                                        || is_array($value)
9✔
163
                                )
164
                                && isset($classMetadata->reflFields[$fieldName])
9✔
165
                        ) {
166
                                if (!$classMetadata->getFieldValue($entity, $fieldName) instanceof Entities\IEntity) {
×
UNCOV
167
                                        $propertyAttributes = $propertyReflection->getAttributes();
×
168

169
                                        $attributes = array_map(
×
170
                                                (static fn (ReflectionAttribute $attribute): string => $attribute->getName()),
×
UNCOV
171
                                                $propertyAttributes,
×
172
                                        );
×
173

UNCOV
174
                                        if (isset($value['entity']) && class_exists($value['entity'])) {
×
175
                                                $className = $value['entity'];
×
176

UNCOV
177
                                        } elseif (in_array(ORM\Mapping\OneToOne::class, $attributes, true)) {
×
UNCOV
178
                                                $propertyAttribute = array_reduce(
×
UNCOV
179
                                                        $propertyAttributes,
×
180
                                                        static function (ReflectionAttribute|null $carry, ReflectionAttribute $attribute): ReflectionAttribute|null {
×
181
                                                                if ($carry === null && $attribute->getName() === ORM\Mapping\OneToOne::class) {
×
UNCOV
182
                                                                        return $attribute;
×
183
                                                                }
184

185
                                                                return $carry;
×
UNCOV
186
                                                        },
×
187
                                                );
×
188
                                                assert($propertyAttribute instanceof ReflectionAttribute);
189

190
                                                $propertyAttribute = $propertyAttribute->newInstance();
×
191
                                                assert($propertyAttribute instanceof ORM\Mapping\OneToOne);
192

193
                                                $className = $propertyAttribute->targetEntity;
×
194

UNCOV
195
                                        } elseif (in_array(ORM\Mapping\OneToMany::class, $attributes, true)) {
×
196
                                                $propertyAttribute = array_reduce(
×
197
                                                        $propertyAttributes,
×
198
                                                        static function (ReflectionAttribute|null $carry, ReflectionAttribute $attribute): ReflectionAttribute|null {
×
UNCOV
199
                                                                if ($carry === null && $attribute->getName() === ORM\Mapping\OneToMany::class) {
×
200
                                                                        return $attribute;
×
201
                                                                }
202

UNCOV
203
                                                                return $carry;
×
UNCOV
204
                                                        },
×
205
                                                );
×
206
                                                assert($propertyAttribute instanceof ReflectionAttribute);
207

208
                                                $propertyAttribute = $propertyAttribute->newInstance();
×
209
                                                assert($propertyAttribute instanceof ORM\Mapping\OneToMany);
210

UNCOV
211
                                                $className = $propertyAttribute->targetEntity;
×
212

UNCOV
213
                                                $items = [];
×
214

215
                                                if ($className !== null && class_exists($className)) {
×
216
                                                        $rc = new ReflectionClass($className);
×
217

UNCOV
218
                                                        $subClassIdProperty = null;
×
219

220
                                                        foreach ($rc->getProperties() as $subClassProperty) {
×
UNCOV
221
                                                                $subClassPropertyAttributes = $subClassProperty->getAttributes();
×
222

223
                                                                $subClassAttributes = array_map(
×
UNCOV
224
                                                                        (static fn (ReflectionAttribute $attribute): string => $attribute->getName()),
×
UNCOV
225
                                                                        $subClassPropertyAttributes,
×
226
                                                                );
×
227

228
                                                                if (in_array(ORM\Mapping\Id::class, $subClassAttributes, true)) {
×
229
                                                                        $subClassIdProperty = $subClassProperty->getName();
×
230

UNCOV
231
                                                                        break;
×
232
                                                                }
233
                                                        }
234

235
                                                        foreach ($value as $item) {
×
236
                                                                assert($item instanceof Utils\ArrayHash);
237
                                                                $subEntity = null;
×
238

239
                                                                $subClassName = $className;
×
240

UNCOV
241
                                                                $rc = new ReflectionClass($className);
×
242

243
                                                                if (
UNCOV
244
                                                                        $rc->isAbstract()
×
UNCOV
245
                                                                        && isset($item['entity'])
×
UNCOV
246
                                                                        && is_string($item['entity'])
×
247
                                                                        && class_exists($item['entity'])
×
248
                                                                ) {
UNCOV
249
                                                                        $subClassName = $item['entity'];
×
250

251
                                                                        $rc = new ReflectionClass($subClassName);
×
252
                                                                }
253

UNCOV
254
                                                                if ($subClassIdProperty !== null && $item->offsetExists($subClassIdProperty)) {
×
255
                                                                        $entityClassManager = $this->managerRegistry->getManagerForClass($subClassName);
×
256

257
                                                                        $subEntity = $entityClassManager
×
258
                                                                                ?->getRepository($subClassName)
×
UNCOV
259
                                                                                ->find($item->offsetGet($subClassIdProperty));
×
260

UNCOV
261
                                                                        if ($subEntity !== null && $subEntity instanceof Entities\IEntity) {
×
UNCOV
262
                                                                                $subEntity = $this->fillEntity($item, $subEntity);
×
263
                                                                        }
264
                                                                }
265

UNCOV
266
                                                                if ($subEntity === null) {
×
267
                                                                        $constructor = $rc->getConstructor();
×
268

UNCOV
269
                                                                        $subEntity = $constructor !== null ? $rc->newInstanceArgs(
×
UNCOV
270
                                                                                Helpers::autowireArguments(
×
271
                                                                                        $constructor,
×
UNCOV
272
                                                                                        array_merge((array) $item, ['parent_entity' => $entity]),
×
UNCOV
273
                                                                                ),
×
274
                                                                        ) : new $subClassName();
×
275

UNCOV
276
                                                                        if ($subEntity instanceof Entities\IEntity) {
×
UNCOV
277
                                                                                $subEntity = $this->fillEntity(
×
UNCOV
278
                                                                                        Utils\ArrayHash::from(
×
UNCOV
279
                                                                                                array_merge(
×
UNCOV
280
                                                                                                        (array) $item,
×
UNCOV
281
                                                                                                        [$this->findAttributeName($entity, $subClassName) => $entity],
×
UNCOV
282
                                                                                                ),
×
UNCOV
283
                                                                                        ),
×
284
                                                                                        $subEntity,
×
285
                                                                                        true,
×
286
                                                                                );
×
287
                                                                        }
288
                                                                }
289

UNCOV
290
                                                                $items[] = $subEntity;
×
291
                                                        }
292

UNCOV
293
                                                        $this->setFieldValue($classMetadata, $entity, $fieldName, $items);
×
294
                                                }
295

296
                                                continue;
×
297
                                        } elseif (in_array(ORM\Mapping\ManyToOne::class, $attributes, true)) {
×
UNCOV
298
                                                $propertyAttribute = array_reduce(
×
299
                                                        $propertyAttributes,
×
300
                                                        static function (ReflectionAttribute|null $carry, ReflectionAttribute $attribute): ReflectionAttribute|null {
×
301
                                                                if ($carry === null && $attribute->getName() === ORM\Mapping\ManyToOne::class) {
×
UNCOV
302
                                                                        return $attribute;
×
303
                                                                }
304

UNCOV
305
                                                                return $carry;
×
306
                                                        },
×
307
                                                );
×
308
                                                assert($propertyAttribute instanceof ReflectionAttribute);
309

UNCOV
310
                                                $propertyAttribute = $propertyAttribute->newInstance();
×
311
                                                assert($propertyAttribute instanceof ORM\Mapping\ManyToOne);
312

UNCOV
313
                                                $className = $propertyAttribute->targetEntity;
×
314

315
                                        } else {
316
                                                $varAnnotation = $this->parseAnnotation($propertyReflection, 'var');
×
317

UNCOV
318
                                                $className = null;
×
319

UNCOV
320
                                                if ($varAnnotation !== null && strpos($varAnnotation, '|') !== false) {
×
321
                                                        foreach (explode('|', $varAnnotation) as $varAnnotationItem) {
×
322
                                                                if (class_exists($varAnnotationItem)) {
×
UNCOV
323
                                                                        $className = $varAnnotationItem;
×
324
                                                                }
325
                                                        }
326
                                                }
327
                                        }
328

329
                                        // Check if class is callable
UNCOV
330
                                        if (is_string($className) && class_exists($className)) {
×
UNCOV
331
                                                $rc = new ReflectionClass($className);
×
332

333
                                                if ($rc->isAbstract() && isset($value['entity']) && class_exists($value['entity'])) {
×
UNCOV
334
                                                        $className = $value['entity'];
×
UNCOV
335
                                                        $rc = new ReflectionClass($value['entity']);
×
336
                                                }
337

UNCOV
338
                                                $subEntityValue = $isNew ? null : $this->getFieldValue($classMetadata, $entity, $fieldName);
×
339

340
                                                if (
UNCOV
341
                                                        $subEntityValue instanceof $className
×
UNCOV
342
                                                        && $subEntityValue instanceof Entities\IEntity
×
343
                                                ) {
UNCOV
344
                                                        $this->setFieldValue(
×
UNCOV
345
                                                                $classMetadata,
×
UNCOV
346
                                                                $entity,
×
UNCOV
347
                                                                $fieldName,
×
UNCOV
348
                                                                $this->fillEntity(
×
UNCOV
349
                                                                        $value instanceof Utils\ArrayHash ? $value : Utils\ArrayHash::from($value),
×
UNCOV
350
                                                                        $subEntityValue,
×
UNCOV
351
                                                                ),
×
UNCOV
352
                                                        );
×
353

UNCOV
354
                                                } elseif ($subEntityValue === null) {
×
UNCOV
355
                                                        $constructor = $rc->getConstructor();
×
356

357
                                                        if ($constructor !== null) {
×
UNCOV
358
                                                                $subEntity = $rc->newInstanceArgs(
×
UNCOV
359
                                                                        Helpers::autowireArguments(
×
360
                                                                                $constructor,
×
UNCOV
361
                                                                                array_merge((array) $value, ['parent_entity' => $entity]),
×
362
                                                                        ),
×
363
                                                                );
×
364

365
                                                                $this->setFieldValue($classMetadata, $entity, $fieldName, $subEntity);
×
366

367
                                                        } else {
UNCOV
368
                                                                $this->setFieldValue($classMetadata, $entity, $fieldName, new $className());
×
369
                                                        }
370
                                                }
371
                                        } else {
372
                                                $this->setFieldValue($classMetadata, $entity, $fieldName, $value);
×
373
                                        }
374
                                }
375

376
                                $fieldValue = $classMetadata->getFieldValue($entity, $fieldName);
×
377

378
                                // Check again if entity was created
379
                                if ($fieldValue !== null && $fieldValue instanceof Entities\IEntity) {
×
380
                                        $this->setFieldValue(
×
381
                                                $classMetadata,
×
UNCOV
382
                                                $entity,
×
UNCOV
383
                                                $fieldName,
×
384
                                                $this->fillEntity(Utils\ArrayHash::from((array) $value), $fieldValue, $isNew),
×
385
                                        );
×
386
                                }
387
                        } else {
388
                                $varAnnotation = $this->parseAnnotation($propertyReflection, 'var');
9✔
389

390
                                $className = $varAnnotation;
9✔
391

392
                                if ($varAnnotation !== null && strpos($varAnnotation, '|') !== false) {
9✔
UNCOV
393
                                        foreach (explode('|', $varAnnotation) as $varAnnotationItem) {
×
UNCOV
394
                                                if (class_exists($varAnnotationItem)) {
×
UNCOV
395
                                                        $className = $varAnnotationItem;
×
396
                                                }
397
                                        }
398
                                }
399

400
                                // Check if class is callable
401
                                if (
402
                                        is_string($className)
9✔
403
                                        && ($value instanceof Utils\ArrayHash || is_array($value))
9✔
404
                                ) {
UNCOV
405
                                        if (class_exists($className)) {
×
UNCOV
406
                                                $rc = new ReflectionClass($className);
×
407

UNCOV
408
                                                if ($rc->isAbstract() && isset($value['entity']) && class_exists($value['entity'])) {
×
UNCOV
409
                                                        $className = $value['entity'];
×
UNCOV
410
                                                        $rc = new ReflectionClass($value['entity']);
×
411
                                                }
412

UNCOV
413
                                                $constructor = $rc->getConstructor();
×
414

UNCOV
415
                                                if ($constructor !== null) {
×
UNCOV
416
                                                        $subEntity = $rc->newInstanceArgs(
×
UNCOV
417
                                                                Helpers::autowireArguments(
×
UNCOV
418
                                                                        $constructor,
×
UNCOV
419
                                                                        array_merge((array) $value, ['parent_entity' => $entity]),
×
UNCOV
420
                                                                ),
×
UNCOV
421
                                                        );
×
422

UNCOV
423
                                                        $this->setFieldValue($classMetadata, $entity, $fieldName, $subEntity);
×
424

425
                                                } else {
UNCOV
426
                                                        $this->setFieldValue($classMetadata, $entity, $fieldName, new $className());
×
427
                                                }
UNCOV
428
                                        } elseif (isset($value['entity']) && class_exists($value['entity'])) {
×
UNCOV
429
                                                $className = $value['entity'];
×
UNCOV
430
                                                $rc = new ReflectionClass($value['entity']);
×
431

432
                                                $constructor = $rc->getConstructor();
×
433

UNCOV
434
                                                $subEntity = $constructor !== null ? $rc->newInstanceArgs(
×
UNCOV
435
                                                        Helpers::autowireArguments(
×
UNCOV
436
                                                                $constructor,
×
UNCOV
437
                                                                array_merge((array) $value, ['parent_entity' => $entity]),
×
UNCOV
438
                                                        ),
×
UNCOV
439
                                                ) : new $className();
×
440

UNCOV
441
                                                if ($subEntity instanceof Entities\IEntity) {
×
UNCOV
442
                                                        $this->setFieldValue(
×
UNCOV
443
                                                                $classMetadata,
×
UNCOV
444
                                                                $entity,
×
UNCOV
445
                                                                $fieldName,
×
UNCOV
446
                                                                $this->fillEntity(
×
UNCOV
447
                                                                        Utils\ArrayHash::from(
×
UNCOV
448
                                                                                array_merge(
×
UNCOV
449
                                                                                        (array) $value,
×
450
                                                                                        [$this->findAttributeName($entity, $className) => $entity],
×
UNCOV
451
                                                                                ),
×
UNCOV
452
                                                                        ),
×
UNCOV
453
                                                                        $subEntity,
×
UNCOV
454
                                                                        true,
×
UNCOV
455
                                                                ),
×
UNCOV
456
                                                        );
×
457
                                                }
458
                                        } else {
UNCOV
459
                                                $this->setFieldValue($classMetadata, $entity, $fieldName, $value);
×
460
                                        }
461
                                } else {
462
                                        $this->setFieldValue($classMetadata, $entity, $fieldName, $value);
9✔
463
                                }
464
                        }
465
                }
466

467
                return $entity;
9✔
468
        }
469

470
        /**
471
         * @throws Exceptions\InvalidState
472
         */
473
        private function findAttributeName(Entities\IEntity $entity, string $className): string
474
        {
UNCOV
475
                if (!class_exists($className)) {
×
UNCOV
476
                        throw new Exceptions\InvalidState(
×
UNCOV
477
                                sprintf('Provided class name %s is not valid class', $className),
×
UNCOV
478
                        );
×
479
                }
480

UNCOV
481
                $rc = new ReflectionClass($className);
×
482

UNCOV
483
                foreach ($rc->getProperties() as $property) {
×
UNCOV
484
                        $propertyAttributes = $property->getAttributes();
×
485

UNCOV
486
                        $attributes = array_map(
×
UNCOV
487
                                (static fn (ReflectionAttribute $attribute): string => $attribute->getName()),
×
UNCOV
488
                                $propertyAttributes,
×
UNCOV
489
                        );
×
490

UNCOV
491
                        $propertyClassName = null;
×
492

UNCOV
493
                        if (in_array(ORM\Mapping\OneToOne::class, $attributes, true)) {
×
UNCOV
494
                                $propertyAttribute = array_reduce(
×
UNCOV
495
                                        $propertyAttributes,
×
UNCOV
496
                                        static function (ReflectionAttribute|null $carry, ReflectionAttribute $attribute): ReflectionAttribute|null {
×
UNCOV
497
                                                if ($carry === null && $attribute->getName() === ORM\Mapping\OneToOne::class) {
×
UNCOV
498
                                                        return $attribute;
×
499
                                                }
500

UNCOV
501
                                                return $carry;
×
UNCOV
502
                                        },
×
UNCOV
503
                                );
×
504
                                assert($propertyAttribute instanceof ReflectionAttribute);
505

UNCOV
506
                                $propertyAttribute = $propertyAttribute->newInstance();
×
507
                                assert($propertyAttribute instanceof ORM\Mapping\OneToOne);
508

UNCOV
509
                                $propertyClassName = $propertyAttribute->targetEntity;
×
510

UNCOV
511
                        } elseif (in_array(ORM\Mapping\OneToMany::class, $attributes, true)) {
×
UNCOV
512
                                $propertyAttribute = array_reduce(
×
UNCOV
513
                                        $propertyAttributes,
×
UNCOV
514
                                        static function (ReflectionAttribute|null $carry, ReflectionAttribute $attribute): ReflectionAttribute|null {
×
UNCOV
515
                                                if ($carry === null && $attribute->getName() === ORM\Mapping\OneToMany::class) {
×
UNCOV
516
                                                        return $attribute;
×
517
                                                }
518

UNCOV
519
                                                return $carry;
×
UNCOV
520
                                        },
×
UNCOV
521
                                );
×
522
                                assert($propertyAttribute instanceof ReflectionAttribute);
523

UNCOV
524
                                $propertyAttribute = $propertyAttribute->newInstance();
×
525
                                assert($propertyAttribute instanceof ORM\Mapping\OneToMany);
526

UNCOV
527
                                $propertyClassName = $propertyAttribute->targetEntity;
×
528

UNCOV
529
                        } elseif (in_array(ORM\Mapping\ManyToOne::class, $attributes, true)) {
×
UNCOV
530
                                $propertyAttribute = array_reduce(
×
UNCOV
531
                                        $propertyAttributes,
×
UNCOV
532
                                        static function (ReflectionAttribute|null $carry, ReflectionAttribute $attribute): ReflectionAttribute|null {
×
UNCOV
533
                                                if ($carry === null && $attribute->getName() === ORM\Mapping\ManyToOne::class) {
×
UNCOV
534
                                                        return $attribute;
×
535
                                                }
536

UNCOV
537
                                                return $carry;
×
UNCOV
538
                                        },
×
UNCOV
539
                                );
×
540
                                assert($propertyAttribute instanceof ReflectionAttribute);
541

UNCOV
542
                                $propertyAttribute = $propertyAttribute->newInstance();
×
543
                                assert($propertyAttribute instanceof ORM\Mapping\ManyToOne);
544

UNCOV
545
                                $propertyClassName = $propertyAttribute->targetEntity;
×
546
                        }
547

UNCOV
548
                        if (is_string($propertyClassName) && $entity instanceof $propertyClassName) {
×
UNCOV
549
                                return $property->getName();
×
550
                        }
551
                }
552

UNCOV
553
                return 'parent_entity';
×
554
        }
555

556
        /**
557
         * @param ORM\Mapping\ClassMetadataInfo<object> $classMetadata
558
         */
559
        private function setFieldValue(
560
                ORM\Mapping\ClassMetadataInfo $classMetadata,
561
                Entities\IEntity $entity,
562
                string $field,
563
                mixed $value,
564
        ): void
565
        {
566
                $methodName = 'set' . ucfirst($field);
9✔
567

568
                if ($value instanceof Utils\ArrayHash) {
9✔
UNCOV
569
                        $value = (array) $value;
×
570
                }
571

572
                try {
573
                        $propertyReflection = new ReflectionMethod($entity::class, $methodName);
9✔
574

575
                        if ($propertyReflection->isPublic()) {
9✔
576
                                $callback = [$entity, $methodName];
9✔
577

578
                                // Try to call state setter
579
                                if (is_callable($callback)) {
9✔
580
                                        call_user_func_array($callback, [$value]);
9✔
581
                                }
UNCOV
582
                        } elseif (isset($classMetadata->reflFields[$field])) {
×
583
                                // Fallback for missing setter
584
                                $classMetadata->setFieldValue($entity, $field, $value);
9✔
585
                        }
586

587
                        // Fallback for missing setter
UNCOV
588
                } catch (ReflectionException) {
×
UNCOV
589
                        $classMetadata->setFieldValue($entity, $field, $value);
×
590
                }
591
        }
592

593
        /**
594
         * @param ORM\Mapping\ClassMetadataInfo<object> $classMetadata
595
         */
596
        private function getFieldValue(
597
                ORM\Mapping\ClassMetadataInfo $classMetadata,
598
                Entities\IEntity $entity,
599
                string $field,
600
        ): mixed
601
        {
UNCOV
602
                $methodName = 'get' . ucfirst($field);
×
603

604
                try {
UNCOV
605
                        $propertyReflection = new ReflectionMethod($entity::class, $methodName);
×
606

UNCOV
607
                        if ($propertyReflection->isPublic()) {
×
UNCOV
608
                                $callback = [$entity, $methodName];
×
609

610
                                // Try to call state setter
UNCOV
611
                                if (is_callable($callback)) {
×
UNCOV
612
                                        return call_user_func($callback);
×
613
                                }
UNCOV
614
                        } elseif (isset($classMetadata->reflFields[$field])) {
×
615
                                // Fallback for missing setter
UNCOV
616
                                return $classMetadata->getFieldValue($entity, $field);
×
617
                        }
618

619
                        // Fallback for missing setter
UNCOV
620
                } catch (ReflectionException) {
×
UNCOV
621
                        return $classMetadata->getFieldValue($entity, $field);
×
622
                }
623

UNCOV
624
                return null;
×
625
        }
626

627
        private function parseAnnotation(Reflector $ref, string $name): string|null
628
        {
629
                $factory = phpDocumentor\Reflection\DocBlockFactory::createInstance();
9✔
630

631
                if (
632
                        !method_exists($ref, 'getDocComment')
9✔
633
                        || !is_string($ref->getDocComment())
9✔
634
                ) {
635
                        return null;
9✔
636
                }
637

UNCOV
638
                $docBlock = $factory->create($ref->getDocComment());
×
639

UNCOV
640
                foreach ($docBlock->getTags() as $tag) {
×
UNCOV
641
                        if ($tag->getName() === $name) {
×
UNCOV
642
                                return trim((string) $tag);
×
643
                        }
644
                }
645

UNCOV
646
                return null;
×
647
        }
648

649
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc