Completed
Branch feature/pre-split (24875e)
by Anton
03:28
created

BelongsToMorphedRelation::queueCommands()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
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
8
namespace Spiral\ORM\Entities\Relations;
9
10
use Spiral\ORM\CommandInterface;
11
use Spiral\ORM\Commands\NullCommand;
12
use Spiral\ORM\ContextualCommandInterface;
13
use Spiral\ORM\Entities\Relations\Traits\LookupTrait;
14
use Spiral\ORM\Exceptions\RelationException;
15
use Spiral\ORM\ORMInterface;
16
use Spiral\ORM\Record;
17
18
/**
19
 * Similar to BelongsTo, however morph key value used to resolve parent record. Record allows
20
 * mutable parent type.
21
 */
22
class BelongsToMorphedRelation extends SingularRelation
23
{
24
    use LookupTrait;
25
26
    /**
27
     * Always saved before parent.
28
     */
29
    const LEADING_RELATION = true;
30
31
    /**
32
     * No placeholder for belongs to.
33
     */
34
    const CREATE_PLACEHOLDER = false;
35
36
    /**
37
     * {@inheritdoc}
38
     */
39
    public function getClass(): string
40
    {
41
        if (empty($parentType = $this->parent->getField($this->key(Record::MORPH_KEY)))) {
42
            return parent::getClass();
43
        }
44
45
        //Resolve parent using role map
46
        return $this->schema[ORMInterface::R_ROLE_NAME][$parentType];
47
    }
48
49
    /**
50
     * {@inheritdoc}
51
     */
52
    public function setRelated($value)
53
    {
54
        //Make sure value is accepted
55
        $this->assertValid($value);
56
57
        $this->loaded = true;
58
        $this->instance = $value;
59
    }
60
61
    /**
62
     * @param ContextualCommandInterface $parentCommand
63
     *
64
     * @return CommandInterface
65
     *
66
     * @throws RelationException
67
     */
68
    public function queueCommands(ContextualCommandInterface $parentCommand): CommandInterface
69
    {
70
        if (!empty($this->instance)) {
71
            return $this->queueRelated($parentCommand);
72
        }
73
74
        if (!$this->schema[Record::NULLABLE]) {
75
            throw new RelationException("No data presented in non nullable relation");
76
        }
77
78
        $parentCommand->addContext($this->schema[Record::INNER_KEY], null);
79
        $parentCommand->addContext($this->schema[Record::MORPH_KEY], null);
80
81
        return new NullCommand();
82
    }
83
84
    /**
85
     * {@inheritdoc}
86
     */
87
    protected function getRoles(): array
88
    {
89
        return $this->schema[ORMInterface::R_ROLE_NAME];
90
    }
91
92
    /**
93
     * Store related instance
94
     *
95
     * @param ContextualCommandInterface $parentCommand
96
     *
97
     * @return ContextualCommandInterface
98
     */
99
    private function queueRelated(
100
        ContextualCommandInterface $parentCommand
101
    ): ContextualCommandInterface {
102
        //Command or command set needed to store
103
        $innerCommand = $this->instance->queueStore(true);
104
105
        if (!$this->isSynced($this->parent, $this->instance)) {
106
            //Syncing FKs before primary command been executed
107
            $innerCommand->onExecute(function ($innerCommand) use ($parentCommand) {
108
                $parentCommand->addContext(
109
                    $this->key(Record::INNER_KEY),
110
                    $this->lookupKey(Record::OUTER_KEY, $this->parent, $innerCommand)
111
                );
112
113
                //Morph key value
114
                $parentCommand->addContext(
115
                    $this->key(Record::MORPH_KEY),
116
                    $this->orm->define(get_class($this->instance), ORMInterface::R_ROLE_NAME)
117
                );
118
            });
119
        }
120
121
        return $innerCommand;
122
    }
123
}