Completed
Push — develop ( 69bf64...c61561 )
by
unknown
17:17 queued 09:01
created

Container   D

Complexity

Total Complexity 142

Size/Duplication

Total Lines 768
Duplicated Lines 5.6 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 8
Bugs 2 Features 2
Metric Value
wmc 142
c 8
b 2
f 2
lcom 1
cbo 5
dl 43
loc 768
rs 4.4444

35 Methods

Rating   Name   Duplication   Size   Complexity  
B disableForm() 0 29 6
A setForms() 0 13 4
C enableForm() 0 26 7
A setFormElementManager() 0 5 1
A getIterator() 0 14 3
A count() 0 4 1
A setIsDisableCapable() 0 6 1
A isDisableCapable() 0 5 2
A setIsDisableElementsCapable() 0 6 1
A isDisableElementsCapable() 0 5 2
D disableElements() 0 29 9
A setOptions() 0 10 2
B setParams() 0 14 5
A getParams() 0 4 1
B setParam() 0 14 5
A getParam() 0 4 2
F getForm() 8 69 19
A executeAction() 7 13 2
C setForm() 0 29 8
B setEntity() 0 16 7
A getEntity() 0 4 2
B mapEntity() 0 21 6
A isValid() 0 9 2
C get() 0 40 16
C setData() 0 24 9
A setParent() 0 5 1
A getParent() 0 4 1
A hasParent() 0 4 1
A renderPre() 0 4 1
A renderPost() 0 4 1
A getActiveFormActual() 0 12 4
A getActiveFormPrevious() 14 14 3
A getActiveFormNext() 14 14 3
A formatAction() 0 4 2
A getActionFor() 0 6 2

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

1
<?php
2
/**
3
 * YAWIK
4
 *
5
 * @filesource
6
 * @copyright (c) 2013 - 2016 Cross Solution (http://cross-solution.de)
7
 * @license   MIT
8
 */
9
10
/** Core forms */
11
namespace Core\Form;
12
13
use Zend\Form\Element;
14
use Zend\Form\FieldsetInterface;
15
use Zend\Stdlib\PriorityList;
16
use Zend\View\Renderer\PhpRenderer as Renderer;
17
use Core\Entity\EntityInterface;
18
use Zend\ServiceManager\ServiceLocatorInterface;
19
20
/**
21
 * Manages a group of formulars.
22
 *
23
 * The container is responsible for creating, populating and binding the formulars from or to
24
 * the corresponding entities.
25
 *
26
 * Formulars are lazy loaded. So it is possible to only retrieve one formular from the container
27
 * for asynchronous saving using ajax calls.
28
 *
29
 * @author Mathias Gelhausen <[email protected]>
30
 */
31
class Container extends Element implements
32
    DisableElementsCapableInterface,
33
    FormParentInterface,
34
    \IteratorAggregate,
35
    \Countable
36
{
37
    /**
38
     * Available/Loaded forms or specification.
39
     * @var array
40
     */
41
    protected $forms = array();
42
    
43
    /**
44
     * Active formulars keys.
45
     *
46
     * Formulars which key is herein are included in the iterator.
47
     * @see getIterator()
48
     * @var array
49
     */
50
    protected $activeForms = array();
51
    
52
    /**
53
     * The form element manager.
54
     * @var \Zend\Form\FormElementManager
55
     */
56
    protected $formElementManager;
57
    
58
    /**
59
     * Entity to bind to the formulars.
60
     *
61
     * @var \Core\Entity\EntityInterface[]
62
     */
63
    protected $entities;
64
    
65
    /**
66
     * Parameters to pass to the formulars.
67
     *
68
     * @var array
69
     */
70
    protected $params = array();
71
72
    protected $parent;
73
74
    /**
75
     * @param ServiceLocatorInterface $formElementManager
76
     * @return Container
77
     */
78
    public function setFormElementManager(ServiceLocatorInterface $formElementManager)
79
    {
80
        $this->formElementManager = $formElementManager;
0 ignored issues
show
Documentation Bug introduced by
It seems like $formElementManager of type object<Zend\ServiceManag...erviceLocatorInterface> is incompatible with the declared type object<Zend\Form\FormElementManager> of property $formElementManager.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
81
        return $this;
82
    }
83
84
    /**
85
     * Gets an iterator to iterate over the enabled formulars.
86
     *
87
     * @return \ArrayIterator
0 ignored issues
show
Documentation introduced by
Should the return type not be PriorityList?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
88
     * @see IteratorAggregate::getIterator()
89
     */
90
    public function getIterator()
91
    {
92
        $iterator = new PriorityList();
93
        $iterator->isLIFO(false);
94
95
        foreach ($this->activeForms as $key) {
96
            $spec = $this->forms[$key];
97
            $priority = isset($spec['priority']) ? $spec['priority'] : 0;
98
99
            $iterator->insert($key, $this->getForm($key), $priority);
100
        }
101
102
        return $iterator;
103
    }
104
    
105
    /**
106
     * Gets the count of enabled formulars
107
     *
108
     * @return int
109
     * @see Countable::count()
110
     */
111
    public function count()
112
    {
113
        return count($this->activeForms);
114
    }
115
116
    /**
117
     * @param bool $flag
118
     * @return $this
119
     */
120
    public function setIsDisableCapable($flag)
121
    {
122
        $this->options['is_disable_capable'] = $flag;
123
124
        return $this;
125
    }
126
127
    /**
128
     * @return bool
129
     */
130
    public function isDisableCapable()
131
    {
132
        return isset($this->options['is_disable_capable'])
133
               ? $this->options['is_disable_capable'] : true;
134
    }
135
136
    /**
137
     * @param bool $flag
138
     * @return $this
139
     */
140
    public function setIsDisableElementsCapable($flag)
141
    {
142
        $this->options['is_disable_elements_capable'] = $flag;
143
144
        return $this;
145
    }
146
147
    /**
148
     * @return bool
149
     */
150
    public function isDisableElementsCapable()
151
    {
152
        return isset($this->options['is_disable_elements_capable'])
153
               ? $this->options['is_disable_elements_capable'] : true;
154
    }
155
156
    /**
157
     * @param array $map
158
     */
159
    public function disableElements(array $map)
160
    {
161
        foreach ($map as $key => $name) {
162
            if (is_numeric($key)) {
163
                if (isset($this->forms[$name])) {
164
                    $form = $this->getForm($name);
165
                    if (false !== $form->getOption('is_disable_capable')) {
166
                        $this->disableForm($name);
167
                    }
168
                }
169
                continue;
170
            }
171
172
            if (!isset($this->forms[$key])) {
173
                continue;
174
            }
175
176
            if (isset($this->forms[$key]['__instance__'])) {
177
                $form = $this->forms[$key]['__instance__'];
178
179
                if ($form instanceof DisableElementsCapableInterface
180
                    && $form->isDisableElementsCapable()
181
                ) {
182
                    $form->disableElements($name);
183
                }
184
            }
185
            $this->forms[$key]['disable_elements'] = $name;
186
        }
187
    }
188
189
    public function setOptions($options)
190
    {
191
        parent::setOptions($options);
192
193
        if (isset($this->options['forms'])) {
194
            $this->setForms($this->options['forms']);
195
        }
196
197
        return $this;
198
    }
199
200
    /**
201
     * Sets formular parameters.
202
     *
203
     * @param array $params
204
     * @return \Core\Form\Container
205
     */
206
    public function setParams(array $params)
207
    {
208
        $this->params = array_merge($this->params, $params);
209
        
210
        foreach ($this->forms as $form) {
211
            if (isset($form['__instance__'])
212
                && is_object($form['__instance__'])
213
                && method_exists($form['__instance__'], 'setParams')
214
            ) {
215
                $form['__instance__']->setParams($params);
216
            }
217
        }
218
        return $this;
219
    }
220
    
221
    /**
222
     * Gets the formular parameters.
223
     *
224
     * @return array:
0 ignored issues
show
Documentation introduced by
The doc-type array: could not be parsed: Unknown type name "array:" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
225
     */
226
    public function getParams()
227
    {
228
        return $this->params;
229
    }
230
    
231
    /**
232
     * Sets a formular parameter.
233
     *
234
     * @param string $key
235
     * @param mixed $value
236
     * @return \Core\Form\Container
237
     */
238
    public function setParam($key, $value)
239
    {
240
        $this->params[$key] = $value;
241
        
242
        foreach ($this->forms as $form) {
243
            if (isset($form['__instance__'])
244
                && is_object($form['__instance__'])
245
                && method_exists($form['__instance__'], 'setParam')
246
            ) {
247
                $form['__instance__']->setParam($key, $value);
248
            }
249
        }
250
        return $this;
251
    }
252
    
253
    /**
254
     * Gets the value of a formular parameter.
255
     *
256
     * Returns the provided <b>$default</b> value or null, if parameter does
257
     * not  exist.
258
     *
259
     * @param string $key
260
     * @param mixed $default
261
     * @return mixed
262
     */
263
    public function getParam($key, $default = null)
264
    {
265
        return isset($this->params[$key]) ? $this->params[$key] : $default;
266
    }
267
268
    /**
269
     * Gets a specific formular.
270
     *
271
     * This formular will be created upon the first retrievement.
272
     * If created, the formular gets passed the formular parameters set in this container.
273
     *
274
     * @param string $key
275
     * @param bool $asInstance if set to false, the specification array is returned, and no instance created.
276
     *
277
     * @return null|\Core\Form\Container|\Zend\Form\FormInterface
278
     * @since 0,25 added $asInstance parameter
279
     */
280
    public function getForm($key, $asInstance = true)
281
    {
282 View Code Duplication
        if (false !== strpos($key, '.')) {
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...
283
            list($key, $childKey) = explode('.', $key, 2);
284
            $container = $this->getForm($key);
285
            return $container->getForm($childKey);
0 ignored issues
show
Bug introduced by
The method getForm does only exist in Core\Form\Container, but not in Zend\Form\FormInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
286
        }
287
        
288
        if (!isset($this->forms[$key])) {
289
            return null;
290
        }
291
        
292
        $form = $this->forms[$key];
293
294
        if (!$asInstance) {
295
            return $form;
296
        }
297
298
        if (isset($form['__instance__']) && is_object($form['__instance__'])) {
299
            return $form['__instance__'];
300
        }
301
302
        $options = isset($form['options']) ? $form['options'] : array();
303 View Code Duplication
        if (!isset($options['name'])) {
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...
304
            $options['name'] = isset($form['name']) ? $form['name'] : $key;
305
        }
306
        if (!isset($options['use_post_array'])) {
307
            $options['use_post_array'] = true;
308
        }
309
        if (!isset($options['use_files_array'])) {
310
            $options['use_files_array'] = false;
311
        }
312
313
        $formInstance = $this->formElementManager->get($form['type'], $options);
314
        $formInstance->setParent($this);
315
        if (isset($form['attributes'])) {
316
            $formInstance->setAttributes($form['attributes']);
317
        }
318
319
        $formName = $this->formatAction($form['name']);
320
        $formInstance->setName($formName);
321
        $formAction = $formInstance->getAttribute('action');
322
323
        if (empty($formAction)) {
324
            $formInstance->setAttribute('action', '?form=' . $formName);
325
        }
326
327
        if (isset($form['label'])) {
328
            $formInstance->setLabel($form['label']);
329
        }
330
331
        if (isset($form['disable_elements'])
332
            && $formInstance instanceof DisableElementsCapableInterface
333
            && $formInstance->isDisableElementsCapable()
334
        ) {
335
            $formInstance->disableElements($form['disable_elements']);
336
        }
337
338
        $entity = $this->getEntity($form['entity']);
339
        if ($entity) {
340
            $this->mapEntity($formInstance, $entity, isset($form['property']) ? $form['property'] : $key);
341
        }
342
343
        $formInstance->setParams($this->getParams());
344
345
        $this->forms[$key]['__instance__'] = $formInstance;
346
        $this->forms[$key]['options'] = $options;
347
        return $formInstance;
348
    }
349
    
350
    /**
351
     * Execute an arbitrary action
352
     *
353
     * @param string $name Name of an action
354
     * @param array $data Arbitrary data
355
     * @return array
356
     */
357
    public function executeAction($name, array $data = [])
358
    {
359 View Code Duplication
        if (false !== strpos($name, '.')) {
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...
360
            list($name, $childKey) = explode('.', $name, 2);
361
            $container = $this->getForm($name);
362
            
363
            // execute child container's action
364
            return $container->executeAction($childKey, $data);
0 ignored issues
show
Bug introduced by
The method executeAction does only exist in Core\Form\Container, but not in Zend\Form\FormInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
365
        }
366
        
367
        // this container defines no actions
368
        return [];
369
    }
370
371
    /**
372
     * Sets a form or form specification.
373
     *
374
     * if <b>$spec</b> is a string, it is used as form type, name is set to <b>$key</b>
375
     *
376
     * @param string       $key
377
     * @param string|array $spec
378
     * @param boolean      $enabled Should the formular be enabled or not
379
     *
380
     * @return self
381
     */
382
    public function setForm($key, $spec, $enabled = true)
383
    {
384
        if (is_object($spec)) {
385
            if ($spec instanceof FormParentInterface) {
386
                $spec->setParent($this);
387
            }
388
389
            $spec = [ '__instance__' => $spec, 'name' => $key, 'entity' => '*' ];
390
        }
391
392
        if (!is_array($spec)) {
393
            $spec = array('type' => $spec, 'name' => $key);
394
        }
395
        if (!isset($spec['name'])) {
396
            $spec['name'] = $key;
397
        }
398
        if (!isset($spec['entity'])) {
399
            $spec['entity'] = '*';
400
        }
401
        
402
        $this->forms[$key] = $spec;
403
404
        if ($enabled) {
405
            $this->enableForm($key);
406
        } elseif (true === $this->activeForms) {
407
            $this->activeForms = false;
0 ignored issues
show
Documentation Bug introduced by
It seems like false of type false is incompatible with the declared type array of property $activeForms.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
408
        }
409
        return $this;
410
    }
411
    
412
    /**
413
     * Sets formulars or specifications.
414
     *
415
     * <b>$forms</b> must be in the format:
416
     * <pre>
417
     *    'name' => [spec]
418
     * </pre>
419
     *
420
     * <b>$spec</b> must be compatible with {@link setForm}.
421
     * Additionally you can include a key 'enabled' in the spec, which will override
422
     * <b>$enabled</b> only for the current formular.
423
     *
424
     * @param array $forms
425
     * @param boolean $enabled
426
     * @return \Core\Form\Container
427
     */
428
    public function setForms(array $forms, $enabled = true)
429
    {
430
        foreach ($forms as $key => $spec) {
431
            if (is_array($spec) && isset($spec['enabled'])) {
432
                $currentEnabled = $spec['enabled'];
433
                unset($spec['enabled']);
434
            } else {
435
                $currentEnabled = $enabled;
436
            }
437
            $this->setForm($key, $spec, $currentEnabled);
438
        }
439
        return $this;
440
    }
441
    
442
    /**
443
     * Enables a formular.
444
     *
445
     * Enabled formulars are included in the {@link getIterator()}
446
     *
447
     * Traverses in child containers through .dot-Notation.
448
     *
449
     * @param string $key
0 ignored issues
show
Documentation introduced by
Should the type for parameter $key not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
450
     * @return \Core\Form\Container
451
     */
452
    public function enableForm($key = null)
453
    {
454
        if (null === $key) {
455
            $this->activeForms = array_keys($this->forms);
456
            return $this;
457
        }
458
        
459
        if (!is_array($key)) {
460
            $key = array($key);
461
        }
462
        
463
        foreach ($key as $k) {
464
            if (false !== strpos($k, '.')) {
465
                // this seems not to be childkey.childform but actualkey.childkey
466
                list($childKey, $childForm) = explode('.', $k, 2);
467
                $child = $this->getForm($childKey);
468
                $child->enableForm($childForm);
0 ignored issues
show
Bug introduced by
The method enableForm does only exist in Core\Form\Container, but not in Zend\Form\FormInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
469
            } else {
470
                if (isset($this->forms[$k]) && !in_array($k, $this->activeForms)) {
471
                    $this->activeForms[] = $k;
472
                }
473
            }
474
        }
475
        
476
        return $this;
477
    }
478
479
    /**
480
     * Disables a formular.
481
     *
482
     * @param string $key
0 ignored issues
show
Documentation introduced by
Should the type for parameter $key not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
483
     *
484
     * @return self
485
     */
486
    public function disableForm($key = null)
487
    {
488
        if (null === $key) {
489
            $this->activeForms = array();
490
            return $this;
491
        }
492
        
493
        if (!is_array($key)) {
494
            $key = array($key);
495
        }
496
        
497
        foreach ($key as $k) {
498
            if (false !== strpos($k, '.')) {
499
                list($childKey, $childForm) = explode('.', $k, 2);
500
                $child = $this->getForm($childKey);
501
                $child->disableForm($childForm);
0 ignored issues
show
Bug introduced by
The method disableForm does only exist in Core\Form\Container, but not in Zend\Form\FormInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
502
            } elseif (isset($this->forms[$k]['__instance__'])) {
503
                unset($this->forms[$k]['__instance__']);
504
            }
505
        }
506
        $this->activeForms = array_filter(
507
            $this->activeForms,
508
            function ($item) use ($key) {
509
                return !in_array($item, $key);
510
            }
511
        );
512
        
513
        return $this;
514
    }
515
    
516
    /**
517
     * @param mixed $entity
518
     * @param string $key
519
     * @throws \InvalidArgumentException
520
     * @return Container
521
     */
522
    public function setEntity($entity, $key='*')
523
    {
524
        if (!$entity instanceof EntityInterface)
525
        {
526
            throw new \InvalidArgumentException(sprintf('$entity must be instance of %s', EntityInterface::class));
527
        }
528
        
529
        $this->entities[$key] = $entity;
530
        
531
        foreach ($this->forms as $formKey => $form) {
532
            if (isset($form['__instance__']) && is_object($form['__instance__']) && $key == $form['entity']) {
533
                $this->mapEntity($form['__instance__'], $entity, isset($form['property']) ? $form['property'] : $formKey);
534
            }
535
        }
536
        return $this;
537
    }
538
539
540
    /**
541
     * Gets the entity.
542
     *
543
     * @return \Core\Entity\EntityInterface
0 ignored issues
show
Documentation introduced by
Should the return type not be EntityInterface|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
544
     */
545
    public function getEntity($key='*')
546
    {
547
        return isset($this->entities[$key]) ? $this->entities[$key] : null;
548
    }
549
    
550
    /**
551
     * Maps entity property to forms or child containers.
552
     *
553
     * @param \Zend\Form\FormInterface $form
554
     * @param \Core\Entity\EntityInterface $entity
555
     * @param string $property
556
     * @return void
557
     */
558
    protected function mapEntity($form, $entity, $property)
559
    {
560
        if (false === $property) {
561
            return;
562
        }
563
564
        if (true === $property) {
565
            $mapEntity = $entity;
566
        } else if ($entity->hasProperty($property) || is_callable([$entity, "get$property"])) {
567
            $getter = "get$property";
568
            $mapEntity = $entity->$getter();
569
        } else {
570
            return;
571
        }
572
        
573
        if ($form instanceof Container) {
574
            $form->setEntity($mapEntity);
575
        } else {
576
            $form->bind($mapEntity);
577
        }
578
    }
579
580
    /**
581
     * Return isValid
582
     *
583
     * @return bool
584
     */
585
    public function isValid()
586
    {
587
        $isValid = true;
588
        foreach ($this->activeForms as $activeFormKey) {
589
            $activeForm = $this->getForm($activeFormKey);
590
            $isValid &= $activeForm->isValid();
591
        }
592
        return $isValid;
593
    }
594
595
    /**
596
     * if fieldsets there is get method to have access to any element by name
597
     * this method is similar
598
     * get('form') gets a form
599
     * get('element') gets an element, if an element has the same name as a form, the form get's first access
600
     * get('form.element') gets an element of a form, this is more efficent because it doesn't expand all forms in the container,
601
     *      but just the one adressed
602
     * @param $key string
603
     * @return null|\Zend\Form\ElementInterface
0 ignored issues
show
Documentation introduced by
Should the return type not be array|null|\Zend\Form\ElementInterface?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
604
     */
605
    public function get($key)
606
    {
607
        $return   = null;
608
        $lastKey  = null;
609
        $searchIn = $this->activeForms;
610
        $keySplit = explode('.', $key);
611
612
        while (0 < count($keySplit)) {
613
            $lastKey = array_shift($keySplit);
614
            foreach ($searchIn as $activeFormKey) {
0 ignored issues
show
Bug introduced by
The expression $searchIn of type null|object<Core\Form\Co...rm\FormInterface>|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...
615
                if ($lastKey == $activeFormKey) {
616
                    $searchIn = $this->getForm($activeFormKey);
617
                    unset($lastKey);
618
                    break;
619
                }
620
            }
621
        }
622
        if (!isset($lastKey) && !empty($keySplit)) {
623
            $lastKey = array_shift($keySplit);
624
        }
625
        if (isset($lastKey) && empty($keySplit)) {
626
            if ($searchIn instanceof FieldsetInterface) {
627
                // has reached a fieldset to search in
628
                $return = $searchIn->get($lastKey);
629
                unset($lastKey);
630
            } elseif (is_array($searchIn) || $searchIn instanceof \Traversable) {
631
                // is probably still in the container
632
                foreach ($searchIn as $activeKey) {
633
                    $activeForm = $this->getForm($activeKey);
634
                    if ($activeForm instanceof FieldsetInterface) {
635
                        $return = $activeForm->get($lastKey);
636
                    }
637
                }
638
            }
639
        }
640
        if (!isset($lastKey) && empty($keySplit) && !isset($return)) {
641
            $return = $searchIn;
642
        }
643
        return $return;
644
    }
645
646
    /**
647
     * @param $data
648
     * @return $this
649
     */
650
    public function setData($data)
651
    {
652
        $filteredData = array();
653
        foreach ($data as $key => $elem) {
654
            if (!array_key_exists($key, $this->params) && $key != 'formName') {
655
                $filteredData[$key] = $elem;
656
            }
657
            if ($key == 'formName' && is_string($elem)) {
658
                // you can activate a specific form with postData
659
                foreach ($this->activeForms as $activeFormKey) {
660
                    if ($activeFormKey == $elem) {
661
                        $this->enableForm($activeFormKey);
662
                    } else {
663
                        $this->disableForm($activeFormKey);
664
                    }
665
                }
666
            }
667
        }
668
        foreach ($this->activeForms as $activeFormKey) {
669
            $activeForm = $this->getForm($activeFormKey);
670
            $activeForm->setData($filteredData);
671
        }
672
        return $this;
673
    }
674
675
    /**
676
     * @param $parent
677
     * @return $this
678
     */
679
    public function setParent($parent)
680
    {
681
        $this->parent = $parent;
682
        return $this;
683
    }
684
685
    /**
686
     * @return mixed
687
     */
688
    public function getParent()
689
    {
690
        return $this->parent;
691
    }
692
693
694
    /**
695
     * @return bool
696
     */
697
    public function hasParent()
698
    {
699
        return isset($this->parent);
700
    }
701
702
    /**
703
     * @param Renderer $renderer
704
     * @return string
705
     */
706
    public function renderPre(Renderer $renderer)
0 ignored issues
show
Unused Code introduced by
The parameter $renderer is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
707
    {
708
        return '';
709
    }
710
711
    /**
712
     * @param Renderer $renderer
713
     * @return string
714
     */
715
    public function renderPost(Renderer $renderer)
716
    {
717
        return '';
718
    }
719
720
    /**
721
     * get the actual active Form
722
     * @param bool $setDefault
723
     * @return mixed|null
724
     */
725
    public function getActiveFormActual($setDefault = true)
726
    {
727
        $key = null;
728
        if (!empty($this->activeForms)) {
729
            $key = $this->activeForms[0];
730
        }
731
        if (!isset($key) && $setDefault) {
732
            $formsAvailable = array_keys($this->forms);
733
            $key = array_shift($formsAvailable);
734
        }
735
        return $key;
736
    }
737
738
    /**
739
     * get the form before the actual active
740
     * @return null
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
741
     */
742 View Code Duplication
    public function getActiveFormPrevious()
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...
743
    {
744
        $key = null;
745
        $actualKey = $this->getActiveFormActual();
746
        if (isset($actualKey)) {
747
            $forms = array_keys($this->forms);
748
            $formsFlip =  array_flip($forms);
749
            $index = $formsFlip[$actualKey];
750
            if (0 < $index) {
751
                $key = $forms[$index-1];
752
            }
753
        }
754
        return $key;
755
    }
756
757
758
    /**
759
     * Gets the form after the actual active
760
     * @return null
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
761
     */
762 View Code Duplication
    public function getActiveFormNext()
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...
763
    {
764
        $key = null;
765
        $actualKey = $this->getActiveFormActual();
766
        if (isset($actualKey)) {
767
            $forms = array_keys($this->forms);
768
            $formsFlip =  array_flip($forms);
769
            $index = $formsFlip[$actualKey];
770
            if ($index < count($forms) - 1) {
771
                $key = $forms[$index+1];
772
            }
773
        }
774
        return $key;
775
    }
776
    
777
    /**
778
     * Format an action name
779
     *
780
     * @param string $name Name of an action
781
     * @return string Formatted name of an action
782
     */
783
    public function formatAction($name)
784
    {
785
        return sprintf('%s%s', $this->hasParent() ? $this->getName() . '.' : '', $name);
786
    }
787
788
    /**
789
     * @param $key
790
     * @return string|null
791
     */
792
    public function getActionFor($key)
793
    {
794
        if (isset($this->forms[$key])) {
795
            return '?form=' . $this->formatAction($this->forms[$key]['name']);
796
        }
797
    }
798
}