Completed
Pull Request — master (#6)
by Eliurkis
01:48
created

CrudController::paginate()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.2
c 0
b 0
f 0
cc 4
eloc 8
nc 4
nop 2
1
<?php
2
3
namespace Eliurkis\Crud;
4
5
use DB;
6
use Illuminate\Http\Request;
7
use App\Http\Controllers\Controller;
8
use Illuminate\Database\QueryException;
9
10
class CrudController extends Controller
11
{
12
    protected $route;
13
    protected $entity;
14
    protected $entityInstance = null;
15
    protected $fields = [];
16
    protected $columns = [];
17
    protected $buttons = [
18
        'create',
19
        'edit',
20
        'delete',
21
    ];
22
    protected $paginate = null;
23
    protected $searchable = [];
24
    protected $filters = [];
25
    protected $queryFilters = [];
26
    protected $filterRequire = [];
27
    protected $textsGeneral = [
28
        'list_title'   => 'Contents',
29
        'create_title' => '',
30
        'edit_title'   => '',
31
    ];
32
    protected $texts = [];
33
    protected $htmlFilters = [];
34
    protected $action = null;
35
    protected $formColsClasses = [
36
        'col-md-10 col-md-offset-1',
37
        'col-md-2',
38
        'col-md-10',
39
    ];
40
    protected $links = [];
41
42
    public function index(Request $request)
43
    {
44
        $entity = $this->entity;
45
46
        // Relation Fields
47
        $belongToFields = $this->getBelongToFields();
48
        if (count($belongToFields)) {
49
            $entity = $this->entity->with($belongToFields);
50
        }
51
52
        // Filters
53
        $entity = $this->filters($entity, $request);
54
55
        // Search
56
        $entity = $this->search($entity, $request);
57
58
        // Pagination
59
        $rows = $this->paginate > 0 ? $this->paginate($entity, $request) : $entity->get();
60
61
        // HTML Filters
62
        $this->htmlFilters();
63
64
        return view('crud::list', compact('rows'))
65
            ->with('fields', $this->fields)
66
            ->with('columns', $this->columns)
67
            ->with('searchable', $this->searchable)
68
            ->with('buttons', $this->buttons)
69
            ->with('paginate', $this->paginate)
70
            ->with('t', $this->texts)
71
            ->with('htmlFilters', $this->htmlFilters)
72
            ->with('links', $this->prepareLinks())
73
            ->with('request', $request)
74
            ->with('route', $this->route);
75
    }
76
77
    public function create()
78
    {
79
        $this->prepareFields();
80
81
        return view('crud::create')
82
            ->with('type', 'create')
83
            ->with('route', $this->route)
84
            ->with('t', $this->texts)
85
            ->with('formColsClasses', $this->formColsClasses)
86
            ->with('links', $this->prepareLinks())
87
            ->with('fields', $this->fields);
88
    }
89
90
    public function store(Request $request)
91
    {
92
        $validate = $this->prepareValidation();
93 View Code Duplication
        if ($validate['rules']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
94
            $this->validate($request, $validate['rules'], $validate['messages'], $validate['customAttributes']);
95
        }
96
97
        DB::beginTransaction();
98
99
        try {
100
            $row = $this->entity->create(array_merge($request->all(), $this->queryFilters));
101
            $this->updateForeignRelations($row, $request);
102
        } catch (QueryException $e) {
0 ignored issues
show
Bug introduced by
The class Illuminate\Database\QueryException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
103
            return redirect()
104
                ->back()
105
                ->with('error', 'Ha ocurrido un error, intente nuevamente');
106
        }
107
108
        DB::commit();
109
110
        return redirect()
111
            ->route($this->route.'.index')
112
            ->with('success', isset($this->textsGeneral['save_action'])
113
                ? $this->textsGeneral['save_action']
114
                : trans('eliurkis::crud.save_action'));
115
    }
116
117
    public function edit($id)
118
    {
119
        if (! $this->entityInstance) {
120
            $this->entityInstance = $this->entity->findOrFail($id);
121
        }
122
123
        $this->prepareFields();
124
125
        return view('crud::create')
126
            ->with('type', 'edit')
127
            ->with('route', $this->route)
128
            ->with('t', $this->texts)
129
            ->with('fields', $this->fields)
130
            ->with('formColsClasses', $this->formColsClasses)
131
            ->with('links', $this->prepareLinks())
132
            ->with('data', $this->entityInstance);
133
    }
134
135
    public function update(Request $request, $id)
136
    {
137
        $validate = $this->prepareValidation();
138 View Code Duplication
        if ($validate['rules']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
139
            $this->validate($request, $validate['rules'], $validate['messages'], $validate['customAttributes']);
140
        }
141
142
        DB::beginTransaction();
143
144
        try {
145
            $row = $this->entity->findOrFail($id);
146
            $row->update(
147
                array_merge(
148
                    $request->all(),
149
                    $this->queryFilters
150
                )
151
            );
152
            $this->updateForeignRelations($row, $request);
153
        } catch (QueryException $e) {
0 ignored issues
show
Bug introduced by
The class Illuminate\Database\QueryException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
154
            return redirect()
155
                ->back()
156
                ->with('error', 'Ha ocurrido un error, intente nuevamente');
157
        }
158
159
        DB::commit();
160
161
        return redirect()
162
            ->route($this->route.'.index', $this->getParamsFilters($row))
163
            ->with('success', isset($this->textsGeneral['save_action'])
164
                ? $this->textsGeneral['save_action']
165
                : trans('eliurkis::crud.save_action'));
166
    }
167
168
    public function destroy($id)
169
    {
170
        $this->entity->destroy($id);
171
172
        return redirect()
173
            ->route($this->route.'.index')
174
            ->with('success', isset($this->textsGeneral['delete_action'])
175
                ? $this->textsGeneral['delete_action']
176
                : trans('eliurkis::crud.delete_action'));
177
    }
178
179
    /* Private Actions */
180
181
    protected function filters($entity, $request)
182
    {
183
        if ($request->query('filter')) {
184
            foreach ($request->query('filter') as $field => $value) {
185
                $entity = $entity->where($field, $value);
186
            }
187
        }
188
189
        if (count($this->queryFilters)) {
190
            foreach ($this->queryFilters as $field => $value) {
191
                $entity = $entity->where($field, $value);
192
            }
193
        }
194
195
        return $entity;
196
    }
197
198
    protected function htmlFilters()
199
    {
200
        $this->htmlFilters = [];
201
        if (count($this->filters)) {
202
            foreach ($this->filters as $filter) {
203
                // Build params
204
                $urlParams = \Input::query();
205
206
                // Default Value
207
                $this->fields[$filter]['config']['default_value'] = isset($urlParams['filter'][$filter])
208
                    ? $urlParams['filter'][$filter]
209
                    : null;
210
211
                // Create URL
212
                if (isset($urlParams['filter'][$filter])) {
213
                    unset($urlParams['filter'][$filter]);
214
                }
215
                $this->fields[$filter]['attributes']['data-filter-url'] = route($this->route.'.index', $urlParams)
216
                    .(count($urlParams) ? '&' : '?');
217
218
                // Create array
219
                $this->action = 'list';
220
                $this->htmlFilters[$filter] = $this->prepareField($filter);
221
            }
222
        }
223
    }
224
225
    protected function paginate($entity, $request)
226
    {
227
        $rows = $entity->paginate($this->paginate);
228
229
        if ($request->get('q') != '') {
230
            $rows->appends(['q' => $request->get('q')]);
231
        }
232
233
        if ($request->get('filter')) {
234
            foreach ($request->get('filter') as $field => $value) {
235
                $rows->appends(['filter['.$field.']' => $value]);
236
            }
237
        }
238
239
        return $rows;
240
    }
241
242
    protected function search($entity, $request)
243
    {
244
        if ($request->get('q') != '') {
245
            $searchableCols = isset($this->searchable['columns']) ? $this->searchable['columns'] : $this->searchable;
246
247
            $entity = $entity->where(function ($query) use ($request, $searchableCols) {
248
                foreach ($searchableCols as $field) {
249
                    $query->orWhere($field, 'like', '%'.$request->get('q').'%');
250
                }
251
            });
252
253
            if (isset($this->searchable['joins'])) {
254
                foreach ($this->searchable['joins'] as $table => $joinFields) {
255
                    $entity = $entity->join($table, $joinFields[0], '=', $joinFields[1]);
256
                }
257
            }
258
        }
259
260
        return $entity;
261
    }
262
263
    protected function getForeignRelationsFields()
264
    {
265
        $foreignRelations = [];
266
        foreach ($this->fields as $field => $options) {
267
            if ($options['type'] === 'foreign') {
268
                $foreignRelations[] = $field;
269
            }
270
        }
271
272
        return $foreignRelations;
273
    }
274
275
    protected function getBelongToFields()
276
    {
277
        $fields = [];
278
        foreach ($this->fields as $field => $options) {
279
            if ($options['type'] === 'select' && isset($options['config']['rel'])) {
280
                $fields[] = $options['config']['rel'];
281
            }
282
        }
283
284
        return $fields;
285
    }
286
287
    protected function updateForeignRelations($row, $request)
288
    {
289
        $foreignRelations = $this->getForeignRelationsFields();
290
291
        foreach ($foreignRelations as $foreignRelation) {
292
            $values = $request->get($foreignRelation);
293
            $row->$foreignRelation()->sync((array) $values);
294
        }
295
    }
296
297
    protected function getParamsFilters($row)
298
    {
299
        $params = [];
300
301
        if (count($this->filterRequire)) {
302
            $params['filter'] = [];
303
304
            foreach ($this->filterRequire as $field) {
305
                $params['filter'][$field] = $row->$field;
306
            }
307
        }
308
309
        return $params;
310
    }
311
312
    protected function prepareLinks()
313
    {
314
        $links = ['index', 'create', 'store'];
315
316
        foreach ($links as $link) {
317
            if (! isset($this->links[$link])) {
318
                $this->links[$link] = route($this->route.'.'.$link);
319
            }
320
        }
321
322
        return $this->links;
323
    }
324
325
    protected function prepareValidation()
326
    {
327
        $validations = [
328
            'rules'            => [],
329
            'messages'         => [],
330
            'customAttributes' => [],
331
        ];
332
333
        foreach ($this->fields as $field => $options) {
334
            if (isset($options['validation'])) {
335
                $validations['rules'][$field] = $options['validation'];
336
                $validations['customAttributes'][$field] = $options['label'];
337
            }
338
        }
339
340
        return $validations;
341
    }
342
343
    protected function prepareRelationalFields($name)
344
    {
345
        // Default values
346
        $config = isset($this->fields[$name]['config']) ? $this->fields[$name]['config'] : [];
347
        $config['options'] = isset($config['options']) ? $config['options'] : [];
348
        $config['cols'] = isset($config['cols']) ? $config['cols'] : 1;
349
350
        // Get foreign values
351
        if (! count($config['options']) && isset($config['entity'])) {
352
            $config['options'] = $config['entity']::get()
353
                ->lists($config['field_value'], $config['field_key'])
354
                ->toArray();
355
        }
356
357
        // No selection for filters
358
        if ($this->action == 'list' && isset($config['filter_no_selection'])) {
359
            $config['options'] = array_merge([
360
                '-1' => $config['filter_no_selection'],
361
            ], $config['options']);
362
        }
363
364
        $this->fields[$name]['config'] = $config;
365
366
        return $this->fields[$name];
367
    }
368
369
    protected function prepareFields()
370
    {
371
        if ($this->entityInstance) {
372
            \Form::model($this->entityInstance);
373
        }
374
375
        foreach ($this->fields as $name => $properties) {
376
            $this->fields[$name]['html'] = $this->prepareField($name, $properties);
377
        }
378
    }
379
380
    protected function prepareField($name, $properties = [])
381
    {
382
        // Init
383
        if (! $properties) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $properties of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
384
            $properties = $this->fields[$name];
385
        }
386
387
        $this->fields[$name]['config'] = isset($properties['config']) ? $properties['config'] : [];
388
        $this->fields[$name]['attributes'] = isset($properties['attributes']) ? $properties['attributes'] : [];
389
        $this->fields[$name]['attributes']['class'] = 'form-control';
390
        $this->fields[$name]['html'] = null;
391
392
        $config = $this->fields[$name]['config'];
393
394
        $value = $this->entityInstance
395
            ? $this->entityInstance->$name
396
            : (isset($config['default_value']) ? $config['default_value'] : null);
397
398
        // Define field type class namespace
399
        $className = '\Eliurkis\Crud\FieldTypes\\'.ucfirst($properties['type']);
400
        if (! class_exists($className)) {
401
            return;
402
        }
403
404
        if ($properties['type'] == 'foreign' || $properties['type'] == 'select') {
405
            $properties = $this->prepareRelationalFields($name);
406
407
            if ($properties['type'] == 'foreign' && $this->entityInstance) {
408
                $value = $this->entityInstance->{$config['rel']}->lists('id')->toArray();
409
            }
410
411
            if ($properties['type'] == 'select') {
412
                $properties['attributes']['class'] = 'form-control chosen-select-width';
413
            }
414
415
            return $className::prepare(
416
                $name,
417
                $properties['config']['options'],
418
                $value,
419
                $properties
420
            );
421
        }
422
423
        return $className::prepare(
424
            $name,
425
            $value,
426
            $this->fields[$name]
427
        );
428
    }
429
}
430