Test Failed
Pull Request — master (#106)
by Alex
08:05
created

MetadataRelationHolder::reset()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace AlgoWeb\PODataLaravel\Models;
4
5
use Illuminate\Database\Eloquent\Model;
6
7
class MetadataRelationHolder
8
{
9
    protected $multConstraints = [ '0..1' => ['1'], '1' => ['0..1', '*'], '*' => ['1', '*']];
10
    protected $relations = [];
11
12
    public function __construct()
13
    {
14
    }
15
16
    /**
17
     * Add model's relationships to holder
18
     *
19
     * @param Model $model
20
     */
21
    public function addModel(Model $model)
22
    {
23
        if (!in_array('AlgoWeb\\PODataLaravel\\Models\\MetadataTrait', class_uses($model))) {
24
            $msg = 'Supplied model does not use MetadataTrait';
25
            throw new \InvalidArgumentException($msg);
26
        }
27
        $className = get_class($model);
28
        if (array_key_exists($className, $this->relations)) {
29
            $msg = $className.' already added';
30
            throw new \InvalidArgumentException($msg);
31
        }
32
        $this->relations[$className] = $model->getRelationships();
33
    }
34
35
    public function getRelationsByKey($className, $keyName)
36
    {
37
        $this->checkClassExists($className);
38
39
        $rels = $this->relations[$className];
40
        if (!array_key_exists($keyName, $rels)) {
41
            $msg = 'Key ' . $keyName . ' not registered on ' . $className;
42
            throw new \InvalidArgumentException($msg);
43
        }
44
45
        $result = [];
46
        $payload = $rels[$keyName];
47
        $principalType = $className;
48
        foreach ($payload as $dependentType => $targDeets) {
49
            if (!array_key_exists($dependentType, $this->relations)) {
50
                continue;
51
            }
52
            // if principal and ostensible dependent type are equal, drop through to specific handler
53
            // at moment, this is only for morphTo relations - morphedByMany doesn't cause this
54
            if ($principalType === $dependentType) {
55
                $morphToLines = $this->getMorphToRelations($principalType, $targDeets, $keyName);
56
                foreach ($morphToLines as $morph) {
57
                    if (!in_array($morph, $result)) {
58
                        $result[] = $morph;
59
                    }
60
                }
61
                continue;
62
            }
63
64
            $foreign = $this->relations[$dependentType];
65
66
            foreach ($targDeets as $principalProperty => $rawDeets) {
67
                $targKey = $rawDeets['local'];
68
                $principalMult = $rawDeets['multiplicity'];
69
                $principalProperty = $rawDeets['property'];
70
                if (!array_key_exists($targKey, $foreign)) {
71
                    continue;
72
                }
73
                $foreignDeets = $foreign[$targKey];
74
                foreach ($foreignDeets as $foreignType => $raw) {
75
                    if (!array_key_exists($foreignType, $this->relations)) {
76
                        continue;
77
                    }
78 View Code Duplication
                    foreach ($raw as $dependentProperty => $dependentPayload) {
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...
79
                        if ($keyName == $dependentPayload['local']) {
80
                            $dependentMult = $dependentPayload['multiplicity'];
81
                            // generate forward and reverse relations
82
                            list($forward, $reverse) = $this->calculateRoundTripRelationsGenForwardReverse(
83
                                $principalType,
84
                                $principalMult,
85
                                $principalProperty,
86
                                $dependentType,
87
                                $dependentMult,
88
                                $dependentProperty
89
                            );
90
                            if (!in_array($forward, $result)) {
91
                                // add forward relation
92
                                $result[] = $forward;
93
                            }
94
                            if (!in_array($reverse, $result)) {
95
                                // add reverse relation
96
                                $result[] = $reverse;
97
                            }
98
                        }
99
                    }
100
                }
101
            }
102
        }
103
        return $result;
104
    }
105
106
    public function getRelationsByClass($className)
107
    {
108
        $this->checkClassExists($className);
109
110
        $rels = $this->relations[$className];
111
        $keys = array_keys($rels);
112
        $results = [];
113
        foreach ($keys as $key) {
114
            $lines = $this->getRelationsByKey($className, $key);
115
            foreach ($lines as $line) {
116
                if (!in_array($line, $results)) {
117
                    $results[] = $line;
118
                }
119
            }
120
        }
121
122
        return $results;
123
    }
124
125
    private function getMorphToRelations($principalType, $targDeets, $keyName)
126
    {
127
        $result = [];
128
        $deetKeys = array_keys($targDeets);
129
        $principalProperty = $deetKeys[0];
130
        $principalDeets = $targDeets[$principalProperty];
131
        $principalMult = $principalDeets['multiplicity'];
132
133
        foreach ($this->relations as $dependentType => $dependentDeets) {
134
            foreach ($dependentDeets as $targKey => $rawDeets) {
135
                foreach ($rawDeets as $targType => $interDeets) {
136
                    if ($targType != $principalType) {
137
                        continue;
138
                    }
139 View Code Duplication
                    foreach ($interDeets as $dependentProperty => $finalDeets) {
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...
140
                        if ($keyName !== $finalDeets['local']) {
141
                            continue;
142
                        }
143
                        $dependentMult = $finalDeets['multiplicity'];
144
                        list($forward, $reverse) = $this->calculateRoundTripRelationsGenForwardReverse(
145
                            $principalType,
146
                            $principalMult,
147
                            $principalProperty,
148
                            $dependentType,
149
                            $dependentMult,
150
                            $dependentProperty
151
                        );
152
                        if (!in_array($forward, $result)) {
153
                            // add forward relation
154
                            $result[] = $forward;
155
                        }
156
                        if (!in_array($reverse, $result)) {
157
                            // add reverse relation
158
                            $result[] = $reverse;
159
                        }
160
                    }
161
                }
162
            }
163
        }
164
        return $result;
165
    }
166
167
    /**
168
     * @param $principalType
169
     * @param $principalMult
170
     * @param $principalProperty
171
     * @param $dependentType
172
     * @param $dependentMult
173
     * @param $dependentProperty
174
     * @return array[]
175
     */
176
    private function calculateRoundTripRelationsGenForwardReverse(
177
        $principalType,
178
        $principalMult,
179
        $principalProperty,
180
        $dependentType,
181
        $dependentMult,
182
        $dependentProperty
183
    ) {
184
        assert(
185
            in_array($dependentMult, $this->multConstraints[$principalMult]),
186
            'Cannot pair multiplicities ' . $dependentMult . ' and ' . $principalMult
187
        );
188
        assert(
189
            in_array($principalMult, $this->multConstraints[$dependentMult]),
190
            'Cannot pair multiplicities ' . $principalMult . ' and ' . $dependentMult
191
        );
192
        $forward = [
193
            'principalType' => $principalType,
194
            'principalMult' => $dependentMult,
195
            'principalProp' => $principalProperty,
196
            'dependentType' => $dependentType,
197
            'dependentMult' => $principalMult,
198
            'dependentProp' => $dependentProperty
199
        ];
200
        $reverse = [
201
            'principalType' => $dependentType,
202
            'principalMult' => $principalMult,
203
            'principalProp' => $dependentProperty,
204
            'dependentType' => $principalType,
205
            'dependentMult' => $dependentMult,
206
            'dependentProp' => $principalProperty
207
        ];
208
        return [$forward, $reverse];
209
    }
210
211
    /**
212
     * @param $className
213
     */
214
    protected function checkClassExists($className)
215
    {
216
        if (!array_key_exists($className, $this->relations)) {
217
            $msg = $className . ' does not exist in holder';
218
            throw new \InvalidArgumentException($msg);
219
        }
220
    }
221
222
    /**
223
     * Reset stored relations
224
     */
225
    public function reset()
226
    {
227
        $this->relations = [];
228
    }
229
}
230