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

BelongsToRelation::queueRelated()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 27
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 14
nc 6
nop 1
dl 0
loc 27
rs 8.439
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\Exceptions\RelationException;
15
use Spiral\ORM\ORMInterface;
16
use Spiral\ORM\Record;
17
18
/**
19
 * Complex relation with ability to mount inner_key context into parent save command.
20
 */
21
class BelongsToRelation extends SingularRelation
22
{
23
    /**
24
     * Always saved before parent.
25
     */
26
    const LEADING_RELATION = true;
27
28
    /**
29
     * Related object changed.
30
     *
31
     * @var bool
32
     */
33
    private $changed = false;
34
35
    /**
36
     * {@inheritdoc}
37
     */
38
    public function setRelated($value)
39
    {
40
        //Make sure value is accepted
41
        $this->assertValid($value);
42
43
        $this->loaded = true;
44
        $this->changed = true;
45
        $this->instance = $value;
46
    }
47
48
    /**
49
     * @param ContextualCommandInterface $command
50
     *
51
     * @return CommandInterface
52
     *
53
     * @throws RelationException
54
     */
55
    public function queueCommands(ContextualCommandInterface $command): CommandInterface
56
    {
57
        if (empty($this->instance)) {
58
            if (!$this->schema[Record::NULLABLE]) {
59
                throw new RelationException("No data presented in non nullable relation");
60
            }
61
62
            $command->addContext($this->schema[Record::INNER_KEY], null);
63
64
            return new NullCommand();
65
        }
66
67
        return $this->queueRelated($command);
68
    }
69
70
    /**
71
     * Store related instance
72
     *
73
     * @param ContextualCommandInterface $command
74
     *
75
     * @return ContextualCommandInterface
76
     */
77
    private function queueRelated(ContextualCommandInterface $command): ContextualCommandInterface
78
    {
79
        $related = $this->instance->queueStore(true);
80
        $leadingCommand = $related instanceof TransactionalCommand ? $related->getLeading() : $related;
81
82
        //Primary key of associated entity
83
        $primaryKey = $this->orm->define(get_class($this->instance), ORMInterface::R_PRIMARY_KEY);
84
85
        if (
86
            $leadingCommand instanceof InsertCommand
87
            && $primaryKey == $this->schema[Record::OUTER_KEY]
88
        ) {
89
            /**
90
             * Particular case when parent entity exists but now saved yet AND outer key is PK.
91
             */
92
            $leadingCommand->onExecute(function (InsertCommand $related) use ($command) {
93
                $command->addContext($this->schema[Record::INNER_KEY], $related->getInsertID());
94
            });
95
        } elseif ($this->changed) {
96
            $command->addContext(
97
                $this->schema[Record::INNER_KEY],
98
                $this->instance->getField($this->schema[Record::OUTER_KEY])
99
            );
100
        }
101
102
        return $related;
103
    }
104
}