platine-php /
orm
| 1 | <?php |
||||
| 2 | |||||
| 3 | /** |
||||
| 4 | * Platine ORM |
||||
| 5 | * |
||||
| 6 | * Platine ORM provides a flexible and powerful ORM implementing a data-mapper pattern. |
||||
| 7 | * |
||||
| 8 | * This content is released under the MIT License (MIT) |
||||
| 9 | * |
||||
| 10 | * Copyright (c) 2020 Platine ORM |
||||
| 11 | * |
||||
| 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
| 13 | * of this software and associated documentation files (the "Software"), to deal |
||||
| 14 | * in the Software without restriction, including without limitation the rights |
||||
| 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
| 16 | * copies of the Software, and to permit persons to whom the Software is |
||||
| 17 | * furnished to do so, subject to the following conditions: |
||||
| 18 | * |
||||
| 19 | * The above copyright notice and this permission notice shall be included in all |
||||
| 20 | * copies or substantial portions of the Software. |
||||
| 21 | * |
||||
| 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
| 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
| 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
| 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
| 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
| 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
| 28 | * SOFTWARE. |
||||
| 29 | */ |
||||
| 30 | |||||
| 31 | /** |
||||
| 32 | * @file DataMapper.php |
||||
| 33 | * |
||||
| 34 | * The Data Mapper class |
||||
| 35 | * |
||||
| 36 | * @package Platine\Orm\Mapper |
||||
| 37 | * @author Platine Developers Team |
||||
| 38 | * @copyright Copyright (c) 2020 |
||||
| 39 | * @license http://opensource.org/licenses/MIT MIT License |
||||
| 40 | * @link https://www.platine-php.com |
||||
| 41 | * @version 1.0.0 |
||||
| 42 | * @filesource |
||||
| 43 | */ |
||||
| 44 | |||||
| 45 | declare(strict_types=1); |
||||
| 46 | |||||
| 47 | namespace Platine\Orm\Mapper; |
||||
| 48 | |||||
| 49 | use DateTime; |
||||
| 50 | use Platine\Database\Query\Select; |
||||
| 51 | use Platine\Orm\Entity; |
||||
| 52 | use Platine\Orm\EntityManager; |
||||
| 53 | use Platine\Orm\Exception\EntityStateException; |
||||
| 54 | use Platine\Orm\Exception\PropertyNotFoundException; |
||||
| 55 | use Platine\Orm\Exception\RelationNotFoundException; |
||||
| 56 | use Platine\Orm\Mapper\DataMapperInterface; |
||||
| 57 | use Platine\Orm\Mapper\EntityMapper; |
||||
| 58 | use Platine\Orm\Relation\BelongsTo; |
||||
| 59 | use Platine\Orm\Relation\HasRelation; |
||||
| 60 | use Platine\Orm\Relation\ShareRelation; |
||||
| 61 | use RuntimeException; |
||||
| 62 | |||||
| 63 | /** |
||||
| 64 | * @class DataMapper |
||||
| 65 | * @package Platine\Orm\Mapper |
||||
| 66 | * @template TEntity as Entity |
||||
| 67 | * @implements DataMapperInterface<TEntity> |
||||
| 68 | */ |
||||
| 69 | class DataMapper implements DataMapperInterface |
||||
| 70 | { |
||||
| 71 | /** |
||||
| 72 | * The raw columns data |
||||
| 73 | * @var array<string, mixed> |
||||
| 74 | */ |
||||
| 75 | protected array $rawColumns = []; |
||||
| 76 | |||||
| 77 | /** |
||||
| 78 | * The current columns data. After refresh, etc. |
||||
| 79 | * @var array<string, mixed> |
||||
| 80 | */ |
||||
| 81 | protected array $columns = []; |
||||
| 82 | |||||
| 83 | /** |
||||
| 84 | * The list of relation loaders |
||||
| 85 | * @var array<string, \Platine\Orm\Relation\RelationLoader<TEntity>> |
||||
|
0 ignored issues
–
show
Documentation
Bug
introduced
by
Loading history...
|
|||||
| 86 | */ |
||||
| 87 | protected array $loaders = []; |
||||
| 88 | |||||
| 89 | /** |
||||
| 90 | * The Entity manager instance |
||||
| 91 | * @var EntityManager<TEntity> |
||||
| 92 | */ |
||||
| 93 | protected EntityManager $manager; |
||||
| 94 | |||||
| 95 | /** |
||||
| 96 | * |
||||
| 97 | * @var EntityMapper<TEntity> |
||||
| 98 | */ |
||||
| 99 | protected EntityMapper $mapper; |
||||
| 100 | |||||
| 101 | /** |
||||
| 102 | * Whether the data is read only |
||||
| 103 | * @var bool |
||||
| 104 | */ |
||||
| 105 | protected bool $isReadOnly = false; |
||||
| 106 | |||||
| 107 | /** |
||||
| 108 | * Whether the data is new |
||||
| 109 | * @var bool |
||||
| 110 | */ |
||||
| 111 | protected bool $isNew = false; |
||||
| 112 | |||||
| 113 | /** |
||||
| 114 | * Whether the data is deleted |
||||
| 115 | * @var bool |
||||
| 116 | */ |
||||
| 117 | protected bool $deleted = false; |
||||
| 118 | |||||
| 119 | /** |
||||
| 120 | * Whether the data need to refreshed from data store |
||||
| 121 | * @var bool |
||||
| 122 | */ |
||||
| 123 | protected bool $refresh = false; |
||||
| 124 | |||||
| 125 | /** |
||||
| 126 | * The name of the sequence to use |
||||
| 127 | * @var string|null |
||||
| 128 | */ |
||||
| 129 | protected ?string $sequence = null; |
||||
| 130 | |||||
| 131 | /** |
||||
| 132 | * The list of modified data |
||||
| 133 | * @var array<string, mixed> |
||||
| 134 | */ |
||||
| 135 | protected array $modified = []; |
||||
| 136 | |||||
| 137 | /** |
||||
| 138 | * The list of relations loaded data (cached) |
||||
| 139 | * @var array<string, mixed> |
||||
| 140 | */ |
||||
| 141 | protected array $relations = []; |
||||
| 142 | |||||
| 143 | /** |
||||
| 144 | * The list of pending links |
||||
| 145 | * @var array<int, array<string, mixed>> |
||||
| 146 | */ |
||||
| 147 | protected array $pendingLinks = []; |
||||
| 148 | |||||
| 149 | /** |
||||
| 150 | * Create new instance |
||||
| 151 | * @param EntityManager<TEntity> $manager |
||||
| 152 | * @param EntityMapper<TEntity> $mapper |
||||
| 153 | * @param array<string, mixed> $columns |
||||
| 154 | * @param array<string, mixed> $loaders |
||||
| 155 | * @param bool $isReadOnly |
||||
| 156 | * @param bool $isNew |
||||
| 157 | */ |
||||
| 158 | public function __construct( |
||||
| 159 | EntityManager $manager, |
||||
| 160 | EntityMapper $mapper, |
||||
| 161 | array $columns, |
||||
| 162 | array $loaders, |
||||
| 163 | bool $isReadOnly, |
||||
| 164 | bool $isNew |
||||
| 165 | ) { |
||||
| 166 | $this->manager = $manager; |
||||
| 167 | $this->mapper = $mapper; |
||||
| 168 | $this->loaders = $loaders; |
||||
| 169 | $this->isReadOnly = $isReadOnly; |
||||
| 170 | $this->isNew = $isNew; |
||||
| 171 | $this->rawColumns = $columns; |
||||
| 172 | |||||
| 173 | if ($isNew && count($columns) > 0) { |
||||
| 174 | $this->rawColumns = []; |
||||
| 175 | $this->fill($columns); |
||||
| 176 | } |
||||
| 177 | } |
||||
| 178 | |||||
| 179 | /** |
||||
| 180 | * |
||||
| 181 | * @return EntityManager<TEntity> |
||||
| 182 | */ |
||||
| 183 | public function getEntityManager(): EntityManager |
||||
| 184 | { |
||||
| 185 | return $this->manager; |
||||
| 186 | } |
||||
| 187 | |||||
| 188 | /** |
||||
| 189 | * |
||||
| 190 | * @return EntityMapper<TEntity> |
||||
| 191 | */ |
||||
| 192 | public function getEntityMapper(): EntityMapper |
||||
| 193 | { |
||||
| 194 | return $this->mapper; |
||||
| 195 | } |
||||
| 196 | |||||
| 197 | /** |
||||
| 198 | * {@inheritedoc} |
||||
| 199 | */ |
||||
| 200 | public function isDeleted(): bool |
||||
| 201 | { |
||||
| 202 | return $this->deleted; |
||||
| 203 | } |
||||
| 204 | |||||
| 205 | /** |
||||
| 206 | * {@inheritedoc} |
||||
| 207 | */ |
||||
| 208 | public function isNew(): bool |
||||
| 209 | { |
||||
| 210 | return $this->isNew; |
||||
| 211 | } |
||||
| 212 | |||||
| 213 | /** |
||||
| 214 | * {@inheritedoc} |
||||
| 215 | */ |
||||
| 216 | public function isReadOnly(): bool |
||||
| 217 | { |
||||
| 218 | return $this->isReadOnly; |
||||
| 219 | } |
||||
| 220 | |||||
| 221 | /** |
||||
| 222 | * {@inheritedoc} |
||||
| 223 | */ |
||||
| 224 | public function wasModified(): bool |
||||
| 225 | { |
||||
| 226 | return count($this->modified) > 0 || count($this->pendingLinks) > 0; |
||||
| 227 | } |
||||
| 228 | |||||
| 229 | /** |
||||
| 230 | * {@inheritedoc} |
||||
| 231 | */ |
||||
| 232 | public function getColumn(string $name): mixed |
||||
| 233 | { |
||||
| 234 | if ($this->refresh) { |
||||
| 235 | $this->hydrate(); |
||||
| 236 | } |
||||
| 237 | |||||
| 238 | if ($this->deleted) { |
||||
| 239 | throw new EntityStateException('The record was deleted'); |
||||
| 240 | } |
||||
| 241 | |||||
| 242 | if (array_key_exists($name, $this->columns)) { |
||||
| 243 | return $this->columns[$name]; |
||||
| 244 | } |
||||
| 245 | |||||
| 246 | if (!array_key_exists($name, $this->rawColumns)) { |
||||
| 247 | throw new PropertyNotFoundException(sprintf( |
||||
| 248 | 'Unknown column [%s]', |
||||
| 249 | $name |
||||
| 250 | )); |
||||
| 251 | } |
||||
| 252 | |||||
| 253 | $value = $this->rawColumns[$name]; |
||||
| 254 | $casts = $this->mapper->getCasts(); |
||||
| 255 | |||||
| 256 | if (isset($casts[$name])) { |
||||
| 257 | $value = $this->castGet($value, $casts[$name]); |
||||
| 258 | } |
||||
| 259 | |||||
| 260 | $primaryKey = $this->mapper->getPrimaryKey(); |
||||
| 261 | if ($name === (string)$primaryKey) { |
||||
| 262 | return $this->columns[$name] = $value; |
||||
| 263 | } |
||||
| 264 | |||||
| 265 | $getters = $this->mapper->getGetters(); |
||||
| 266 | if (isset($getters[$name])) { |
||||
| 267 | $callback = $getters[$name]; |
||||
| 268 | $value = ($callback)($value, $this); |
||||
| 269 | } |
||||
| 270 | |||||
| 271 | return $this->columns[$name] = $value; |
||||
| 272 | } |
||||
| 273 | |||||
| 274 | /** |
||||
| 275 | * {@inheritedoc} |
||||
| 276 | */ |
||||
| 277 | public function setColumn(string $name, mixed $value): void |
||||
| 278 | { |
||||
| 279 | if ($this->isReadOnly) { |
||||
| 280 | throw new EntityStateException('The record is readonly'); |
||||
| 281 | } |
||||
| 282 | |||||
| 283 | if ($this->deleted) { |
||||
| 284 | throw new EntityStateException('The record was deleted'); |
||||
| 285 | } |
||||
| 286 | |||||
| 287 | if ($this->refresh) { |
||||
| 288 | $this->hydrate(); |
||||
| 289 | } |
||||
| 290 | |||||
| 291 | $casts = $this->mapper->getCasts(); |
||||
| 292 | $setters = $this->mapper->getSetters(); |
||||
| 293 | |||||
| 294 | if (isset($setters[$name])) { |
||||
| 295 | $callback = $setters[$name]; |
||||
| 296 | $value = ($callback)($value, $this); |
||||
| 297 | } |
||||
| 298 | |||||
| 299 | if (isset($casts[$name])) { |
||||
| 300 | $value = $this->castSet($value, $casts[$name]); |
||||
| 301 | } |
||||
| 302 | |||||
| 303 | $this->modified[$name] = true; |
||||
| 304 | unset($this->columns[$name]); |
||||
| 305 | $this->rawColumns[$name] = $value; |
||||
| 306 | } |
||||
| 307 | |||||
| 308 | /** |
||||
| 309 | * {@inheritedoc} |
||||
| 310 | */ |
||||
| 311 | public function clearColumn(string $name, bool $raw = false): void |
||||
| 312 | { |
||||
| 313 | unset($this->columns[$name]); |
||||
| 314 | |||||
| 315 | if ($raw) { |
||||
| 316 | unset($this->rawColumns[$name]); |
||||
| 317 | } |
||||
| 318 | } |
||||
| 319 | |||||
| 320 | /** |
||||
| 321 | * {@inheritedoc} |
||||
| 322 | */ |
||||
| 323 | public function hasColumn(string $column): bool |
||||
| 324 | { |
||||
| 325 | return array_key_exists($column, $this->columns) |
||||
| 326 | || array_key_exists($column, $this->rawColumns); |
||||
| 327 | } |
||||
| 328 | |||||
| 329 | /** |
||||
| 330 | * {@inheritedoc} |
||||
| 331 | */ |
||||
| 332 | public function getModifiedColumns(): array |
||||
| 333 | { |
||||
| 334 | return array_keys($this->modified); |
||||
| 335 | } |
||||
| 336 | |||||
| 337 | /** |
||||
| 338 | * {@inheritedoc} |
||||
| 339 | */ |
||||
| 340 | public function getRawColumns(): array |
||||
| 341 | { |
||||
| 342 | return $this->rawColumns; |
||||
| 343 | } |
||||
| 344 | |||||
| 345 | /** |
||||
| 346 | * {@inheritedoc} |
||||
| 347 | */ |
||||
| 348 | public function setRawColumn(string $name, mixed $value): void |
||||
| 349 | { |
||||
| 350 | $this->modified[$name] = true; |
||||
| 351 | unset($this->columns[$name]); |
||||
| 352 | $this->rawColumns[$name] = $value; |
||||
| 353 | } |
||||
| 354 | |||||
| 355 | /** |
||||
| 356 | * {@inheritedoc} |
||||
| 357 | */ |
||||
| 358 | public function getRelated(string $name, ?callable $callback = null): mixed |
||||
| 359 | { |
||||
| 360 | if (array_key_exists($name, $this->relations)) { |
||||
| 361 | return $this->relations[$name]; |
||||
| 362 | } |
||||
| 363 | |||||
| 364 | /** @var array<string, \Platine\Orm\Relation\Relation<TEntity>> $relations */ |
||||
| 365 | $relations = $this->mapper->getRelations(); |
||||
| 366 | |||||
| 367 | $cacheKey = $name; |
||||
| 368 | |||||
| 369 | $index = strpos($name, ':'); |
||||
| 370 | if ($index !== false) { |
||||
| 371 | $name = substr($name, $index + 1); |
||||
| 372 | } |
||||
| 373 | |||||
| 374 | if (!isset($relations[$name])) { |
||||
| 375 | throw new RelationNotFoundException(sprintf( |
||||
| 376 | 'Unknown relation [%s]', |
||||
| 377 | $name |
||||
| 378 | )); |
||||
| 379 | } |
||||
| 380 | |||||
| 381 | $this->hydrate(); |
||||
| 382 | |||||
| 383 | //Race condition |
||||
| 384 | //@codeCoverageIgnoreStart |
||||
| 385 | if (isset($this->relations[$cacheKey])) { |
||||
| 386 | return $this->relations[$cacheKey]; |
||||
| 387 | } |
||||
| 388 | //@codeCoverageIgnoreEnd |
||||
| 389 | |||||
| 390 | if (isset($this->loaders[$cacheKey])) { |
||||
| 391 | return $this->relations[$cacheKey] = $this->loaders[$name]->getResult($this); |
||||
| 392 | } |
||||
| 393 | |||||
| 394 | return $this->relations[$cacheKey] = $relations[$name]->getResult($this, $callback); |
||||
| 395 | } |
||||
| 396 | |||||
| 397 | /** |
||||
| 398 | * {@inheritedoc} |
||||
| 399 | */ |
||||
| 400 | public function setRelated(string $name, ?Entity $entity = null): void |
||||
| 401 | { |
||||
| 402 | $relations = $this->mapper->getRelations(); |
||||
| 403 | |||||
| 404 | if (!isset($relations[$name])) { |
||||
| 405 | throw new RelationNotFoundException(sprintf( |
||||
| 406 | 'Unknown relation [%s]', |
||||
| 407 | $name |
||||
| 408 | )); |
||||
| 409 | } |
||||
| 410 | |||||
| 411 | /** @var \Platine\Orm\Relation\Relation<TEntity> $rel */ |
||||
| 412 | $rel = $relations[$name]; |
||||
| 413 | |||||
| 414 | if (!($rel instanceof BelongsTo) && !($rel instanceof HasRelation)) { |
||||
| 415 | throw new RuntimeException('Unsupported relation type'); |
||||
| 416 | } |
||||
| 417 | |||||
| 418 | if ($entity === null && !($rel instanceof BelongsTo)) { |
||||
| 419 | throw new RuntimeException('Unsupported relation type'); |
||||
| 420 | } |
||||
| 421 | |||||
| 422 | $rel->addRelatedEntity($this, $entity); |
||||
|
0 ignored issues
–
show
It seems like
$entity can also be of type null; however, parameter $entity of Platine\Orm\Relation\Has...ion::addRelatedEntity() does only seem to accept Platine\Orm\Entity, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 423 | } |
||||
| 424 | |||||
| 425 | /** |
||||
| 426 | * {@inheritedoc} |
||||
| 427 | */ |
||||
| 428 | public function clearRelated(string $name, bool $loaders = false): void |
||||
| 429 | { |
||||
| 430 | $cacheKey = $name; |
||||
| 431 | |||||
| 432 | $index = strpos($name, ':'); |
||||
| 433 | if ($index !== false) { |
||||
| 434 | $name = substr($name, $index + 1); |
||||
| 435 | } |
||||
| 436 | |||||
| 437 | unset($this->relations[$cacheKey]); |
||||
| 438 | |||||
| 439 | if ($loaders) { |
||||
| 440 | unset($this->loaders[$name]); |
||||
| 441 | } |
||||
| 442 | } |
||||
| 443 | |||||
| 444 | /** |
||||
| 445 | * {@inheritedoc} |
||||
| 446 | */ |
||||
| 447 | public function hasRelation(string $relation): bool |
||||
| 448 | { |
||||
| 449 | $relations = $this->mapper->getRelations(); |
||||
| 450 | |||||
| 451 | return isset($relations[$relation]); |
||||
| 452 | } |
||||
| 453 | |||||
| 454 | /** |
||||
| 455 | * {@inheritedoc} |
||||
| 456 | */ |
||||
| 457 | public function link(string $relation, Entity $entity): void |
||||
| 458 | { |
||||
| 459 | $this->setLink($relation, $entity, true); |
||||
| 460 | } |
||||
| 461 | |||||
| 462 | /** |
||||
| 463 | * {@inheritedoc} |
||||
| 464 | */ |
||||
| 465 | public function unlink(string $relation, Entity $entity): void |
||||
| 466 | { |
||||
| 467 | $this->setLink($relation, $entity, false); |
||||
| 468 | } |
||||
| 469 | |||||
| 470 | /** |
||||
| 471 | * {@inheritedoc} |
||||
| 472 | */ |
||||
| 473 | public function refresh(): void |
||||
| 474 | { |
||||
| 475 | $this->refresh = true; |
||||
| 476 | } |
||||
| 477 | |||||
| 478 | /** |
||||
| 479 | * {@inheritedoc} |
||||
| 480 | */ |
||||
| 481 | public function fill(array $columns): void |
||||
| 482 | { |
||||
| 483 | $fillable = $this->mapper->getFillable(); |
||||
| 484 | $guarded = $this->mapper->getGuarded(); |
||||
| 485 | |||||
| 486 | if (count($fillable) > 0) { |
||||
| 487 | $columns = array_intersect_key($columns, array_flip($fillable)); |
||||
| 488 | } elseif (count($guarded) > 0) { |
||||
| 489 | $columns = array_diff_key($columns, array_flip($guarded)); |
||||
| 490 | } |
||||
| 491 | |||||
| 492 | foreach ($columns as $name => $value) { |
||||
| 493 | $this->setColumn($name, $value); |
||||
| 494 | } |
||||
| 495 | } |
||||
| 496 | |||||
| 497 | /** |
||||
| 498 | * Mark the entity as saved |
||||
| 499 | * @param mixed $id |
||||
| 500 | * @return bool |
||||
| 501 | */ |
||||
| 502 | public function markAsSaved(mixed $id): bool |
||||
| 503 | { |
||||
| 504 | $primaryKey = $this->mapper->getPrimaryKey(); |
||||
| 505 | if ($primaryKey->isComposite() === false) { |
||||
| 506 | $columns = $primaryKey->columns(); |
||||
| 507 | $this->rawColumns[$columns[0]] = $id; |
||||
| 508 | } else { |
||||
| 509 | foreach ($primaryKey->columns() as $pkColumn) { |
||||
| 510 | $this->rawColumns[$pkColumn] = $id[$pkColumn]; |
||||
| 511 | } |
||||
| 512 | } |
||||
| 513 | |||||
| 514 | $this->refresh = true; |
||||
| 515 | $this->isNew = false; |
||||
| 516 | $this->modified = []; |
||||
| 517 | |||||
| 518 | if (count($this->pendingLinks) > 0) { |
||||
| 519 | $this->executePendingLinkage(); |
||||
| 520 | } |
||||
| 521 | |||||
| 522 | return true; |
||||
| 523 | } |
||||
| 524 | |||||
| 525 | /** |
||||
| 526 | * Mark the entity as updated |
||||
| 527 | * @param string|null $updatedAt |
||||
| 528 | * @return bool |
||||
| 529 | */ |
||||
| 530 | public function markAsUpdated(?string $updatedAt = null): bool |
||||
| 531 | { |
||||
| 532 | if ($updatedAt !== null) { |
||||
| 533 | list(, $column) = $this->mapper->getTimestampColumns(); |
||||
| 534 | unset($this->columns[$column]); |
||||
| 535 | $this->rawColumns[$column] = $updatedAt; |
||||
| 536 | } |
||||
| 537 | |||||
| 538 | $this->modified = []; |
||||
| 539 | |||||
| 540 | // some relation already loaded still in the cache |
||||
| 541 | // so force reload it |
||||
| 542 | $this->relations = []; |
||||
| 543 | |||||
| 544 | if (count($this->pendingLinks) > 0) { |
||||
| 545 | $this->executePendingLinkage(); |
||||
| 546 | } |
||||
| 547 | |||||
| 548 | return true; |
||||
| 549 | } |
||||
| 550 | |||||
| 551 | /** |
||||
| 552 | * Mark the entity as deleted |
||||
| 553 | * @return bool |
||||
| 554 | */ |
||||
| 555 | public function markAsDeleted(): bool |
||||
| 556 | { |
||||
| 557 | return $this->deleted = true; |
||||
| 558 | } |
||||
| 559 | |||||
| 560 | /** |
||||
| 561 | * Execute the pending links |
||||
| 562 | * @return void |
||||
| 563 | */ |
||||
| 564 | public function executePendingLinkage(): void |
||||
| 565 | { |
||||
| 566 | foreach ($this->pendingLinks as $item) { |
||||
| 567 | /** @var \Platine\Orm\Relation\ShareOne<TEntity>|\Platine\Orm\Relation\ShareMany<TEntity> $rel */ |
||||
| 568 | $rel = $item['relation']; |
||||
| 569 | |||||
| 570 | if (isset($item['link'])) { |
||||
| 571 | if ($item['link'] === true) { |
||||
| 572 | $rel->link($this, $item['entity']); |
||||
| 573 | } else { |
||||
| 574 | $rel->unlink($this, $item['entity']); |
||||
| 575 | } |
||||
| 576 | } |
||||
| 577 | } |
||||
| 578 | |||||
| 579 | $this->pendingLinks = []; |
||||
| 580 | } |
||||
| 581 | |||||
| 582 | /** |
||||
| 583 | * Get fresh data from data store |
||||
| 584 | * @return void |
||||
| 585 | */ |
||||
| 586 | protected function hydrate(): void |
||||
| 587 | { |
||||
| 588 | if ($this->refresh === false) { |
||||
| 589 | return; |
||||
| 590 | } |
||||
| 591 | |||||
| 592 | $select = new Select($this->manager->getConnection(), $this->mapper->getTable()); |
||||
| 593 | |||||
| 594 | $primaryKeys = $this->mapper->getPrimaryKey()->getValue($this->rawColumns, true); |
||||
| 595 | if (is_array($primaryKeys)) { |
||||
| 596 | foreach ($primaryKeys as $pkColumn => $pkValue) { |
||||
| 597 | $select->where($pkColumn)->is($pkValue); |
||||
| 598 | } |
||||
| 599 | } |
||||
| 600 | |||||
| 601 | $columns = $select->select()->fetchAssoc()->get(); |
||||
| 602 | |||||
| 603 | if ($columns === false) { |
||||
| 604 | $this->deleted = true; |
||||
| 605 | return; |
||||
| 606 | } |
||||
| 607 | |||||
| 608 | $this->rawColumns = $columns; |
||||
| 609 | $this->columns = []; |
||||
| 610 | $this->relations = []; |
||||
| 611 | $this->loaders = []; |
||||
| 612 | $this->refresh = false; |
||||
| 613 | } |
||||
| 614 | |||||
| 615 | /** |
||||
| 616 | * Cast the value to the given type for get |
||||
| 617 | * @param mixed $value |
||||
| 618 | * @param string $type |
||||
| 619 | * |
||||
| 620 | * @return mixed |
||||
| 621 | */ |
||||
| 622 | protected function castGet(mixed $value, string $type): mixed |
||||
| 623 | { |
||||
| 624 | $original = $type; |
||||
| 625 | |||||
| 626 | if ($type[0] === '?') { |
||||
| 627 | if ($value === null) { |
||||
| 628 | return null; |
||||
| 629 | } |
||||
| 630 | $type = substr($type, 1); |
||||
| 631 | } |
||||
| 632 | |||||
| 633 | switch ($type) { |
||||
| 634 | case 'int': |
||||
| 635 | case 'integer': |
||||
| 636 | $value = (int) $value; |
||||
| 637 | break; |
||||
| 638 | case 'float': |
||||
| 639 | case 'double': |
||||
| 640 | $value = (float) $value; |
||||
| 641 | break; |
||||
| 642 | case 'bool': |
||||
| 643 | case 'boolean': |
||||
| 644 | $value = (bool) $value; |
||||
| 645 | break; |
||||
| 646 | case 'string': |
||||
| 647 | $value = (string) $value; |
||||
| 648 | break; |
||||
| 649 | case 'date': |
||||
| 650 | $value = DateTime::createFromFormat($this->manager->getDateFormat(), $value); |
||||
| 651 | break; |
||||
| 652 | case 'json': |
||||
| 653 | $value = json_decode($value); |
||||
| 654 | break; |
||||
| 655 | case 'json-assoc': |
||||
| 656 | $value = json_decode($value, true); |
||||
| 657 | break; |
||||
| 658 | default: |
||||
| 659 | throw new RuntimeException(sprintf( |
||||
| 660 | 'Invalid cast type [%s]', |
||||
| 661 | $original |
||||
| 662 | )); |
||||
| 663 | } |
||||
| 664 | |||||
| 665 | return $value; |
||||
| 666 | } |
||||
| 667 | |||||
| 668 | /** |
||||
| 669 | * Cast the value to the given type for set |
||||
| 670 | * @param mixed $value |
||||
| 671 | * @param string $type |
||||
| 672 | * |
||||
| 673 | * @return mixed |
||||
| 674 | */ |
||||
| 675 | protected function castSet(mixed $value, string $type): mixed |
||||
| 676 | { |
||||
| 677 | $original = $type; |
||||
| 678 | |||||
| 679 | if ($type[0] === '?') { |
||||
| 680 | if ($value === null) { |
||||
| 681 | return null; |
||||
| 682 | } |
||||
| 683 | $type = substr($type, 1); |
||||
| 684 | } |
||||
| 685 | |||||
| 686 | switch ($type) { |
||||
| 687 | case 'int': |
||||
| 688 | case 'integer': |
||||
| 689 | $value = (int) $value; |
||||
| 690 | break; |
||||
| 691 | case 'float': |
||||
| 692 | case 'double': |
||||
| 693 | $value = (float) $value; |
||||
| 694 | break; |
||||
| 695 | case 'bool': |
||||
| 696 | case 'boolean': |
||||
| 697 | $value = (bool) $value; |
||||
| 698 | break; |
||||
| 699 | case 'string': |
||||
| 700 | $value = (string) $value; |
||||
| 701 | break; |
||||
| 702 | case 'date': |
||||
| 703 | $value = /** @var DateTime $value */ $value->format($this->manager->getDateFormat()); |
||||
| 704 | break; |
||||
| 705 | case 'json': |
||||
| 706 | case 'json-assoc': |
||||
| 707 | $value = json_encode($value); |
||||
| 708 | break; |
||||
| 709 | default: |
||||
| 710 | throw new RuntimeException(sprintf( |
||||
| 711 | 'Invalid cast type [%s]', |
||||
| 712 | $original |
||||
| 713 | )); |
||||
| 714 | } |
||||
| 715 | |||||
| 716 | return $value; |
||||
| 717 | } |
||||
| 718 | |||||
| 719 | /** |
||||
| 720 | * Set |
||||
| 721 | * @param string $relation |
||||
| 722 | * @param TEntity $entity |
||||
|
0 ignored issues
–
show
The type
Platine\Orm\Mapper\TEntity was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||
| 723 | * @param bool $link |
||||
| 724 | * @return void |
||||
| 725 | */ |
||||
| 726 | private function setLink(string $relation, Entity $entity, bool $link): void |
||||
| 727 | { |
||||
| 728 | $relations = $this->mapper->getRelations(); |
||||
| 729 | |||||
| 730 | if (!isset($relations[$relation])) { |
||||
| 731 | throw new RelationNotFoundException(sprintf( |
||||
| 732 | 'Unknown relation [%s]', |
||||
| 733 | $relation |
||||
| 734 | )); |
||||
| 735 | } |
||||
| 736 | |||||
| 737 | /** @var \Platine\Orm\Relation\Relation<TEntity> $rel */ |
||||
| 738 | $rel = $relations[$relation]; |
||||
| 739 | if (!($rel instanceof ShareRelation)) { |
||||
| 740 | throw new RuntimeException('Unsupported relation type'); |
||||
| 741 | } |
||||
| 742 | |||||
| 743 | $this->pendingLinks[] = [ |
||||
| 744 | 'relation' => $rel, |
||||
| 745 | 'entity' => $entity, |
||||
| 746 | 'link' => $link |
||||
| 747 | ]; |
||||
| 748 | } |
||||
| 749 | } |
||||
| 750 |