1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* This file is part of the Superdesk Web Publisher Template Engine 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
|
|
|
namespace SWP\Bundle\TemplateEngineBundle\Controller; |
15
|
|
|
|
16
|
|
|
use FOS\RestBundle\Controller\FOSRestController; |
17
|
|
|
use Nelmio\ApiDocBundle\Annotation\ApiDoc; |
18
|
|
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; |
19
|
|
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; |
20
|
|
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache; |
21
|
|
|
use FOS\RestBundle\View\View; |
22
|
|
|
use Symfony\Component\HttpFoundation\Request; |
23
|
|
|
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException; |
24
|
|
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; |
25
|
|
|
use SWP\Bundle\TemplateEngineBundle\Form\Type\ContainerType; |
26
|
|
|
use SWP\Bundle\TemplateEngineBundle\Model\Widget; |
27
|
|
|
use SWP\Bundle\TemplateEngineBundle\Model\ContainerWidget; |
28
|
|
|
use SWP\Bundle\TemplateEngineBundle\Model\ContainerData; |
29
|
|
|
use SWP\Component\Common\Event\HttpCacheEvent; |
30
|
|
|
|
31
|
|
|
class ContainerController extends FOSRestController |
32
|
|
|
{ |
33
|
|
|
/** |
34
|
|
|
* Lists all registered containers. |
35
|
|
|
* |
36
|
|
|
* @ApiDoc( |
37
|
|
|
* resource=true, |
38
|
|
|
* description="Lists all registered containers", |
39
|
|
|
* statusCodes={ |
40
|
|
|
* 200="Returned on success." |
41
|
|
|
* } |
42
|
|
|
* ) |
43
|
|
|
* @Route("/api/{version}/templates/containers/", options={"expose"=true}, defaults={"version"="v1"}, name="swp_api_templates_list_containers") |
44
|
|
|
* @Method("GET") |
45
|
|
|
* @Cache(expires="10 minutes", public=true) |
46
|
|
|
*/ |
47
|
|
View Code Duplication |
public function listAction(Request $request) |
|
|
|
|
48
|
|
|
{ |
49
|
|
|
$entityManager = $this->get('doctrine')->getManager(); |
50
|
|
|
$paginator = $this->get('knp_paginator'); |
51
|
|
|
$containers = $paginator->paginate($entityManager->getRepository('SWP\Bundle\TemplateEngineBundle\Model\Container')->getAll()); |
52
|
|
|
|
53
|
|
|
if (count($containers) == 0) { |
54
|
|
|
throw new NotFoundHttpException('Containers were not found.'); |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
return $this->handleView(View::create($this->container->get('swp_pagination_rep')->createRepresentation($containers, $request), 200)); |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Get single container. |
62
|
|
|
* |
63
|
|
|
* @ApiDoc( |
64
|
|
|
* resource=true, |
65
|
|
|
* description="Get single container", |
66
|
|
|
* statusCodes={ |
67
|
|
|
* 200="Returned on success.", |
68
|
|
|
* 404="Container not found", |
69
|
|
|
* 422="Container id is not number" |
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(Request $request, $id) |
|
|
|
|
77
|
|
|
{ |
78
|
|
|
$container = $this->get('doctrine')->getManager() |
79
|
|
|
->getRepository('SWP\Bundle\TemplateEngineBundle\Model\Container') |
80
|
|
|
->getById($id) |
81
|
|
|
->getOneOrNullResult(); |
82
|
|
|
|
83
|
|
|
if (!$container) { |
84
|
|
|
throw new NotFoundHttpException('Container with this id was not found.'); |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
$this->get('event_dispatcher') |
88
|
|
|
->dispatch(HttpCacheEvent::EVENT_NAME, new HttpCacheEvent($container)); |
89
|
|
|
|
90
|
|
|
return $this->handleView(View::create($container, 200)); |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* Update single container. |
95
|
|
|
* |
96
|
|
|
* @ApiDoc( |
97
|
|
|
* resource=true, |
98
|
|
|
* description="Update single container", |
99
|
|
|
* statusCodes={ |
100
|
|
|
* 201="Returned on success.", |
101
|
|
|
* 404="Container not found", |
102
|
|
|
* 422="Container id is not number" |
103
|
|
|
* }, |
104
|
|
|
* input="SWP\Bundle\TemplateEngineBundle\Form\Type\ContainerType" |
105
|
|
|
* ) |
106
|
|
|
* @Route("/api/{version}/templates/containers/{id}", requirements={"id"="\d+"}, options={"expose"=true}, defaults={"version"="v1"}, name="swp_api_templates_update_container") |
107
|
|
|
* @Method("PATCH") |
108
|
|
|
*/ |
109
|
|
|
public function updateAction(Request $request, $id) |
110
|
|
|
{ |
111
|
|
|
$entityManager = $this->get('doctrine')->getManager(); |
112
|
|
|
$container = $entityManager->getRepository('SWP\Bundle\TemplateEngineBundle\Model\Container') |
113
|
|
|
->getById($id) |
114
|
|
|
->getOneOrNullResult(); |
115
|
|
|
|
116
|
|
|
if (!$container) { |
117
|
|
|
throw new NotFoundHttpException('Container with this id was not found.'); |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
$form = $this->createForm(ContainerType::class, $container, array( |
121
|
|
|
'method' => $request->getMethod(), |
122
|
|
|
)); |
123
|
|
|
|
124
|
|
|
$form->handleRequest($request); |
125
|
|
|
if ($form->isValid()) { |
126
|
|
|
$extraData = $form->get('data')->getExtraData(); |
127
|
|
|
if ($extraData && is_array($extraData)) { |
|
|
|
|
128
|
|
|
// Remove old containerData's |
129
|
|
|
foreach ($container->getData() as $containerData) { |
130
|
|
|
$entityManager->remove($containerData); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
// Apply new containerData's |
134
|
|
|
foreach ($extraData as $key => $value) { |
135
|
|
|
$containerData = new ContainerData($key, $value); |
136
|
|
|
$containerData->setContainer($container); |
137
|
|
|
$entityManager->persist($containerData); |
138
|
|
|
$container->addData($containerData); |
139
|
|
|
} |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
$entityManager->flush($container); |
143
|
|
|
$entityManager->refresh($container); |
144
|
|
|
$this->get('event_dispatcher') |
145
|
|
|
->dispatch(HttpCacheEvent::EVENT_NAME, new HttpCacheEvent($container)); |
146
|
|
|
|
147
|
|
|
return $this->handleView(View::create($container, 201)); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
return $this->handleView(View::create($form, 200)); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* Link or Unlink resource with Container. |
155
|
|
|
* |
156
|
|
|
* **link or unlink widget**: |
157
|
|
|
* |
158
|
|
|
* header name: "link" |
159
|
|
|
* header value: "</api/{version}/templates/widgets/{id}; rel="widget">" |
160
|
|
|
* |
161
|
|
|
* or with specific position: |
162
|
|
|
* |
163
|
|
|
* header name: "link" |
164
|
|
|
* header value: "</api/{version}/templates/widgets/{id}; rel="widget">,<1; rel="widget-position">" |
165
|
|
|
* |
166
|
|
|
* @ApiDoc( |
167
|
|
|
* statusCodes={ |
168
|
|
|
* 201="Returned when successful", |
169
|
|
|
* 404="Returned when resource not found", |
170
|
|
|
* 409={ |
171
|
|
|
* "Returned when the link already exists", |
172
|
|
|
* } |
173
|
|
|
* } |
174
|
|
|
* ) |
175
|
|
|
* |
176
|
|
|
* @Route("/api/{version}/templates/containers/{id}", requirements={"id"="\d+"}, defaults={"version"="v1"}, name="swp_api_templates_link_container") |
177
|
|
|
* |
178
|
|
|
* @Method("LINK|UNLINK") |
179
|
|
|
* |
180
|
|
|
* @return \Symfony\Component\HttpFoundation\Response |
181
|
|
|
*/ |
182
|
|
|
public function linkUnlinkToContainerAction(Request $request, $id) |
183
|
|
|
{ |
184
|
|
|
if (!$id) { |
185
|
|
|
throw new UnprocessableEntityHttpException('You need to provide container Id (integer).'); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
$entityManager = $this->get('doctrine')->getManager(); |
189
|
|
|
$container = $entityManager->getRepository('SWP\Bundle\TemplateEngineBundle\Model\Container') |
190
|
|
|
->getById($id) |
191
|
|
|
->getOneOrNullResult(); |
192
|
|
|
|
193
|
|
|
if (!$container) { |
194
|
|
|
throw new NotFoundHttpException('Container with this id was not found.'); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
$matched = false; |
198
|
|
|
foreach ($request->attributes->get('links', array()) as $key => $objectArray) { |
199
|
|
|
if (!is_array($objectArray)) { |
200
|
|
|
continue; |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
$resourceType = $objectArray['resourceType']; |
|
|
|
|
204
|
|
|
$object = $objectArray['object']; |
205
|
|
|
|
206
|
|
|
if ($object instanceof \Exception) { |
207
|
|
|
throw $object; |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
if ($object instanceof Widget) { |
211
|
|
|
$containerWidget = $entityManager->getRepository('SWP\Bundle\TemplateEngineBundle\Model\ContainerWidget') |
212
|
|
|
->findOneBy([ |
213
|
|
|
'widget' => $object, |
214
|
|
|
'container' => $container, |
215
|
|
|
]); |
216
|
|
|
if ($request->getMethod() === 'LINK') { |
217
|
|
|
$position = false; |
218
|
|
|
if (count($notConvertedLinks = $this->getNotConvertedLinks($request)) > 0) { |
219
|
|
|
foreach ($notConvertedLinks as $link) { |
220
|
|
|
if (isset($link['resourceType']) && $link['resourceType'] == 'widget-position') { |
221
|
|
|
$position = $link['resource']; |
222
|
|
|
} |
223
|
|
|
} |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
if ($position === false && $containerWidget) { |
227
|
|
|
throw new \Exception('Widget is already linked to container', 409); |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
if (!$containerWidget) { |
231
|
|
|
$containerWidget = new ContainerWidget($container, $object); |
232
|
|
|
$entityManager->persist($containerWidget); |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
if ($position !== false) { |
236
|
|
|
$containerWidget->setPosition($position); |
237
|
|
|
$entityManager->persist($containerWidget); |
238
|
|
|
$entityManager->flush($containerWidget); |
239
|
|
|
} |
240
|
|
|
} elseif ($request->getMethod() === 'UNLINK') { |
241
|
|
|
if (!$container->getWidgets()->contains($containerWidget)) { |
242
|
|
|
throw new \Exception('Widget is not linked to container', 409); |
243
|
|
|
} |
244
|
|
|
$entityManager->remove($containerWidget); |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
$entityManager->flush(); |
248
|
|
|
$this->get('event_dispatcher') |
249
|
|
|
->dispatch(HttpCacheEvent::EVENT_NAME, new HttpCacheEvent($container)); |
250
|
|
|
$matched = true; |
251
|
|
|
break; |
252
|
|
|
} |
253
|
|
|
} |
254
|
|
|
if ($matched === false) { |
255
|
|
|
throw new NotFoundHttpException('Any supported link object was not found'); |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
return $this->handleView(View::create($container, 201)); |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
/** |
262
|
|
|
* @param Request $request |
263
|
|
|
*/ |
264
|
|
|
private function getNotConvertedLinks($request) |
265
|
|
|
{ |
266
|
|
|
$links = array(); |
267
|
|
|
foreach ($request->attributes->get('links') as $idx => $link) { |
268
|
|
|
if (is_string($link)) { |
269
|
|
|
$linkParams = explode(';', trim($link)); |
270
|
|
|
$resourceType = null; |
271
|
|
View Code Duplication |
if (count($linkParams) > 1) { |
|
|
|
|
272
|
|
|
$resourceType = trim(preg_replace('/<|>/', '', $linkParams[1])); |
273
|
|
|
$resourceType = str_replace('"', '', str_replace('rel=', '', $resourceType)); |
274
|
|
|
} |
275
|
|
|
$resource = array_shift($linkParams); |
276
|
|
|
$resource = preg_replace('/<|>/', '', $resource); |
277
|
|
|
|
278
|
|
|
$links[] = array( |
279
|
|
|
'resource' => $resource, |
280
|
|
|
'resourceType' => $resourceType, |
281
|
|
|
); |
282
|
|
|
} |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
return $links; |
286
|
|
|
} |
287
|
|
|
} |
288
|
|
|
|
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.