1 | <?php |
||||||||||
2 | |||||||||||
3 | declare(strict_types=1); |
||||||||||
4 | |||||||||||
5 | namespace Cycle\ORM\Mapper; |
||||||||||
6 | |||||||||||
7 | use Cycle\ORM\Command\CommandInterface; |
||||||||||
8 | use Cycle\ORM\Command\Database\Delete; |
||||||||||
9 | use Cycle\ORM\Command\Database\Insert; |
||||||||||
10 | use Cycle\ORM\Command\Database\Update; |
||||||||||
11 | use Cycle\ORM\Heap\Node; |
||||||||||
12 | use Cycle\ORM\Heap\State; |
||||||||||
13 | use Cycle\ORM\MapperInterface; |
||||||||||
14 | use Cycle\ORM\ORMInterface; |
||||||||||
15 | use Cycle\ORM\Parser\CastableInterface; |
||||||||||
16 | use Cycle\ORM\Parser\TypecastInterface; |
||||||||||
17 | use Cycle\ORM\Parser\UncastableInterface; |
||||||||||
18 | use Cycle\ORM\Service\RelationProviderInterface; |
||||||||||
19 | use Cycle\ORM\Service\TypecastProviderInterface; |
||||||||||
20 | use Cycle\ORM\RelationMap; |
||||||||||
21 | use Cycle\ORM\SchemaInterface; |
||||||||||
22 | use Cycle\ORM\Select\SourceInterface; |
||||||||||
23 | |||||||||||
24 | /** |
||||||||||
25 | * Provides basic capabilities to work with entities persisted in SQL databases. |
||||||||||
26 | */ |
||||||||||
27 | abstract class DatabaseMapper implements MapperInterface |
||||||||||
28 | { |
||||||||||
29 | protected SourceInterface $source; |
||||||||||
30 | protected array $columns = []; |
||||||||||
31 | protected array $parentColumns = []; |
||||||||||
32 | |||||||||||
33 | /** @var string[] */ |
||||||||||
34 | protected array $primaryColumns = []; |
||||||||||
35 | |||||||||||
36 | /** @var string[] */ |
||||||||||
37 | protected array $primaryKeys; |
||||||||||
38 | |||||||||||
39 | protected RelationMap $relationMap; |
||||||||||
40 | private ?TypecastInterface $typecast; |
||||||||||
41 | |||||||||||
42 | /** @var array<non-empty-string, int> */ |
||||||||||
0 ignored issues
–
show
Documentation
Bug
introduced
by
![]() |
|||||||||||
43 | 6842 | private array $generatedFields; |
|||||||||
44 | |||||||||||
45 | public function __construct( |
||||||||||
46 | ORMInterface $orm, |
||||||||||
47 | 6842 | protected string $role, |
|||||||||
48 | 6842 | ) { |
|||||||||
49 | 6842 | $this->source = $orm->getSource($role); |
|||||||||
50 | $this->typecast = $orm->getService(TypecastProviderInterface::class)->getTypecast($role); |
||||||||||
51 | 6842 | $this->relationMap = $orm->getService(RelationProviderInterface::class)->getRelationMap($role); |
|||||||||
52 | 6842 | ||||||||||
53 | 6842 | $schema = $orm->getSchema(); |
|||||||||
54 | foreach ($schema->define($role, SchemaInterface::COLUMNS) as $property => $column) { |
||||||||||
55 | $this->columns[\is_int($property) ? $column : $property] = $column; |
||||||||||
56 | } |
||||||||||
57 | 6842 | ||||||||||
58 | 6842 | $this->generatedFields = $schema->define($role, SchemaInterface::GENERATED_FIELDS) ?? []; |
|||||||||
59 | 800 | // Parent's fields |
|||||||||
60 | 800 | $parent = $schema->define($role, SchemaInterface::PARENT); |
|||||||||
61 | while ($parent !== null) { |
||||||||||
62 | 800 | foreach ($schema->define($parent, SchemaInterface::COLUMNS) as $property => $column) { |
|||||||||
63 | $this->parentColumns[\is_int($property) ? $column : $property] = $column; |
||||||||||
64 | } |
||||||||||
65 | 6842 | $parent = $schema->define($parent, SchemaInterface::PARENT); |
|||||||||
66 | 6842 | } |
|||||||||
67 | 6842 | ||||||||||
68 | $this->primaryKeys = (array) $schema->define($role, SchemaInterface::PRIMARY_KEY); |
||||||||||
69 | foreach ($this->primaryKeys as $PK) { |
||||||||||
70 | $this->primaryColumns[] = $this->columns[$PK] ?? $PK; |
||||||||||
71 | 1578 | } |
|||||||||
72 | } |
||||||||||
73 | 1578 | ||||||||||
74 | public function getRole(): string |
||||||||||
75 | { |
||||||||||
76 | 6598 | return $this->role; |
|||||||||
77 | } |
||||||||||
78 | 6598 | ||||||||||
79 | 3464 | public function cast(array $data): array |
|||||||||
80 | { |
||||||||||
81 | if ($this->typecast instanceof CastableInterface) { |
||||||||||
82 | $data = $this->typecast->cast($data); |
||||||||||
0 ignored issues
–
show
The method
cast() does not exist on Cycle\ORM\Parser\TypecastInterface . It seems like you code against a sub-type of said class. However, the method does not exist in Cycle\ORM\Parser\UncastableInterface . Are you sure you never get one of those?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() The method
cast() does not exist on null .
(
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. ![]() |
|||||||||||
83 | 6598 | } |
|||||||||
84 | 5188 | ||||||||||
85 | 3196 | // Cast relations |
|||||||||
86 | foreach ($this->relationMap->getRelations() as $field => $relation) { |
||||||||||
87 | 3530 | if (!\array_key_exists($field, $data)) { |
|||||||||
88 | 3530 | continue; |
|||||||||
89 | } |
||||||||||
90 | $value = $data[$field]; |
||||||||||
91 | if (!\is_array($value) && $value !== null) { |
||||||||||
92 | 3530 | continue; |
|||||||||
93 | 3530 | } |
|||||||||
94 | // break links |
||||||||||
95 | unset($data[$field]); |
||||||||||
96 | 6598 | $data[$field] = $relation->cast($value); |
|||||||||
97 | } |
||||||||||
98 | |||||||||||
99 | 2548 | return $data; |
|||||||||
100 | } |
||||||||||
101 | 2548 | ||||||||||
102 | 2476 | public function uncast(array $data): array |
|||||||||
103 | { |
||||||||||
104 | if (!$this->typecast instanceof UncastableInterface) { |
||||||||||
105 | 224 | return $data; |
|||||||||
106 | } |
||||||||||
107 | |||||||||||
108 | 1700 | return $this->typecast->uncast($data); |
|||||||||
0 ignored issues
–
show
The method
uncast() does not exist on Cycle\ORM\Parser\TypecastInterface . It seems like you code against a sub-type of said class. However, the method does not exist in Cycle\ORM\Tests\Function...\Fixture\ParentTypecast or Cycle\ORM\Parser\CastableInterface or Cycle\ORM\Tests\Function...cast\Fixture\Typecaster or Cycle\ORM\Tests\Function...Case408\Type\TypeCaster or Cycle\ORM\Tests\Function...st\Fixture\UuidTypecast . Are you sure you never get one of those?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
109 | } |
||||||||||
110 | 1700 | ||||||||||
111 | public function queueCreate(object $entity, Node $node, State $state): CommandInterface |
||||||||||
112 | { |
||||||||||
113 | 1700 | $values = $state->getData(); |
|||||||||
114 | |||||||||||
115 | 1700 | // sync the state |
|||||||||
116 | 1700 | $state->setStatus(Node::SCHEDULED_INSERT); |
|||||||||
117 | 1428 | ||||||||||
118 | 16 | foreach ($this->primaryKeys as $key) { |
|||||||||
119 | if (!isset($values[$key])) { |
||||||||||
120 | 1428 | foreach ($this->nextPrimaryKey() ?? [] as $pk => $value) { |
|||||||||
0 ignored issues
–
show
Are you sure the usage of
$this->nextPrimaryKey() targeting Cycle\ORM\Mapper\DatabaseMapper::nextPrimaryKey() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||||||||
121 | $state->register($pk, $value); |
||||||||||
122 | } |
||||||||||
123 | break; |
||||||||||
124 | 1700 | } |
|||||||||
125 | 1700 | } |
|||||||||
126 | 1700 | ||||||||||
127 | return new Insert( |
||||||||||
128 | $this->source->getDatabase(), |
||||||||||
129 | 1700 | $this->source->getTable(), |
|||||||||
130 | 1700 | $state, |
|||||||||
131 | $this, |
||||||||||
132 | $this->primaryKeys, |
||||||||||
133 | \count($this->primaryColumns) === 1 ? $this->primaryColumns[0] : null, |
||||||||||
134 | 1148 | $this->generatedFields, |
|||||||||
135 | ); |
||||||||||
136 | 1148 | } |
|||||||||
137 | |||||||||||
138 | 1148 | public function queueUpdate(object $entity, Node $node, State $state): CommandInterface |
|||||||||
139 | 1148 | { |
|||||||||
140 | 1148 | $fromData = $state->getTransactionData(); |
|||||||||
141 | |||||||||||
142 | $update = new Update( |
||||||||||
143 | 1148 | $this->source->getDatabase(), |
|||||||||
144 | $this->source->getTable(), |
||||||||||
145 | $state, |
||||||||||
146 | 1148 | $this, |
|||||||||
147 | $this->primaryKeys, |
||||||||||
148 | 1148 | ); |
|||||||||
149 | |||||||||||
150 | foreach ($this->primaryKeys as $pk) { |
||||||||||
151 | 1148 | // set update criteria right now |
|||||||||
152 | $update->setScope($pk, $fromData[$pk]); |
||||||||||
153 | } |
||||||||||
154 | 480 | ||||||||||
155 | return $update; |
||||||||||
156 | 480 | } |
|||||||||
157 | 480 | ||||||||||
158 | 480 | public function queueDelete(object $entity, Node $node, State $state): CommandInterface |
|||||||||
159 | { |
||||||||||
160 | $delete = new Delete( |
||||||||||
161 | $this->source->getDatabase(), |
||||||||||
162 | $this->source->getTable(), |
||||||||||
163 | 480 | $state, |
|||||||||
164 | $this, |
||||||||||
165 | 480 | ); |
|||||||||
166 | 480 | ||||||||||
167 | 480 | $state->setStatus(Node::SCHEDULED_DELETE); |
|||||||||
168 | |||||||||||
169 | 480 | $delete->waitScope(...$this->primaryKeys); |
|||||||||
170 | $fromData = $node->getData(); |
||||||||||
171 | foreach ($this->primaryKeys as $pk) { |
||||||||||
172 | 480 | // set update criteria right now |
|||||||||
173 | $delete->setScope($pk, $fromData[$pk]); |
||||||||||
174 | } |
||||||||||
175 | |||||||||||
176 | return $delete; |
||||||||||
177 | } |
||||||||||
178 | 1412 | ||||||||||
179 | public function mapColumns(array &$values): array |
||||||||||
180 | 1412 | { |
|||||||||
181 | $result = []; |
||||||||||
182 | foreach ($values as $column => $value) { |
||||||||||
183 | 2548 | if (isset($this->columns[$column])) { |
|||||||||
184 | $result[$this->columns[$column]] = $value; |
||||||||||
185 | 2548 | } else { |
|||||||||
186 | 2548 | unset($values[$column]); |
|||||||||
187 | 2508 | } |
|||||||||
188 | 2508 | } |
|||||||||
189 | |||||||||||
190 | 168 | return $result; |
|||||||||
191 | } |
||||||||||
192 | |||||||||||
193 | /** |
||||||||||
194 | 2548 | * Generate next sequential entity ID. Return null to use autoincrement value. |
|||||||||
195 | */ |
||||||||||
196 | protected function nextPrimaryKey(): ?array |
||||||||||
197 | { |
||||||||||
198 | return null; |
||||||||||
199 | } |
||||||||||
200 | } |
||||||||||
201 |