Completed
Push — master ( 243f23...de48bf )
by Song
07:06
created

Model::get()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 23
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 12
nc 4
nop 0
dl 0
loc 23
rs 8.7972
c 0
b 0
f 0
1
<?php
2
3
namespace Encore\Admin\Grid;
4
5
use Illuminate\Database\Eloquent\Model as EloquentModel;
6
use Illuminate\Database\Eloquent\Relations\Relation;
7
use Illuminate\Pagination\AbstractPaginator;
8
use Illuminate\Support\Collection;
9
use Illuminate\Support\Facades\Input;
10
11
class Model
12
{
13
    /**
14
     * Eloquent model instance of the grid model.
15
     *
16
     * @var EloquentModel
17
     */
18
    protected $model;
19
20
    /**
21
     * Array of queries of the eloquent model.
22
     *
23
     * @var array
24
     */
25
    protected $queries = [];
26
27
    /**
28
     * Sort parameters of the model.
29
     *
30
     * @var array
31
     */
32
    protected $sort;
33
34
    /**
35
     * @var array
36
     */
37
    protected $data = [];
38
39
    /*
40
     * 20 items per page as default.
41
     *
42
     * @var int
43
     */
44
    protected $perPage = 20;
45
46
    /**
47
     * @var bool
48
     */
49
    protected $usePaginate = true;
50
51
    /**
52
     * Create a new grid model instance.
53
     *
54
     * @param EloquentModel $model
55
     */
56
    public function __construct(EloquentModel $model)
57
    {
58
        $this->model = $model;
59
60
        $this->queries = collect();
0 ignored issues
show
Documentation Bug introduced by
It seems like collect() of type object<Illuminate\Support\Collection> is incompatible with the declared type array of property $queries.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
61
    }
62
63
    /**
64
     * Get the eloquent model of the grid model.
65
     *
66
     * @return EloquentModel
67
     */
68
    public function eloquent()
69
    {
70
        return $this->model;
71
    }
72
73
    /**
74
     * Enable or disable pagination.
75
     *
76
     * @param bool $use
77
     */
78
    public function usePaginate($use = true)
79
    {
80
        $this->usePaginate = $use;
81
    }
82
83
    /**
84
     * Build.
85
     *
86
     * @return array
87
     */
88
    public function buildData()
89
    {
90
        if (empty($this->data)) {
91
            $this->data = $this->get()->toArray();
92
        }
93
94
        return $this->data;
95
    }
96
97
    /**
98
     * Add conditions to grid model.
99
     *
100
     * @param array $conditions
101
     *
102
     * @return void
103
     */
104
    public function addConditions(array $conditions)
105
    {
106
        foreach ($conditions as $condition) {
107
            call_user_func_array([$this, key($condition)], current($condition));
108
        }
109
    }
110
111
    /**
112
     * Get table of the model.
113
     *
114
     * @return string
115
     */
116
    public function getTable()
117
    {
118
        return $this->model->getTable();
119
    }
120
121
    /**
122
     * @throws \Exception
123
     *
124
     * @return Collection
125
     */
126
    protected function get()
127
    {
128
        if ($this->model instanceof AbstractPaginator) {
129
            return $this->model;
130
        }
131
132
        $this->setSort();
133
        $this->setPaginate();
134
135
        $this->queries->each(function ($query) {
0 ignored issues
show
Bug introduced by
The method each cannot be called on $this->queries (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
136
            $this->model = call_user_func_array([$this->model, $query['method']], $query['arguments']);
137
        });
138
139
        if ($this->model instanceof Collection) {
140
            return $this->model;
141
        }
142
143
        if ($this->model instanceof AbstractPaginator) {
144
            return $this->model->getCollection();
145
        }
146
147
        throw new \Exception('Grid query error');
148
    }
149
150
    /**
151
     * Set the grid paginate.
152
     *
153
     * @return void
154
     */
155
    protected function setPaginate()
156
    {
157
        $paginate = $this->findQueryByMethod('paginate')->first();
0 ignored issues
show
Documentation Bug introduced by
The method first does not exist on object<Encore\Admin\Grid\Model>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
158
159
        $this->queries = $this->queries->reject(function ($query) {
0 ignored issues
show
Bug introduced by
The method reject cannot be called on $this->queries (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
160
            return $query['method'] == 'paginate';
161
        });
162
163
        if (!$this->usePaginate) {
164
            $query = [
165
                'method'    => 'get',
166
                'arguments' => [],
167
            ];
168
        } else {
169
            $query = [
170
                'method'    => 'paginate',
171
                'arguments' => is_null($paginate) ? [$this->perPage] : $paginate['arguments'],
172
            ];
173
        }
174
175
        $this->queries->push($query);
176
    }
177
178
    /**
179
     * Find query by method name.
180
     *
181
     * @param $method
182
     *
183
     * @return static
184
     */
185
    protected function findQueryByMethod($method)
186
    {
187
        return $this->queries->filter(function ($query) use ($method) {
0 ignored issues
show
Bug introduced by
The method filter cannot be called on $this->queries (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
188
            return $query['method'] == $method;
189
        });
190
    }
191
192
    /**
193
     * Set the grid sort.
194
     *
195
     * @return void
196
     */
197
    protected function setSort()
198
    {
199
        $this->sort = Input::get('_sort', []);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Illuminate\Support\Faca...::get('_sort', array()) of type * is incompatible with the declared type array of property $sort.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
200
        if (!is_array($this->sort)) {
201
            return;
202
        }
203
204
        if (empty($this->sort['column']) || empty($this->sort['type'])) {
205
            return;
206
        }
207
208
        if (str_contains($this->sort['column'], '.')) {
209
            $this->setRelationSort($this->sort['column']);
210
        } else {
211
            $this->queries->push([
0 ignored issues
show
Bug introduced by
The method push cannot be called on $this->queries (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
212
                'method'    => 'orderBy',
213
                'arguments' => [$this->sort['column'], $this->sort['type']],
214
            ]);
215
        }
216
    }
217
218
    /**
219
     * Set relation sort.
220
     *
221
     * @param string $column
222
     *
223
     * @return void
224
     */
225
    protected function setRelationSort($column)
226
    {
227
        list($relationName, $relationColumn) = explode('.', $column);
228
229
        if ($this->queries->contains(function ($key, $query) use ($relationName) {
0 ignored issues
show
Bug introduced by
The method contains cannot be called on $this->queries (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
230
            return $query['method'] == 'with' && in_array($relationName, $query['arguments']);
231
        })) {
232
            $relation = $this->model->$relationName();
233
234
            $this->queries->push([
0 ignored issues
show
Bug introduced by
The method push cannot be called on $this->queries (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
235
                'method'    => 'join',
236
                'arguments' => $this->joinParameters($relation),
237
            ]);
238
239
            $this->queries->push([
0 ignored issues
show
Bug introduced by
The method push cannot be called on $this->queries (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
240
                'method'    => 'orderBy',
241
                'arguments' => [
242
                    $relation->getRelated()->getTable().'.'.$relationColumn,
243
                    $this->sort['type'],
244
                ],
245
            ]);
246
        }
247
    }
248
249
    /**
250
     * Build join parameters.
251
     *
252
     * @param Relation $relation
253
     *
254
     * @return array
255
     */
256
    protected function joinParameters(Relation $relation)
257
    {
258
        return [
259
            $relation->getRelated()->getTable(),
260
            $relation->getQualifiedParentKeyName(),
261
            '=',
262
            $relation->getForeignKey(),
263
        ];
264
    }
265
266
    /**
267
     * @param string $method
268
     * @param array  $arguments
269
     *
270
     * @return $this
271
     */
272
    public function __call($method, $arguments)
273
    {
274
        $this->queries->push([
0 ignored issues
show
Bug introduced by
The method push cannot be called on $this->queries (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
275
            'method'    => $method,
276
            'arguments' => $arguments,
277
        ]);
278
279
        return $this;
280
    }
281
282
    /**
283
     * @param $key
284
     *
285
     * @return mixed
286
     */
287
    public function __get($key)
288
    {
289
        $data = $this->buildData();
290
291
        if (array_key_exists($key, $data)) {
292
            return $data[$key];
293
        }
294
    }
295
}
296