Test Setup Failed
Push — master ( 4c1de8...3a35d5 )
by Gabriel
02:10
created

AbstractForm   F

Complexity

Total Complexity 60

Size/Duplication

Total Lines 415
Duplicated Lines 2.17 %

Coupling/Cohesion

Components 7
Dependencies 10

Test Coverage

Coverage 24.31%

Importance

Changes 0
Metric Value
wmc 60
lcom 7
cbo 10
dl 9
loc 415
ccs 35
cts 144
cp 0.2431
rs 3.6
c 0
b 0
f 0

34 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A init() 0 4 1
A initAction() 0 6 2
A setAction() 0 4 1
A postInit() 0 3 1
A __get() 0 9 2
A addButton() 0 6 1
A newButton() 0 10 1
A getButton() 0 8 2
A getButtons() 0 4 1
A setOption() 0 7 1
A getOption() 9 9 2
A setMethod() 0 9 2
A execute() 0 8 2
A submited() 0 9 3
A processRequest() 0 10 2
A validate() 0 8 2
B getDataFromRequest() 0 26 9
A processValidation() 0 9 3
A isValid() 0 4 2
A process() 0 3 1
A setRendererType() 0 6 1
A setRendererClass() 0 7 1
A setRenderer() 0 4 1
A getNewRenderer() 0 9 1
A getCache() 0 4 1
A setCache() 0 4 1
A isCache() 0 4 1
A getName() 0 4 1
A __toString() 0 10 2
A render() 0 4 1
A getRenderer() 0 8 2
A getControllerView() 0 8 2
A getData() 0 12 3

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

1
<?php
2
3
namespace Nip\Form;
4
5
use Nip\Form\Renderer\AbstractRenderer;
6
use Nip\Form\Traits\HasAttributesTrait;
7
use Nip\Form\Traits\HasClassTrait;
8
use Nip\Form\Traits\HasDisplayGroupsTrait;
9
use Nip\Form\Traits\HasElementsTrait;
10
use Nip\Form\Traits\HasErrorsTrait;
11
use Nip\Form\Traits\MagicMethodElementsFormTrait;
12
use Nip\Form\Traits\MessagesTrait;
13
use Nip\Form\Traits\NewElementsMethods;
14
use Nip\View;
15
use Nip_Form_Button_Abstract as ButtonAbstract;
16
use Nip_Form_Element_Abstract as ElementAbstract;
17
18
/**
19
 * Class AbstractForm
20
 *
21
 */
22
abstract class AbstractForm
23
{
24
    use MagicMethodElementsFormTrait;
25
    use HasElementsTrait;
26
    use NewElementsMethods;
27
    use HasDisplayGroupsTrait;
28
    use MessagesTrait;
29
    use HasErrorsTrait;
30
    use HasAttributesTrait;
31
    use HasClassTrait;
32
33
    const ENCTYPE_URLENCODED = 'application/x-www-form-urlencoded';
34
    const ENCTYPE_MULTIPART = 'multipart/form-data';
35
36
    /**
37
     * @var array
38
     */
39
    protected $methods = ['delete', 'get', 'post', 'put'];
40
41
    protected $_options = [];
42
    protected $_buttons;
43
44
    protected $_decorators = [];
45
    protected $_renderer;
46
    protected $_cache;
47
48
    protected $controllerView = false;
49
50
    /**
51
     * AbstractForm constructor.
52
     */
53 11
    public function __construct()
54
    {
55 11
        $this->init();
56 11
        $this->postInit();
57 11
    }
58
59 11
    public function init()
60
    {
61 11
        $this->initAction();
62 11
    }
63
64 11
    protected function initAction()
65
    {
66 11
        if (function_exists('current_url')) {
67
            $this->setAction(current_url());
68
        }
69 11
    }
70
71
    /**
72
     * @param string $action
73
     * @return AbstractForm
74
     */
75
    public function setAction($action)
76
    {
77
        return $this->setAttrib('action', (string)$action);
78
    }
79
80 11
    public function postInit()
81
    {
82 11
    }
83
84
    /**
85
     * @param $name
86
     * @return ElementAbstract|null
87
     */
88 1
    public function __get($name)
89
    {
90 1
        $element = $this->getElement($name);
91 1
        if ($element) {
92 1
            return $element;
93
        }
94
95
        return null;
96
    }
97
98
    /**
99
     * @param $name
100
     * @param bool $label
101
     * @param string $type
102
     * @return $this
103
     */
104
    public function addButton($name, $label = false, $type = 'button')
105
    {
106
        $this->_buttons[$name] = $this->newButton($name, $label, $type);
107
108
        return $this;
109
    }
110
111
    /**
112
     * @param $name
113
     * @param bool $label
114
     * @param string $type
115
     * @return ButtonAbstract
116
     */
117
    protected function newButton($name, $label = false, $type = 'button')
118
    {
119
        $class = 'Nip_Form_Button_'.ucfirst($type);
120
        /** @var ButtonAbstract $button */
121
        $button = new $class($this);
122
        $button->setName($name)
123
            ->setLabel($label);
0 ignored issues
show
Documentation introduced by
$label is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
124
125
        return $button;
126
    }
127
128
    /**
129
     * @param $name
130
     * @return ElementAbstract
131
     */
132
    public function getButton($name)
133
    {
134
        if (array_key_exists($name, $this->_buttons)) {
135
            return $this->_buttons[$name];
136
        }
137
138
        return null;
139
    }
140
141
142
    /**
143
     * @return ButtonAbstract[]
144
     */
145
    public function getButtons()
146
    {
147
        return $this->_buttons;
148
    }
149
150
151
    /**
152
     * @param $key
153
     * @param $value
154
     * @return $this
155
     */
156
    public function setOption($key, $value)
157
    {
158
        $key = (string)$key;
159
        $this->_options[$key] = $value;
160
161
        return $this;
162
    }
163
164
    /**
165
     * @param string $key
166
     * @return mixed|null
167
     */
168 View Code Duplication
    public function getOption($key)
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...
169
    {
170
        $key = (string)$key;
171
        if (!isset($this->_options[$key])) {
172
            return null;
173
        }
174
175
        return $this->_options[$key];
176
    }
177
178
    /**
179
     * @param $method
180
     * @return AbstractForm
181
     */
182
    public function setMethod($method)
183
    {
184
        if (in_array($method, $this->methods)) {
185
            return $this->setAttrib('method', $method);
186
        }
187
        trigger_error('Method is not valid', E_USER_ERROR);
188
189
        return null;
190
    }
191
192
    /**
193
     * @return bool
194
     */
195
    public function execute()
196
    {
197
        if ($this->submited()) {
198
            return $this->processRequest();
199
        }
200
201
        return false;
202
    }
203
204
    /**
205
     * @return bool
206
     */
207
    public function submited()
208
    {
209
        $request = $this->getAttrib('method') == 'post' ? $_POST : $_GET;
210
        if (count($request)) {
211
            return true;
212
        }
213
214
        return false;
215
    }
216
217
    /**
218
     * @return bool
219
     */
220
    public function processRequest()
221
    {
222
        if ($this->validate()) {
223
            $this->process();
224
225
            return true;
226
        }
227
228
        return false;
229
    }
230
231
    /**
232
     * @return bool
233
     */
234
    public function validate()
235
    {
236
        $request = $this->getAttrib('method') == 'post' ? $_POST : $_GET;
237
        $this->getDataFromRequest($request);
238
        $this->processValidation();
239
240
        return $this->isValid();
241
    }
242
243
    /**
244
     * @param $request
245
     */
246
    protected function getDataFromRequest($request)
247
    {
248
        $elements = $this->getElements();
249
        if (is_array($elements)) {
250
            foreach ($elements as $name => $element) {
251
                if ($element->isGroup() && $element->isRequestArray()) {
252
                    $name = str_replace('[]', '', $name);
253
                    $data = is_array($request[$name]) ? $request[$name] : [$request[$name]];
254
                    $element->getData($data, 'request');
255
                } else {
256
                    $value = $request[$name];
257
                    if (strpos($name, '[') && strpos($name, ']')) {
258
                        $arrayPrimary = substr($name, 0, strpos($name, '['));
259
                        $arrayKeys = str_replace($arrayPrimary, '', $name);
260
261
                        preg_match_all('/\[([^\]]*)\]/', $arrayKeys, $arr_matches, PREG_PATTERN_ORDER);
262
                        $value = $request[$arrayPrimary];
263
                        foreach ($arr_matches[1] as $dimension) {
264
                            $value = $value[$dimension];
265
                        }
266
                    }
267
                    $element->getData($value, 'request');
268
                }
269
            }
270
        }
271
    }
272
273
    public function processValidation()
274
    {
275
        $elements = $this->getElements();
276
        if (is_array($elements)) {
277
            foreach ($elements as $name => $element) {
278
                $element->validate();
279
            }
280
        }
281
    }
282
283
    /**
284
     * @return bool
285
     */
286
    public function isValid()
287
    {
288
        return count($this->getErrors()) > 0 ? false : true;
289
    }
290
291
    public function process()
292
    {
293
    }
294
295
296
    /**
297
     * @param $type
298
     * @return $this
299
     */
300 3
    public function setRendererType($type)
301
    {
302 3
        $this->setRenderer($this->getNewRenderer($type));
303
304 3
        return $this;
305
    }
306
307
    /**
308
     * @param string $class
309
     */
310
    protected function setRendererClass($class)
311
    {
312
        /** @var AbstractRenderer $renderer */
313
        $renderer = new $class();
314
        $renderer->setForm($this);
315
        $this->setRenderer($renderer);
316
    }
317
318
    /**
319
     * @param AbstractRenderer $renderer
320
     */
321 3
    public function setRenderer($renderer)
322
    {
323 3
        $this->_renderer = $renderer;
324 3
    }
325
326
    /**
327
     * @param string $type
328
     * @return AbstractRenderer
329
     */
330 3
    public function getNewRenderer($type = 'basic')
331
    {
332 3
        $name = 'Nip_Form_Renderer_'.ucfirst($type);
333
        /** @var AbstractRenderer $renderer */
334 3
        $renderer = new $name();
335 3
        $renderer->setForm($this);
336
337 3
        return $renderer;
338
    }
339
340
    /**
341
     * @param $key
342
     * @return mixed
343
     */
344 1
    public function getCache($key)
345
    {
346 1
        return $this->_cache[$key];
347
    }
348
349
    /**
350
     * @param string $key
351
     * @param $value
352
     */
353 1
    public function setCache($key, $value)
354
    {
355 1
        $this->_cache[$key] = $value;
356 1
    }
357
358
    /**
359
     * @param $key
360
     * @return bool
361
     */
362
    public function isCache($key)
363
    {
364
        return isset($this->_cache[$key]);
365
    }
366
367
    /**
368
     * @return string
369
     */
370
    public function getName()
371
    {
372
        return get_class($this);
373
    }
374
375
    /**
376
     * @return null|string
377
     */
378
    public function __toString()
379
    {
380
        $backtrace = debug_backtrace();
381
        if ($backtrace[1]['class'] == 'Monolog\Formatter\NormalizerFormatter') {
382
            return null;
383
        }
384
        trigger_error('form __toString', E_USER_WARNING);
385
386
        return $this->render();
387
    }
388
389
    /**
390
     * @return string
391
     */
392
    public function render()
393
    {
394
        return $this->getRenderer()->render();
395
    }
396
397
    /**
398
     * @return AbstractRenderer
399
     */
400 3
    public function getRenderer()
401
    {
402 3
        if (!$this->_renderer) {
403
            $this->_renderer = $this->getNewRenderer();
404
        }
405
406 3
        return $this->_renderer;
407
    }
408
409
    /**
410
     * @return View|null
411
     */
412
    public function getControllerView()
413
    {
414
        if (!$this->controllerView) {
415
            $this->controllerView = app('kernel')->getDispatcher()->getCurrentController()->getView();
416
        }
417
418
        return $this->controllerView;
419
    }
420
421
    /**
422
     * @return array
423
     */
424
    protected function getData()
425
    {
426
        $data = [];
427
        $elements = $this->getElements();
428
        if (is_array($elements)) {
429
            foreach ($elements as $name => $element) {
430
                $data[$name] = $element->getValue();
431
            }
432
        }
433
434
        return $data;
435
    }
436
}
437