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

ContainerController   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 285
Duplicated Lines 1.4 %

Coupling/Cohesion

Components 1
Dependencies 14

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 35
lcom 1
cbo 14
dl 4
loc 285
ccs 93
cts 93
cp 1
rs 9
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A listAction() 0 8 1
A getAction() 0 13 2
A renderAction() 0 16 2
C updateAction() 0 41 7
C linkUnlinkToContainerAction() 0 76 19
B getNotConvertedLinks() 4 23 4

How to fix   Duplicated Code   

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:

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