These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | /* |
||
6 | * This file is part of the Sonata Project package. |
||
7 | * |
||
8 | * (c) Thomas Rabaix <[email protected]> |
||
9 | * |
||
10 | * For the full copyright and license information, please view the LICENSE |
||
11 | * file that was distributed with this source code. |
||
12 | */ |
||
13 | |||
14 | namespace Sonata\MediaBundle\Controller\Api; |
||
15 | |||
16 | use FOS\RestBundle\Context\Context; |
||
17 | use FOS\RestBundle\Controller\Annotations\QueryParam; |
||
18 | use FOS\RestBundle\Controller\Annotations\View; |
||
19 | use FOS\RestBundle\Request\ParamFetcherInterface; |
||
20 | use FOS\RestBundle\View\View as FOSRestView; |
||
21 | use Nelmio\ApiDocBundle\Annotation\ApiDoc; |
||
22 | use Sonata\DatagridBundle\Pager\PagerInterface; |
||
23 | use Sonata\MediaBundle\Model\GalleryInterface; |
||
24 | use Sonata\MediaBundle\Model\GalleryItemInterface; |
||
25 | use Sonata\MediaBundle\Model\GalleryManagerInterface; |
||
26 | use Sonata\MediaBundle\Model\MediaInterface; |
||
27 | use Sonata\MediaBundle\Model\MediaManagerInterface; |
||
28 | use Symfony\Component\Form\FormFactoryInterface; |
||
29 | use Symfony\Component\Form\FormInterface; |
||
30 | use Symfony\Component\HttpFoundation\Request; |
||
31 | use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; |
||
32 | |||
33 | /** |
||
34 | * @final since sonata-project/media-bundle 3.21.0 |
||
35 | * |
||
36 | * @author Hugo Briand <[email protected]> |
||
37 | */ |
||
38 | class GalleryController |
||
39 | { |
||
40 | /** |
||
41 | * @var GalleryManagerInterface |
||
42 | */ |
||
43 | protected $galleryManager; |
||
44 | |||
45 | /** |
||
46 | * @var MediaManagerInterface |
||
47 | */ |
||
48 | protected $mediaManager; |
||
49 | |||
50 | /** |
||
51 | * @var FormFactoryInterface |
||
52 | */ |
||
53 | protected $formFactory; |
||
54 | |||
55 | /** |
||
56 | * @var string |
||
57 | */ |
||
58 | protected $galleryItemClass; |
||
59 | |||
60 | /** |
||
61 | * Constructor. |
||
62 | * |
||
63 | * @param string $galleryItemClass |
||
64 | */ |
||
65 | public function __construct(GalleryManagerInterface $galleryManager, MediaManagerInterface $mediaManager, FormFactoryInterface $formFactory, $galleryItemClass) |
||
66 | { |
||
67 | $this->galleryManager = $galleryManager; |
||
68 | $this->mediaManager = $mediaManager; |
||
69 | $this->formFactory = $formFactory; |
||
70 | $this->galleryItemClass = $galleryItemClass; |
||
71 | } |
||
72 | |||
73 | /** |
||
74 | * Retrieves the list of galleries (paginated). |
||
75 | * |
||
76 | * @ApiDoc( |
||
77 | * resource=true, |
||
78 | * output={"class"="Sonata\DatagridBundle\Pager\PagerInterface", "groups"={"sonata_api_read"}} |
||
79 | * ) |
||
80 | * |
||
81 | * @QueryParam( |
||
82 | * name="page", |
||
83 | * requirements="\d+", |
||
84 | * default="1", |
||
85 | * description="Page for gallery list pagination" |
||
86 | * ) |
||
87 | * @QueryParam( |
||
88 | * name="count", |
||
89 | * requirements="\d+", |
||
90 | * default="10", |
||
91 | * description="Number of galleries by page" |
||
92 | * ) |
||
93 | * @QueryParam( |
||
94 | * name="enabled", |
||
95 | * requirements="0|1", |
||
96 | * nullable=true, |
||
97 | * strict=true, |
||
98 | * description="Enabled/Disabled galleries filter" |
||
99 | * ) |
||
100 | * @QueryParam( |
||
101 | * name="orderBy", |
||
102 | * map=true, |
||
103 | * requirements="ASC|DESC", |
||
104 | * nullable=true, |
||
105 | * strict=true, |
||
106 | * description="Order by array (key is field, value is direction)" |
||
107 | * ) |
||
108 | * |
||
109 | * @View(serializerGroups={"sonata_api_read"}, serializerEnableMaxDepthChecks=true) |
||
110 | * |
||
111 | * @return PagerInterface |
||
112 | */ |
||
113 | public function getGalleriesAction(ParamFetcherInterface $paramFetcher) |
||
114 | { |
||
115 | $supportedCriteria = [ |
||
116 | 'enabled' => '', |
||
117 | ]; |
||
118 | |||
119 | $page = $paramFetcher->get('page'); |
||
120 | $limit = $paramFetcher->get('count'); |
||
121 | $sort = $paramFetcher->get('orderBy'); |
||
122 | $criteria = array_intersect_key($paramFetcher->all(), $supportedCriteria); |
||
123 | |||
124 | foreach ($criteria as $key => $value) { |
||
125 | if (null === $value) { |
||
126 | unset($criteria[$key]); |
||
127 | } |
||
128 | } |
||
129 | |||
130 | if (!$sort) { |
||
131 | $sort = []; |
||
132 | } elseif (!\is_array($sort)) { |
||
133 | $sort = [$sort => 'asc']; |
||
134 | } |
||
135 | |||
136 | return $this->getGalleryManager()->getPager($criteria, $page, $limit, $sort); |
||
137 | } |
||
138 | |||
139 | /** |
||
140 | * Retrieves a specific gallery. |
||
141 | * |
||
142 | * @ApiDoc( |
||
143 | * requirements={ |
||
144 | * {"name"="id", "dataType"="integer", "requirement"="\d+", "description"="gallery id"} |
||
145 | * }, |
||
146 | * output={"class"="sonata_media_api_form_gallery", "groups"={"sonata_api_read"}}, |
||
147 | * statusCodes={ |
||
148 | * 200="Returned when successful", |
||
149 | * 404="Returned when gallery is not found" |
||
150 | * } |
||
151 | * ) |
||
152 | * |
||
153 | * @View(serializerGroups={"sonata_api_read"}, serializerEnableMaxDepthChecks=true) |
||
154 | * |
||
155 | * @param $id |
||
156 | * |
||
157 | * @return GalleryInterface |
||
158 | */ |
||
159 | public function getGalleryAction($id) |
||
160 | { |
||
161 | return $this->getGallery($id); |
||
162 | } |
||
163 | |||
164 | /** |
||
165 | * Retrieves the medias of specified gallery. |
||
166 | * |
||
167 | * @ApiDoc( |
||
168 | * requirements={ |
||
169 | * {"name"="id", "dataType"="integer", "requirement"="\d+", "description"="gallery id"} |
||
170 | * }, |
||
171 | * output={"class"="Sonata\MediaBundle\Model\Media", "groups"={"sonata_api_read"}}, |
||
172 | * statusCodes={ |
||
173 | * 200="Returned when successful", |
||
174 | * 404="Returned when gallery is not found" |
||
175 | * } |
||
176 | * ) |
||
177 | * |
||
178 | * @View(serializerGroups={"sonata_api_read"}, serializerEnableMaxDepthChecks=true) |
||
179 | * |
||
180 | * @param $id |
||
181 | * |
||
182 | * @return MediaInterface[] |
||
183 | */ |
||
184 | public function getGalleryMediasAction($id) |
||
185 | { |
||
186 | $galleryItems = $this->getGallery($id)->getGalleryItems(); |
||
187 | |||
188 | $media = []; |
||
189 | foreach ($galleryItems as $galleryItem) { |
||
190 | $media[] = $galleryItem->getMedia(); |
||
191 | } |
||
192 | |||
193 | return $media; |
||
194 | } |
||
195 | |||
196 | /** |
||
197 | * Retrieves the gallery items of specified gallery. |
||
198 | * |
||
199 | * @ApiDoc( |
||
200 | * requirements={ |
||
201 | * {"name"="id", "dataType"="integer", "requirement"="\d+", "description"="gallery id"} |
||
202 | * }, |
||
203 | * output={"class"="Sonata\MediaBundle\Model\GalleryItem", "groups"={"sonata_api_read"}}, |
||
204 | * statusCodes={ |
||
205 | * 200="Returned when successful", |
||
206 | * 404="Returned when gallery is not found" |
||
207 | * } |
||
208 | * ) |
||
209 | * |
||
210 | * @View(serializerGroups={"sonata_api_read"}, serializerEnableMaxDepthChecks=true) |
||
211 | * |
||
212 | * @param $id |
||
213 | * |
||
214 | * @return GalleryItemInterface[] |
||
215 | */ |
||
216 | public function getGalleryGalleryItemAction($id) |
||
217 | { |
||
218 | return $this->getGallery($id)->getGalleryItems(); |
||
219 | } |
||
220 | |||
221 | /** |
||
222 | * Adds a gallery. |
||
223 | * |
||
224 | * @ApiDoc( |
||
225 | * input={"class"="sonata_media_api_form_gallery", "name"="", "groups"={"sonata_api_write"}}, |
||
226 | * output={"class"="sonata_media_api_form_gallery", "groups"={"sonata_api_read"}}, |
||
227 | * statusCodes={ |
||
228 | * 200="Returned when successful", |
||
229 | * 400="Returned when an error has occurred while gallery creation", |
||
230 | * } |
||
231 | * ) |
||
232 | * |
||
233 | * @param Request $request A Symfony request |
||
234 | * |
||
235 | * @throws NotFoundHttpException |
||
236 | * |
||
237 | * @return GalleryInterface |
||
238 | */ |
||
239 | public function postGalleryAction(Request $request) |
||
240 | { |
||
241 | return $this->handleWriteGallery($request); |
||
242 | } |
||
243 | |||
244 | /** |
||
245 | * Updates a gallery. |
||
246 | * |
||
247 | * @ApiDoc( |
||
248 | * requirements={ |
||
249 | * {"name"="id", "dataType"="integer", "requirement"="\d+", "description"="gallery identifier"} |
||
250 | * }, |
||
251 | * input={"class"="sonata_media_api_form_gallery", "name"="", "groups"={"sonata_api_write"}}, |
||
252 | * output={"class"="sonata_media_api_form_gallery", "groups"={"sonata_api_read"}}, |
||
253 | * statusCodes={ |
||
254 | * 200="Returned when successful", |
||
255 | * 400="Returned when an error has occurred while gallery creation", |
||
256 | * 404="Returned when unable to find gallery" |
||
257 | * } |
||
258 | * ) |
||
259 | * |
||
260 | * @param int $id User id |
||
261 | * @param Request $request A Symfony request |
||
262 | * |
||
263 | * @throws NotFoundHttpException |
||
264 | * |
||
265 | * @return GalleryInterface |
||
266 | */ |
||
267 | public function putGalleryAction($id, Request $request) |
||
268 | { |
||
269 | return $this->handleWriteGallery($request, $id); |
||
270 | } |
||
271 | |||
272 | /** |
||
273 | * Adds a media to a gallery. |
||
274 | * |
||
275 | * @ApiDoc( |
||
276 | * requirements={ |
||
277 | * {"name"="galleryId", "dataType"="integer", "requirement"="\d+", "description"="gallery identifier"}, |
||
278 | * {"name"="mediaId", "dataType"="integer", "requirement"="\d+", "description"="media identifier"} |
||
279 | * }, |
||
280 | * input={"class"="sonata_media_api_form_gallery_item", "name"="", "groups"={"sonata_api_write"}}, |
||
281 | * output={"class"="sonata_media_api_form_gallery", "groups"={"sonata_api_read"}}, |
||
282 | * statusCodes={ |
||
283 | * 200="Returned when successful", |
||
284 | * 400="Returned when an error has occurred while gallery/media attachment", |
||
285 | * } |
||
286 | * ) |
||
287 | * |
||
288 | * @param int $galleryId A gallery identifier |
||
289 | * @param int $mediaId A media identifier |
||
290 | * @param Request $request A Symfony request |
||
291 | * |
||
292 | * @throws NotFoundHttpException |
||
293 | * |
||
294 | * @return GalleryInterface |
||
295 | */ |
||
296 | public function postGalleryMediaGalleryItemAction($galleryId, $mediaId, Request $request) |
||
297 | { |
||
298 | $gallery = $this->getGallery($galleryId); |
||
299 | $media = $this->getMedia($mediaId); |
||
300 | |||
301 | foreach ($gallery->getGalleryItems() as $galleryItem) { |
||
302 | if ($galleryItem->getMedia()->getId() === $media->getId()) { |
||
303 | return FOSRestView::create([ |
||
304 | 'error' => sprintf('Gallery "%s" already has media "%s"', $galleryId, $mediaId), |
||
305 | ], 400); |
||
306 | } |
||
307 | } |
||
308 | |||
309 | return $this->handleWriteGalleryItem($gallery, $media, null, $request); |
||
310 | } |
||
311 | |||
312 | /** |
||
313 | * Updates a media to a gallery. |
||
314 | * |
||
315 | * @ApiDoc( |
||
316 | * requirements={ |
||
317 | * {"name"="galleryId", "dataType"="integer", "requirement"="\d+", "description"="gallery identifier"}, |
||
318 | * {"name"="mediaId", "dataType"="integer", "requirement"="\d+", "description"="media identifier"} |
||
319 | * }, |
||
320 | * input={"class"="sonata_media_api_form_gallery_item", "name"="", "groups"={"sonata_api_write"}}, |
||
321 | * output={"class"="sonata_media_api_form_gallery", "groups"={"sonata_api_read"}}, |
||
322 | * statusCodes={ |
||
323 | * 200="Returned when successful", |
||
324 | * 404="Returned when an error if media cannot be found in gallery", |
||
325 | * } |
||
326 | * ) |
||
327 | * |
||
328 | * @param int $galleryId A gallery identifier |
||
329 | * @param int $mediaId A media identifier |
||
330 | * @param Request $request A Symfony request |
||
331 | * |
||
332 | * @throws NotFoundHttpException |
||
333 | * |
||
334 | * @return GalleryInterface |
||
335 | */ |
||
336 | public function putGalleryMediaGalleryItemAction($galleryId, $mediaId, Request $request) |
||
337 | { |
||
338 | $gallery = $this->getGallery($galleryId); |
||
339 | $media = $this->getMedia($mediaId); |
||
340 | |||
341 | foreach ($gallery->getGalleryItems() as $galleryItem) { |
||
342 | if ($galleryItem->getMedia()->getId() === $media->getId()) { |
||
343 | return $this->handleWriteGalleryItem($gallery, $media, $galleryItem, $request); |
||
344 | } |
||
345 | } |
||
346 | |||
347 | throw new NotFoundHttpException(sprintf('Gallery "%s" does not have media "%s"', $galleryId, $mediaId)); |
||
348 | } |
||
349 | |||
350 | /** |
||
351 | * Deletes a media association to a gallery. |
||
352 | * |
||
353 | * @ApiDoc( |
||
354 | * requirements={ |
||
355 | * {"name"="galleryId", "dataType"="integer", "requirement"="\d+", "description"="gallery identifier"}, |
||
356 | * {"name"="mediaId", "dataType"="integer", "requirement"="\d+", "description"="media identifier"} |
||
357 | * }, |
||
358 | * statusCodes={ |
||
359 | * 200="Returned when media is successfully deleted from gallery", |
||
360 | * 400="Returned when an error has occurred while media deletion of gallery", |
||
361 | * 404="Returned when unable to find gallery or media" |
||
362 | * } |
||
363 | * ) |
||
364 | * |
||
365 | * @param int $galleryId A gallery identifier |
||
366 | * @param int $mediaId A media identifier |
||
367 | * |
||
368 | * @throws NotFoundHttpException |
||
369 | * |
||
370 | * @return View |
||
371 | */ |
||
372 | public function deleteGalleryMediaGalleryItemAction($galleryId, $mediaId) |
||
373 | { |
||
374 | $gallery = $this->getGallery($galleryId); |
||
375 | $media = $this->getMedia($mediaId); |
||
376 | |||
377 | foreach ($gallery->getGalleryItems() as $key => $galleryItem) { |
||
378 | if ($galleryItem->getMedia()->getId() === $media->getId()) { |
||
379 | $gallery->getGalleryItems()->remove($key); |
||
0 ignored issues
–
show
|
|||
380 | $this->getGalleryManager()->save($gallery); |
||
381 | |||
382 | return ['deleted' => true]; |
||
0 ignored issues
–
show
The return type of
return array('deleted' => true); (array<string,boolean> ) is incompatible with the return type documented by Sonata\MediaBundle\Contr...yMediaGalleryItemAction of type FOS\RestBundle\Controller\Annotations\View .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function ![]() |
|||
383 | } |
||
384 | } |
||
385 | |||
386 | return FOSRestView::create([ |
||
387 | 'error' => sprintf('Gallery "%s" does not have media "%s" associated', $galleryId, $mediaId), |
||
388 | ], 400); |
||
389 | } |
||
390 | |||
391 | /** |
||
392 | * Deletes a gallery. |
||
393 | * |
||
394 | * @ApiDoc( |
||
395 | * requirements={ |
||
396 | * {"name"="id", "dataType"="integer", "requirement"="\d+", "description"="gallery identifier"} |
||
397 | * }, |
||
398 | * statusCodes={ |
||
399 | * 200="Returned when gallery is successfully deleted", |
||
400 | * 400="Returned when an error has occurred while gallery deletion", |
||
401 | * 404="Returned when unable to find gallery" |
||
402 | * } |
||
403 | * ) |
||
404 | * |
||
405 | * @param int $id A Gallery identifier |
||
406 | * |
||
407 | * @throws NotFoundHttpException |
||
408 | * |
||
409 | * @return View |
||
410 | */ |
||
411 | public function deleteGalleryAction($id) |
||
412 | { |
||
413 | $gallery = $this->getGallery($id); |
||
414 | |||
415 | $this->galleryManager->delete($gallery); |
||
416 | |||
417 | return ['deleted' => true]; |
||
418 | } |
||
419 | |||
420 | /** |
||
421 | * Write a GalleryItem, this method is used by both POST and PUT action methods. |
||
422 | * |
||
423 | * @return FormInterface |
||
424 | */ |
||
425 | protected function handleWriteGalleryItem(GalleryInterface $gallery, MediaInterface $media, GalleryItemInterface $galleryItem = null, Request $request) |
||
426 | { |
||
427 | $form = $this->formFactory->createNamed(null, 'sonata_media_api_form_gallery_item', $galleryItem, [ |
||
428 | 'csrf_protection' => false, |
||
429 | ]); |
||
430 | |||
431 | $form->handleRequest($request); |
||
432 | |||
433 | if ($form->isValid()) { |
||
434 | $galleryItem = $form->getData(); |
||
435 | $galleryItem->setMedia($media); |
||
436 | |||
437 | $gallery->addGalleryItem($galleryItem); |
||
438 | $this->galleryManager->save($gallery); |
||
439 | |||
440 | $view = FOSRestView::create($galleryItem); |
||
441 | |||
442 | $context = new Context(); |
||
443 | $context->setGroups(['sonata_api_read']); |
||
444 | $context->enableMaxDepth(); |
||
445 | |||
446 | $view->setContext($context); |
||
447 | |||
448 | return $view; |
||
0 ignored issues
–
show
The return type of
return $view; (FOS\RestBundle\View\View ) is incompatible with the return type documented by Sonata\MediaBundle\Contr...:handleWriteGalleryItem of type Symfony\Component\Form\FormInterface .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function ![]() |
|||
449 | } |
||
450 | |||
451 | return $form; |
||
452 | } |
||
453 | |||
454 | /** |
||
455 | * Retrieves gallery with id $id or throws an exception if it doesn't exist. |
||
456 | * |
||
457 | * @param $id |
||
458 | * |
||
459 | * @throws NotFoundHttpException |
||
460 | * |
||
461 | * @return GalleryInterface |
||
462 | */ |
||
463 | protected function getGallery($id) |
||
464 | { |
||
465 | $gallery = $this->getGalleryManager()->findOneBy(['id' => $id]); |
||
466 | |||
467 | if (null === $gallery) { |
||
468 | throw new NotFoundHttpException(sprintf('Gallery (%d) not found', $id)); |
||
469 | } |
||
470 | |||
471 | return $gallery; |
||
472 | } |
||
473 | |||
474 | /** |
||
475 | * Retrieves media with id $id or throws an exception if it doesn't exist. |
||
476 | * |
||
477 | * @param $id |
||
478 | * |
||
479 | * @throws NotFoundHttpException |
||
480 | * |
||
481 | * @return MediaInterface |
||
482 | */ |
||
483 | protected function getMedia($id) |
||
484 | { |
||
485 | $media = $this->getMediaManager()->findOneBy(['id' => $id]); |
||
486 | |||
487 | if (null === $media) { |
||
488 | throw new NotFoundHttpException(sprintf('Media (%d) not found', $id)); |
||
489 | } |
||
490 | |||
491 | return $media; |
||
492 | } |
||
493 | |||
494 | /** |
||
495 | * @return GalleryManagerInterface |
||
496 | */ |
||
497 | protected function getGalleryManager() |
||
498 | { |
||
499 | return $this->galleryManager; |
||
500 | } |
||
501 | |||
502 | /** |
||
503 | * @return MediaManagerInterface |
||
504 | */ |
||
505 | protected function getMediaManager() |
||
506 | { |
||
507 | return $this->mediaManager; |
||
508 | } |
||
509 | |||
510 | /** |
||
511 | * Write a Gallery, this method is used by both POST and PUT action methods. |
||
512 | * |
||
513 | * @param Request $request Symfony request |
||
514 | * @param int|null $id A Gallery identifier |
||
515 | * |
||
516 | * @return View|FormInterface |
||
517 | */ |
||
518 | protected function handleWriteGallery($request, $id = null) |
||
519 | { |
||
520 | $gallery = $id ? $this->getGallery($id) : null; |
||
521 | |||
522 | $form = $this->formFactory->createNamed(null, 'sonata_media_api_form_gallery', $gallery, [ |
||
523 | 'csrf_protection' => false, |
||
524 | ]); |
||
525 | |||
526 | $form->handleRequest($request); |
||
527 | |||
528 | if ($form->isValid()) { |
||
529 | $gallery = $form->getData(); |
||
530 | $this->galleryManager->save($gallery); |
||
531 | |||
532 | $context = new Context(); |
||
533 | $context->setGroups(['sonata_api_read']); |
||
534 | $context->enableMaxDepth(); |
||
535 | |||
536 | $view = FOSRestView::create($gallery); |
||
537 | $view->setContext($context); |
||
538 | |||
539 | return $view; |
||
540 | } |
||
541 | |||
542 | return $form; |
||
543 | } |
||
544 | } |
||
545 |
Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.