Test Setup Failed
Pull Request — master (#47)
by Alex
03:00
created

calculateRoundTripRelationsSecondPass()   C

Complexity

Conditions 9
Paths 10

Size

Total Lines 60
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 60
ccs 0
cts 0
cp 0
rs 6.8358
cc 9
eloc 43
nc 10
nop 2
crap 90

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace AlgoWeb\PODataLaravel\Providers;
4
5
use Illuminate\Support\Facades\App;
6
use Illuminate\Support\ServiceProvider;
7
use Illuminate\Support\Facades\Cache;
8
use POData\Providers\Metadata\IMetadataProvider;
9
use POData\Providers\Metadata\SimpleMetadataProvider;
10
use Illuminate\Support\Facades\Route;
11
use Illuminate\Support\Facades\Schema as Schema;
12
13
class MetadataProvider extends MetadataBaseProvider
14
{
15
    protected $multConstraints = [ '0..1' => ['1'], '1' => ['0..1', '*'], '*' => ['1', '*']];
16
    protected static $METANAMESPACE = "Data";
17
18
    /**
19
     * Bootstrap the application services.  Post-boot.
20 1
     *
21
     * @return void
22 1
     */
23
    public function boot()
24
    {
25 1
        self::$METANAMESPACE = env('ODataMetaNamespace', 'Data');
26
        // If we aren't migrated, there's no DB tables to pull metadata _from_, so bail out early
27
        try {
28 1
            if (!Schema::hasTable('migrations')) {
29 1
                return;
30
            }
31
        } catch (\Exception $e) {
32
            return;
33
        }
34
35
        self::setupRoute();
36
        $isCaching = true === $this->getIsCaching();
37
        $hasCache = Cache::has('metadata');
38
39
        if ($isCaching && $hasCache) {
40
            $meta = Cache::get('metadata');
41
            App::instance('metadata', $meta);
1 ignored issue
show
Bug introduced by
The method instance() does not exist on Illuminate\Support\Facades\App. Did you maybe mean clearResolvedInstance()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
42
            return;
43
        }
44
        $meta = App::make('metadata');
45
46
        $modelNames = $this->getCandidateModels();
47
48
        list($EntityTypes, $ResourceSets, $ends) = $this->getEntityTypesAndResourceSets($meta, $modelNames);
49
50
        // now that endpoints are hooked up, tackle the relationships
51
        // if we'd tried earlier, we'd be guaranteed to try to hook a relation up to null, which would be bad
52
        foreach ($ends as $bitter) {
53
            $fqModelName = $bitter;
54
            $instance = new $fqModelName();
55
            $instance->hookUpRelationships($EntityTypes, $ResourceSets);
56
        }
57
58
        $key = 'metadata';
59
        $this->handlePostBoot($isCaching, $hasCache, $key, $meta);
60
    }
61
62
    private static function setupRoute()
63
    {
64
        $valueArray = [];
0 ignored issues
show
Unused Code introduced by
$valueArray is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
65
66
        Route::any('odata.svc/{section}', 'AlgoWeb\PODataLaravel\Controllers\ODataController@index')
67
            ->where(['section' => '.*']);
68
        Route::any('odata.svc', 'AlgoWeb\PODataLaravel\Controllers\ODataController@index');
69
    }
70
71
    /**
72
     * Register the application services.  Boot-time only.
73
     *
74
     * @return void
75
     */
76
    public function register()
77
    {
78
        $this->app->singleton('metadata', function ($app) {
0 ignored issues
show
Unused Code introduced by
The parameter $app is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
79
            return new SimpleMetadataProvider('Data', self::$METANAMESPACE);
80
        });
81
    }
82
83
    /**
84
     * @return array
85
     */
86
    protected function getCandidateModels()
87
    {
88
        $Classes = $this->getClassMap();
89
        $ends = [];
90
        $startName = defined('PODATA_LARAVEL_APP_ROOT_NAMESPACE') ? PODATA_LARAVEL_APP_ROOT_NAMESPACE : "App";
91
        foreach ($Classes as $name) {
92
            if (\Illuminate\Support\Str::startsWith($name, $startName)) {
93
                if (in_array("AlgoWeb\\PODataLaravel\\Models\\MetadataTrait", class_uses($name))) {
94
                    $ends[] = $name;
95
                }
96
            }
97
        }
98
        return $ends;
99
    }
100
101
    /**
102
     * @param $meta
103
     * @param $ends
104
     * @return array
105
     */
106
    protected function getEntityTypesAndResourceSets($meta, $ends)
107
    {
108
        assert($meta instanceof IMetadataProvider, get_class($meta));
109
        $EntityTypes = [];
110
        $ResourceSets = [];
111
        $begins = [];
112
        $numEnds = count($ends);
113
114
        for ($i = 0; $i < $numEnds; $i++) {
115
            $bitter = $ends[$i];
116
            $fqModelName = $bitter;
117
118
            $instance = App::make($fqModelName);
119
            $name = strtolower($instance->getEndpointName());
120
            $metaSchema = $instance->getXmlSchema();
121
122
            // if for whatever reason we don't get an XML schema, move on to next entry and drop current one from
123
            // further processing
124
            if (null == $metaSchema) {
125
                continue;
126
            }
127
            $EntityTypes[$fqModelName] = $metaSchema;
128
            $ResourceSets[$fqModelName] = $meta->addResourceSet($name, $metaSchema);
129
            $begins[] = $bitter;
130
        }
131
132
        return array($EntityTypes, $ResourceSets, $begins);
133
    }
134
135
    public function calculateRoundTripRelations()
136
    {
137
        $modelNames = $this->getCandidateModels();
138
139
        $hooks = [];
140
        foreach ($modelNames as $name) {
141
            $model = new $name();
142
            $rels = $model->getRelationships();
143
            if (0 < count($rels)) {
144
                $hooks[$name] = $rels;
145
            }
146
        }
147
148
        // models with non-empty relation gubbins are assembled, now the hard bit starts
149
        // storing assembled bidirectional relationship schema
150
        $lines = [];
151
        // storing unprocessed relation gubbins for second-pass processing
152
        $remix = [];
153
        $this->calculateRoundTripRelationsFirstPass($hooks, $lines, $remix);
154
155
        // now for second processing pass, to pick up stuff that first didn't handle
156
        $lines = $this->calculateRoundTripRelationsSecondPass($remix, $lines);
157
158
        return $lines;
159
    }
160
161
    /**
162
     * @param $remix
163
     * @param $lines
164
     * @return array
165
     */
166
    private function calculateRoundTripRelationsSecondPass($remix, $lines)
167
    {
168
        foreach ($remix as $principalType => $value) {
169
            foreach ($value as $fk => $localRels) {
170
                foreach ($localRels as $dependentType => $deets) {
171
                    $principalMult = $deets['multiplicity'];
172
                    $principalProperty = $deets['property'];
173
                    $principalKey = $deets['local'];
174
175
                    if (!isset($remix[$dependentType])) {
176
                        continue;
177
                    }
178
                    $foreign = $remix[$dependentType];
179
                    if (!isset($foreign[$principalKey])) {
180
                        continue;
181
                    }
182
                    $foreign = $foreign[$principalKey];
183
                    $dependentKey = $foreign[$dependentType]['local'];
184
                    if ($fk != $dependentKey) {
185
                        continue;
186
                    }
187
                    $dependentMult = $foreign[$dependentType]['multiplicity'];
188
                    $dependentProperty = $foreign[$dependentType]['property'];
189
                    assert(
190
                        in_array($dependentMult, $this->multConstraints[$principalMult]),
191
                        "Cannot pair multiplicities " . $dependentMult . " and " . $principalMult
192
                    );
193
                    assert(
194
                        in_array($principalMult, $this->multConstraints[$dependentMult]),
195
                        "Cannot pair multiplicities " . $principalMult . " and " . $dependentMult
196
                    );
197
                    // add forward relation
198
                    $forward = [
199
                        'principalType' => $principalType,
200
                        'principalMult' => $principalMult,
201
                        'principalProp' => $principalProperty,
202
                        'dependentType' => $dependentType,
203
                        'dependentMult' => $dependentMult,
204
                        'dependentProp' => $dependentProperty
205
                    ];
206
                    if (!in_array($forward, $lines)) {
207
                        $lines[] = $forward;
208
                    }
209
                    // add reverse relation
210
                    $reverse = [
211
                        'principalType' => $dependentType,
212
                        'principalMult' => $dependentMult,
213
                        'principalProp' => $dependentProperty,
214
                        'dependentType' => $principalType,
215
                        'dependentMult' => $principalMult,
216
                        'dependentProp' => $principalProperty
217
                    ];
218
                    if (!in_array($reverse, $lines)) {
219
                        $lines[] = $reverse;
220
                    }
221
                }
222
            }
223
        }
224
        return $lines;
225
    }
226
227
    /**
228
     * @param $hooks
229
     * @param $lines
230
     * @param $remix
231
     */
232
    private function calculateRoundTripRelationsFirstPass($hooks, &$lines, &$remix)
233
    {
234
        foreach ($hooks as $principalType => $value) {
235
            foreach ($value as $fk => $localRels) {
236
                foreach ($localRels as $dependentType => $deets) {
237
                    $principalMult = $deets['multiplicity'];
238
                    $principalProperty = $deets['property'];
239
                    $principalKey = $deets['local'];
240
241
                    $foreign = $hooks[$dependentType];
242
                    $foreign = null != $foreign && isset($foreign[$principalKey]) ? $foreign[$principalKey] : null;
243
244
                    if (null != $foreign && isset($foreign[$principalType])) {
245
                        $foreign = $foreign[$principalType];
246
                        $dependentMult = $foreign['multiplicity'];
247
                        $dependentProperty = $foreign['property'];
248
                        assert(
249
                            in_array($dependentMult, $this->multConstraints[$principalMult]),
250
                            "Cannot pair multiplicities " . $dependentMult . " and " . $principalMult
251
                        );
252
                        assert(
253
                            in_array($principalMult, $this->multConstraints[$dependentMult]),
254
                            "Cannot pair multiplicities " . $principalMult . " and " . $dependentMult
255
                        );
256
                        // add forward relation
257
                        $forward = [
258
                            'principalType' => $principalType,
259
                            'principalMult' => $principalMult,
260
                            'principalProp' => $principalProperty,
261
                            'dependentType' => $dependentType,
262
                            'dependentMult' => $dependentMult,
263
                            'dependentProp' => $dependentProperty
264
                        ];
265
                        if (!in_array($forward, $lines)) {
266
                            $lines[] = $forward;
267
                        }
268
                        // add reverse relation
269
                        $reverse = [
270
                            'principalType' => $dependentType,
271
                            'principalMult' => $dependentMult,
272
                            'principalProp' => $dependentProperty,
273
                            'dependentType' => $principalType,
274
                            'dependentMult' => $principalMult,
275
                            'dependentProp' => $principalProperty
276
                        ];
277
                        if (!in_array($reverse, $lines)) {
278
                            $lines[] = $reverse;
279
                        }
280
                    } else {
281
                        if (!isset($remix[$principalType])) {
282
                            $remix[$principalType] = [];
283
                        }
284
                        if (!isset($remix[$principalType][$fk])) {
285
                            $remix[$principalType][$fk] = [];
286
                        }
287
                        if (!isset($remix[$principalType][$fk][$dependentType])) {
288
                            $remix[$principalType][$fk][$dependentType] = $deets;
289
                        }
290
                        assert(isset($remix[$principalType][$fk][$dependentType]));
291
                    }
292
                }
293
            }
294
        }
295
    }
296
}
297