Completed
Push — master ( 11675b...1688ee )
by A
04:37
created

AbstractField::parseBaseData()   D

Complexity

Conditions 10
Paths 256

Size

Total Lines 53
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 1 Features 0
Metric Value
c 5
b 1
f 0
dl 0
loc 53
rs 4.8
cc 10
eloc 26
nc 256
nop 1

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 Code4\Forms\Fields;
4
5
use Code4\View\Attributes;
6
7
abstract class AbstractField implements FieldsInterface {
8
9
    protected $name;
10
11
    protected $title;
12
13
    protected $label;
14
15
    /**
16
     * @var string Index elementu w pliku konfiguracyjnym
17
     */
18
    protected $fieldName;
19
20
    protected $id;
21
22
    protected $attributes;
23
24
    /**
25
     * List of all properties
26
     * @var array
27
     */
28
    protected $properties = [];
29
30
    protected $value;
31
32
    protected $rules;
33
    protected $customRules;
34
35
    protected $optionKeys;
36
37
    protected $_viewNamespace = 'forms::';
38
    protected $_view; //Widok do załadowania
39
    protected $_type; //Typ elementu (np text, password) ten sam widok tylko inny typ
40
41
    /**
42
     * Pola specjalne dla których nie nadajemy automatycznie klas (form-control) itp.
43
     * @var array
44
     */
45
    protected $specialFields = [
46
        'separator', 'header', 'htmlTag'
47
    ];
48
49
    /**
50
     * Constructs base element
51
     * @param $fieldName
52
     * @param array $data
53
     */
54
    public function __construct($fieldName, $data = []) {
55
        $this->fieldName = $fieldName;
56
        $this->parseBaseData($data);
57
    }
58
59
    /**
60
     * Parses base data passed to field. More field specific data has to be parsed in classes extending AbstractField
61
     * @param array $data
62
     */
63
    public function parseBaseData($data) {
64
        //Attributes
65
        if (array_key_exists('attributes', $data)) {
66
            $this->attributes($data['attributes']);
67
            unset($data['attributes']);
68
        }
69
70
        //Name
71
        if (array_key_exists('name', $data)) {
72
            $this->name = $data['name'];
73
            unset($data['name']);
74
        } else {
75
            $this->name = $this->fieldName;
76
        }
77
78
        //Pre set title
79
        $this->title($this->name);
80
81
        //Values
82
        if (array_key_exists('value', $data)) {
83
            $this->setValue($data['value']);
84
            unset($data['value']);
85
        }
86
87
        //Rules
88
        if (array_key_exists('rules', $data)) {
89
            $this->rules($data['rules']);
90
            unset($data['rules']);
91
        }
92
93
        //Setting remaining properties
94
        //Title
95
        if (array_key_exists('title', $data)) {
96
            $this->title($data['title']);
97
            unset($data['title']);
98
        }
99
100
        //Title
101
        if (array_key_exists('label', $data)) {
102
            $this->label($data['label']);
0 ignored issues
show
Documentation Bug introduced by
The method label does not exist on object<Code4\Forms\Fields\AbstractField>? 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...
103
            unset($data['label']);
104
        }
105
106
        foreach ($data as $propertyName => $value) {
107
            $this->setProperty($propertyName, $value);
108
        }
109
110
        //If classes not set - default = form-control
111
        if (!$this->attributes()->has('class') && !in_array($this->_type,$this->specialFields)) {
112
            $this->attributes()->add('class', 'form-control');
113
        }
114
115
    }
116
117
    /**
118
     * Gets or sets attributes
119
     * @param null|array $data
120
     * @return Attributes
121
     */
122
    public function attributes($data = null) {
123
        if ($data !== null) {
124
            $this->attributes = new Attributes($data);
125
        }
126
        if (is_null($this->attributes)) {
127
            $this->attributes = new Attributes();
128
        }
129
        return $this->attributes;
130
    }
131
132
    /**
133
     * Sets or gets value
134
     * @param $value
135
     * @param $key
136
     * @return FieldsInterface|mixed $this
137
     */
138
    public function value($value = null, $key = null) {
139
140
        if ($value === null) {
141
            if (is_array($this->value) && count($this->value) == 1) {
142
                return (string)$this->value[0];
143
            }
144
            if (is_array($this->value) && count($this->value) > 1) {
145
                return $this->value;
146
            }
147
            return (string)$this->value;
148
        }
149
150
        // Store value as array if string or numeric
151
        if (is_string($value) || is_numeric($value) || is_bool($value)) {
152
            $this->value = [$value];
153
            return $this;
154
        }
155
156
        //If value is assoc array store only keys
157
        //Usually key=>value pairs represent value=>description eg. in select fields
158
        if (is_array($value) && $this->isAssoc($value)) {
159
            $this->value = [];
160
            foreach ($value as $k=>$v) {
161
                $this->value[] = $k;
162
            }
163
            return $this;
164
        }
165
166
        //Normal array of values (checkboxes)
167
        if (is_array($value)) {
168
            $this->value = $value;
169
            return $this;
170
        }
171
172
        //Values are in object. To extract them we need property names (keys)
173
        //$optionKeys is used also to extract value=>description for option field
174
        //So in config $optionsKeys is an 2 element array
175
        if (is_object($value)) {
176
            if (is_null($key) && count($this->optionKeys) == 2) {
177
                $key = $this->optionKeys[0];
178
            }
179
180
            //If still no key - try using name as key??
181
            if (is_null($key)) {
182
                $key = $this->name;
183
            }
184
185
            if (!$key) {
186
                return $this;
187
            }
188
189
            $this->value = [];
190
            //iterating over $value object because it may be an collection eg. results from DB
191
            foreach($value as $objectKey=>$o) {
192
                if (is_object($o) && property_exists($o, $key)) {
193
                    $this->value[] = $o->$key;
194
                } else {
195
                    //If passed object is not an iterable collection loop will iterate over properties
196
                    if ($objectKey == $key) {
197
                        $this->value[] = $o;
198
                        return $this;
199
                    }
200
                }
201
            }
202
            return $this;
203
        }
204
        return $this;
205
    }
206
207
    /**
208
     * Shortcut for values() method. Used to set value of field after initiation from config. Is needed for fields
209
     * with checked traits where method is overrided
210
     * @param null $value
211
     * @param null $key
212
     * @return FieldsInterface|mixed
213
     */
214
    public function setValue($value = null, $key = null) {
215
        return $this->value($value = null, $key = null);
216
    }
217
218
    /**
219
     * @param null $id
220
     * @return string|FieldsInterface
221
     */
222 View Code Duplication
    public function id($id = null) {
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...
223
        if (is_null($id)) {
224
            return $this->id;
225
        } else {
226
            $this->id = $id;
227
        }
228
        return $this;
229
    }
230
231
    /**
232
     * @param null $name
233
     * @return string|FieldsInterface
234
     */
235 View Code Duplication
    public function name($name = null) {
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...
236
        if (is_null($name)) {
237
            return $this->name;
238
        } else {
239
            $this->name = $name;
240
        }
241
        return $this;
242
    }
243
244
    /**
245
     * @param null $title
246
     * @return string|FieldsInterface
247
     */
248
    public function title($title = null) {
249
        if (is_null($title)) {
250
            return $this->title;
251
        } else {
252
            $this->title = $title;
253
        }
254
        return $this;
255
    }
256
257
    /**
258
     * @param null $_type
259
     * @return string|FieldsInterface
260
     */
261
    public function _type($_type = null) {
262
        if (is_null($_type)) {
263
            return $this->_type;
264
        } else {
265
            $this->_type = $_type;
266
        }
267
        return $this;
268
    }
269
270
    /**
271
     * Sets or retrives rules for field and child fields
272
     * @param null $rules
273
     * @return string|FieldsInterface
274
     */
275
    public function rules($rules = null) {
276
        if (is_null($rules)) {
277
            return $this->rules;
278
        } else {
279
            $this->rules = $rules;
280
        }
281
        return $this;
282
    }
283
284
    /**
285
     * Returns name=>rules array for validator
286
     * @return array
287
     */
288
    public function getRulesForValidator() {
289
        if ($this->rules == '') {
290
            return [];
291
        }
292
293
        return [$this->getDotNotatedName() => $this->rules];
294
    }
295
296
    /**
297
     * Returns name of field in 'dot' notation. Eg. field[] -> field, field[test] -> field.test
298
     * @return string
299
     */
300
    public function getDotNotatedName() {
301
        $name = $this->name();
302
303
        //multi value fields are validated as single value
304
        $name = str_replace('[]','',$name);
305
306
        //if in config field field is named field[test][tes2] replace that to: field.test.test2
307
        $pattern = '/\[{1}([^\]]+)\]{1}/';
308
        //preg_replace("/\[{1}([^\]]+)\]{1}/", ".$1", $input_lines);
309
        $name = preg_replace($pattern, ".$1", $name);
310
        return $name;
311
    }
312
313
    /**
314
     * Adds rule if it don't exist
315
     * @param $rule
316
     * @return $this
317
     */
318 View Code Duplication
    public function addRule($rule) {
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...
319
        $rules = explode("|", $this->rules);
320
        if (array_search($rule, $rules) === false) {
321
            array_push($rules, $rule);
322
        }
323
        $this->rules = trim(implode("|", $rules), "|");
324
        return $this;
325
    }
326
327
    /**
328
     * Removes rule from field
329
     * @param $rule
330
     * @return $this
331
     */
332 View Code Duplication
    public function removeRule($rule) {
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...
333
        $rules = explode("|", $this->rules);
334
        if (($index = array_search($rule, $rules)) !== false) {
335
            unset($rules[$index]);
336
        }
337
        $this->rules = trim(implode("|", $rules), "|");
338
        return $this;
339
    }
340
341
    /**
342
     * @param null $customRules
343
     * @return string|FieldsInterface
344
     */
345
    public function customRules($customRules = null) {
346
        if (is_null($customRules)) {
347
            return $this->customRules;
348
        } else {
349
            $this->customRules[] = $customRules;
350
        }
351
        return $this;
352
    }
353
354
    /**
355
     * Renders element
356
     * @return \Illuminate\View\View
357
     */
358
    public function render() {
359
        return view($this->_viewNamespace.$this->_view, ['el'=>$this])->render();
360
    }
361
362
    /**
363
     * @return string
364
     */
365
    public function __toString() {
366
        return $this->render();
367
    }
368
369
    /**
370
     * Sets property
371
     * @param string $propertyName
372
     * @param mixed $value
373
     * @return $this
374
     */
375
    public function setProperty($propertyName, $value) {
376
        if (property_exists($this, $propertyName)) {
377
            $this->$propertyName = $value;
378
        } else {
379
            $this->properties[$propertyName] = $value;
380
        }
381
        return $this;
382
    }
383
384
    /**
385
     * Gets property
386
     * @param string $propertyName
387
     * @return mixed
388
     */
389
    public function getProperty($propertyName) {
390
        if (property_exists($this, $propertyName)) {
391
            return $this->$propertyName;
392
        } else
393
        {
394
            return array_key_exists($propertyName, $this->properties) ? $this->properties[$propertyName] : '';
395
        }
396
    }
397
398
    /**
399
     * Magic methods
400
     * @param $method
401
     * @param $args
402
     * @return AbstractField|mixed
403
     */
404
    public function __call($method, $args) {
405
        if (count($args) == 0) {
406
            return $this->getProperty($method);
407
        }
408
409
        if (count($args) == 1) {
410
            return $this->setProperty($method, $args[0]);
411
        }
412
    }
413
414
415
    /**
416
     * Checks if passed array is associative or indexed
417
     * @param $arr
418
     * @return bool
419
     */
420
    private function isAssoc($arr) {
421
        return array_keys($arr) !== range(0, count($arr) - 1);
422
    }
423
424
425
}