Completed
Push — master ( d3cb7c...64c6e5 )
by Christopher
13s
created

MetadataTrait::isRunningInArtisan()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 2
eloc 2
nc 2
nop 0
crap 6
1
<?php
2
namespace AlgoWeb\PODataLaravel\Models;
3
4
use AlgoWeb\PODataLaravel\Models\ObjectMap\Entities\Associations\AssociationStubMonomorphic;
5
use AlgoWeb\PODataLaravel\Models\ObjectMap\Entities\Associations\AssociationStubPolymorphic;
6
use AlgoWeb\PODataLaravel\Models\ObjectMap\Entities\Associations\AssociationStubRelationType;
7
use AlgoWeb\PODataLaravel\Models\ObjectMap\Entities\EntityField;
8
use AlgoWeb\PODataLaravel\Models\ObjectMap\Entities\EntityFieldPrimitiveType;
9
use AlgoWeb\PODataLaravel\Models\ObjectMap\Entities\EntityFieldType;
10
use AlgoWeb\PODataLaravel\Models\ObjectMap\Entities\EntityGubbins;
11
use AlgoWeb\PODataLaravel\Query\LaravelReadQuery;
12
use Illuminate\Database\Eloquent\Model;
13
use Illuminate\Database\Eloquent\Relations\BelongsTo;
14
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
15
use Illuminate\Database\Eloquent\Relations\MorphMany;
16
use Illuminate\Database\Eloquent\Relations\MorphOne;
17
use Illuminate\Database\Eloquent\Relations\MorphToMany;
18
use Illuminate\Database\Eloquent\Relations\Relation;
19
use Illuminate\Support\Facades\App;
20
use Mockery\Mock;
21
use POData\Providers\Metadata\Type\EdmPrimitiveType;
22
23
trait MetadataTrait
24
{
25
    protected static $relationHooks = [];
26
    protected static $relationCategories = [];
27
    protected static $methodPrimary = [];
28 3
    protected static $methodAlternate = [];
29
    protected $loadEagerRelations = [];
30 3
31
    /*
32
     * Retrieve and assemble this model's metadata for OData packaging
33 2
     */
34 2
    public function metadata()
35
    {
36 2
        assert($this instanceof Model, get_class($this));
37
38 2
        // Break these out separately to enable separate reuse
39 1
        $connect = $this->getConnection();
40
        $builder = $connect->getSchemaBuilder();
41
42 1
        $table = $this->getTable();
43 1
44 1
        if (!$builder->hasTable($table)) {
45
            return [];
46 1
        }
47
48 1
        $columns = $builder->getColumnListing($table);
49 1
        $mask = $this->metadataMask();
50 1
        $columns = array_intersect($columns, $mask);
51
52 1
        $tableData = [];
53 1
54 1
        $rawFoo = $connect->getDoctrineSchemaManager()->listTableColumns($table);
55
        $foo = [];
56 1
        $getters = $this->collectGetters();
57
58 1
        foreach ($rawFoo as $key => $val) {
59 1
            // Work around glitch in Doctrine when reading from MariaDB which added ` characters to root key value
60 1
            $key = trim($key, '`');
61 1
            $foo[$key] = $val;
62 1
        }
63 1
64 1
        foreach ($columns as $column) {
65
            // Doctrine schema manager returns columns with lowercased names
66 1
            $rawColumn = $foo[strtolower($column)];
67
            $nullable = !($rawColumn->getNotNull());
68
            $fillable = in_array($column, $this->getFillable());
69
            $rawType = $rawColumn->getType();
70
            $type = $rawType->getName();
71
            $default = $this->$column;
72
            $tableData[$column] = ['type' => $type,
73 4
                'nullable' => $nullable,
74
                'fillable' => $fillable,
75 4
                'default' => $default
76
            ];
77 4
        }
78 4
79 4
        foreach ($getters as $get) {
80 2
            if (isset($tableData[$get])) {
81 4
                continue;
82 1
            }
83 1
            $default = $this->$get;
84
            $tableData[$get] = ['type' => 'text', 'nullable' => true, 'fillable' => false, 'default' => $default];
85 4
        }
86
87
        return $tableData;
88
    }
89
90
    /*
91 5
     * Return the set of fields that are permitted to be in metadata
92
     * - following same visible-trumps-hidden guideline as Laravel
93 5
     */
94 5
    public function metadataMask()
95 1
    {
96
        $attribs = array_keys($this->getAllAttributes());
97
98 4
        $visible = $this->getVisible();
99
        $hidden = $this->getHidden();
100 4
        if (0 < count($visible)) {
101
            assert(!empty($visible));
102 4
            $attribs = array_intersect($visible, $attribs);
103 4
        } elseif (0 < count($hidden)) {
104 4
            assert(!empty($hidden));
105 4
            $attribs = array_diff($attribs, $hidden);
106 4
        }
107 4
108
        return $attribs;
109 4
    }
110 1
111 1
    /*
112 1
     * Get the endpoint name being exposed
113 1
     *
114
     */
115 4
    public function getEndpointName()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
116 4
    {
117
        $endpoint = isset($this->endpoint) ? $this->endpoint : null;
118 4
119
        if (!isset($endpoint)) {
120
            $bitter = get_class();
121
            $name = substr($bitter, strrpos($bitter, '\\')+1);
122
            return ($name);
123
        }
124
        return ($endpoint);
125
    }
126
127
    /**
128
     * Get model's relationships.
129
     *
130
     * @return array
131
     */
132
    public function getRelationships()
133
    {
134
        if (empty(static::$relationHooks)) {
135
            $hooks = [];
136
137
            $rels = $this->getRelationshipsFromMethods(true);
138
139
            $this->getRelationshipsUnknownPolyMorph($rels, $hooks);
140
141
            $this->getRelationshipsKnownPolyMorph($rels, $hooks);
142
143
            $this->getRelationshipsHasOne($rels, $hooks);
144
145
            $this->getRelationshipsHasMany($rels, $hooks);
146
147
            static::$relationHooks = $hooks;
148
        }
149
150
        return static::$relationHooks;
151
    }
152
153
    protected function getAllAttributes()
154
    {
155
        // Adapted from http://stackoverflow.com/a/33514981
156
        // $columns = $this->getFillable();
157
        // Another option is to get all columns for the table like so:
158
        $builder = $this->getConnection()->getSchemaBuilder();
159
        $columns = $builder->getColumnListing($this->getTable());
160
        // but it's safer to just get the fillable fields
161
162
        $attributes = $this->getAttributes();
163
164
        foreach ($columns as $column) {
165
            if (!array_key_exists($column, $attributes)) {
166
                $attributes[$column] = null;
167
            }
168
        }
169
170
        $methods = $this->collectGetters();
171
172
        foreach ($methods as $method) {
173
            $attributes[$method] = null;
174
        }
175 3
176
        return $attributes;
177 3
    }
178
179 3
    /**
180 3
     * @param bool $biDir
181 3
     *
182 3
     * @return array
183 3
     */
184 3
    protected function getRelationshipsFromMethods($biDir = false)
185 3
    {
186 3
        $biDirVal = intval($biDir);
187 3
        $isCached = isset(static::$relationCategories[$biDirVal]) && !empty(static::$relationCategories[$biDirVal]);
188 3
        if (!$isCached) {
189
            $model = $this;
190 3
            $relationships = [
191
                'HasOne' => [],
192 3
                'UnknownPolyMorphSide' => [],
193 3
                'HasMany' => [],
194 3
                'KnownPolyMorphSide' => []
195 3
            ];
196 3
            $methods = get_class_methods($model);
197 3
            if (!empty($methods)) {
198 3
                foreach ($methods as $method) {
199 3
                    if (!method_exists('Illuminate\Database\Eloquent\Model', $method)
200 3
                        && !method_exists(Mock::class, $method)
201 3
                        && !method_exists(MetadataTrait::class, $method)
202
                    ) {
203 3
                        //Use reflection to inspect the code, based on Illuminate/Support/SerializableClosure.php
204 3
                        $reflection = new \ReflectionMethod($model, $method);
205 3
                        $fileName = $reflection->getFileName();
206 3
207 3
                        $file = new \SplFileObject($fileName);
208 3
                        $file->seek($reflection->getStartLine()-1);
209 3
                        $code = '';
210 3
                        while ($file->key() < $reflection->getEndLine()) {
211
                            $code .= $file->current();
212 3
                            $file->next();
213 3
                        }
214 3
215
                        $code = trim(preg_replace('/\s\s+/', '', $code));
216 3
                        assert(
217 3
                            false !== stripos($code, 'function'),
218 3
                            'Function definition must have keyword \'function\''
219 3
                        );
220 3
                        $begin = strpos($code, 'function(');
221
                        $code = substr($code, $begin, strrpos($code, '}')-$begin+1);
222 1
                        $lastCode = $code[strlen($code)-1];
223 3
                        assert('}' == $lastCode, 'Final character of function definition must be closing brace');
224
                        foreach ([
225 1
                                        'hasMany',
226
                                        'hasManyThrough',
227 1
                                        'belongsToMany',
228
                                        'hasOne',
229 1
                                        'belongsTo',
230
                                        'morphOne',
231 3
                                        'morphTo',
232 2
                                        'morphMany',
233 2
                                        'morphToMany',
234 3
                                        'morphedByMany'
235 3
                                    ] as $relation) {
236 3
                            $search = '$this->' . $relation . '(';
237 3
                            if ($pos = stripos($code, $search)) {
238 3
                                //Resolve the relation's model to a Relation object.
239 3
                                $relationObj = $model->$method();
240 3
                                if ($relationObj instanceof Relation) {
241
                                    $relObject = $relationObj->getRelated();
242
                                    $relatedModel = '\\' . get_class($relObject);
243
                                    if (in_array(MetadataTrait::class, class_uses($relatedModel))) {
244
                                        $relations = [
245
                                            'hasManyThrough',
246
                                            'belongsToMany',
247
                                            'hasMany',
248
                                            'morphMany',
249
                                            'morphToMany',
250
                                            'morphedByMany'
251
                                        ];
252
                                        if (in_array($relation, $relations)) {
253
                                            //Collection or array of models (because Collection is Arrayable)
254
                                            $relationships['HasMany'][$method] = $biDir ? $relationObj : $relatedModel;
255
                                        } elseif ('morphTo' === $relation) {
256
                                            // Model isn't specified because relation is polymorphic
257
                                            $relationships['UnknownPolyMorphSide'][$method] =
258
                                                $biDir ? $relationObj : '\Illuminate\Database\Eloquent\Model|\Eloquent';
259
                                        } else {
260
                                            //Single model is returned
261
                                            $relationships['HasOne'][$method] = $biDir ? $relationObj : $relatedModel;
262
                                        }
263
                                        if (in_array($relation, ['morphMany', 'morphOne', 'morphToMany'])) {
264
                                            $relationships['KnownPolyMorphSide'][$method] =
265
                                                $biDir ? $relationObj : $relatedModel;
266
                                        }
267
                                        if (in_array($relation, ['morphedByMany'])) {
268
                                            $relationships['UnknownPolyMorphSide'][$method] =
269
                                                $biDir ? $relationObj : $relatedModel;
270
                                        }
271
                                    }
272
                                }
273
                            }
274
                        }
275
                    }
276
                }
277
            }
278
            static::$relationCategories[$biDirVal] = $relationships;
279
        }
280
        return static::$relationCategories[$biDirVal];
281
    }
282
283
    /**
284
     * Get the visible attributes for the model.
285
     *
286
     * @return array
287
     */
288
    abstract public function getVisible();
289
290
    /**
291
     * Get the hidden attributes for the model.
292
     *
293
     * @return array
294
     */
295
    abstract public function getHidden();
296
297
    /**
298
     * Get the primary key for the model.
299
     *
300
     * @return string
301
     */
302
    abstract public function getKeyName();
303
304
    /**
305
     * Get the current connection name for the model.
306
     *
307
     * @return string
308
     */
309
    abstract public function getConnectionName();
310
311
    /**
312
     * Get the database connection for the model.
313
     *
314
     * @return \Illuminate\Database\Connection
315
     */
316
    abstract public function getConnection();
317
318
    /**
319
     * Get all of the current attributes on the model.
320
     *
321
     * @return array
322
     */
323
    abstract public function getAttributes();
324
325
    /**
326
     * Get the table associated with the model.
327
     *
328
     * @return string
329
     */
330
    abstract public function getTable();
331
332
    /**
333
     * Get the fillable attributes for the model.
334
     *
335
     * @return array
336
     */
337
    abstract public function getFillable();
338
339
    /**
340
     * Dig up all defined getters on the model.
341
     *
342
     * @return array
343
     */
344
    protected function collectGetters()
345
    {
346
        $getterz = [];
347
        $methods = get_class_methods($this);
348
        foreach ($methods as $method) {
349
            if (12 < strlen($method) && 'get' == substr($method, 0, 3)) {
350
                if ('Attribute' == substr($method, -9)) {
351
                    $getterz[] = $method;
352
                }
353
            }
354
        }
355
        $methods = [];
356
357
        foreach ($getterz as $getter) {
358
            $residual = substr($getter, 3);
359
            $residual = substr($residual, 0, -9);
360
            $methods[] = $residual;
361
        }
362
        return $methods;
363
    }
364
365
    /**
366
     * @param       $foo
367
     * @param mixed $condition
368
     *
369
     * @return array
370
     */
371
    private function polyglotKeyMethodNames($foo, $condition = false)
372
    {
373
        $fkList = ['getQualifiedForeignKeyName', 'getForeignKey'];
374
        $rkList = ['getQualifiedRelatedKeyName', 'getOtherKey', 'getOwnerKey'];
375
376
        $fkMethodName = null;
377
        $rkMethodName = null;
378
        if ($condition) {
379
            if (array_key_exists(get_class($foo), static::$methodPrimary)) {
380
                $line = static::$methodPrimary[get_class($foo)];
381
                $fkMethodName = $line['fk'];
382
                $rkMethodName = $line['rk'];
383
            } else {
384
                $methodList = get_class_methods(get_class($foo));
385
                $fkMethodName = 'getQualifiedForeignPivotKeyName';
386
                foreach ($fkList as $option) {
387
                    if (in_array($option, $methodList)) {
388
                        $fkMethodName = $option;
389
                        break;
390
                    }
391
                }
392
                assert(
393
                    in_array($fkMethodName, $methodList),
394
                    'Selected method, ' . $fkMethodName . ', not in method list'
395
                );
396
                $rkMethodName = 'getQualifiedRelatedPivotKeyName';
397
                foreach ($rkList as $option) {
398
                    if (in_array($option, $methodList)) {
399
                        $rkMethodName = $option;
400
                        break;
401
                    }
402
                }
403
                assert(
404
                    in_array($rkMethodName, $methodList),
405
                    'Selected method, ' . $rkMethodName . ', not in method list'
406
                );
407
                $line = ['fk' => $fkMethodName, 'rk' => $rkMethodName];
408
                static::$methodPrimary[get_class($foo)] = $line;
409
            }
410
        }
411
        return [$fkMethodName, $rkMethodName];
412
    }
413
414
    private function polyglotKeyMethodBackupNames($foo, $condition = false)
415
    {
416
        $fkList = ['getForeignKey', 'getForeignKeyName'];
417
        $rkList = ['getOtherKey', 'getQualifiedParentKeyName'];
418
419
        $fkMethodName = null;
420
        $rkMethodName = null;
421
        if ($condition) {
422
            if (array_key_exists(get_class($foo), static::$methodAlternate)) {
423
                $line = static::$methodAlternate[get_class($foo)];
424
                $fkMethodName = $line['fk'];
425
                $rkMethodName = $line['rk'];
426
            } else {
427
                $methodList = get_class_methods(get_class($foo));
428
                $fkCombo = array_values(array_intersect($fkList, $methodList));
429
                assert(1 <= count($fkCombo), 'Expected at least 1 element in foreign-key list, got ' . count($fkCombo));
430
                $fkMethodName = $fkCombo[0];
431
                assert(
432
                    in_array($fkMethodName, $methodList),
433
                    'Selected method, ' . $fkMethodName . ', not in method list'
434
                );
435
                $rkCombo = array_values(array_intersect($rkList, $methodList));
436
                assert(1 <= count($rkCombo), 'Expected at least 1 element in related-key list, got ' . count($rkCombo));
437
                $rkMethodName = $rkCombo[0];
438
                assert(
439
                    in_array($rkMethodName, $methodList),
440
                    'Selected method, ' . $rkMethodName . ', not in method list'
441
                );
442
                $line = ['fk' => $fkMethodName, 'rk' => $rkMethodName];
443
                static::$methodAlternate[get_class($foo)] = $line;
444
            }
445
        }
446
        return [$fkMethodName, $rkMethodName];
447
    }
448
449
    /**
450
     * @param             $hooks
451
     * @param             $first
452
     * @param             $property
453
     * @param             $last
454
     * @param             $mult
455
     * @param             $targ
456
     * @param string|null $targ
457
     * @param null|mixed  $type
458
     */
459
    private function addRelationsHook(&$hooks, $first, $property, $last, $mult, $targ, $type = null)
460
    {
461
        if (!isset($hooks[$first])) {
462
            $hooks[$first] = [];
463
        }
464
        if (!isset($hooks[$first][$targ])) {
465
            $hooks[$first][$targ] = [];
466
        }
467
        $hooks[$first][$targ][$property] = [
468
            'property' => $property,
469
            'local' => $last,
470
            'multiplicity' => $mult,
471
            'type' => $type
472
        ];
473
    }
474
475
    /**
476
     * @param $rels
477
     * @param $hooks
478
     */
479
    private function getRelationshipsHasMany($rels, &$hooks)
480
    {
481
        foreach ($rels['HasMany'] as $property => $foo) {
482
            if ($foo instanceof MorphMany || $foo instanceof MorphToMany) {
483
                continue;
484
            }
485
            $isBelong = $foo instanceof BelongsToMany;
486
            $mult = '*';
487
            $targ = get_class($foo->getRelated());
488
489
            list($fkMethodName, $rkMethodName) = $this->polyglotKeyMethodNames($foo, $isBelong);
490
            list($fkMethodAlternate, $rkMethodAlternate) = $this->polyglotKeyMethodBackupNames($foo, !$isBelong);
491
492
            $keyRaw = $isBelong ? $foo->$fkMethodName() : $foo->$fkMethodAlternate();
493
            $keySegments = explode('.', $keyRaw);
494
            $keyName = $keySegments[count($keySegments)-1];
495
            $localRaw = $isBelong ? $foo->$rkMethodName() : $foo->$rkMethodAlternate();
496
            $localSegments = explode('.', $localRaw);
497
            $localName = $localSegments[count($localSegments)-1];
498
            $first = $keyName;
499
            $last = $localName;
500
            $this->addRelationsHook($hooks, $first, $property, $last, $mult, $targ);
501
        }
502
    }
503
504
    /**
505
     * @param $rels
506
     * @param $hooks
507
     */
508
    private function getRelationshipsHasOne($rels, &$hooks)
509
    {
510
        foreach ($rels['HasOne'] as $property => $foo) {
511
            if ($foo instanceof MorphOne) {
512
                continue;
513
            }
514
            $isBelong = $foo instanceof BelongsTo;
515
            $mult = $isBelong ? '1' : '0..1';
516
            $targ = get_class($foo->getRelated());
517
518
            list($fkMethodName, $rkMethodName) = $this->polyglotKeyMethodNames($foo, $isBelong);
519
            list($fkMethodAlternate, $rkMethodAlternate) = $this->polyglotKeyMethodBackupNames($foo, !$isBelong);
520
521
            $keyName = $isBelong ? $foo->$fkMethodName() : $foo->$fkMethodAlternate();
522
            $keySegments = explode('.', $keyName);
523
            $keyName = $keySegments[count($keySegments)-1];
524
            $localRaw = $isBelong ? $foo->$rkMethodName() : $foo->$rkMethodAlternate();
525
            $localSegments = explode('.', $localRaw);
526
            $localName = $localSegments[count($localSegments)-1];
527
            $first = $isBelong ? $localName : $keyName;
528
            $last = $isBelong ? $keyName : $localName;
529
            $this->addRelationsHook($hooks, $first, $property, $last, $mult, $targ);
530
        }
531
    }
532
533
    /**
534
     * @param $rels
535
     * @param $hooks
536
     */
537
    private function getRelationshipsKnownPolyMorph($rels, &$hooks)
538
    {
539
        foreach ($rels['KnownPolyMorphSide'] as $property => $foo) {
540
            $isMany = $foo instanceof MorphToMany;
541
            $targ = get_class($foo->getRelated());
542
            $mult = $isMany ? '*' : $foo instanceof MorphMany ? '*' : '1';
543
            $mult = $foo instanceof MorphOne ? '0..1' : $mult;
544
545
            list($fkMethodName, $rkMethodName) = $this->polyglotKeyMethodNames($foo, $isMany);
546
            list($fkMethodAlternate, $rkMethodAlternate) = $this->polyglotKeyMethodBackupNames($foo, !$isMany);
547
548
            $keyRaw = $isMany ? $foo->$fkMethodName() : $foo->$fkMethodAlternate();
549
            $keySegments = explode('.', $keyRaw);
550
            $keyName = $keySegments[count($keySegments)-1];
551
            $localRaw = $isMany ? $foo->$rkMethodName() : $foo->$rkMethodAlternate();
552
            $localSegments = explode('.', $localRaw);
553
            $localName = $localSegments[count($localSegments)-1];
554
            $first = $isMany ? $keyName : $localName;
555
            $last = $isMany ? $localName : $keyName;
556
            $this->addRelationsHook($hooks, $first, $property, $last, $mult, $targ, 'unknown');
557
        }
558
    }
559
560
    /**
561
     * @param $rels
562
     * @param $hooks
563
     */
564
    private function getRelationshipsUnknownPolyMorph($rels, &$hooks)
565
    {
566
        foreach ($rels['UnknownPolyMorphSide'] as $property => $foo) {
567
            $isMany = $foo instanceof MorphToMany;
568
            $targ = get_class($foo->getRelated());
569
            $mult = $isMany ? '*' : '1';
570
571
            list($fkMethodName, $rkMethodName) = $this->polyglotKeyMethodNames($foo, $isMany);
572
            list($fkMethodAlternate, $rkMethodAlternate) = $this->polyglotKeyMethodBackupNames($foo, !$isMany);
573
574
            $keyRaw = $isMany ? $foo->$fkMethodName() : $foo->$fkMethodAlternate();
575
            $keySegments = explode('.', $keyRaw);
576
            $keyName = $keySegments[count($keySegments)-1];
577
            $localRaw = $isMany ? $foo->$rkMethodName() : $foo->$rkMethodAlternate();
578
            $localSegments = explode('.', $localRaw);
579
            $localName = $localSegments[count($localSegments)-1];
580
581
            $first = $keyName;
582
            $last = (isset($localName) && '' != $localName) ? $localName : $foo->getRelated()->getKeyName();
583
            $this->addRelationsHook($hooks, $first, $property, $last, $mult, $targ, 'known');
584
        }
585
    }
586
587
    /**
588
     * SUpplemental function to retrieve cast array for Laravel versions that do not supply hasCasts.
589
     *
590
     * @return array
591
     */
592
    public function retrieveCasts()
593
    {
594
        return $this->casts;
595
    }
596
597
    /**
598
     * Return list of relations to be eager-loaded by Laravel query provider.
599
     *
600
     * @return array
601
     */
602
    public function getEagerLoad()
603
    {
604
        assert(is_array($this->loadEagerRelations));
605
        return $this->loadEagerRelations;
606
    }
607
608
    /**
609
     * Set list of relations to be eager-loaded.
610
     *
611
     * @param array $relations
612
     */
613
    public function setEagerLoad(array $relations)
614
    {
615
        $check = array_map('strval', $relations);
616
        assert($relations == $check, 'All supplied relations must be resolvable to strings');
617
        $this->loadEagerRelations = $relations;
618
    }
619
620
    /*
621
     * Is this model the known side of at least one polymorphic relation?
622
     */
623
    public function isKnownPolymorphSide()
624
    {
625
        // isKnownPolymorph needs to be checking KnownPolymorphSide results - if you're checking UnknownPolymorphSide,
626
        // you're turned around
627
        $rels = $this->getRelationshipsFromMethods();
628
        return !empty($rels['KnownPolyMorphSide']);
629
    }
630
631
    /*
632
     * Is this model on the unknown side of at least one polymorphic relation?
633
     */
634
    public function isUnknownPolymorphSide()
635
    {
636
        // isUnknownPolymorph needs to be checking UnknownPolymorphSide results - if you're checking KnownPolymorphSide,
637
        // you're turned around
638
        $rels = $this->getRelationshipsFromMethods();
639
        return !empty($rels['UnknownPolyMorphSide']);
640
    }
641
642
    /**
643
     * Extract entity gubbins detail for later downstream use.
644
     *
645
     * @return EntityGubbins
646
     */
647
    public function extractGubbins()
648
    {
649
        $multArray = [
650
            '*' => AssociationStubRelationType::MANY(),
651
            '1' => AssociationStubRelationType::ONE(),
652
            '0..1' => AssociationStubRelationType::NULL_ONE()
653
        ];
654
655
        $gubbins = new EntityGubbins();
656
        $gubbins->setName($this->getEndpointName());
657
        $gubbins->setClassName(get_class($this));
658
659
        $fields = $this->metadata();
660
        $entityFields = [];
661
        foreach ($fields as $name => $field) {
662
            $nuField = new EntityField();
663
            $nuField->setName($name);
664
            $nuField->setIsNullable($field['nullable']);
665
            $nuField->setReadOnly(false);
666
            $nuField->setCreateOnly(false);
667
            $nuField->setDefaultValue($field['default']);
668
            $nuField->setIsKeyField($this->getKeyName() == $name);
669
            $nuField->setFieldType(EntityFieldType::PRIMITIVE());
670
            $nuField->setPrimitiveType(new EntityFieldPrimitiveType($field['type']));
671
            $entityFields[$name] = $nuField;
672
        }
673
        $isEmpty = (0 === count($entityFields));
674
        if (!($isEmpty && $this->isRunningInArtisan())) {
675
            $gubbins->setFields($entityFields);
676
        }
677
678
        $rawRels = $this->getRelationships();
679
        $stubs = [];
680
        foreach ($rawRels as $key => $rel) {
681
            foreach ($rel as $rawName => $deets) {
682
                foreach ($deets as $relName => $relGubbins) {
683
                    $gubbinsType = $relGubbins['type'];
684
                    $property = $relGubbins['property'];
685
                    $isPoly = isset($gubbinsType);
686
                    $targType = 'known' != $gubbinsType ? $rawName : null;
687
                    $stub = $isPoly ? new AssociationStubPolymorphic() : new AssociationStubMonomorphic();
688
                    $stub->setBaseType(get_class($this));
689
                    $stub->setRelationName($property);
690
                    $stub->setKeyField($relGubbins['local']);
691
                    $stub->setForeignField($targType ? $key : null);
692
                    $stub->setMultiplicity($multArray[$relGubbins['multiplicity']]);
693
                    $stub->setTargType($targType);
694
                    assert($stub->isOk());
695
                    $stubs[$property] = $stub;
696
                }
697
            }
698
        }
699
        $gubbins->setStubs($stubs);
700
701
        return $gubbins;
702
    }
703
704
    public function synthLiteralPK()
705
    {
706
        if (!$this->isKnownPolymorphSide()) {
707
            return;
708
        }
709
        $fieldName = LaravelReadQuery::PK;
710
        $this->$fieldName = $this->getKey();
711
    }
712
713
    public function isRunningInArtisan()
714
    {
715
        return App::runningInConsole() && !App::runningUnitTests();
716
    }
717
}
718