Passed
Push — master ( 5b2592...ed3d59 )
by Alex
03:16
created

FieldsAlgorithms   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 356
Duplicated Lines 0 %

Importance

Changes 3
Bugs 1 Features 1
Metric Value
eloc 98
dl 0
loc 356
rs 8.96
c 3
b 1
f 1
wmc 43

16 Methods

Rating   Name   Duplication   Size   Complexity  
A getSecureValue() 0 5 1
A getExternalValue() 0 7 2
B getTypedValue() 0 30 6
A getDateValue() 0 6 2
A removeField() 0 6 2
A getValuesForPrefix() 0 11 3
A fetchField() 0 8 4
A getSecureValues() 0 13 3
A fetchCustomField() 0 17 5
A __construct() 0 11 2
A constructControl() 0 19 4
A getEntityName() 0 3 1
A getCompiledField() 0 5 1
A getObject() 0 3 1
A setSessionId() 0 3 1
A initObject() 0 11 5

How to fix   Complexity   

Complex Class

Complex classes like FieldsAlgorithms 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.

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 FieldsAlgorithms, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace Mezon\Gui;
3
4
use Mezon\Gui\Field\InputFile;
5
use Mezon\Gui\Field\InputDate;
6
use Mezon\Gui\Field\CustomField;
7
use Mezon\Gui\FormBuilder\FormHeader;
8
use Mezon\Gui\Field\LabelField;
9
use Mezon\Gui\Field\Select;
10
use Mezon\Gui\Field\InputText;
11
use Mezon\Gui\Field\Textarea;
12
use Mezon\Gui\FormBuilder\RowsField;
13
use Mezon\Security\Security;
14
use Mezon\FieldsSet;
15
16
/**
17
 * Class FieldsAlgorithms
18
 *
19
 * @package Gui
20
 * @subpackage FieldsAlgorithms
21
 * @author Dodonov A.A.
22
 * @version v.1.0 (2019/08/08)
23
 * @copyright Copyright (c) 2019, http://aeon.su
24
 */
25
26
/**
27
 * Class constructs forms
28
 */
29
class FieldsAlgorithms extends FieldsSet
30
{
31
32
    /**
33
     * List of control objects
34
     *
35
     * @var array
36
     */
37
    private $fieldObjects = [];
38
39
    /**
40
     * Entity name
41
     *
42
     * @var string
43
     */
44
    private $entityName = false;
45
46
    /**
47
     * Session Id
48
     *
49
     * @var string
50
     */
51
    private $sessionId = '';
52
53
    /**
54
     * Supported types
55
     *
56
     * @var array
57
     */
58
    public static $typeMap = [
59
        'file' => InputFile::class,
60
        'date' => InputDate::class,
61
        'custom' => CustomField::class,
62
        'header' => FormHeader::class,
63
        'label' => LabelField::class
64
    ];
65
66
    /**
67
     * Constructor
68
     *
69
     * @param array $fields
70
     *            list of all fields
71
     * @param string $entityName
72
     *            entity name
73
     */
74
    public function __construct(array $fields = [], string $entityName = '')
75
    {
76
        parent::__construct($fields);
77
78
        $this->entityName = $entityName;
79
80
        foreach ($this->getFields() as $name => $field) {
81
            $field['name'] = $name;
82
            $field['name-prefix'] = $this->entityName;
83
84
            $this->fieldObjects[$name] = $this->initObject($field);
85
        }
86
    }
87
88
    /**
89
     * Returning date value
90
     *
91
     * @param string $value
92
     *            value to be made secure
93
     * @return string secure value
94
     */
95
    protected function getDateValue(string $value): string
96
    {
97
        if ($value == '""') {
98
            return '';
99
        } else {
100
            return date('Y-m-d', strtotime($value));
101
        }
102
    }
103
104
    /**
105
     * Returning date value
106
     *
107
     * @param array $value
108
     *            value to be made secure
109
     * @return array secure value
110
     */
111
    protected function getExternalValue(array $value): array
112
    {
113
        foreach ($value as $i => $item) {
114
            $value[$i] = intval($item);
115
        }
116
117
        return $value;
118
    }
119
120
    /**
121
     * Method returns typed value
122
     *
123
     * @param string $type
124
     *            of the field
125
     * @param string|array $value
126
     *            of the field
127
     * @param bool $storeFiles
128
     *            need the uploaded file to be stored
129
     * @return mixed secured value
130
     */
131
    public function getTypedValue(string $type, $value, bool $storeFiles = true)
132
    {
133
        $result = '';
134
135
        switch ($type) {
136
            case ('integer'):
137
                $result = intval($value);
138
                break;
139
140
            case ('string'):
141
                $result = Security::getStringValue($value);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type array; however, parameter $value of Mezon\Security\Security::getStringValue() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

141
                $result = Security::getStringValue(/** @scrutinizer ignore-type */ $value);
Loading history...
142
                break;
143
144
            case ('file'):
145
                $result = Security::getFileValue($value, $storeFiles);
146
                break;
147
148
            case ('date'):
149
                $result = $this->getDateValue($value);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type array; however, parameter $value of Mezon\Gui\FieldsAlgorithms::getDateValue() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

149
                $result = $this->getDateValue(/** @scrutinizer ignore-type */ $value);
Loading history...
150
                break;
151
152
            case ('external'):
153
                $result = $this->getExternalValue($value);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type string; however, parameter $value of Mezon\Gui\FieldsAlgorithms::getExternalValue() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

153
                $result = $this->getExternalValue(/** @scrutinizer ignore-type */ $value);
Loading history...
154
                break;
155
156
            default:
157
                throw (new \Exception('Undefined type "' . $type . '"'));
158
        }
159
160
        return $result;
161
    }
162
163
    /**
164
     * Getting secure value
165
     *
166
     * @param string $field
167
     *            field name
168
     * @param mixed $value
169
     *            field value
170
     * @param bool $storeFiles
171
     *            should we store files
172
     * @return mixed secure value of the field
173
     */
174
    public function getSecureValue(string $field, $value, bool $storeFiles = true)
175
    {
176
        $this->validateFieldExistance($field);
177
178
        return $this->getTypedValue($this->fieldObjects[$field]->getType(), $value, $storeFiles);
179
    }
180
181
    /**
182
     * Getting secure values
183
     *
184
     * @param string $field
185
     *            field name
186
     * @param mixed $values
187
     *            field values
188
     * @param bool $storeFiles
189
     *            should we store files
190
     * @return mixed secure values of the field or one value
191
     */
192
    public function getSecureValues(string $field, $values, bool $storeFiles = true)
193
    {
194
        $return = [];
195
196
        if (is_array($values)) {
197
            foreach ($values as $i => $value) {
198
                $return[$i] = $this->getSecureValue($field, $value, $storeFiles);
199
            }
200
        } else {
201
            $return = $this->getSecureValue($field, $values, $storeFiles);
202
        }
203
204
        return $return;
205
    }
206
207
    /**
208
     * Method returns field wich names are started from $prefix
209
     *
210
     * @param string $prefix
211
     *            of the fields to be fetched
212
     * @param bool $storeFiles
213
     *            should we store files
214
     * @return array fetched fields
215
     */
216
    public function getValuesForPrefix(string $prefix, bool $storeFiles = true): array
217
    {
218
        $records = [];
219
220
        foreach (array_keys($this->fieldObjects) as $name) {
221
            if (isset($_POST[$prefix . $name])) {
222
                $records[$name] = $this->getSecureValues($name, $_POST[$prefix . $name], $storeFiles);
223
            }
224
        }
225
226
        return $records;
227
    }
228
229
    /**
230
     * Method removes field
231
     *
232
     * @param string $fieldName
233
     *            field name
234
     */
235
    public function removeField($fieldName): void
236
    {
237
        parent::removeField($fieldName);
238
239
        if (isset($this->fieldObjects[$fieldName])) {
240
            unset($this->fieldObjects[$fieldName]);
241
        }
242
    }
243
244
    /**
245
     * Method fetches returns custom fields for saving
246
     *
247
     * @param array $record
248
     *            record to be extended
249
     * @param string $name
250
     *            name od the field
251
     * @return array extended record
252
     */
253
    public function fetchCustomField(array &$record, string $name): array
254
    {
255
        if (! isset($this->fieldObjects[$name])) {
256
            return $record;
257
        }
258
259
        $nestedFields = $this->fieldObjects[$name]->getFields();
260
261
        foreach ($nestedFields as $name => $field) {
262
            $fieldName = $this->entityName === '' ? $name : $this->entityName . '-' . $name;
263
264
            if (isset($_POST[$fieldName])) {
265
                $record[$name] = $this->getTypedValue($field['type'], $_POST[$fieldName], true);
266
            }
267
        }
268
269
        return $record;
270
    }
271
272
    /**
273
     * Method fetches submitted field
274
     *
275
     * @param array $record
276
     *            record to be extended
277
     * @param string $name
278
     *            name od the field
279
     */
280
    public function fetchField(array &$record, string $name):void
281
    {
282
        if (isset($_POST[$this->entityName . '-' . $name])) {
283
            $record[$name] = $this->getSecureValue($name, $_POST[$this->entityName . '-' . $name]);
284
        } elseif (isset($_FILES[$this->entityName . '-' . $name])) {
285
            $record[$name] = $this->getSecureValue($name, $_FILES[$this->entityName . '-' . $name]);
286
        } elseif ($this->hasCustomFields()) {
287
            $record = $this->fetchCustomField($record, $name);
288
        }
289
    }
290
291
    /**
292
     * Factory method for creating controls
293
     *
294
     * @param array $field
295
     *            field description
296
     * @return Field|Control constructed control
297
     */
298
    protected function constructControl(array $field)
299
    {
300
        if (isset($field['items'])) {
301
            return new Select($field);
302
        } elseif (isset($field['type'])) {
303
            if (in_array($field['type'], array_keys(self::$typeMap))) {
304
                $className = self::$typeMap[$field['type']];
305
306
                $field['session-id'] = $this->sessionId;
307
308
                /** @var Control|Field $control */
309
                $control = new $className($field);
310
311
                return $control;
312
            } else {
313
                return new InputText($field);
314
            }
315
        } else {
316
            throw (new \Exception('Can not define control\'s type', - 1));
317
        }
318
    }
319
320
    /**
321
     * Method inits control
322
     *
323
     * @param array $field
324
     *            field
325
     * @return mixed control
326
     */
327
    protected function initObject(array $field)
328
    {
329
        if (isset($field['control']) && $field['control'] == 'textarea') {
330
            $control = new Textarea($field);
331
        } elseif (isset($field['type']) && $field['type'] == 'rows') {
332
            $control = new RowsField($field['type']['rows'], $this->entityName);
333
        } else {
334
            $control = $this->constructControl($field);
335
        }
336
337
        return $control;
338
    }
339
340
    /**
341
     * Method returns field object
342
     *
343
     * @param string $name
344
     *            field name
345
     * @return Field field object
346
     */
347
    public function getObject(string $name): Field
348
    {
349
        return $this->fieldObjects[$name];
350
    }
351
352
    /**
353
     * Method compiles field DOM
354
     *
355
     * @param string $name
356
     *            field name
357
     * @return string compiled HTML
358
     */
359
    public function getCompiledField(string $name): string
360
    {
361
        $control = $this->getObject($name);
362
363
        return $control->html();
364
    }
365
366
    /**
367
     * Method returns entity name
368
     *
369
     * @return string entity name
370
     */
371
    public function getEntityName(): string
372
    {
373
        return $this->entityName;
374
    }
375
376
    /**
377
     * Method sets session id
378
     *
379
     * @param string $sessionId
380
     *            new session id
381
     */
382
    public function setSessionId(string $sessionId): void
383
    {
384
        $this->sessionId = $sessionId;
385
    }
386
}
387