Test Failed
Pull Request — master (#106)
by Alex
04:11
created

MetadataRelationHolder::getMorphToRelations()   D

Complexity

Conditions 9
Paths 5

Size

Total Lines 41
Code Lines 27

Duplication

Lines 22
Ratio 53.66 %

Importance

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