Completed
Push — master ( f6198e...300d99 )
by Paweł
53:20
created

ContainerController::linkUnlinkToContainerAction()   C

Complexity

Conditions 19
Paths 32

Size

Total Lines 76
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 42
CRAP Score 19

Importance

Changes 0
Metric Value
dl 0
loc 76
ccs 42
cts 42
cp 1
rs 5.222
c 0
b 0
f 0
cc 19
eloc 47
nc 32
nop 2
crap 19

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the Superdesk Web Publisher Core Bundle.
5
 *
6
 * Copyright 2015 Sourcefabric z.u. and contributors.
7
 *
8
 * For the full copyright and license information, please see the
9
 * AUTHORS and LICENSE files distributed with this source code.
10
 *
11
 * @copyright 2015 Sourcefabric z.ú
12
 * @license http://www.superdesk.org/license
13
 */
14
15
namespace SWP\Bundle\CoreBundle\Controller;
16
17
use SWP\Component\Common\Criteria\Criteria;
18
use SWP\Component\Common\Pagination\PaginationData;
19
use SWP\Component\TemplatesSystem\Gimme\Model\ContainerInterface;
20
use SWP\Component\TemplatesSystem\Gimme\Model\WidgetModelInterface;
21
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
22
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
23
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
24
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
25
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
26
use SWP\Component\Common\Response\ResourcesListResponse;
27
use SWP\Component\Common\Response\ResponseContext;
28
use SWP\Component\Common\Response\SingleResourceResponse;
29
use SWP\Bundle\TemplatesSystemBundle\Form\Type\ContainerType;
30
use SWP\Bundle\TemplatesSystemBundle\Model\ContainerData;
31
use SWP\Bundle\TemplatesSystemBundle\Model\ContainerWidget;
32
use Symfony\Component\HttpFoundation\Request;
33
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
34
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
35
36
class ContainerController extends Controller
37
{
38
    /**
39
     * Lists all registered containers.
40
     *
41
     * @ApiDoc(
42
     *     resource=true,
43
     *     description="Lists all registered containers",
44
     *     statusCodes={
45
     *         200="Returned on success."
46
     *     }
47
     * )
48
     * @Route("/api/{version}/templates/containers/", options={"expose"=true}, defaults={"version"="v1"}, name="swp_api_templates_list_containers")
49
     * @Method("GET")
50 1
     * @Cache(expires="10 minutes", public=true)
51
     */
52 1
    public function listAction(Request $request)
53 1
    {
54 1
        $repository = $this->get('swp.repository.container');
55 1
56 1
        $containers = $repository->getPaginatedByCriteria(new Criteria(), [], new PaginationData($request));
57 1
58
        return new ResourcesListResponse($containers);
59
    }
60 1
61
    /**
62
     * Get single container.
63
     *
64 1
     * @ApiDoc(
65
     *     resource=true,
66
     *     description="Get single container",
67
     *     statusCodes={
68
     *         200="Returned on success.",
69
     *         404="Container not found"
70
     *     }
71
     * )
72
     * @Route("/api/{version}/templates/containers/{id}", requirements={"id"="\d+"}, options={"expose"=true}, defaults={"version"="v1"}, name="swp_api_templates_get_container")
73
     * @Method("GET")
74
     * @Cache(expires="10 minutes", public=true)
75
     */
76
    public function getAction($id)
77
    {
78
        $container = $this->get('doctrine')->getManager()
79
            ->getRepository('SWP\Bundle\CoreBundle\Model\Container')
80
            ->getById($id)
81
            ->getOneOrNullResult();
82
83 1
        if (!$container) {
84
            throw new NotFoundHttpException('Container with this id was not found.');
85 1
        }
86 1
87 1
        return new SingleResourceResponse($container);
88 1
    }
89
90 1
    /**
91
     * Render single container and it's widgets.
92
     *
93
     * @ApiDoc(
94 1
     *     resource=true,
95
     *     description="Render single container and it's widgets.",
96
     *     statusCodes={
97
     *         200="Returned on success.",
98
     *         404="Container not found"
99
     *     }
100
     * )
101
     * @Route("/api/{version}/templates/containers/{id}/render", requirements={"id"="\d+"}, options={"expose"=true}, defaults={"version"="v1"}, name="swp_api_templates_render_container")
102
     * @Method("GET")
103
     * @Cache(expires="10 minutes", public=true)
104
     */
105
    public function renderAction($id)
106
    {
107
        /** @var ContainerInterface $container */
108
        $container = $this->get('swp.repository.container')
109
            ->getById($id)
110
            ->getOneOrNullResult();
111
112
        if (!$container) {
113 3
            throw new NotFoundHttpException('Container with this id was not found.');
114
        }
115 3
116 3
        $content = $this->get('templating')
117 3
            ->render('SWPCoreBundle:Container:render.html.twig', ['containerName' => $container->getName()]);
118 3
119
        return new SingleResourceResponse(['content' => $content]);
120 3
    }
121
122
    /**
123
     * Update single container.
124 3
     *
125 3
     * @ApiDoc(
126
     *     resource=true,
127
     *     description="Update single container",
128 3
     *     statusCodes={
129 3
     *         201="Returned on success.",
130 3
     *         404="Container not found",
131 3
     *         422="Container id is not number"
132
     *     },
133 1
     *     input="SWP\Bundle\TemplatesSystemBundle\Form\Type\ContainerType"
134 1
     * )
135
     * @Route("/api/{version}/templates/containers/{id}", requirements={"id"="\d+"}, options={"expose"=true}, defaults={"version"="v1"}, name="swp_api_templates_update_container")
136
     * @Method("PATCH")
137
     */
138 1
    public function updateAction(Request $request, $id)
139 1
    {
140 1
        $entityManager = $this->get('doctrine')->getManager();
141 1
        $container = $entityManager->getRepository('SWP\Bundle\CoreBundle\Model\Container')
142 1
            ->getById($id)
143
            ->getOneOrNullResult();
144
145
        if (!$container) {
146 3
            throw new NotFoundHttpException('Container with this id was not found.');
147 3
        }
148
149 3
        $form = $this->createForm(ContainerType::class, $container, [
150
            'method' => $request->getMethod(),
151
        ]);
152
153
        $form->handleRequest($request);
154
        if ($form->isValid()) {
155
            $extraData = $form->get('data')->getExtraData();
156
            if (!empty($extraData) && is_array($extraData)) {
157
                // Remove old containerData's
158
                foreach ($container->getData() as $containerData) {
159
                    $entityManager->remove($containerData);
160
                }
161
162
                // Apply new containerData's
163
                foreach ($extraData as $key => $value) {
164
                    $containerData = new ContainerData($key, $value);
165
                    $containerData->setContainer($container);
166
                    $entityManager->persist($containerData);
167
                    $container->addData($containerData);
168
                }
169
            }
170
171
            $entityManager->flush($container);
172
            $entityManager->refresh($container);
173
174
            return new SingleResourceResponse($container, new ResponseContext(201));
175
        }
176
177
        return new SingleResourceResponse($form);
178
    }
179
180
    /**
181
     * Link or Unlink resource with Container.
182
     *
183
     * **link or unlink widget**:
184
     *
185
     *     header name: "link"
186
     *     header value: "</api/{version}/templates/widgets/{id}; rel="widget">"
187
     *
188
     * or with specific position:
189
     *
190 2
     *     header name: "link"
191
     *     header value: "</api/{version}/templates/widgets/{id}; rel="widget">,<1; rel="widget-position">"
192 2
     *
193
     * @ApiDoc(
194
     *     statusCodes={
195
     *         201="Returned when successful",
196 2
     *         404="Returned when resource not found",
197 2
     *         409={
198 2
     *           "Returned when the link already exists",
199 2
     *         }
200
     *     }
201 2
     * )
202
     *
203
     * @Route("/api/{version}/templates/containers/{id}", requirements={"id"="\d+"}, defaults={"version"="v1"}, name="swp_api_templates_link_container")
204
     *
205 2
     * @Method("LINK|UNLINK")
206 2
     *
207 2
     * @param Request $request
208
     * @param string  $id
209
     *
210
     * @throws NotFoundHttpException
211 2
     * @throws \Exception
212 2
     *
213
     * @return \Symfony\Component\HttpFoundation\Response
214
     */
215
    public function linkUnlinkToContainerAction(Request $request, $id)
216 2
    {
217 2
        if (!$id) {
218 2
            throw new UnprocessableEntityHttpException('You need to provide container Id (integer).');
219 2
        }
220 2
221
        $entityManager = $this->get('doctrine')->getManager();
222 2
        $container = $entityManager->getRepository('SWP\Bundle\CoreBundle\Model\Container')
223 2
            ->getById($id)
224 2
            ->getOneOrNullResult();
225 1
226 1
        if (!$container) {
227 1
            throw new NotFoundHttpException('Container with this id was not found.');
228
        }
229
230
        $matched = false;
231
        foreach ($request->attributes->get('links', []) as $key => $objectArray) {
232 2
            if (!is_array($objectArray)) {
233
                continue;
234
            }
235
236 2
            $object = $objectArray['object'];
237 2
            if ($object instanceof \Exception) {
238 2
                throw $object;
239
            }
240
241 2
            if ($object instanceof WidgetModelInterface) {
242 1
                $containerWidget = $entityManager->getRepository('SWP\Bundle\TemplatesSystemBundle\Model\ContainerWidget')
243 1
                    ->findOneBy([
244 1
                        'widget' => $object,
245 2
                        'container' => $container,
246
                    ]);
247 1
                if ($request->getMethod() === 'LINK') {
248 1
                    $position = false;
249
                    if (count($notConvertedLinks = $this->getNotConvertedLinks($request)) > 0) {
250
                        foreach ($notConvertedLinks as $link) {
251 1
                            if (isset($link['resourceType']) && $link['resourceType'] == 'widget-position') {
252
                                $position = $link['resource'];
253
                            }
254 2
                        }
255 2
                    }
256
257
                    if ($position === false && $containerWidget) {
258 2
                        throw new \Exception('WidgetModel is already linked to container', 409);
259
                    }
260
261
                    if (!$containerWidget) {
262 2
                        $containerWidget = new ContainerWidget($container, $object);
263
                        $entityManager->persist($containerWidget);
264 2
                    }
265
266
                    if ($position !== false) {
267
                        $containerWidget->setPosition($position);
268
                        $entityManager->persist($containerWidget);
269
                        $container->addWidget($containerWidget);
270
                        $entityManager->flush();
271
                    }
272 2
                } elseif ($request->getMethod() === 'UNLINK') {
273
                    if (!$container->getWidgets()->contains($containerWidget)) {
274 2
                        throw new \Exception('WidgetModel is not linked to container', 409);
275 2
                    }
276 2
                    $entityManager->remove($containerWidget);
277 1
                }
278 1
279 1
                $matched = true;
280 1
                break;
281 1
            }
282
        }
283 1
        if ($matched === false) {
284 1
            throw new NotFoundHttpException('Any supported link object was not found');
285
        }
286 1
287 1
        $entityManager->flush();
288 2
289
        return new SingleResourceResponse($container, new ResponseContext(201));
290
    }
291
292
    /**
293 2
     * @param Request $request
294
     *
295
     * @return array
296
     */
297
    private function getNotConvertedLinks($request)
298
    {
299
        $links = [];
300
        foreach ($request->attributes->get('links') as $idx => $link) {
301
            if (is_string($link)) {
302
                $linkParams = explode(';', trim($link));
303
                $resourceType = null;
304 View Code Duplication
                if (count($linkParams) > 1) {
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...
305
                    $resourceType = trim(preg_replace('/<|>/', '', $linkParams[1]));
306
                    $resourceType = str_replace('"', '', str_replace('rel=', '', $resourceType));
307
                }
308
                $resource = array_shift($linkParams);
309
                $resource = preg_replace('/<|>/', '', $resource);
310
311
                $links[] = [
312
                    'resource' => $resource,
313
                    'resourceType' => $resourceType,
314
                ];
315
            }
316
        }
317
318
        return $links;
319
    }
320
}
321