Completed
Pull Request — master (#306)
by Piotr
02:21
created

BatchFormValidRequestHandler   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 178
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Importance

Changes 0
Metric Value
wmc 27
lcom 1
cbo 12
dl 0
loc 178
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
B action() 0 35 6
A getObjects() 0 21 4
A isValidPostRequest() 0 15 4
A getRedirectResponse() 0 8 2
A getPreSaveEventName() 0 4 1
A getPostSaveEventName() 0 4 1
A setWarningMessage() 0 6 2
A checkIfAbort() 0 8 2
A checkIfSkip() 0 8 2
A isAbortIfSkipped() 0 4 2
1
<?php
2
3
/**
4
 * (c) FSi sp. z o.o. <[email protected]>
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace FSi\Bundle\AdminBundle\Admin\CRUD\Context\Request;
11
12
use FSi\Bundle\AdminBundle\Admin\Context\Request\AbstractFormValidRequestHandler;
13
use FSi\Bundle\AdminBundle\Admin\CRUD\BatchElement;
14
use FSi\Bundle\AdminBundle\Admin\CRUD\DeleteElement;
15
use FSi\Bundle\AdminBundle\Event\BatchEvent;
16
use FSi\Bundle\AdminBundle\Event\BatchEvents;
17
use FSi\Bundle\AdminBundle\Event\FormEvent;
18
use FSi\Bundle\AdminBundle\Exception\RequestHandlerException;
19
use FSi\Bundle\AdminBundle\Message\FlashMessages;
20
use LogicException;
21
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
22
use Symfony\Component\HttpFoundation\RedirectResponse;
23
use Symfony\Component\HttpFoundation\Request;
24
use Symfony\Component\Routing\RouterInterface;
25
26
class BatchFormValidRequestHandler extends AbstractFormValidRequestHandler
27
{
28
    /**
29
     * @var \FSi\Bundle\AdminBundle\Message\FlashMessages
30
     */
31
    private $flashMessages;
32
33
    /**
34
     * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $eventDispatcher
35
     * @param \Symfony\Component\Routing\RouterInterface $router
36
     * @param \FSi\Bundle\AdminBundle\Message\FlashMessages|null
37
     */
38
    public function __construct(
39
        EventDispatcherInterface $eventDispatcher,
40
        RouterInterface $router,
41
        FlashMessages $flashMessages = null
42
    ) {
43
        parent::__construct($eventDispatcher, $router);
44
        $this->flashMessages = $flashMessages;
45
    }
46
47
    /**
48
     * @param \FSi\Bundle\AdminBundle\Event\FormEvent $event
49
     * @param \Symfony\Component\HttpFoundation\Request $request
50
     */
51
    protected function action(FormEvent $event, Request $request)
52
    {
53
        /** @var \FSi\Bundle\AdminBundle\Admin\CRUD\BatchElement $element */
54
        $element = $event->getElement();
55
        $objects = $this->getObjects($element, $request);
56
57
        if (empty($objects)) {
58
            $this->setWarningMessage();
59
            return;
60
        }
61
62
        foreach ($objects as $object) {
63
            $preEvent = $this->eventDispatcher->dispatch(
64
                BatchEvents::BATCH_OBJECT_PRE_APPLY,
65
                new BatchEvent($object)
0 ignored issues
show
Bug introduced by
The call to BatchEvent::__construct() misses some required arguments starting with $request.
Loading history...
66
            );
67
68
            $skip = $this->checkIfSkip($preEvent);
0 ignored issues
show
Compatibility introduced by
$preEvent of type object<Symfony\Component\EventDispatcher\Event> is not a sub-type of object<FSi\Bundle\AdminBundle\Event\BatchEvent>. It seems like you assume a child class of the class Symfony\Component\EventDispatcher\Event to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
69
            $abort = $this->checkIfAbort($preEvent);
0 ignored issues
show
Compatibility introduced by
$preEvent of type object<Symfony\Component\EventDispatcher\Event> is not a sub-type of object<FSi\Bundle\AdminBundle\Event\BatchEvent>. It seems like you assume a child class of the class Symfony\Component\EventDispatcher\Event to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
70
            if ($abort || $this->isAbortIfSkipped($element)) {
71
                return;
72
            }
73
74
            if ($skip) {
75
                continue;
76
            }
77
78
            $element->apply($object);
79
80
            $this->eventDispatcher->dispatch(
81
                BatchEvents::BATCH_OBJECT_POST_APPLY,
82
                new BatchEvent($object)
0 ignored issues
show
Bug introduced by
The call to BatchEvent::__construct() misses some required arguments starting with $request.
Loading history...
83
            );
84
        }
85
    }
86
87
    /**
88
     * @param \FSi\Bundle\AdminBundle\Admin\CRUD\BatchElement $element
89
     * @param \Symfony\Component\HttpFoundation\Request $request
90
     * @return array
91
     * @throws \FSi\Bundle\AdminBundle\Exception\RequestHandlerException
92
     */
93
    private function getObjects(BatchElement $element, Request $request)
94
    {
95
        $objects = [];
96
        $indexes = $request->request->get('indexes', []);
97
98
        if (!count($indexes)) {
99
            return [];
100
        }
101
102
        foreach ($indexes as $index) {
103
            $object = $element->getDataIndexer()->getData($index);
104
105
            if (!isset($object)) {
106
                throw new RequestHandlerException(sprintf("Can't find object with id %s", $index));
107
            }
108
109
            $objects[] = $object;
110
        }
111
112
        return $objects;
113
    }
114
115
    /**
116
     * @param \FSi\Bundle\AdminBundle\Event\FormEvent $event
117
     * @param \Symfony\Component\HttpFoundation\Request $request
118
     * @return bool
119
     */
120
    protected function isValidPostRequest(FormEvent $event, Request $request)
121
    {
122
        $element = $event->getElement();
123
        if ($element instanceof DeleteElement
124
            && $element->hasOption('allow_delete')
125
            && !$element->getOption('allow_delete')
126
        ) {
127
            throw new LogicException(sprintf(
128
                'Tried to delete objects through element "%s", which has option "allow_delete" set to false',
129
                get_class($element)
130
            ));
131
        }
132
133
        return parent::isValidPostRequest($event, $request);
134
    }
135
136
    /**
137
     * @param FormEvent $event
138
     * @param Request $request
139
     * @return RedirectResponse
140
     */
141
    protected function getRedirectResponse(FormEvent $event, Request $request)
142
    {
143
        if ($request->query->has('redirect_uri')) {
144
            return new RedirectResponse($request->query->get('redirect_uri'));
145
        }
146
147
        return parent::getRedirectResponse($event, $request);
148
    }
149
150
    /**
151
     * @return string
152
     */
153
    protected function getPreSaveEventName()
154
    {
155
        return BatchEvents::BATCH_OBJECTS_PRE_APPLY;
156
    }
157
158
    /**
159
     * @return string
160
     */
161
    protected function getPostSaveEventName()
162
    {
163
        return BatchEvents::BATCH_OBJECTS_POST_APPLY;
164
    }
165
166
    private function setWarningMessage()
167
    {
168
        if ($this->flashMessages) {
169
            $this->flashMessages->warning('messages.batch.no_elements');
170
        }
171
    }
172
173
    /**
174
     * @param BatchEvent $event
175
     * @return boolean
176
     */
177
    private function checkIfAbort($event)
178
    {
179
        if (!($event instanceof BatchEvent)) {
180
            return false;
181
        }
182
183
        return $event->getAbort();
184
    }
185
186
    /**
187
     * @param BatchEvent $event
188
     * @return boolean
189
     */
190
    private function checkIfSkip($event)
191
    {
192
        if (!($event instanceof BatchEvent)) {
193
            return false;
194
        }
195
196
        return $event->getSkipElement();
197
    }
198
199
    private function isAbortIfSkipped(BatchElement $element)
200
    {
201
        return $element->hasOption('abort_if_skipped') && $element->getOption('abort_if_skipped');
202
    }
203
}
204