Completed
Push — master ( d27d79...fd5cc8 )
by
unknown
06:45
created

Model::getConfig()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 1
cts 1
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
namespace Anavel\Crud\Abstractor\Eloquent;
3
4
use Anavel\Crud\Abstractor\Eloquent\Traits\HandleFiles;
5
use Anavel\Crud\Abstractor\Eloquent\Traits\ModelFields;
6
use Anavel\Crud\Contracts\Abstractor\Field as FieldContract;
7
use Anavel\Crud\Contracts\Abstractor\Model as ModelAbstractorContract;
8
use Anavel\Crud\Abstractor\ConfigurationReader;
9
use Anavel\Crud\Contracts\Abstractor\Relation;
10
use Anavel\Crud\Contracts\Abstractor\RelationFactory as RelationFactoryContract;
11
use Anavel\Crud\Contracts\Abstractor\FieldFactory as FieldFactoryContract;
12
use ANavallaSuiza\Laravel\Database\Contracts\Dbal\AbstractionLayer;
13
use FormManager\ElementInterface;
14
use Illuminate\Database\Eloquent\Model as LaravelModel;
15
use App;
16
use Anavel\Crud\Contracts\Form\Generator as FormGenerator;
17
use Anavel\Crud\Abstractor\Exceptions\AbstractorException;
18
use Illuminate\Http\Request;
19
use Illuminate\Support\Collection;
20
use League\Flysystem\Adapter\Local;
21
use League\Flysystem\Filesystem;
22
23
class Model implements ModelAbstractorContract
24
{
25
    use ConfigurationReader;
26
    use ModelFields;
27
    use HandleFiles;
28
29
    protected $dbal;
30
    protected $relationFactory;
31
    protected $fieldFactory;
32
    protected $generator;
33
34
    protected $model;
35
    protected $config;
36
37
    protected $slug;
38
    protected $name;
39
    protected $instance;
40
41 17
    public function __construct(
42
        $config,
43
        AbstractionLayer $dbal,
44
        RelationFactoryContract $relationFactory,
45
        FieldFactoryContract $fieldFactory,
46
        FormGenerator $generator
47
    ) {
48 17
        if (is_array($config)) {
49 17
            $this->model = $config['model'];
50 17
            $this->config = $config;
51 17
        } else {
52
            $this->model = $config;
53
            $this->config = [];
54
        }
55
56 17
        $this->dbal = $dbal;
57 17
        $this->relationFactory = $relationFactory;
58 17
        $this->fieldFactory = $fieldFactory;
59 17
        $this->generator = $generator;
60 17
    }
61
62 3
    public function setSlug($slug)
63
    {
64 3
        $this->slug = $slug;
65
66 3
        return $this;
67
    }
68
69 2
    public function setName($name)
70
    {
71 2
        $this->name = $name;
72
73 2
        return $this;
74
    }
75
76 5
    public function setInstance($instance)
77
    {
78 5
        $this->instance = $instance;
79
80 5
        return $this;
81
    }
82
83
    public function getSlug()
84
    {
85
        return $this->slug;
86
    }
87
88
    public function getName()
89
    {
90
        return transcrud($this->name);
91
    }
92
93 1
    public function getModel()
94
    {
95 1
        return $this->model;
96
    }
97
98
    public function getInstance()
99
    {
100
        return $this->instance;
101
    }
102
103
    /**
104
     * @return array
105
     */
106
    public function getConfig()
107
    {
108 8
        return $this->config;
109
    }
110 8
111
    public function isSoftDeletes()
112 8
    {
113 8
        return $this->getConfigValue('soft_deletes') ? true : false;
114 8
    }
115 8
116 8
    public function getColumns($action, $withForeignKeys = false)
117
    {
118
        $tableColumns = $this->dbal->getTableColumns();
119 8
120 8
        $filteredColumns = [];
121 8
        foreach ($tableColumns as $name => $column) {
122
            $filteredColumns[str_replace('`', '', $name)] = $column;
123 8
        }
124
        $tableColumns = $filteredColumns;
125
126
127 8
        $foreignKeysName = [];
128 8
        if ($withForeignKeys === false) {
129
            $foreignKeys = $this->dbal->getTableForeignKeys();
130 8
131 8
            foreach ($foreignKeys as $foreignKey) {
132
                foreach ($foreignKey->getColumns() as $columnName) {
133 8
                    $foreignKeysName[] = $columnName;
134 8
                }
135 8
            }
136 8
        }
137
138
        $customDisplayedColumns = $this->getConfigValue($action, 'display');
139
        $customHiddenColumns = $this->getConfigValue($action, 'hide') ? : [];
140 8
141 8
        $relations = $this->getRelations();
142 8
143
        $columns = array();
144
        if (! empty($customDisplayedColumns) && is_array($customDisplayedColumns)) {
145
            foreach ($customDisplayedColumns as $customColumn) {
146
                if (strpos($customColumn, '.')) {
147
                    $customColumnRelation = explode('.', $customColumn);
148
149
                    if (! $relations->has($customColumnRelation[0])) {
150
                        throw new AbstractorException("Relation " . $customColumnRelation[0] . " not configured on " . $this->getModel());
151
                    }
152
153
                    $relation = $relations->get($customColumnRelation[0]);
154
155
                    $relationColumns = $relation->getModelAbstractor()->getColumns($action);
156 8
157
                    if (! array_key_exists($customColumnRelation[1], $relationColumns)) {
158
                        throw new AbstractorException("Column " . $customColumnRelation[1] . " does not exist on relation ".$customColumnRelation[0]. " of model " . $this->getModel());
159
                    }
160
161
                    $columns[$customColumn] = $relationColumns[$customColumnRelation[1]];
162 4
                } else {
163
                    if (! array_key_exists($customColumn, $tableColumns)) {
164 4
                        throw new AbstractorException("Column " . $customColumn . " does not exist on " . $this->getModel());
165
                    }
166 4
167
                    $columns[$customColumn] = $tableColumns[$customColumn];
168 4
                }
169 4
            }
170 4
        } else {
171
            foreach ($tableColumns as $name => $column) {
172
                if (in_array($name, $customHiddenColumns)) {
173
                    continue;
174 4
                }
175 4
176 4
                if (in_array($name, $foreignKeysName)) {
177
                    continue;
178
                }
179 4
180
                $columns[$name] = $column;
181 4
            }
182
        }
183
184 4
        return $columns;
185 4
    }
186 4
187
    /**
188 4
     * @return \Illuminate\Support\Collection
189
     */
190
    public function getRelations()
191 4
    {
192 1
        $configRelations = $this->getConfigValue('relations');
193 1
194 1
        $relations = collect();
195 1
196 1
        if (! empty($configRelations)) {
197 3
            foreach ($configRelations as $relationName => $configRelation) {
198
                if (is_int($relationName)) {
199
                    $relationName = $configRelation;
200 4
                }
201 4
202
                $config = [];
203 4
                if ($configRelation !== $relationName) {
204
                    if (! is_array($configRelation)) {
205
                        $config['type'] = $configRelation;
206
                    } else {
207
                        $config = $configRelation;
208
                    }
209
                }
210
211 2
                /** @var Relation $relation */
212
                $relation = $this->relationFactory->setModel($this->instance)
213 2
                    ->setConfig($config)
214
                    ->get($relationName);
215 2
216
                $secondaryRelations = $relation->getSecondaryRelations();
217 2
218 2
219 2
                if (! $secondaryRelations->isEmpty()) {
220 2
                    $relations->put(
221 2
                        $relationName,
222 2
                        collect(['relation' => $relation, 'secondaryRelations' => $secondaryRelations])
223
                    );
224
                } else {
225 2
                    $relations->put($relationName, $relation);
226 2
                }
227 2
228 2
            }
229
        }
230 2
231
        return $relations;
232 2
    }
233 2
234 2
    /**
235 2
     * @param string|null $arrayKey
236 2
     * @return array
237
     * @throws AbstractorException
238 2
     */
239 View Code Duplication
    public function getListFields($arrayKey = 'main')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
240
    {
241
        $columns = $this->getColumns('list');
242
243
        $fieldsPresentation = $this->getConfigValue('fields_presentation') ? : [];
244
245
        $fields = array();
246 2
        foreach ($columns as $name => $column) {
247
            $presentation = null;
248 2
            if (array_key_exists($name, $fieldsPresentation)) {
249
                $presentation = $fieldsPresentation[$name];
250 2
            }
251
252 2
            $config = [
253 2
                'name'         => $name,
254 2
                'presentation' => $presentation,
255 2
                'form_type'    => null,
256 2
                'validation'   => null,
257 2
                'functions'    => null
258
            ];
259
260 2
            $fields[$arrayKey][] = $this->fieldFactory
261 2
                ->setColumn($column)
262 2
                ->setConfig($config)
263 2
                ->get();
264
        }
265 2
266
        return $fields;
267 2
    }
268 2
269 2
    /**
270 2
     * @param string|null $arrayKey
271 2
     * @return array
272
     * @throws AbstractorException
273 2
     */
274 View Code Duplication
    public function getDetailFields($arrayKey = 'main')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
275
    {
276
        $columns = $this->getColumns('detail');
277
278
        $fieldsPresentation = $this->getConfigValue('fields_presentation') ? : [];
279
280
        $fields = array();
281
        foreach ($columns as $name => $column) {
282 4
            $presentation = null;
283
            if (array_key_exists($name, $fieldsPresentation)) {
284 4
                $presentation = $fieldsPresentation[$name];
285
            }
286 4
287
            $config = [
288 4
                'name'         => $name,
289 4
                'presentation' => $presentation,
290 4
                'form_type'    => null,
291 4
                'validation'   => null,
292 4
                'functions'    => null
293
            ];
294
295
            $fields[$arrayKey][] = $this->fieldFactory
296
                ->setColumn($column)
297 4
                ->setConfig($config)
298 4
                ->get();
299 4
        }
300 4
301
        return $fields;
302 4
    }
303
304 4
    /**
305
     * @param bool|null $withForeignKeys
306 4
     * @param string|null $arrayKey
307 4
     * @return array
308 4
     * @throws AbstractorException
309 4
     */
310
    public function getEditFields($withForeignKeys = false, $arrayKey = 'main')
311 4
    {
312
        $columns = $this->getColumns('edit', $withForeignKeys);
0 ignored issues
show
Bug introduced by
It seems like $withForeignKeys defined by parameter $withForeignKeys on line 310 can also be of type null; however, Anavel\Crud\Abstractor\E...ent\Model::getColumns() does only seem to accept boolean, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
313
314
        $this->readConfig('edit');
315 4
316
        $fields = array();
317 4
        foreach ($columns as $name => $column) {
318 4
            if (! in_array($name, $this->getReadOnlyColumns())) {
319 4
                $presentation = null;
320 4
                if (array_key_exists($name, $this->fieldsPresentation)) {
321 4
                    $presentation = $this->fieldsPresentation[$name];
322 4
                }
323 4
324 4
                $config = [
325
                    'name'         => $name,
326 4
                    'presentation' => $presentation,
327 4
                    'form_type'    => null,
328 4
                    'validation'   => null,
329 4
                    'functions'    => null
330 4
                ];
331 4
332
                $config = $this->setConfig($config, $name);
333 4
334
                $field = $this->fieldFactory
335
                    ->setColumn($column)
336 4
                    ->setConfig($config)
337
                    ->get();
338 4
339
                if (! empty($this->instance) && ! empty($this->instance->getAttribute($name))) {
340 4
                    $field->setValue($this->instance->getAttribute($name));
341
                }
342 4
343
                $fields[$arrayKey][$name] = $field;
344
345 View Code Duplication
                if (! empty($config['form_type']) && $config['form_type'] === 'file') {
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...
346
                    $field = $this->fieldFactory
347
                        ->setColumn($column)
348
                        ->setConfig([
349 2
                            'name'         => $name . '__delete',
350
                            'presentation' => null,
351 2
                            'form_type'    => 'checkbox',
352 2
                            'no_validate'  => true,
353
                            'functions'    => null
354 2
                        ])
355
                        ->get();
356
                    $fields[$arrayKey][$name . '__delete'] = $field;
357
                }
358
            }
359
        }
360
361 1
        return $fields;
362
    }
363
364 1
    protected function getReadOnlyColumns()
365 1
    {
366
        $columns = [LaravelModel::CREATED_AT, LaravelModel::UPDATED_AT];
367
368 1
        $columns[] = $this->dbal->getModel()->getKeyName();
369
370
        return $columns;
371
    }
372 1
373 1
    /**
374
     * @param string $action
375
     * @return ElementInterface
376
     */
377 1
    public function getForm($action)
378 1
    {
379 1
        $this->generator->setModelFields($this->getEditFields());
380
        $this->generator->setRelatedModelFields($this->getRelations());
381 1
382
        return $this->generator->getForm($action);
383
    }
384
385 1
    /**
386 1
     * @param array $requestForm
0 ignored issues
show
Documentation introduced by
There is no parameter named $requestForm. Did you maybe mean $request?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
387
     * @return mixed
388 1
     */
389
    public function persist(Request $request)
390
    {
391
        /** @var \ANavallaSuiza\Laravel\Database\Contracts\Manager\ModelManager $modelManager */
392
        $modelManager = App::make('ANavallaSuiza\Laravel\Database\Contracts\Manager\ModelManager');
393
        if (! empty($this->instance)) {
394
            $item = $this->instance;
395
        } else {
396
            $item = $modelManager->getModelInstance($this->getModel());
397
        }
398
399
400 1
        $fields = $this->getEditFields(true);
401
        if (empty($fields['main']) && $this->getRelations()->isEmpty()) {
402
            return;
403
        }
404
405
        if (! empty($fields['main'])) {
406
            $skip = null;
407
            foreach ($fields['main'] as $key => $field) {
408
                /** @var FieldContract $field */
409
                if ($skip === $key) {
410
                    $skip = null;
411 1
                    continue;
412
                }
413
                $fieldName = $field->getName();
414
                $requestValue = $request->input("main.{$fieldName}");
415 1
416 1
                if (get_class($field->getFormField()) === \FormManager\Fields\Checkbox::class) {
417 1
                    if (empty($requestValue)) {
418 1
                        // Unchecked checkboxes are not sent, so we force setting them to false
419 1
                        $item->setAttribute(
420 1
                            $fieldName,
421 1
                            $field->applyFunctions(null)
422 1
                        );
423
                    } else {
424 1
                        $requestValue = true;
425
                    }
426 1
                }
427
428
                if (get_class($field->getFormField()) === \FormManager\Fields\File::class) {
429 1
                    $handleResult = $this->handleField($request, $item, $fields['main'], 'main', $fieldName);
430 1
                    if (! empty($handleResult['skip'])) {
431 1
                        $skip = $handleResult['skip'];
432
                    }
433
                    if (! empty($handleResult['requestValue'])) {
434
                        $requestValue = $handleResult['requestValue'];
435 1
                    }
436
                }
437 1
438 1
439
                if (! $field->saveIfEmpty() && empty($requestValue)) {
440 1
                    continue;
441
                }
442
443
                if (! empty($requestValue) || (empty($requestValue) && ! empty($item->getAttribute($fieldName)))) {
444
                    $item->setAttribute(
445
                        $fieldName,
446 1
                        $field->applyFunctions($requestValue)
447
                    );
448 1
                }
449
            }
450
        }
451
452
        $item->save();
453
454
        $this->setInstance($item);
455
456
457
        if (! empty($relations = $this->getRelations())) {
458
            foreach ($relations as $relationKey => $relation) {
459
                if ($relation instanceof Collection) {
460
                    $input = $request->input($relationKey);
461
                    $relation->get('relation')->persist($input, $request);
462
                } else {
463
                    $relation->persist($request->input($relationKey), $request);
464
                }
465
            }
466
        }
467
468
        return $item;
469
    }
470
471
    /**
472
     * @return array
473
     */
474
    public function getValidationRules()
475
    {
476
        return $this->generator->getValidationRules();
477
    }
478
479
    public function getFieldValue($item, $fieldName)
480
    {
481
        $value = null;
0 ignored issues
show
Unused Code introduced by
$value 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...
482
483
        if (strpos($fieldName, '.')) {
484
            $customColumnRelation = explode('.', $fieldName);
485
486
            $relation = $item->$customColumnRelation[0];
487
            if (empty($relation)) {
488
                return null;
489
            }
490
491
            if ($relation instanceof \Illuminate\Support\Collection) {
492
                $relations = $this->getRelations();
493
494
                $relationAbstractor = $relations->get($customColumnRelation[0]);
495
496
                if ($relationAbstractor instanceof \Anavel\Crud\Abstractor\Eloquent\Relation\Translation) {
497
                    $value = $item->getAttribute($customColumnRelation[1]);
498
                } else {
499
                    $value = $relation->implode($customColumnRelation[1], ', ');
500
                }
501
            } else {
502
                $value = $relation->getAttribute($customColumnRelation[1]);
503
            }
504
        } else {
505
            $value = $item->getAttribute($fieldName);
506
        }
507
508
        return $value;
509
    }
510
}
511