1 | <?php |
||
2 | /** |
||
3 | * Cycle DataMapper ORM |
||
4 | * |
||
5 | * @license MIT |
||
6 | * @author Anton Titov (Wolfy-J) |
||
7 | */ |
||
8 | declare(strict_types=1); |
||
9 | |||
10 | namespace Cycle\ORM\Relation; |
||
11 | |||
12 | use Cycle\ORM\Command\Branch\Condition; |
||
13 | use Cycle\ORM\Command\Branch\ContextSequence; |
||
14 | use Cycle\ORM\Command\Branch\Nil; |
||
15 | use Cycle\ORM\Command\CommandInterface; |
||
16 | use Cycle\ORM\Command\ContextCarrierInterface as CC; |
||
17 | use Cycle\ORM\Heap\Node; |
||
18 | use Cycle\ORM\Promise\ReferenceInterface; |
||
19 | use Cycle\ORM\Relation\Traits\PromiseOneTrait; |
||
20 | |||
21 | /** |
||
22 | * Provides the ability to own and forward context values to child entity. |
||
23 | */ |
||
24 | class HasOne extends AbstractRelation |
||
25 | { |
||
26 | use PromiseOneTrait; |
||
27 | |||
28 | /** |
||
29 | * @inheritdoc |
||
30 | */ |
||
31 | public function queue(CC $parentStore, $parentEntity, Node $parentNode, $related, $original): CommandInterface |
||
32 | { |
||
33 | if ($original instanceof ReferenceInterface) { |
||
34 | $original = $this->resolve($original); |
||
35 | } |
||
36 | |||
37 | if ($related instanceof ReferenceInterface) { |
||
38 | $related = $this->resolve($related); |
||
39 | } |
||
40 | |||
41 | if (is_null($related)) { |
||
42 | if ($related === $original) { |
||
43 | // no changes |
||
44 | return new Nil(); |
||
45 | } |
||
46 | |||
47 | if (!is_null($original)) { |
||
48 | return $this->deleteOriginal($original); |
||
49 | } |
||
50 | } |
||
51 | |||
52 | $resStore = $this->orm->queueStore($related); |
||
53 | $relNode = $this->getNode($related, +1); |
||
54 | $this->assertValid($relNode); |
||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
55 | |||
56 | // store command with mounted context paths |
||
57 | $relStore = $this->forwardContext($parentNode, $this->innerKey, $resStore, $relNode, $this->outerKey); |
||
58 | |||
59 | if (is_null($original)) { |
||
60 | return $relStore; |
||
61 | } |
||
62 | |||
63 | $sequence = new ContextSequence(); |
||
64 | $sequence->addCommand($this->deleteOriginal($original)); |
||
65 | $sequence->addPrimary($relStore); |
||
66 | |||
67 | return $sequence; |
||
68 | } |
||
69 | |||
70 | /** |
||
71 | * Delete original related entity of no other objects reference to it. |
||
72 | * |
||
73 | * @param object $original |
||
74 | * @return CommandInterface |
||
75 | */ |
||
76 | protected function deleteOriginal($original): CommandInterface |
||
77 | { |
||
78 | $relNode = $this->getNode($original); |
||
79 | |||
80 | if (!$this->isRequired()) { |
||
81 | $store = $this->orm->queueStore($original); |
||
82 | $store->register($this->outerKey, null, true); |
||
83 | $relNode->getState()->decClaim(); |
||
84 | |||
85 | return new Condition($store, function () use ($relNode) { |
||
86 | return !$relNode->getState()->hasClaims(); |
||
87 | }); |
||
88 | } |
||
89 | |||
90 | // only delete original child when no other objects claim it |
||
91 | return new Condition($this->orm->queueDelete($original), function () use ($relNode) { |
||
92 | return !$relNode->getState()->hasClaims(); |
||
93 | }); |
||
94 | } |
||
95 | } |