GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — development-bs3 ( 4d7eb0...5b169c )
by butschster
09:36 queued 26s
created

OrderByClause::loadRelationOrder()   B

Complexity

Conditions 7
Paths 13

Size

Total Lines 32
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 1 Features 0
Metric Value
cc 7
eloc 20
nc 13
nop 2
dl 0
loc 32
rs 8.6666
c 5
b 1
f 0
1
<?php
2
3
namespace SleepingOwl\Admin\Display\Column;
4
5
use Illuminate\Support\Str;
6
use Mockery\Matcher\Closure;
7
use Illuminate\Support\Collection;
8
use Illuminate\Support\Facades\DB;
9
use Illuminate\Database\Eloquent\Model;
10
use Illuminate\Database\Eloquent\Builder;
11
use Illuminate\Database\Eloquent\Relations\MorphTo;
12
use Illuminate\Database\Eloquent\Relations\Relation;
13
use Illuminate\Database\Eloquent\Relations\BelongsTo;
14
use Illuminate\Database\Eloquent\Relations\HasOneOrMany;
15
use SleepingOwl\Admin\Contracts\Display\OrderByClauseInterface;
16
17
class OrderByClause implements OrderByClauseInterface
18
{
19
    /**
20
     * @var string|\Closure
21
     */
22
    protected $name;
23
24
    /**
25
     * @var string|null
26
     */
27
    protected $sortedColumnAlias = null;
28
29
    /**
30
     * OrderByClause constructor.
31
     *
32
     * @param string|Closure $name
33
     */
34
    public function __construct($name)
35
    {
36
        $this->setName($name);
37
    }
38
39
    /**
40
     * @param Builder $query
41
     * @param string $direction
42
     */
43
    public function modifyQuery(Builder $query, $direction = 'asc')
44
    {
45
        $this->name instanceof \Closure
46
            ? $this->callCallable($query, $direction)
47
            : $this->callDefaultClause($query, $direction);
48
    }
49
50
    /**
51
     * @param string|\Closure $name
52
     *
53
     * @return $this
54
     */
55
    public function setName($name)
56
    {
57
        $this->name = $name;
58
59
        return $this;
60
    }
61
62
    /**
63
     * @param Builder $query
64
     * @param string $direction
65
     */
66
    protected function callCallable(Builder $query, $direction)
67
    {
68
        call_user_func_array($this->name, [$query, $direction]);
69
    }
70
71
    /**
72
     * @param Builder $query
73
     * @param string $direction
74
     */
75
    protected function callDefaultClause(Builder $query, $direction)
76
    {
77
        if ($this->isRelationName($this->name)) {
78
            $this->loadRelationOrder($query, $direction);
79
        } else {
80
            $query->orderBy($this->name, $direction);
81
        }
82
    }
83
84
    /**
85
     * @param $name
86
     * @return bool
87
     */
88
    protected function isRelationName($name)
89
    {
90
        return Str::contains($name, '.');
91
    }
92
93
    /**
94
     * Make EagerLoad.
95
     */
96
    protected function eagerLoad()
97
    {
98
    }
99
100
    /**
101
     * Load Relations by this->name.
102
     * @param Builder $query
103
     * @param $direction
104
     */
105
    protected function loadRelationOrder(Builder $query, $direction)
106
    {
107
        /** @var Relation $relationClass */
108
        $relations = collect(explode('.', $this->name));
0 ignored issues
show
Bug introduced by
It seems like $this->name can also be of type Closure; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

108
        $relations = collect(explode('.', /** @scrutinizer ignore-type */ $this->name));
Loading history...
109
        $loop = 0;
110
        if ($relations->count() >= 2) {
111
            $query->select($query->getModel()->getTable().'.*');
112
113
            do {
114
                $model = ! $loop++ ? $query->getModel() : $relationClass->getModel();
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $relationClass does not seem to be defined for all execution paths leading up to this point.
Loading history...
115
                $relation = $relations->shift();
116
117
                if (method_exists($model, $relation)) {
118
                    $relationClass = $model->{$relation}();
119
                    $loadRelationMethod = implode('', ['load', class_basename(get_class($relationClass))]);
120
121
                    if ($relationClass instanceof MorphTo) {
122
                        /**
123
                         * @see loadMorphTo
124
                         */
125
                        $relationModel = null;
126
                    } else {
127
                        $relationModel = $relationClass->getRelated();
128
                    }
129
                    call_user_func([$this, $loadRelationMethod], $relations, $relationClass, $relationModel, $model, $query, $direction);
130
                } else {
131
                    break;
132
                }
133
            } while (true);
134
135
            if ($this->sortedColumnAlias) {
136
                $query->orderBy(DB::raw($this->sortedColumnAlias), $direction);
137
            }
138
        }
139
    }
140
141
    /**
142
     * Load HasOneOrMany keys.
143
     * @param Collection $relations
144
     * @param HasOneOrMany $relationClass
145
     * @param Model $relationModel
146
     * @param Model $model
147
     * @param Builder $query
148
     * @param $direction
149
     */
150
    protected function loadHasOne(
151
        Collection $relations,
152
        HasOneOrMany $relationClass,
153
        Model $relationModel,
154
        Model $model,
155
        Builder $query,
156
        $direction
157
    ) {
158
        $this->loadHasOneOrMany($relations, $relationClass, $relationModel, $model, $query, $direction);
159
    }
160
161
    /**
162
     * Load HasMany keys.
163
     * @param Collection $relations
164
     * @param HasOneOrMany $relationClass
165
     * @param Model $relationModel
166
     * @param Model $model
167
     * @param Builder $query
168
     * @param $direction
169
     */
170
    protected function loadHasMany(
171
        Collection $relations,
172
        HasOneOrMany $relationClass,
173
        Model $relationModel,
174
        Model $model,
175
        Builder $query,
176
        $direction
177
    ) {
178
        $this->loadHasOneOrMany($relations, $relationClass, $relationModel, $model, $query, $direction);
179
    }
180
181
    /**
182
     * Load HasOneOrMany keys.
183
     * @param Collection $relations
184
     * @param HasOneOrMany $relationClass
185
     * @param Model $relationModel
186
     * @param Model $model
187
     * @param Builder $query
188
     * @param $direction
189
     */
190
    protected function loadHasOneOrMany(
191
        Collection $relations,
192
        HasOneOrMany $relationClass,
193
        Model $relationModel,
194
        Model $model,
195
        Builder $query,
196
        $direction
197
    ) {
198
        $ownerTable = $model->getTable();
0 ignored issues
show
Unused Code introduced by
The assignment to $ownerTable is dead and can be removed.
Loading history...
199
        $foreignTable = $relationModel->getTable();
200
201
        $ownerColumn = $relationClass->getQualifiedForeignKeyName();
202
        $foreignColumn = $relationClass->getQualifiedParentKeyName();
203
        $sortedColumnRaw = '`'.$foreignTable.'`.`'.$relations->last().'`';
204
        $sortedColumnAlias = implode('__', [$foreignTable, $relations->last()]);
205
206
        $this->sortedColumnAlias = $sortedColumnAlias;
207
208
        $query
209
            ->addSelect([DB::raw($sortedColumnRaw.' AS '.$sortedColumnAlias)])
210
            ->join($foreignTable, $foreignColumn, '=', $ownerColumn, 'left');
211
    }
212
213
    /**
214
     * Load keys for BelongsTo.
215
     * @param Collection $relations
216
     * @param BelongsTo $relationClass
217
     * @param Model $relationModel
218
     * @param Model $model
219
     * @param Builder $query
220
     */
221
    protected function loadBelongsTo(
222
        Collection $relations,
223
        BelongsTo $relationClass,
224
        Model $relationModel,
225
        Model $model,
226
        Builder $query
227
    ) {
228
        if (version_compare(app()->version(), '5.8.0', 'gt')) {
0 ignored issues
show
introduced by
The method version() does not exist on Illuminate\Container\Container. Are you sure you never get this type here, but always one of the subclasses? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

228
        if (version_compare(app()->/** @scrutinizer ignore-call */ version(), '5.8.0', 'gt')) {
Loading history...
229
            $foreignKey = $relationClass->getOwnerKeyName();
230
            $ownerKey = $relationClass->getForeignKeyName();
231
        } else {
232
            $foreignKey = $relationClass->getOwnerKey();
233
            $ownerKey = $relationClass->getForeignKey();
234
        }
235
236
        $ownerTable = $model->getTable();
237
        $foreignTable = $relationModel->getTable();
238
239
        $ownerColumn = implode('.', [$ownerTable, $ownerKey]);
240
        $foreignColumn = implode('.', [$foreignTable, $foreignKey]);
241
        $sortedColumnRaw = '`'.$foreignTable.'`.`'.$relations->last().'`';
242
        $sortedColumnAlias = implode('__', [$foreignTable, $relations->last()]);
243
244
        $this->sortedColumnAlias = $sortedColumnAlias;
245
246
        $query
247
            ->addSelect([DB::raw($sortedColumnRaw.' AS '.$sortedColumnAlias)])
248
            ->join($foreignTable, $foreignColumn, '=', $ownerColumn, 'left');
249
    }
250
251
    /**
252
     * Load keys for MorphTo.
253
     * @param Collection $relations
254
     * @param MorphTo $relationClass
255
     * @param null $relationModel
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $relationModel is correct as it would always require null to be passed?
Loading history...
256
     * @param Model $model
257
     * @param Builder $query
258
     */
259
    protected function loadMorphTo(
260
        Collection $relations,
261
        MorphTo $relationClass,
262
        $relationModel,
263
        Model $model,
264
        Builder $query
265
    ) {
266
        if (version_compare(app()->version(), '5.8.0', 'gt')) {
267
            $foreignKey = $relationClass->getOwnerKeyName();
268
            $ownerKey = $relationClass->getForeignKeyName();
269
        } else {
270
            $foreignKey = $relationClass->getOwnerKey();
271
            $ownerKey = $relationClass->getForeignKey();
272
        }
273
274
        $foreignKey = $foreignKey ?? 'id';
275
        $ownerTable = $model->getTable();
276
        $ownerColumn = implode('.', [$ownerTable, $ownerKey]);
277
        $morphType = $relationClass->getMorphType();
278
279
        $foreignTablePrefix = 'morphTo'.mt_rand(99, 999);
280
        $foreignTableField = $relations->last();
281
        $sortedColumnAlias = implode('__', [$foreignTablePrefix, $foreignTableField]);
282
        $this->sortedColumnAlias = $sortedColumnAlias;
283
284
        // Get all exists morph types from table
285
        $existsMorphTypes = (new $model())
286
            ->distinct()
287
            ->selectRaw($morphType)
288
            ->get()
289
            ->pluck($morphType)
290
            ->toArray();
291
292
        // Make morph map
293
        $morphMap = Relation::$morphMap;
294
        $existsMorphTypesTablesMap = [];
295
        foreach ($existsMorphTypes as $existsMorphType) {
296
            $existsMorphTypeAlias = $existsMorphType;
297
            $relatedModelClassName = @$morphMap[$existsMorphType] ?: $existsMorphType;
298
            $tableName = (new $relatedModelClassName())->getTable();
299
            $existsMorphTypesTablesMap[] = [
300
                'morph_type_alias' => $existsMorphTypeAlias,
301
                'morph_type'       => $existsMorphType,
302
                'table_name'       => $tableName,
303
            ];
304
        }
305
306
        // Join all related tables from morph map & generate SQL CASE-WHEN-THEN-END statement
307
        $sortedColumnRaw = [];
308
        foreach ($existsMorphTypesTablesMap as $array) {
309
            $existsMorphType = $array['morph_type'];
310
            $existsMorphTypeAlias = $array['morph_type_alias'];
311
            $tableName = $array['table_name'];
312
            $tableAlias = $foreignTablePrefix.'_'.$tableName;
313
            $sortedColumnRaw[] = "WHEN '$existsMorphType' THEN {$tableAlias}.`{$foreignTableField}`";
314
315
            $query->leftJoin(DB::raw('`'.$tableName.'` AS '.$tableAlias), function ($join) use ($tableAlias, $foreignKey, $ownerColumn, $ownerTable, $morphType, $existsMorphTypeAlias) {
316
                $join
317
                    ->on(DB::raw($tableAlias.'.`'.$foreignKey.'`'), '=', $ownerColumn)
318
                    ->where(DB::raw('`'.$ownerTable.'`.`'.$morphType.'`'), '=', DB::raw("'".$existsMorphTypeAlias."'"));
319
            });
320
        }
321
        $sortedColumnRaw = "(CASE `{$ownerTable}`.`{$morphType}` ".implode(' ', $sortedColumnRaw).' END)';
322
323
        // Add sorted field to result
324
        $query->addSelect([DB::raw($sortedColumnRaw.' AS '.$sortedColumnAlias)]);
325
    }
326
}
327