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

CollectionContainer::count()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
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
namespace Core\Form;
11
12
use Core\Form\Element\ViewHelperProviderInterface;
13
use Doctrine\Common\Collections\Collection;
14
use Core\Form\Form as CoreForm;
15
use Zend\EventManager\EventInterface as Event;
16
use ArrayIterator;
17
18
/**
19
 * Manages CRUD operations for the given collection by creating a group of independent forms
20
 *
21
 * It is recommended to use a collection indexed by entry identifiers
22
 * You can use the \Core\Collection\IdentityWrapper as an adapter for a numerically
23
 * indexed collection
24
 *
25
 * @author fedys
26
 */
27
class CollectionContainer extends Container implements ViewHelperProviderInterface
28
{
29
    const NEW_ENTRY = '__new_entry__';
30
    
31
    /**
32
     * @var string
33
     */
34
    protected $formService;
35
    
36
    /**
37
     * @var mixed
38
     */
39
    protected $newEntry;
40
    
41
    /**
42
     * @var string
43
     */
44
    protected $viewHelper = 'formCollectionContainer';
45
    
46
    /**
47
     * @param string $formService
48
     * @param mixed $newEntry
49
     */
50
    public function __construct($formService, $newEntry)
51
    {
52
        $this->formService = $formService;
53
        $this->newEntry = $newEntry;
54
    }
55
56
    /**
57
     * @see IteratorAggregate::getIterator()
58
     */
59
    public function getIterator()
60
    {
61
        return new ArrayIterator($this->getForms());
62
    }
63
    
64
    /**
65
     * @see Countable::count()
66
     */
67
    public function count()
68
    {
69
        return count($this->getCollection());
70
    }
71
    
72
    /**
73
     * @see \Core\Form\ContainerInterface::getForm()
74
     */
75
    public function getForm($key, $asInstance = true)
76
    {
77
        $collection = $this->getCollection();
78
        
79
        if ($key === static::NEW_ENTRY) {
80
            $collection[] = $this->newEntry;
81
            $form = $this->buildForm($key, $this->newEntry);
82
            $eventManager = $form->getEventManager();
83
			$eventManager->attach(CoreForm::EVENT_IS_VALID, function (Event $event) use ($collection) {
84
                if (!$event->getParam('isValid')) {
85
                    $collection->removeElement($this->newEntry);
0 ignored issues
show
Bug introduced by
The method removeElement cannot be called on $collection (of type array<integer,*>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
86
                }
87
            });
88
			$eventManager->attach(CoreForm::EVENT_PREPARE, function (Event $event) use ($collection) {
89
                $this->setupForm($event->getTarget(), $collection->indexOf($this->newEntry));
0 ignored issues
show
Bug introduced by
The method indexOf cannot be called on $collection (of type array<integer,*>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
Documentation introduced by
$event->getTarget() is of type null|string|object, but the function expects a object<Core\Form\Form>.

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...
90
            });
91
            
92
            return $form;
93
        } elseif (isset($collection[$key])) {
94
            return $this->buildForm($key, $collection[$key]);
95
        }
96
    }
97
98
    /**
99
     * @see \Core\Form\Container::executeAction()
100
     */
101
    public function executeAction($name, array $data = array())
102
    {
103
        switch ($name) {
104
            case 'remove':
105
                $success = false;
106
                if (isset($data['key'])) {
107
                    $success = $this->getCollection()->remove($data['key']) !== null;
0 ignored issues
show
Bug introduced by
The method remove() does not seem to exist on object<Core\Entity\EntityInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
108
                }
109
                return [
110
                    'success' => $success
111
                ];
112
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
113
            
114
            default:
115
                return [];
116
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
117
        }
118
    }
119
    
120
	/**
121
     * @see \Core\Form\Element\ViewHelperProviderInterface::getViewHelper()
122
     */
123
    public function getViewHelper()
124
    {
125
        return $this->viewHelper;
126
    }
127
128
    /**
129
     * @see \Core\Form\Element\ViewHelperProviderInterface::setViewHelper()
130
     */
131
    public function setViewHelper($helper)
132
    {
133
        $this->viewHelper = $helper;
134
        
135
        return $this;
136
    }
137
    
138
    /**
139
     * @see \Core\Form\Container::setEntity()
140
     */
141
    public function setEntity($entity, $key = '*')
142
    {
143
        if (!$entity instanceof Collection)
144
        {
145
            throw new \InvalidArgumentException(sprintf('$entity must be instance of %s', Collection::class));
146
        }
147
        
148
        $this->entities['*'] = $entity;
149
        
150
        return $this;
151
    }
152
    
153
    /**
154
     * Returns the template form for creating a new form via JavaScript
155
     *
156
     * @return CoreForm
157
     */
158
    public function getTemplateForm()
159
    {
160
        return $this->buildForm(static::NEW_ENTRY);
161
    }
162
163
    /**
164
     * @return CoreForm[]
165
     */
166
    protected function getForms()
167
    {
168
        $forms = [];
169
        
170
        foreach ($this->getCollection() as $key => $entry)
0 ignored issues
show
Bug introduced by
The expression $this->getCollection() of type object<Core\Entity\EntityInterface> is not traversable.
Loading history...
171
        {
172
            $form = $this->buildForm($key, $entry);
173
            
174
            $forms[$key] = $form;
175
        }
176
        
177
        return $forms;
178
    }
179
    
180
    /**
181
     * @throws \RuntimeException
182
     * @return Collection
0 ignored issues
show
Documentation introduced by
Should the return type not be \Core\Entity\EntityInterface?

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...
183
     */
184
    protected function getCollection()
185
    {
186
        $collection = $this->getEntity();
187
        
188
        if (!$collection) {
189
            throw new \RuntimeException('Entity must be set');
190
        }
191
        
192
        return $collection;
193
    }
194
    
195
    /**
196
     * @param string $key
197
     * @param mixed $entry
198
     * @throws \RuntimeException
199
     * @return CoreForm
200
     */
201
    protected function buildForm($key, $entry = null)
202
    {
203
        $form = $this->formElementManager->get($this->formService);
204
        
205
        if (!$form instanceof CoreForm) {
206
            throw new \RuntimeException(sprintf('$form must be instance of %s', CoreForm::class));
207
        }
208
        
209
        $this->setupForm($form, $key);
210
        
211
        if (isset($entry)) {
212
            $form->bind($entry);
213
        }
214
            
215
        return $form;
216
    }
217
    
218
    /**
219
     * @param CoreForm $form
220
     * @param string $key
221
     */
222
    protected function setupForm(CoreForm $form, $key)
223
    {
224
         $form->setAttribute('action', sprintf('?form=%s', $this->formatAction($key)))
225
            ->setAttribute('data-entry-key', $key);
226
    }
227
}