Completed
Push — master ( 386a3a...dd6ab7 )
by Mihail
02:44
created

Model::validateRecursive()   D

Complexity

Conditions 20
Paths 197

Size

Total Lines 92
Code Lines 57

Duplication

Lines 0
Ratio 0 %

Importance

Changes 12
Bugs 4 Features 0
Metric Value
c 12
b 4
f 0
dl 0
loc 92
rs 4.4507
cc 20
eloc 57
nc 197
nop 5

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Ffcms\Core\Arch;
4
5
use Ffcms\Core\App;
6
use Ffcms\Core\Exception\SyntaxException;
7
use Dflydev\DotAccessData\Data as DotData;
8
use Ffcms\Core\Helper\Type\Obj;
9
use Ffcms\Core\Helper\Type\Str;
10
use Ffcms\Core\Traits\DynamicGlobal;
11
use Ffcms\Core\Traits\ModelValidator;
12
13
class Model
14
{
15
    use DynamicGlobal, ModelValidator;
16
17
    public function __construct()
18
    {
19
        $this->before();
20
    }
21
22
    public function before() {}
23
24
    /**
25
     * Get label value by variable name
26
     * @param string $param
27
     * @return mixed
28
     */
29
    final public function getLabel($param)
30
    {
31
        $labels = $this->labels();
32
        $response = null;
0 ignored issues
show
Unused Code introduced by
$response 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...
33
        // maybe array-dotted declaration?
34
        if (Str::contains('.', $param)) {
35
            // not defined for all array-dotted nesting?
36
            if (Str::likeEmpty($labels[$param])) {
37
                // lets set default array label (before first dot-separation)
38
                $response = $labels[Str::firstIn($param, '.')];
39
            } else {
40
                $response = $labels[$param];
41
            }
42
        } else {
43
            $response = $labels[$param];
44
        }
45
46
        return (Str::likeEmpty($response) ? Str::replace('.', ' ', Str::splitCamelCase($param)) : $response);
47
    }
48
49
    /**
50
     * Set attribute labels for model variables
51
     * @return array
52
     */
53
    public function labels()
54
    {
55
        return [];
56
    }
57
58
    /**
59
     * Set of model validation rules
60
     * @return array
61
     */
62
    public function rules()
63
    {
64
        return [];
65
    }
66
67
    /**
68
     * Validate defined rules in app
69
     * @return bool
70
     * @throws SyntaxException
71
     */
72
    final public function validate()
73
    {
74
        // get all rules as array from method rules()
75
        $rules = $this->rules();
76
        // get default values of attributes
77
        $defaultAttr = $this->getAllProperties();
78
79
        // start validation as save boolean value
80
        $success = $this->runValidate($rules);
81
82
        // get not-passed validation fields as array
83
        $badAttributes = $this->getBadAttribute();
84
        // prevent warnings
85
        if (Obj::isArray($badAttributes) && count($badAttributes) > 0) {
86
            foreach ($badAttributes as $attr) {
0 ignored issues
show
Bug introduced by
The expression $badAttributes of type null|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
87
                if (Str::contains('.', $attr)) { // sounds like dot-separated array attr
88
                    $attrName = strstr($attr, '.', true); // get attr name
89
                    $attrArray = trim(strstr($attr, '.'), '.'); // get dot-based array path
90
91
                    $defaultValue = new DotData($defaultAttr); // load default attr
92
93
                    $dotData = new DotData($this->{$attrName}); // load local attr variable
94
                    $dotData->set($attrArray, $defaultValue->get($attr)); // set to local prop. variable default value
95
96
                    $this->{$attrName} = $dotData->export(); // export to model
97
                } else {
98
                    $this->{$attr} = App::$Security->strip_tags($defaultAttr[$attr]); // just set ;)
99
                }
100
                // add message about wrong attribute to session holder, later display it
101
                $attrLabel = $attr;
102
                if ($this->getLabel($attr) !== null) {
103
                    $attrLabel = $this->getLabel($attr);
104
                }
105
                App::$Session->getFlashBag()->add('warning', __('Field "%field%" is incorrect', ['field' => $attrLabel]));
106
            }
107
        }
108
109
        return $success;
110
    }
111
112
    /**
113
     * Export model values for safe-using in HTML pages.
114
     * @return $this
115
     */
116
    final public function export()
117
    {
118
        $properties = get_object_vars($this);
119
        foreach ($properties as $var => $value) {
120
            if (Str::startsWith('_', $var)) { // ignore $_var
121
                continue;
122
            }
123
            $this->{$var} = App::$Security->secureHtml($value);
124
        }
125
        return $this;
126
    }
127
128
129
    /**
130
     * Get all properties for current model in key=>value array
131
     * @return array|null
132
     */
133
    public function getAllProperties()
134
    {
135
        $properties = null;
136
        foreach ($this as $property => $value) {
0 ignored issues
show
Bug introduced by
The expression $this of type this<Ffcms\Core\Arch\Model> is not traversable.
Loading history...
137
            if (Str::startsWith('_', $property)) {
138
                continue;
139
            }
140
            $properties[$property] = $value;
141
        }
142
        return $properties;
143
    }
144
145
    /**
146
     * Get validation rules for field
147
     * @param string $field
148
     * @return array
149
     */
150
    final public function getValidationRule($field)
151
    {
152
        $rules = $this->rules();
153
        $response = [];
154
155
        foreach ($rules as $rule) {
156
            if (Obj::isArray($rule[0])) { // 2 or more rules [['field1', 'field2'], 'filter', 'filter_argv']
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
157
                foreach ($rule[0] as $tfield) {
158
                    if ($tfield == $field) {
159
                        $response[$rule[1]] = $rule[2]; // ['min_length' => 1, 'required' => null]
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
160
                    }
161
                }
162
            } else { // 1 rule ['field1', 'filter', 'filter_argv']
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
163
                if ($rule[0] === $field) {
164
                    $response[$rule[1]] = $rule[2];
165
                }
166
            }
167
        }
168
169
        return $response;
170
    }
171
172
}