Failed Conditions
Push — issue#808 ( 868db7...3c2936 )
by Guilherme
07:23
created

DynamicFormService::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 6
dl 0
loc 14
ccs 7
cts 7
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of the login-cidadao project or it's bundles.
4
 *
5
 * (c) Guilherme Donato <guilhermednt on github>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace LoginCidadao\DynamicFormBundle\Service;
12
13
use Doctrine\ORM\EntityManagerInterface;
14
use FOS\UserBundle\Event\FilterUserResponseEvent;
15
use FOS\UserBundle\Event\FormEvent;
16
use FOS\UserBundle\Event\GetResponseUserEvent;
17
use FOS\UserBundle\FOSUserEvents;
18
use FOS\UserBundle\Model\UserManagerInterface;
19
use LoginCidadao\DynamicFormBundle\DynamicFormEvents;
20
use LoginCidadao\CoreBundle\Entity\City;
21
use LoginCidadao\CoreBundle\Entity\Country;
22
use LoginCidadao\CoreBundle\Entity\PersonAddress;
23
use LoginCidadao\CoreBundle\Entity\State;
24
use LoginCidadao\CoreBundle\Entity\StateRepository;
25
use LoginCidadao\CoreBundle\Model\IdCardInterface;
26
use LoginCidadao\CoreBundle\Model\PersonInterface;
27
use LoginCidadao\CoreBundle\Model\LocationSelectData;
28
use LoginCidadao\DynamicFormBundle\Form\DynamicFormBuilder;
29
use LoginCidadao\DynamicFormBundle\Model\DynamicFormData;
30
use LoginCidadao\OAuthBundle\Model\ClientInterface;
31
use LoginCidadao\OpenIDBundle\Task\CompleteUserInfoTask;
32
use LoginCidadao\TaskStackBundle\Service\TaskStackManagerInterface;
33
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
34
use Symfony\Component\Form\FormInterface;
35
use Symfony\Component\HttpFoundation\RedirectResponse;
36
use Symfony\Component\HttpFoundation\Request;
37
use Symfony\Component\HttpFoundation\Response;
38
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
39
use Symfony\Component\Routing\RouterInterface;
40
41
class DynamicFormService implements DynamicFormServiceInterface
42
{
43
    /** @var EntityManagerInterface */
44
    private $em;
45
46
    /** @var EventDispatcherInterface */
47
    private $dispatcher;
48
49
    /** @var UserManagerInterface */
50
    private $userManager;
51
52
    /** @var TaskStackManagerInterface */
53
    private $taskStackManager;
54
55
    /** @var DynamicFormBuilder */
56
    private $dynamicFormBuilder;
57
58
    /** @var RouterInterface */
59
    private $router;
60
61
    /**
62
     * DynamicFormService constructor.
63
     * @param EntityManagerInterface $em
64
     * @param EventDispatcherInterface $dispatcher
65
     * @param UserManagerInterface $userManager
66
     * @param TaskStackManagerInterface $taskStackManager
67
     * @param DynamicFormBuilder $dynamicFormBuilder
68
     * @param RouterInterface $router
69
     */
70 18
    public function __construct(
71
        EntityManagerInterface $em,
72
        EventDispatcherInterface $dispatcher,
73
        UserManagerInterface $userManager,
74
        TaskStackManagerInterface $taskStackManager,
75
        DynamicFormBuilder $dynamicFormBuilder,
76
        RouterInterface $router
77
    ) {
78 18
        $this->em = $em;
79 18
        $this->dispatcher = $dispatcher;
80 18
        $this->userManager = $userManager;
81 18
        $this->taskStackManager = $taskStackManager;
82 18
        $this->dynamicFormBuilder = $dynamicFormBuilder;
83 18
        $this->router = $router;
84 18
    }
85
86 4
    public function getDynamicFormData(PersonInterface $person, Request $request, $scope)
87
    {
88 4
        $nextTask = $this->taskStackManager->getNextTask();
89 4
        $redirectUrl = $request->get('redirect_url');
90 4
        if ($nextTask) {
91 3
            $redirectUrl = $this->taskStackManager->getTargetUrl($nextTask->getTarget());
92
        }
93 4
        if (!$redirectUrl) {
94 1
            $redirectUrl = $this->router->generate('lc_dashboard');
95
        }
96
97 4
        $placeOfBirth = new LocationSelectData();
98 4
        $placeOfBirth->getFromObject($person);
99
100 4
        $data = new DynamicFormData();
101 4
        $data->setPerson($person)
102 4
            ->setRedirectUrl($redirectUrl)
103 4
            ->setScope($scope)
104 4
            ->setPlaceOfBirth($placeOfBirth)
105 4
            ->setIdCardState($this->getStateFromRequest($request));
106
107 4
        $this->dispatchProfileEditInitialize($request, $person);
108
109 4
        return $data;
110
    }
111
112 1
    public function buildForm(FormInterface $form, DynamicFormData $data, array $scopes)
113
    {
114 1
        foreach ($scopes as $scope) {
115 1
            $this->dynamicFormBuilder->addFieldFromScope($form, $scope, $data);
116
        }
117 1
        $form->add('redirect_url', 'hidden')
118 1
            ->add('scope', 'hidden');
119
120 1
        return $form;
121
    }
122
123 3
    public function processForm(FormInterface $form, Request $request)
124
    {
125
        $dynamicFormResponse = [
126 3
            'response' => null,
127 3
            'form' => $form,
128
        ];
129 3
        $form->handleRequest($request);
130 3
        if (!$form->isValid()) {
131 1
            return $dynamicFormResponse;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $dynamicFormResponse returns the type array<string,Symfony\Com...orm\FormInterface|null> which is incompatible with the return type mandated by LoginCidadao\DynamicForm...nterface::processForm() of Symfony\Component\Form\FormInterface.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
132
        }
133
134 2
        $this->dispatchFormEvent($form, $request, DynamicFormEvents::POST_FORM_VALIDATION);
135 2
        $event = null;
136 2
        if ($form->has('person')) {
137 1
            $event = $this->dispatchFormEvent($form->get('person'), $request, FOSUserEvents::PROFILE_EDIT_SUCCESS);
138
        }
139
140
        /** @var DynamicFormData $data */
141 2
        $data = $form->getData();
142 2
        $person = $data->getPerson();
143 2
        $address = $data->getAddress();
144 2
        $idCard = $data->getIdCard();
145 2
        $placeOfBirth = $data->getPlaceOfBirth();
146
147 2
        if ($placeOfBirth instanceof LocationSelectData) {
0 ignored issues
show
introduced by
$placeOfBirth is always a sub-type of LoginCidadao\CoreBundle\Model\LocationSelectData.
Loading history...
148 1
            $placeOfBirth->toObject($person);
149
        }
150
151 2
        $this->userManager->updateUser($person);
152
153 2
        if ($address instanceof PersonAddress) {
0 ignored issues
show
introduced by
$address is always a sub-type of LoginCidadao\CoreBundle\Entity\PersonAddress.
Loading history...
154 2
            $address->setPerson($person);
155 2
            $this->em->persist($address);
156
        }
157
158 2
        if ($idCard instanceof IdCardInterface) {
0 ignored issues
show
introduced by
$idCard is always a sub-type of LoginCidadao\CoreBundle\Model\IdCardInterface.
Loading history...
159 1
            $this->em->persist($idCard);
160
        }
161
162 2
        $currentTask = $this->taskStackManager->getCurrentTask();
163 2
        if ($currentTask instanceof CompleteUserInfoTask) {
164 2
            $this->taskStackManager->setTaskSkipped($currentTask);
165
        }
166
167 2
        $response = new RedirectResponse($data->getRedirectUrl());
168 2
        $response = $this->taskStackManager->processRequest($request, $response);
169 2
        if ($event && $response) {
170 1
            $event->setResponse($response);
171
        }
172 2
        $this->dispatchProfileEditCompleted($person, $request, $response);
173 2
        $this->em->flush();
174
175 2
        if ($form->has('person')) {
176 1
            $this->dispatcher->dispatch(DynamicFormEvents::POST_FORM_EDIT, $event);
177 1
            $this->dispatcher->dispatch(DynamicFormEvents::PRE_REDIRECT, $event);
178
        }
179
180 2
        $dynamicFormResponse['response'] = $response;
181 2
        if ($event) {
182 1
            $dynamicFormResponse['response'] = $event->getResponse();
183
        }
184
185 2
        return $dynamicFormResponse;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $dynamicFormResponse returns the type array<string,Symfony\Com...orm\FormInterface|null> which is incompatible with the return type mandated by LoginCidadao\DynamicForm...nterface::processForm() of Symfony\Component\Form\FormInterface.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
186
    }
187
188 3
    public function getClient($clientId)
189
    {
190 3
        $parsing = explode('_', $clientId, 2);
191 3
        if (count($parsing) !== 2) {
192 1
            throw new \InvalidArgumentException('Invalid client_id.');
193
        }
194
195 2
        $client = $this->em->getRepository('LoginCidadaoOAuthBundle:Client')
196 2
            ->findOneBy(['id' => $parsing[0], 'randomId' => $parsing[1]]);
197
198 2
        if (!$client instanceof ClientInterface) {
199 1
            throw new NotFoundHttpException('Client not found');
200
        }
201
202 1
        return $client;
203
    }
204
205 4
    private function dispatchProfileEditInitialize(Request $request, PersonInterface $person)
206
    {
207 4
        $event = new GetResponseUserEvent($person, $request);
208 4
        $this->dispatcher->dispatch(FOSUserEvents::PROFILE_EDIT_INITIALIZE, $event);
209
210 4
        return $event;
211
    }
212
213 2
    private function dispatchFormEvent(FormInterface $form, Request $request, $eventName)
214
    {
215 2
        $event = new FormEvent($form, $request);
216 2
        $this->dispatcher->dispatch($eventName, $event);
217
218 2
        return $event;
219
    }
220
221 2
    private function dispatchProfileEditCompleted(PersonInterface $person, Request $request, Response $response)
222
    {
223 2
        $event = new FilterUserResponseEvent($person, $request, $response);
224 2
        $this->dispatcher->dispatch(FOSUserEvents::PROFILE_EDIT_COMPLETED, $event);
225
226 2
        return $event;
227
    }
228
229
    /**
230
     * @param Request $request
231
     * @return State
232
     */
233 4
    private function getStateFromRequest(Request $request)
234
    {
235
        /** @var StateRepository $repo */
236 4
        $repo = $this->em->getRepository('LoginCidadaoCoreBundle:State');
237
238 4
        $stateId = $request->get('id_card_state_id', null);
239 4
        if ($stateId !== null) {
240
            /** @var State $state */
241 1
            $state = $repo->find($stateId);
242
243 1
            return $state;
244
        }
245
246 3
        $stateAcronym = $request->get('id_card_state', null);
247 3
        if ($stateAcronym !== null) {
248
            /** @var State $state */
249 1
            $state = $repo->findOneBy(['acronym' => $stateAcronym]);
250
251 1
            return $state;
252
        }
253
254 2
        return null;
255
    }
256
257 4
    public function getLocationDataFromRequest(Request $request)
258
    {
259 4
        $country = $this->getLocation($request, 'country');
260 4
        $state = $this->getLocation($request, 'state');
261 4
        $city = $this->getLocation($request, 'city');
262
263 4
        $locationData = new LocationSelectData();
264
265 4
        if ($city instanceof City) {
266 1
            $locationData->setCity($city)
267 1
                ->setState($city->getState())
268 1
                ->setCountry($city->getState()->getCountry());
269 3
        } elseif ($state instanceof State) {
270 1
            $locationData->setCity(null)
271 1
                ->setState($state)
272 1
                ->setCountry($state->getCountry());
273 2
        } elseif ($country instanceof Country) {
274 1
            $locationData->setCity(null)
275 1
                ->setState(null)
276 1
                ->setCountry($country);
277
        }
278
279 4
        $data = new DynamicFormData();
280 4
        $data->setPlaceOfBirth($locationData);
281
282 4
        return $data;
283
    }
284
285 3
    private function getLocationRepository($type)
286
    {
287 3
        $repo = null;
288
        switch ($type) {
289 3
            case 'city':
290 3
            case 'state':
291 3
            case 'country':
292 3
                $repo = $this->em->getRepository('LoginCidadaoCoreBundle:'.ucfirst($type));
293 3
                break;
294
        }
295
296 3
        return $repo;
297
    }
298
299 4
    private function getLocation(Request $request, $type)
300
    {
301 4
        $id = $request->get($type);
302 4
        if ($id === null) {
303 1
            return null;
304
        }
305 3
        $repo = $this->getLocationRepository($type);
306
307 3
        return $repo->find($id);
308
    }
309
310 1
    public function skipCurrent(Request $request, Response $defaultResponse)
311
    {
312 1
        $task = $this->taskStackManager->getCurrentTask();
313 1
        if ($task instanceof CompleteUserInfoTask) {
314 1
            $this->taskStackManager->setTaskSkipped($task);
315
        }
316
317 1
        return $this->taskStackManager->processRequest($request, $defaultResponse);
318
    }
319
320 2
    public function getSkipUrl(DynamicFormData $data)
321
    {
322 2
        $task = $this->taskStackManager->getCurrentTask();
323 2
        if ($task instanceof CompleteUserInfoTask) {
324 1
            return $this->router->generate('dynamic_form_skip');
325
        }
326
327 1
        return $data->getRedirectUrl();
328
    }
329
}
330