Completed
Branch feature/pre-split (c41c6b)
by Anton
03:19
created

HasOneRelation   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 112
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 0
Metric Value
dl 0
loc 112
rs 10
c 0
b 0
f 0
wmc 10
lcom 1
cbo 7

4 Methods

Rating   Name   Duplication   Size   Complexity  
A setRelated() 0 13 2
A queueCommands() 0 19 2
B queueRelated() 0 30 4
A whereStatement() 0 14 2
1
<?php
2
/**
3
 * components
4
 *
5
 * @author    Wolfy-J
6
 */
7
8
namespace Spiral\ORM\Entities\Relations;
9
10
use Spiral\ORM\CommandInterface;
11
use Spiral\ORM\Commands\NullCommand;
12
use Spiral\ORM\Commands\TransactionalCommand;
13
use Spiral\ORM\ContextualCommandInterface;
14
use Spiral\ORM\Entities\Relations\Traits\LookupTrait;
15
use Spiral\ORM\ORMInterface;
16
use Spiral\ORM\Record;
17
use Spiral\ORM\RecordInterface;
18
19
class HasOneRelation extends SingularRelation
20
{
21
    use LookupTrait;
22
23
    /** Automatically create related model when empty. */
24
    const CREATE_PLACEHOLDER = true;
25
26
    /**
27
     * Previously binded instance, to be deleted.
28
     *
29
     * @var RecordInterface
30
     */
31
    private $previous = null;
32
33
    /**
34
     * {@inheritdoc}
35
     */
36
    public function setRelated($value)
37
    {
38
        //Make sure value is accepted
39
        $this->assertValid($value);
40
41
        $this->loaded = true;
42
        if (empty($this->previous)) {
43
            //We are only keeping reference to the oldest (ie loaded) instance
44
            $this->previous = $this->instance;
45
        }
46
47
        $this->instance = $value;
48
    }
49
50
    /**
51
     * {@inheritdoc}
52
     */
53
    public function queueCommands(ContextualCommandInterface $parentCommand): CommandInterface
54
    {
55
        if (!empty($this->previous)) {
56
            $transaction = new TransactionalCommand();
57
58
            //Delete old entity
59
            $transaction->addCommand($this->previous->queueDelete());
60
61
            //Store new entity if any (leading)
62
            $transaction->addCommand($this->queueRelated($parentCommand), true);
63
64
            //We don't need previous reference anymore
65
            $this->previous = null;
66
67
            return $transaction;
68
        }
69
70
        return $this->queueRelated($parentCommand);
71
    }
72
73
    /**
74
     * Store related instance.
75
     *
76
     * @param ContextualCommandInterface $parentCommand
77
     *
78
     * @return CommandInterface
79
     */
80
    private function queueRelated(ContextualCommandInterface $parentCommand): CommandInterface
81
    {
82
        if (empty($this->instance)) {
83
            return new NullCommand();
84
        }
85
86
        //Related entity store command
87
        $innerCommand = $this->instance->queueStore(true);
88
89
        //Inversed version of BelongsTo
90
        if (!$this->isSynced($this->parent, $this->instance)) {
91
            //Syncing FKs after primary command been executed
92
            $parentCommand->onExecute(function ($outerCommand) use ($innerCommand) {
93
                $innerCommand->addContext(
94
                    $this->key(Record::OUTER_KEY),
95
                    $this->lookupKey(Record::INNER_KEY, $this->parent, $outerCommand)
96
                );
97
98
                if (!empty($morphKey = $this->key(Record::MORPH_KEY))) {
99
                    //HasOne relation support additional morph key
100
                    $innerCommand->addContext(
101
                        $this->key(Record::MORPH_KEY),
102
                        $this->orm->define(get_class($this->parent), ORMInterface::R_ROLE_NAME)
103
                    );
104
                }
105
            });
106
        }
107
108
        return $innerCommand;
109
    }
110
111
    /**
112
     * Where statement to load outer record.
113
     *
114
     * @return array
115
     */
116
    protected function whereStatement(): array
117
    {
118
        $where = parent::whereStatement();
119
120
        if (!empty($morphKey = $this->key(Record::MORPH_KEY))) {
121
            //HasOne relation support additional morph key
122
            $where[$this->key(Record::MORPH_KEY)] = $this->orm->define(
123
                get_class($this->parent),
124
                ORMInterface::R_ROLE_NAME
125
            );
126
        }
127
128
        return $where;
129
    }
130
}