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

ClasslessProxyFactory   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 101
Duplicated Lines 0 %

Test Coverage

Coverage 95.83%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 49
dl 0
loc 101
ccs 46
cts 48
cp 0.9583
rs 10
c 1
b 0
f 0
wmc 17

6 Methods

Rating   Name   Duplication   Size   Complexity  
A create() 0 12 2
A extractRelations() 0 13 4
A upgrade() 0 8 2
A entityToArray() 0 9 3
A extractData() 0 3 1
A defineClass() 0 35 5
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cycle\ORM\Mapper\Proxy;
6
7
use Cycle\ORM\RelationMap;
8
9
/**
10
 * @internal
11
 */
12
class ClasslessProxyFactory
13
{
14
    /**
15
     * @var string[]
16
     * @psalm-var class-string
17
     */
18
    private array $classMap = [];
19
20
    /**
21
     * Create empty entity
22
     */
23 216
    public function create(
24
        RelationMap $relMap,
25
        string $role,
26
        array $data
27
    ): object {
28 216
        $class = array_key_exists($role, $this->classMap)
29 40
            ? $this->classMap[$role]
30 216
            : $this->defineClass($role, $relMap, $data);
31
32 216
        $proxy = new $class();
33 216
        $proxy->__cycle_orm_rel_map = $relMap;
34 216
        return $proxy;
35
    }
36
37 216
    public function upgrade(
38
        object $entity,
39
        array $data
40
    ): object {
41 216
        foreach ($data as $key => $value) {
42 208
            $entity->$key = $value;
43
        }
44 216
        return $entity;
45
    }
46
47 48
    public function extractRelations(RelationMap $relMap, object $entity): array
48
    {
49 48
        if (!property_exists($entity, '__cycle_orm_rel_data')) {
50
            return array_intersect_key($this->entityToArray($entity), $relMap->getRelations());
51
        }
52 48
        $currentData = $entity->__cycle_orm_rel_data;
53 48
        foreach ($relMap->getRelations() as $key => $relation) {
54 48
            if (!array_key_exists($key, $currentData)) {
55 40
                $arrayData ??= $this->entityToArray($entity);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $arrayData does not seem to be defined for all execution paths leading up to this point.
Loading history...
56 40
                $currentData[$key] = $arrayData[$key];
57
            }
58
        }
59 48
        return $currentData;
60
    }
61
62 104
    public function extractData(RelationMap $relMap, object $entity): array
63
    {
64 104
        return array_diff_key($this->entityToArray($entity), $relMap->getRelations());
65
    }
66
67 216
    public function entityToArray(object $entity): array
68
    {
69 216
        $result = [];
70 216
        foreach ((array)$entity as $key => $value) {
71 216
            $result[$key[0] === "\0" ? substr($key, strrpos($key, "\0", 1) + 1) : $key] = $value;
72
        }
73 216
        $relations = $result['__cycle_orm_rel_data'];
74 216
        unset($result['__cycle_orm_rel_map'], $result['__cycle_orm_rel_data']);
75 216
        return $relations + $result;
76
    }
77
78 216
    private function defineClass(string $role, RelationMap $relMap, array $fields): ?string
79
    {
80 216
        if (array_key_exists($role, $this->classMap)) {
81
            return $this->classMap[$role];
82
        }
83 216
        $i = 0;
84
        do {
85 216
            $className = "Classless {$role} {$i} Cycle ORM Proxy";
86 216
            $namespace = 'Cycle\\ORM\\ClasslessProxy';
87 216
            $class = $namespace . '\\' . $className;
88 216
            ++$i;
89 216
        } while (class_exists($class, false));
90
91 216
        $properties = [];
92
        // Generate properties
93 216
        foreach ($fields as $field) {
94 216
            $properties[] = "public \${$field};";
95
        }
96 216
        foreach ($relMap->getRelations() as $field => $relation) {
97 56
            $properties[] = "private \${$field};";
98
        }
99 216
        $properties = implode("\n    ", $properties);
100
101 216
        $this->classMap[$role] = $class;
102
        /** @see \Cycle\ORM\Mapper\Proxy\ClasslessProxyTrait */
103 216
        $classStr = <<<PHP
104
            namespace {$namespace};
105
            class {$className} implements \\Cycle\\ORM\\EntityProxyInterface {
106
                use \\Cycle\ORM\\Mapper\\Proxy\\ClasslessProxyTrait;
107
108
                {$properties}
109
            }
110
            PHP;
111 216
        eval($classStr);
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
112 216
        return $class;
113
    }
114
}
115