Test Setup Failed
Pull Request — master (#48)
by Alex
03:31
created

MetadataProvider::boot()   C

Complexity

Conditions 12
Paths 8

Size

Total Lines 76
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 134.8003

Importance

Changes 8
Bugs 0 Features 0
Metric Value
dl 0
loc 76
ccs 3
cts 58
cp 0.0517
rs 5.2846
c 8
b 0
f 0
cc 12
eloc 50
nc 8
nop 0
crap 134.8003

How to fix   Long Method    Complexity   

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\ResourceType;
10
use POData\Providers\Metadata\SimpleMetadataProvider;
11
use Illuminate\Support\Facades\Route;
12
use Illuminate\Support\Facades\Schema as Schema;
13
14
class MetadataProvider extends MetadataBaseProvider
15
{
16
    protected $multConstraints = [ '0..1' => ['1'], '1' => ['0..1', '*'], '*' => ['1', '*']];
17
    protected static $METANAMESPACE = "Data";
18
19
    /**
20 1
     * Bootstrap the application services.  Post-boot.
21
     *
22 1
     * @return void
23
     */
24
    public function boot()
25 1
    {
26
        self::$METANAMESPACE = env('ODataMetaNamespace', 'Data');
27
        // If we aren't migrated, there's no DB tables to pull metadata _from_, so bail out early
28 1
        try {
29 1
            if (!Schema::hasTable('migrations')) {
30
                return;
31
            }
32
        } catch (\Exception $e) {
33
            return;
34
        }
35
36
        self::setupRoute();
37
        $isCaching = true === $this->getIsCaching();
38
        $hasCache = Cache::has('metadata');
39
40
        if ($isCaching && $hasCache) {
41
            $meta = Cache::get('metadata');
42
            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...
43
            return;
44
        }
45
        $meta = App::make('metadata');
46
47
        $modelNames = $this->getCandidateModels();
48
49
        list($EntityTypes, $ResourceSets, $ends) = $this->getEntityTypesAndResourceSets($meta, $modelNames);
0 ignored issues
show
Unused Code introduced by
The assignment to $ResourceSets is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
Unused Code introduced by
The assignment to $ends is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
50
51
        // need to lift EntityTypes
52
        $biDirect = $this->calculateRoundTripRelations();
53
54
        // now that endpoints are hooked up, tackle the relationships
55
        // if we'd tried earlier, we'd be guaranteed to try to hook a relation up to null, which would be bad
56
        foreach ($biDirect as $line) {
57
            $principalType = $line['principalType'];
58
            $principalMult = $line['principalMult'];
59
            $principalProp = $line['principalProp'];
60
            $dependentType = $line['dependentType'];
61
            $dependentMult = $line['dependentMult'];
62
            $dependentProp = $line['dependentProp'];
63
            if (!isset($EntityTypes[$principalType]) || !isset($EntityTypes[$dependentType])) {
64
                continue;
65
            }
66
            $principal = $EntityTypes[$principalType];
67
            $dependent = $EntityTypes[$dependentType];
68
            //many-to-many
69
            if ('*' == $principalMult && '*' == $dependentMult) {
70
                $meta->addResourceSetReferencePropertyBidirectional(
71
                    $principal,
72
                    $dependent,
73
                    $principalProp,
74
                    $dependentProp
75
                );
76
                continue;
77
            }
78
            //one-to-one
79
            if ('0..1' == $principalMult || '0..1' == $dependentMult) {
80
                $meta->addResourceReferenceSinglePropertyBidirectional(
81
                    $principal,
82
                    $dependent,
83
                    $principalProp,
84
                    $dependentProp
85
                );
86
                continue;
87
            }
88
            //one-to-many
89
            $meta->addResourceReferencePropertyBidirectional(
90
                $principal,
91
                $dependent,
92
                $principalProp,
93
                $dependentProp
94
            );
95
        }
96
97
        $key = 'metadata';
98
        $this->handlePostBoot($isCaching, $hasCache, $key, $meta);
99
    }
100
101
    private static function setupRoute()
102
    {
103
        $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...
104
105
        Route::any('odata.svc/{section}', 'AlgoWeb\PODataLaravel\Controllers\ODataController@index')
106
            ->where(['section' => '.*']);
107
        Route::any('odata.svc', 'AlgoWeb\PODataLaravel\Controllers\ODataController@index');
108
    }
109
110
    /**
111
     * Register the application services.  Boot-time only.
112
     *
113
     * @return void
114
     */
115
    public function register()
116
    {
117
        $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...
118
            return new SimpleMetadataProvider('Data', self::$METANAMESPACE);
119
        });
120
    }
121
122
    /**
123
     * @return array
124
     */
125
    protected function getCandidateModels()
126
    {
127
        $Classes = $this->getClassMap();
128
        $ends = [];
129
        $startName = defined('PODATA_LARAVEL_APP_ROOT_NAMESPACE') ? PODATA_LARAVEL_APP_ROOT_NAMESPACE : "App";
130
        foreach ($Classes as $name) {
131
            if (\Illuminate\Support\Str::startsWith($name, $startName)) {
132
                if (in_array("AlgoWeb\\PODataLaravel\\Models\\MetadataTrait", class_uses($name))) {
133
                    $ends[] = $name;
134
                }
135
            }
136
        }
137
        return $ends;
138
    }
139
140
    /**
141
     * @param $meta
142
     * @param $ends
143
     * @return array
144
     */
145
    protected function getEntityTypesAndResourceSets($meta, $ends)
146
    {
147
        assert($meta instanceof IMetadataProvider, get_class($meta));
148
        $EntityTypes = [];
149
        $ResourceSets = [];
150
        $begins = [];
151
        $numEnds = count($ends);
152
153
        for ($i = 0; $i < $numEnds; $i++) {
154
            $bitter = $ends[$i];
155
            $fqModelName = $bitter;
156
157
            $instance = App::make($fqModelName);
158
            $name = strtolower($instance->getEndpointName());
159
            $metaSchema = $instance->getXmlSchema();
160
161
            // if for whatever reason we don't get an XML schema, move on to next entry and drop current one from
162
            // further processing
163
            if (null == $metaSchema) {
164
                continue;
165
            }
166
            $EntityTypes[$fqModelName] = $metaSchema;
167
            $ResourceSets[$fqModelName] = $meta->addResourceSet($name, $metaSchema);
168
            $begins[] = $bitter;
169
        }
170
171
        return array($EntityTypes, $ResourceSets, $begins);
172
    }
173
174
    public function calculateRoundTripRelations()
175
    {
176
        $modelNames = $this->getCandidateModels();
177
178
        $hooks = [];
179
        foreach ($modelNames as $name) {
180
            $model = new $name();
181
            $rels = $model->getRelationships();
182
            // it doesn't matter if a model has no relationships here, that lack will simply be skipped over
183
            // during hookup processing
184
            $hooks[$name] = $rels;
185
        }
186
187
        // model relation gubbins are assembled, now the hard bit starts
188
        // storing assembled bidirectional relationship schema
189
        $rawLines = [];
190
        // storing unprocessed relation gubbins for second-pass processing
191
        $remix = [];
192
        $this->calculateRoundTripRelationsFirstPass($hooks, $rawLines, $remix);
193
194
        // now for second processing pass, to pick up stuff that first didn't handle
195
        $rawLines = $this->calculateRoundTripRelationsSecondPass($remix, $rawLines);
196
197
        // deduplicate rawLines - can't use array_unique as array value elements are themselves arrays
198
        $lines = [];
199
        foreach ($rawLines as $line) {
200
            if (!in_array($line, $lines)) {
201
                $lines[] = $line;
202
            }
203
        }
204
205
        return $lines;
206
    }
207
208
    /**
209
     * @param $remix
210
     * @param $lines
211
     * @return array
212
     */
213
    private function calculateRoundTripRelationsSecondPass($remix, $lines)
214
    {
215
        foreach ($remix as $principalType => $value) {
216
            foreach ($value as $fk => $localRels) {
217
                foreach ($localRels as $dependentType => $deets) {
218
                    $principalMult = $deets['multiplicity'];
219
                    $principalProperty = $deets['property'];
220
                    $principalKey = $deets['local'];
221
222
                    if (!isset($remix[$dependentType])) {
223
                        continue;
224
                    }
225
                    $foreign = $remix[$dependentType];
226
                    if (!isset($foreign[$principalKey])) {
227
                        continue;
228
                    }
229
                    $foreign = $foreign[$principalKey];
230
                    $dependentKey = $foreign[$dependentType]['local'];
231
                    if ($fk != $dependentKey) {
232
                        continue;
233
                    }
234
                    $dependentMult = $foreign[$dependentType]['multiplicity'];
235
                    $dependentProperty = $foreign[$dependentType]['property'];
236
                    assert(
237
                        in_array($dependentMult, $this->multConstraints[$principalMult]),
238
                        "Cannot pair multiplicities " . $dependentMult . " and " . $principalMult
239
                    );
240
                    assert(
241
                        in_array($principalMult, $this->multConstraints[$dependentMult]),
242
                        "Cannot pair multiplicities " . $principalMult . " and " . $dependentMult
243
                    );
244
                    // generate forward and reverse relations
245
                    list($forward, $reverse) = $this->calculateRoundTripRelationsGenForwardReverse(
246
                        $principalType,
247
                        $principalMult,
248
                        $principalProperty,
249
                        $dependentType,
250
                        $dependentMult,
251
                        $dependentProperty
252
                    );
253
                    // add forward relation
254
                    $lines[] = $forward;
255
                    // add reverse relation
256
                    $lines[] = $reverse;
257
                }
258
            }
259
        }
260
        return $lines;
261
    }
262
263
    /**
264
     * @param $hooks
265
     * @param $lines
266
     * @param $remix
267
     */
268
    private function calculateRoundTripRelationsFirstPass($hooks, &$lines, &$remix)
269
    {
270
        foreach ($hooks as $principalType => $value) {
271
            foreach ($value as $fk => $localRels) {
272
                foreach ($localRels as $dependentType => $deets) {
273
                    if (!isset($hooks[$dependentType])) {
274
                        continue;
275
                    }
276
                    $principalMult = $deets['multiplicity'];
277
                    $principalProperty = $deets['property'];
278
                    $principalKey = $deets['local'];
279
280
                    $foreign = $hooks[$dependentType];
281
                    $foreign = null != $foreign && isset($foreign[$principalKey]) ? $foreign[$principalKey] : null;
282
283
                    if (null != $foreign && isset($foreign[$principalType])) {
284
                        $foreign = $foreign[$principalType];
285
                        $dependentMult = $foreign['multiplicity'];
286
                        $dependentProperty = $foreign['property'];
287
                        assert(
288
                            in_array($dependentMult, $this->multConstraints[$principalMult]),
289
                            "Cannot pair multiplicities " . $dependentMult . " and " . $principalMult
290
                        );
291
                        assert(
292
                            in_array($principalMult, $this->multConstraints[$dependentMult]),
293
                            "Cannot pair multiplicities " . $principalMult . " and " . $dependentMult
294
                        );
295
                        // generate forward and reverse relations
296
                        list($forward, $reverse) = $this->calculateRoundTripRelationsGenForwardReverse(
297
                            $principalType,
298
                            $principalMult,
299
                            $principalProperty,
300
                            $dependentType,
301
                            $dependentMult,
302
                            $dependentProperty
303
                        );
304
                        // add forward relation
305
                        $lines[] = $forward;
306
                        // add reverse relation
307
                        $lines[] = $reverse;
308
                    } else {
309
                        if (!isset($remix[$principalType])) {
310
                            $remix[$principalType] = [];
311
                        }
312
                        if (!isset($remix[$principalType][$fk])) {
313
                            $remix[$principalType][$fk] = [];
314
                        }
315
                        if (!isset($remix[$principalType][$fk][$dependentType])) {
316
                            $remix[$principalType][$fk][$dependentType] = $deets;
317
                        }
318
                        assert(isset($remix[$principalType][$fk][$dependentType]));
319
                    }
320
                }
321
            }
322
        }
323
    }
324
325
    /**
326
     * @param $principalType
327
     * @param $principalMult
328
     * @param $principalProperty
329
     * @param $dependentType
330
     * @param $dependentMult
331
     * @param $dependentProperty
332
     * @return array
333
     */
334
    private function calculateRoundTripRelationsGenForwardReverse(
335
        $principalType,
336
        $principalMult,
337
        $principalProperty,
338
        $dependentType,
339
        $dependentMult,
340
        $dependentProperty
341
    ) {
342
        $forward = [
343
            'principalType' => $principalType,
344
            'principalMult' => $principalMult,
345
            'principalProp' => $principalProperty,
346
            'dependentType' => $dependentType,
347
            'dependentMult' => $dependentMult,
348
            'dependentProp' => $dependentProperty
349
        ];
350
        $reverse = [
351
            'principalType' => $dependentType,
352
            'principalMult' => $dependentMult,
353
            'principalProp' => $dependentProperty,
354
            'dependentType' => $principalType,
355
            'dependentMult' => $principalMult,
356
            'dependentProp' => $principalProperty
357
        ];
358
        return array($forward, $reverse);
359
    }
360
}
361