Passed
Push — master ( 9676b0...44a032 )
by Anton
02:07
created

src/Relation/HasOne.php (1 issue)

Labels
Severity
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
It seems like $relNode can also be of type null; however, parameter $relNode of Cycle\ORM\Relation\AbstractRelation::assertValid() does only seem to accept Cycle\ORM\Heap\Node, 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 ignore-type  annotation

54
        $this->assertValid(/** @scrutinizer ignore-type */ $relNode);
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
}