Completed
Push — master ( ed12a7...bef77f )
by Anton
02:20
created

ManyToMorphedRelation::isLoaded()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 5
nc 3
nop 0
1
<?php
2
/**
3
 * Spiral, Core 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\TransactionalCommand;
12
use Spiral\ORM\ContextualCommandInterface;
13
use Spiral\ORM\Exceptions\RelationException;
14
use Spiral\ORM\ORMInterface;
15
use Spiral\ORM\Record;
16
17
/**
18
 * ManyToMorphed relation used to aggregate multiple ManyToMany relations based on their role type.
19
 * In addition it can route some function to specified nested ManyToMany relation based on record
20
 * role.
21
 *
22
 * Works similary to RelationMap and does not work as direct relation but rather bypassed calls to
23
 * sub relations.
24
 *
25
 * Example:
26
 * dump($tag->tagged->posts->count());
27
 *
28
 * @see ManyToMany
29
 * @see \Spiral\ORM\Schemas\Relations\ManyToMorphedSchema
30
 */
31
class ManyToMorphedRelation extends AbstractRelation
32
{
33
    /**
34
     * Set of nested relations.
35
     *
36
     * @var ManyToManyRelation[]
37
     */
38
    private $nested = [];
39
40
    /**
41
     * {@inheritdoc}
42
     */
43
    public function isLoaded(): bool
44
    {
45
        foreach ($this->nested as $relation) {
46
            if ($relation->isLoaded()) {
47
                return true;
48
            }
49
        }
50
51
        return false;
52
    }
53
54
    /**
55
     * {@inheritdoc}
56
     */
57
    public function hasRelated(): bool
58
    {
59
        throw new RelationException(
60
            "Unable to check existence of related data in ManyToMorphed relation, use nested relation"
61
        );
62
    }
63
64
    /**
65
     * {@inheritdoc}
66
     */
67
    public function setRelated($value)
68
    {
69
        throw new RelationException(
70
            "Unable to set related data to ManyToMorphed relation, use nested relation"
71
        );
72
    }
73
74
    /**
75
     * {@inheritdoc}
76
     */
77
    public function getRelated()
78
    {
79
        return $this;
80
    }
81
82
    /**
83
     * All possible outer variations.
84
     *
85
     * @return array
86
     */
87
    public function getVariations(): array
88
    {
89
        return $this->schema[Record::MORPHED_ALIASES];
90
    }
91
92
    /**
93
     * Get nested relation for a given variation.
94
     *
95
     * @param string $variation
96
     *
97
     * @return ManyToManyRelation
98
     *
99
     * @throws RelationException
100
     */
101
    public function getVariation(string $variation): ManyToManyRelation
102
    {
103
        if (isset($this->nested[$variation])) {
104
            return $this->nested[$variation];
105
        }
106
107
        if (!isset($this->schema[Record::MORPHED_ALIASES][$variation])) {
108
            throw new RelationException("Undefined morphed variation '{$variation}'");
109
        }
110
111
        $class = $this->schema[Record::MORPHED_ALIASES][$variation];
112
113
        $relation = new ManyToManyRelation(
114
            $class,
115
            $this->makeSchema($class),
116
            $this->orm,
117
            $this->orm->define($class, ORMInterface::R_ROLE_NAME)
118
        );
119
120
        return $this->nested[$variation] = $relation->withContext($this->parent, false);
121
    }
122
123
    /**
124
     * @param string $name
125
     *
126
     * @return ManyToManyRelation
127
     */
128
    public function __get(string $name)
129
    {
130
        return $this->getVariation($name);
131
    }
132
133
    /**
134
     * @param string $variation
135
     * @param mixed  $value
136
     */
137
    public function __set(string $variation, $value)
138
    {
139
        $this->getVariation($variation)->setRelated($value);
140
    }
141
142
    /**
143
     * @param string $variation
144
     *
145
     * @return bool
146
     */
147
    public function __isset(string $variation)
148
    {
149
        return $this->getVariation($variation)->hasRelated();
150
    }
151
152
    /**
153
     * @param string $variation
154
     */
155
    public function __unset(string $variation)
156
    {
157
        $this->getVariation($variation)->setRelated(null);
158
    }
159
160
    /**
161
     * {@inheritdoc}
162
     */
163
    public function queueCommands(ContextualCommandInterface $parentCommand): CommandInterface
164
    {
165
        $transaction = new TransactionalCommand();
166
        foreach ($this->nested as $relation) {
167
            if ($relation->isLoaded()) {
168
                $transaction->addCommand($relation->queueCommands($parentCommand));
169
            }
170
        }
171
172
        return $transaction;
173
    }
174
175
    /**
176
     * Create relation schema for nested relation.
177
     *
178
     * @param string $class
179
     *
180
     * @return array
181
     */
182
    protected function makeSchema(string $class): array
183
    {
184
        //Using as basement
185
        $schema = $this->schema;
186
        unset($schema[Record::MORPHED_ALIASES]);
187
188
        //We do not have this information in morphed relation but it's required for ManyToMany
189
        $schema[Record::WHERE] = [];
190
191
        //This must be unified in future, for now we can fetch columns directly from there
192
        $recordSchema = $this->orm->define($class, ORMInterface::R_SCHEMA);
193
        $schema[Record::RELATION_COLUMNS] = array_keys($recordSchema[Record::SH_DEFAULTS]);
194
195
        return $schema;
196
    }
197
}