Completed
Push — 2.x ( 0b6590...78009d )
by Aleksei
20s queued 15s
created

EntityFactory   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 81
Duplicated Lines 0 %

Test Coverage

Coverage 92.11%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 39
dl 0
loc 81
ccs 35
cts 38
cp 0.9211
rs 10
c 1
b 0
f 0
wmc 14

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
C make() 0 70 13
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cycle\ORM\Service\Implementation;
6
7
use Cycle\ORM\Heap\HeapInterface;
8
use Cycle\ORM\Heap\Node;
9
use Cycle\ORM\Reference\ReferenceInterface;
10
use Cycle\ORM\Service\EntityFactoryInterface;
11
use Cycle\ORM\Service\IndexProviderInterface;
12
use Cycle\ORM\Service\MapperProviderInterface;
13
use Cycle\ORM\Service\RelationProviderInterface;
14
use Cycle\ORM\SchemaInterface;
15
use Cycle\ORM\Select\LoaderInterface;
16
use Cycle\ORM\Service\RoleResolverInterface;
17
18
/**
19
 * @internal
20
 */
21
final class EntityFactory implements EntityFactoryInterface
22
{
23 7418
    public function __construct(
24
        private HeapInterface $heap,
25
        private SchemaInterface $schema,
26
        private MapperProviderInterface $mapperProvider,
27
        private RelationProviderInterface $relationProvider,
28
        private IndexProviderInterface $indexProvider,
29
        private RoleResolverInterface $roleResolver,
30
    ) {}
31
32 4986
    public function make(
33
        string $role,
34
        array $data = [],
35
        int $status = Node::NEW,
36
        bool $typecast = false,
37
    ): object {
38 4986
        $role = $data[LoaderInterface::ROLE_KEY] ?? $role;
39 4986
        unset($data[LoaderInterface::ROLE_KEY]);
40
        // Resolved role
41 4986
        $rRole = $this->roleResolver->resolveRole($role);
42 4986
        $relMap = $this->relationProvider->getRelationMap($rRole);
43 4986
        $mapper = $this->mapperProvider->getMapper($rRole);
44
45 4986
        $castedData = $typecast ? $mapper->cast($data) : $data;
46
47 4986
        if ($status !== Node::NEW) {
48
            // unique entity identifier
49 4742
            $pk = $this->schema->define($role, SchemaInterface::PRIMARY_KEY);
50 4742
            if (\is_array($pk)) {
51 616
                $ids = [];
52 616
                foreach ($pk as $key) {
53 616
                    if (!isset($data[$key])) {
54
                        $ids = null;
55
                        break;
56
                    }
57 616
                    $ids[$key] = $data[$key];
58
                }
59
            } else {
60 4206
                $ids = isset($data[$pk]) ? [$pk => $data[$pk]] : null;
61
            }
62
63 4742
            if ($ids !== null) {
64 4742
                $e = $this->heap->find($rRole, $ids);
65
66 4742
                if ($e !== null) {
67 674
                    $relations = $relMap->getRelations();
68
                    $fetched = $mapper->fetchRelations($e);
69
70 674
                    // Get not resolved (references) or not set relations
71
                    $overwrite = [];
72
                    foreach ($relations as $name => $_) {
73
                        if (!\array_key_exists($name, $fetched) || $fetched[$name] instanceof ReferenceInterface) {
74
                            $overwrite[$name] = true;
75 4930
                        }
76 4930
                    }
77
78
                    if ($overwrite === []) {
79 4930
                        return $e;
80
                    }
81 4930
82
                    $node = $this->heap->get($e);
83
                    \assert($node !== null);
84 7154
85
                    // Replace references with actual relation data
86 7154
                    return $mapper->hydrate($e, $relMap->init(
87 5216
                        $this,
88 5216
                        $node,
89 5068
                        \array_intersect_key($castedData, $overwrite),
90
                    ));
91
                }
92 1582
            }
93 1582
        }
94 40
95
        $node = new Node($status, $castedData, $rRole);
96 40
        $e = $mapper->init($data, $role);
97
98 40
        /** Entity should be attached before {@see RelationMap::init()} running */
99
        $this->heap->attach($e, $node, $this->indexProvider->getIndexes($rRole));
100
101
        return $mapper->hydrate($e, $relMap->init($this, $node, $castedData));
102 40
    }
103
}
104