Completed
Push — master ( a55455...2f0ff4 )
by Anton
27:28 queued 27:28
created

BelongsTo::isLoadable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
namespace Spiral\ORM\Entities\Relations;
9
10
use Spiral\Models\EntityInterface;
11
use Spiral\ORM\Exceptions\RelationException;
12
use Spiral\ORM\ORM;
13
use Spiral\ORM\RecordEntity;
14
15
/**
16
 * Represents simple BELONGS_TO relation with ability to associate and de-associate parent.
17
 */
18
class BelongsTo extends HasOne
19
{
20
    /**
21
     * Relation type, required to fetch record class from relation definition.
22
     */
23
    const RELATION_TYPE = RecordEntity::BELONGS_TO;
24
25
    /**
26
     * {@inheritdoc}
27
     */
28
    public function isLoaded()
29
    {
30
        $this->fromCache();
31
32
        if (empty($this->parent->getField($this->definition[RecordEntity::INNER_KEY], false))) {
33
            return true;
34
        }
35
36
        return $this->loaded;
37
    }
38
39
    /**
40
     * {@inheritdoc}
41
     */
42
    public function getRelated()
43
    {
44
        $this->fromCache();
45
46
        return parent::getRelated();
47
    }
48
49
    /**
50
     * {@inheritdoc}
51
     *
52
     * Parent record MUST be saved in order to preserve parent association.
53
     */
54
    public function associate(EntityInterface $related = null)
55
    {
56
        if ($related === null) {
57
            $this->deassociate();
58
59
            return;
60
        }
61
62
        /**
63
         * @var RecordEntity $related
64
         */
65
        if (!$related->isLoaded()) {
66
            throw new RelationException(
67
                "Unable to set 'belongs to' parent, parent has be fetched from database."
68
            );
69
        }
70
71
        parent::associate($related);
72
73
        //Key in parent record
74
        $outerKey = $this->definition[RecordEntity::OUTER_KEY];
75
76
        //Key in child record
77
        $innerKey = $this->definition[RecordEntity::INNER_KEY];
78
79 View Code Duplication
        if ($this->parent->getField($innerKey, false) != $related->getField($outerKey, false)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
80
            //We are going to set relation keys right on assertion
81
            $this->parent->setField($innerKey, $related->getField($outerKey, false));
82
        }
83
    }
84
85
    /**
86
     * {@inheritdoc}
87
     */
88
    protected function mountRelation(EntityInterface $record)
89
    {
90
        //Nothing to do, children can not update parent relation
91
        return $record;
92
    }
93
94
    /**
95
     * {@inheritdoc}
96
     *
97
     * @throws RelationException
98
     */
99
    protected function createSelector()
100
    {
101
        if (empty($this->parent->getField($this->definition[RecordEntity::INNER_KEY], false))) {
102
            throw new RelationException(
103
                "Belongs-to selector can not be constructed when inner key ("
104
                . $this->definition[RecordEntity::INNER_KEY]
105
                . ") is null."
106
            );
107
        }
108
109
        return parent::createSelector();
110
    }
111
112
    /**
113
     * {@inheritdoc}
114
     *
115
     * Belongs-to can not automatically create parent.
116
     */
117
    protected function emptyRecord()
118
    {
119
        return null;
120
    }
121
122
    /**
123
     * De associate related record.
124
     */
125
    protected function deassociate()
126
    {
127
        if (!$this->definition[RecordEntity::NULLABLE]) {
128
            throw new RelationException(
129
                "Unable to de-associate relation data, relation is not nullable."
130
            );
131
        }
132
133
        $innerKey = $this->definition[RecordEntity::INNER_KEY];
134
        $this->parent->setField($innerKey, null);
135
136
        $this->loaded = true;
137
        $this->instance = null;
138
        $this->data = [];
139
    }
140
141
    /**
142
     * Loadable when parent is loaded as well.
143
     *
144
     * @return bool
145
     */
146
    protected function isLoadable()
147
    {
148
        return true;
149
    }
150
151
    /**
152
     * Try to fetch outer model using entity cache.
153
     */
154
    private function fromCache()
155
    {
156
        if ($this->loaded) {
157
            return;
158
        }
159
160
        $innerKey = $this->parent->getField($this->definition[RecordEntity::INNER_KEY], false);
161
162
        if (empty($innerKey)) {
163
            return;
164
        }
165
166
        if (empty($this->definition[ORM::M_PRIMARY_KEY])) {
167
            //Linked not by primary key
168
            return;
169
        }
170
171
        if (empty($entity = $this->orm->cache()->get($this->getClass(), $innerKey))) {
172
            return;
173
        }
174
175
        $this->loaded = true;
176
        $this->instance = $entity;
177
    }
178
}