Passed
Push — 2.x ( 0b5227...cb81b7 )
by butschster
16:17
created

EntityFactory::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 0
nc 1
nop 5
dl 0
loc 7
ccs 0
cts 0
cp 0
crap 2
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cycle\ORM\Service\Implementation;
6
7
use Cycle\ORM\EntityProxyInterface;
8
use Cycle\ORM\Exception\ORMException;
9
use Cycle\ORM\Heap\HeapInterface;
10
use Cycle\ORM\Heap\Node;
11
use Cycle\ORM\Service\EntityFactoryInterface;
12
use Cycle\ORM\Service\IndexProviderInterface;
13
use Cycle\ORM\Service\MapperProviderInterface;
14
use Cycle\ORM\Service\RelationProviderInterface;
15
use Cycle\ORM\SchemaInterface;
16
use Cycle\ORM\Select\LoaderInterface;
17
18
/**
19
 * @internal
20
 */
21
final class EntityFactory implements EntityFactoryInterface
22
{
23
    public function __construct(
24
        private HeapInterface $heap,
25
        private SchemaInterface $schema,
26
        private MapperProviderInterface $mapperProvider,
27
        private RelationProviderInterface $relationProvider,
28
        private IndexProviderInterface $indexProvider,
29
    ) {
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->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
                    $node = $this->heap->get($e);
68
                    \assert($node !== null);
69
70 674
                    return $mapper->hydrate($e, $relMap->init($this, $node, $castedData));
71
                }
72
            }
73
        }
74
75 4930
        $node = new Node($status, $castedData, $rRole);
76 4930
        $e = $mapper->init($data, $role);
77
78
        /** Entity should be attached before {@see RelationMap::init()} running */
79 4930
        $this->heap->attach($e, $node, $this->indexProvider->getIndexes($rRole));
80
81 4930
        return $mapper->hydrate($e, $relMap->init($this, $node, $castedData));
82
    }
83
84 7154
    public function resolveRole(object|string $entity): string
85
    {
86 7154
        if (\is_object($entity)) {
87 5216
            $node = $this->heap->get($entity);
88 5216
            if ($node !== null) {
89 5068
                return $node->getRole();
90
            }
91
92 1582
            $class = $entity::class;
93 1582
            if (!$this->schema->defines($class)) {
94 40
                $parentClass = get_parent_class($entity);
95
96 40
                if ($parentClass === false
97
                    || !$entity instanceof EntityProxyInterface
98 40
                    || !$this->schema->defines($parentClass)
99
                ) {
100
                    throw new ORMException("Unable to resolve role of `$class`.");
101
                }
102 40
                $class = $parentClass;
103
            }
104
105 1582
            $entity = $class;
106
        }
107
108 7154
        return $this->schema->resolveAlias($entity) ?? throw new ORMException("Unable to resolve role `$entity`.");
109
    }
110
}
111