Completed
Push — master ( 7dac91...3d08cb )
by
unknown
05:39
created

Model   C

Complexity

Total Complexity 67

Size/Duplication

Total Lines 419
Duplicated Lines 16.95 %

Coupling/Cohesion

Components 2
Dependencies 13

Test Coverage

Coverage 78.45%

Importance

Changes 14
Bugs 0 Features 0
Metric Value
wmc 67
c 14
b 0
f 0
lcom 2
cbo 13
dl 71
loc 419
ccs 182
cts 232
cp 0.7845
rs 5.2808

18 Methods

Rating   Name   Duplication   Size   Complexity  
A setSlug() 0 6 1
A setName() 0 6 1
A setInstance() 0 6 1
A getSlug() 0 4 1
A getName() 0 4 1
A getModel() 0 4 1
A getInstance() 0 4 1
A isSoftDeletes() 0 4 2
A getReadOnlyColumns() 0 8 1
A getForm() 0 7 1
A __construct() 0 20 2
C getColumns() 0 50 13
C getRelations() 0 41 7
B getListFields() 29 29 4
B getDetailFields() 29 29 4
B getEditFields() 13 53 8
C persist() 0 74 17
A getValidationRules() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Model often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Model, and based on these observations, apply Extract Interface, too.

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
    public function isSoftDeletes()
104
    {
105
        return $this->getConfigValue('soft_deletes') ? true : false;
106
    }
107
108 8
    public function getColumns($action, $withForeignKeys = false)
109
    {
110 8
        $tableColumns = $this->dbal->getTableColumns();
111
112 8
        $filteredColumns = [];
113 8
        foreach ($tableColumns as $name => $column) {
114 8
            $filteredColumns[str_replace('`', '', $name)] = $column;
115 8
        }
116 8
        $tableColumns = $filteredColumns;
117
118
119 8
        $foreignKeysName = [];
120 8
        if ($withForeignKeys === false) {
121 8
            $foreignKeys = $this->dbal->getTableForeignKeys();
122
123 8
            foreach ($foreignKeys as $foreignKey) {
124
                foreach ($foreignKey->getColumns() as $columnName) {
125
                    $foreignKeysName[] = $columnName;
126
                }
127 8
            }
128 8
        }
129
130 8
        $customDisplayedColumns = $this->getConfigValue($action, 'display');
131 8
        $customHiddenColumns = $this->getConfigValue($action, 'hide') ? : [];
132
133 8
        $columns = array();
134 8
        if (! empty($customDisplayedColumns) && is_array($customDisplayedColumns)) {
135 8
            foreach ($customDisplayedColumns as $customColumn) {
136 8
                if (! array_key_exists($customColumn, $tableColumns)) {
137
                    throw new AbstractorException("Column " . $customColumn . " does not exist on " . $this->getModel());
138
                }
139
140 8
                $columns[$customColumn] = $tableColumns[$customColumn];
141 8
            }
142 8
        } else {
143
            foreach ($tableColumns as $name => $column) {
144
                if (in_array($name, $customHiddenColumns)) {
145
                    continue;
146
                }
147
148
                if (in_array($name, $foreignKeysName)) {
149
                    continue;
150
                }
151
152
                $columns[$name] = $column;
153
            }
154
        }
155
156 8
        return $columns;
157
    }
158
159
    /**
160
     * @return \Illuminate\Support\Collection
161
     */
162 4
    public function getRelations()
163
    {
164 4
        $configRelations = $this->getConfigValue('relations');
165
166 4
        $relations = collect();
167
168 4
        if (! empty($configRelations)) {
169 4
            foreach ($configRelations as $relationName => $configRelation) {
170 4
                if (is_int($relationName)) {
171
                    $relationName = $configRelation;
172
                }
173
174 4
                $config = [];
175 4
                if ($configRelation !== $relationName) {
176 4
                    if (! is_array($configRelation)) {
177
                        $config['type'] = $configRelation;
178
                    } else {
179 4
                        $config = $configRelation;
180
                    }
181 4
                }
182
183
                /** @var Relation $relation */
184 4
                $relation = $this->relationFactory->setModel($this->instance)
185 4
                    ->setConfig($config)
186 4
                    ->get($relationName);
187
188 4
                $secondaryRelations = $relation->getSecondaryRelations();
189
190
191 4
                if (! $secondaryRelations->isEmpty()) {
192 1
                    $relations->put($relationName,
193 1
                        collect(['relation' => $relation, 'secondaryRelations' => $secondaryRelations]));
194 1
                } else {
195 3
                    $relations->put($relationName, $relation);
196
                }
197
198 4
            }
199 4
        }
200
201 4
        return $relations;
202
    }
203
204
    /**
205
     * @param string|null $arrayKey
206
     * @return array
207
     * @throws AbstractorException
208
     */
209 2 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...
210
    {
211 2
        $columns = $this->getColumns('list');
212
213 2
        $fieldsPresentation = $this->getConfigValue('fields_presentation') ? : [];
214
215 2
        $fields = array();
216 2
        foreach ($columns as $name => $column) {
217 2
            $presentation = null;
218 2
            if (array_key_exists($name, $fieldsPresentation)) {
219 2
                $presentation = $fieldsPresentation[$name];
220 2
            }
221
222
            $config = [
223 2
                'name'         => $name,
224 2
                'presentation' => $presentation,
225 2
                'form_type'    => null,
226 2
                'validation'   => null,
227
                'functions'    => null
228 2
            ];
229
230 2
            $fields[$arrayKey][] = $this->fieldFactory
231 2
                ->setColumn($column)
232 2
                ->setConfig($config)
233 2
                ->get();
234 2
        }
235
236 2
        return $fields;
237
    }
238
239
    /**
240
     * @param string|null $arrayKey
241
     * @return array
242
     * @throws AbstractorException
243
     */
244 2 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...
245
    {
246 2
        $columns = $this->getColumns('detail');
247
248 2
        $fieldsPresentation = $this->getConfigValue('fields_presentation') ? : [];
249
250 2
        $fields = array();
251 2
        foreach ($columns as $name => $column) {
252 2
            $presentation = null;
253 2
            if (array_key_exists($name, $fieldsPresentation)) {
254 2
                $presentation = $fieldsPresentation[$name];
255 2
            }
256
257
            $config = [
258 2
                'name'         => $name,
259 2
                'presentation' => $presentation,
260 2
                'form_type'    => null,
261 2
                'validation'   => null,
262
                'functions'    => null
263 2
            ];
264
265 2
            $fields[$arrayKey][] = $this->fieldFactory
266 2
                ->setColumn($column)
267 2
                ->setConfig($config)
268 2
                ->get();
269 2
        }
270
271 2
        return $fields;
272
    }
273
274
    /**
275
     * @param bool|null $withForeignKeys
276
     * @param string|null $arrayKey
277
     * @return array
278
     * @throws AbstractorException
279
     */
280 4
    public function getEditFields($withForeignKeys = false, $arrayKey = 'main')
281
    {
282 4
        $columns = $this->getColumns('edit', $withForeignKeys);
0 ignored issues
show
Bug introduced by
It seems like $withForeignKeys defined by parameter $withForeignKeys on line 280 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...
283
284 4
        $this->readConfig('edit');
285
286 4
        $fields = array();
287 4
        foreach ($columns as $name => $column) {
288 4
            if (! in_array($name, $this->getReadOnlyColumns())) {
289 4
                $presentation = null;
290 4
                if (array_key_exists($name, $this->fieldsPresentation)) {
291
                    $presentation = $this->fieldsPresentation[$name];
292
                }
293
294
                $config = [
295 4
                    'name'         => $name,
296 4
                    'presentation' => $presentation,
297 4
                    'form_type'    => null,
298 4
                    'validation'   => null,
299
                    'functions'    => null
300 4
                ];
301
302 4
                $config = $this->setConfig($config, $name);
303
304 4
                $field = $this->fieldFactory
305 4
                    ->setColumn($column)
306 4
                    ->setConfig($config)
307 4
                    ->get();
308
309 4
                if (! empty($this->instance) && ! empty($this->instance->getAttribute($name))) {
310
                    $field->setValue($this->instance->getAttribute($name));
311
                }
312
313 4
                $fields[$arrayKey][$name] = $field;
314
315 4 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...
316 4
                    $field = $this->fieldFactory
317 4
                        ->setColumn($column)
318 4
                        ->setConfig([
319 4
                            'name'         => $name . '__delete',
320 4
                            'presentation' => null,
321 4
                            'form_type'    => 'checkbox',
322 4
                            'no_validate'  => true,
323
                            'functions'    => null
324 4
                        ])
325 4
                        ->get();
326 4
                    $fields[$arrayKey][$name . '__delete'] = $field;
327 4
                }
328 4
            }
329 4
        }
330
331 4
        return $fields;
332
    }
333
334 4
    protected function getReadOnlyColumns()
335
    {
336 4
        $columns = [LaravelModel::CREATED_AT, LaravelModel::UPDATED_AT];
337
338 4
        $columns[] = $this->dbal->getModel()->getKeyName();
339
340 4
        return $columns;
341
    }
342
343
    /**
344
     * @param string $action
345
     * @return ElementInterface
346
     */
347 2
    public function getForm($action)
348
    {
349 2
        $this->generator->setModelFields($this->getEditFields());
350 2
        $this->generator->setRelatedModelFields($this->getRelations());
351
352 2
        return $this->generator->getForm($action);
353
    }
354
355
    /**
356
     * @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...
357
     * @return mixed
358
     */
359 1
    public function persist(Request $request)
360
    {
361
        /** @var \ANavallaSuiza\Laravel\Database\Contracts\Manager\ModelManager $modelManager */
362 1
        $modelManager = App::make('ANavallaSuiza\Laravel\Database\Contracts\Manager\ModelManager');
363 1
        if (! empty($this->instance)) {
364
            $item = $this->instance;
365
        } else {
366 1
            $item = $modelManager->getModelInstance($this->getModel());
367
        }
368
369
370 1
        $fields = $this->getEditFields(true);
371 1
        if (empty($fields['main']) && $this->getRelations()->isEmpty()) {
372
            return;
373
        }
374
375 1
        if (! empty($fields['main'])) {
376 1
            $skipNext = false;
377 1
            foreach ($fields['main'] as $key => $field) {
378
                /** @var FieldContract $field */
379 1
                if ($skipNext === true) {
380
                    $skipNext = false;
381
                    continue;
382
                }
383 1
                $fieldName = $field->getName();
384 1
                $requestValue = $request->input("main.{$fieldName}");
385
386 1
                if (get_class($field->getFormField()) === \FormManager\Fields\Checkbox::class) {
387
                    if (empty($requestValue)) {
388
                        // Unchecked checkboxes are not sent, so we force setting them to false
389
                        $requestValue = false;
390
                    }
391
                }
392
393 1
                if (get_class($field->getFormField()) === \FormManager\Fields\File::class) {
394
                    $handleResult = $this->handleField($request, $item, $fields['main'], 'main', $fieldName);
395
                    if (! empty($handleResult['skipNext'])) {
396
                        $skipNext = $handleResult['skipNext'];
397
                    }
398
                    if (! empty($handleResult['requestValue'])) {
399
                        $requestValue = $handleResult['requestValue'];
400
                    }
401
                }
402
403
404 1
                if (! $field->saveIfEmpty() && empty($requestValue)) {
405
                    continue;
406
                }
407
408 1
                $item->setAttribute(
409 1
                    $fieldName,
410 1
                    $field->applyFunctions($requestValue)
411 1
                );
412 1
            }
413 1
        }
414
415 1
        $item->save();
416
417 1
        $this->setInstance($item);
418
419
420 1
        if (! empty($relations = $this->getRelations())) {
421 1
            foreach ($relations as $relationKey => $relation) {
422 1
                if ($relation instanceof Collection) {
423
                    $input = $request->input($relationKey);
424
                    $relation->get('relation')->persist($input, $request);
425
                } else {
426 1
                    $relation->persist($request->input($relationKey), $request);
427
                }
428 1
            }
429 1
        }
430
431 1
        return $item;
432
    }
433
434
    /**
435
     * @return array
436
     */
437 1
    public function getValidationRules()
438
    {
439 1
        return $this->generator->getValidationRules();
440
    }
441
}
442