Completed
Branch feature/pre-split (4ff102)
by Anton
03:27
created

HasOneRelation::setRelated()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 1
dl 0
loc 15
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * components
4
 *
5
 * @author    Wolfy-J
6
 */
7
namespace Spiral\ORM\Entities\Relations;
8
9
use Spiral\ORM\CommandInterface;
10
use Spiral\ORM\Commands\InsertCommand;
11
use Spiral\ORM\Commands\NullCommand;
12
use Spiral\ORM\Commands\TransactionalCommand;
13
use Spiral\ORM\ContextualCommandInterface;
14
use Spiral\ORM\ORMInterface;
15
use Spiral\ORM\Record;
16
use Spiral\ORM\RecordInterface;
17
18
class HasOneRelation extends SingularRelation
19
{
20
    const CREATE_PLACEHOLDER = true;
21
22
    /**
23
     * Previously binded instance, to be deleted.
24
     *
25
     * @var RecordInterface
26
     */
27
    private $previous = null;
28
29
    /**
30
     * Related object changed.
31
     *
32
     * @var bool
33
     */
34
    private $changed = true;
35
36
    /**
37
     * {@inheritdoc}
38
     */
39
    public function setRelated($value)
40
    {
41
        //Make sure value is accepted
42
        $this->assertValid($value);
43
44
        $this->loaded = true;
45
        $this->changed = true;
46
47
        if (empty($this->previous)) {
48
            //We are only keeping reference to the oldest (ie loaded) instance
49
            $this->previous = $this->instance;
50
        }
51
52
        $this->instance = $value;
53
    }
54
55
    /**
56
     * {@inheritdoc}
57
     */
58
    public function queueCommands(ContextualCommandInterface $command): CommandInterface
59
    {
60
        if (!empty($this->previous)) {
61
            $transaction = new TransactionalCommand();
62
63
            //Delete old entity
64
            $transaction->addCommand($this->previous->queueDelete());
65
66
            //Store new entity if any
67
            $transaction->addCommand($this->queueRelated($command));
68
69
            //We don't need previous reference anymore
70
            $this->previous = null;
71
72
            return $transaction;
73
        }
74
75
        return $this->queueRelated($command);
76
    }
77
78
    /**
79
     * Store related instance.
80
     *
81
     * @param ContextualCommandInterface $command
82
     *
83
     * @return CommandInterface
84
     */
85
    private function queueRelated(ContextualCommandInterface $command): CommandInterface
86
    {
87
        if (empty($this->instance)) {
88
            return new NullCommand();
89
        }
90
91
        $related = $this->instance->queueStore(true);
92
93
        //Primary key of parent entity
94
        $primaryKey = $this->orm->define(get_class($this->parent), ORMInterface::R_PRIMARY_KEY);
95
96
        if (
97
            $command instanceof InsertCommand
98
            && $primaryKey == $this->schema[Record::INNER_KEY]
99
        ) {
100
            /**
101
             * Particular case when parent entity exists but now saved yet AND outer key is PK.
102
             *
103
             * Basically inversed case of BELONGS_TO.
104
             */
105
            $command->onExecute(function (InsertCommand $command) use ($related) {
106
                $related->addContext($this->schema[Record::OUTER_KEY], $command->getInsertID());
107
            });
108
        } elseif ($this->changed) {
109
            //Delete old one!
110
            $related->addContext(
111
                $this->schema[Record::OUTER_KEY],
112
                $this->parent->getField($this->schema[Record::INNER_KEY])
113
            );
114
        }
115
116
        return $related;
117
    }
118
}