Completed
Pull Request — 5.6 (#2830)
by Jeroen
14:14
created

MediaBundle/Controller/MediaController.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Kunstmaan\MediaBundle\Controller;
4
5
use Exception;
6
use Kunstmaan\AdminBundle\FlashMessages\FlashTypes;
7
use Kunstmaan\MediaBundle\Entity\Folder;
8
use Kunstmaan\MediaBundle\Entity\Media;
9
use Kunstmaan\MediaBundle\Form\BulkMoveMediaType;
10
use Kunstmaan\MediaBundle\Helper\MediaManager;
11
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
12
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
13
use Symfony\Component\HttpFoundation\File\File;
14
use Symfony\Component\HttpFoundation\JsonResponse;
15
use Symfony\Component\HttpFoundation\RedirectResponse;
16
use Symfony\Component\HttpFoundation\Request;
17
use Symfony\Component\HttpFoundation\Response;
18
use Symfony\Component\Routing\Annotation\Route;
19
20
/**
21
 * MediaController
22
 */
23
class MediaController extends Controller
24
{
25
    /**
26
     * @param int $mediaId
27
     *
28
     * @Route("/{mediaId}", requirements={"mediaId" = "\d+"}, name="KunstmaanMediaBundle_media_show")
29
     *
30
     * @return Response
31
     */
32
    public function showAction(Request $request, $mediaId)
33
    {
34
        $em = $this->getDoctrine()->getManager();
35
36
        /* @var Media $media */
37
        $media = $em->getRepository(Media::class)->getMedia($mediaId);
38
        $folder = $media->getFolder();
39
40
        /* @var MediaManager $mediaManager */
41
        $mediaManager = $this->get('kunstmaan_media.media_manager');
42
        $handler = $mediaManager->getHandler($media);
43
        $helper = $handler->getFormHelper($media);
44
45
        $form = $this->createForm($handler->getFormType(), $helper, $handler->getFormTypeOptions());
46
47
        if ($request->isMethod('POST')) {
48
            $form->handleRequest($request);
49
            if ($form->isSubmitted() && $form->isValid()) {
50
                $media = $helper->getMedia();
51
                $em->getRepository(Media::class)->save($media);
52
53
                return new RedirectResponse(
54
                    $this->generateUrl(
55
                        'KunstmaanMediaBundle_media_show',
56
                        ['mediaId' => $media->getId()]
57
                    )
58
                );
59
            }
60
        }
61
        $showTemplate = $mediaManager->getHandler($media)->getShowTemplate($media);
62
63
        return $this->render(
64
            $showTemplate,
65
            [
66
                'handler' => $handler,
67
                'foldermanager' => $this->get('kunstmaan_media.folder_manager'),
68
                'mediamanager' => $this->get('kunstmaan_media.media_manager'),
69
                'editform' => $form->createView(),
70
                'media' => $media,
71
                'helper' => $helper,
72
                'folder' => $folder,
73
            ]
74
        );
75
    }
76
77
    /**
78
     * @param int $mediaId
79
     *
80
     * @Route("/delete/{mediaId}", requirements={"mediaId" = "\d+"}, name="KunstmaanMediaBundle_media_delete")
81
     *
82
     * @return RedirectResponse
83
     */
84
    public function deleteAction(Request $request, $mediaId)
85
    {
86
        $em = $this->getDoctrine()->getManager();
87
88
        /* @var Media $media */
89
        $media = $em->getRepository(Media::class)->getMedia($mediaId);
90
        $medianame = $media->getName();
91
        $folder = $media->getFolder();
92
93
        $em->getRepository(Media::class)->delete($media);
94
95
        $this->addFlash(
96
            FlashTypes::SUCCESS,
97
            $this->get('translator')->trans(
98
                'kuma_admin.media.flash.deleted_success.%medianame%',
99
                [
100
                    '%medianame%' => $medianame,
101
                ]
102
            )
103
        );
104
105
        // If the redirect url is passed via the url we use it
106
        $redirectUrl = $request->query->get('redirectUrl');
107
        if (empty($redirectUrl) || (\strpos($redirectUrl, $request->getSchemeAndHttpHost()) !== 0 && strncmp($redirectUrl, '/', 1) !== 0)) {
108
            $redirectUrl = $this->generateUrl(
109
                'KunstmaanMediaBundle_folder_show',
110
                ['folderId' => $folder->getId()]
111
            );
112
        }
113
114
        return new RedirectResponse($redirectUrl);
115
    }
116
117
    /**
118
     * @param int $folderId
119
     *
120
     * @Route("bulkupload/{folderId}", requirements={"folderId" = "\d+"}, name="KunstmaanMediaBundle_media_bulk_upload")
121
     * @Template("@KunstmaanMedia/Media/bulkUpload.html.twig")
122
     *
123
     * @return array|RedirectResponse
124
     */
125
    public function bulkUploadAction($folderId)
126
    {
127
        $em = $this->getDoctrine()->getManager();
128
129
        /* @var Folder $folder */
130
        $folder = $em->getRepository(Folder::class)->getFolder($folderId);
131
132
        return ['folder' => $folder];
133
    }
134
135
    /**
136
     * @param int $folderId
137
     *
138
     * @Route("bulkuploadsubmit/{folderId}", requirements={"folderId" = "\d+"}, name="KunstmaanMediaBundle_media_bulk_upload_submit")
139
     *
140
     * @return JsonResponse
141
     */
142
    public function bulkUploadSubmitAction(Request $request, $folderId)
143
    {
144
        // Settings
145
        if (\ini_get('upload_tmp_dir')) {
146
            $tempDir = \ini_get('upload_tmp_dir');
147
        } else {
148
            $tempDir = \sys_get_temp_dir();
149
        }
150
        $targetDir = \rtrim($tempDir, '/') . DIRECTORY_SEPARATOR . 'plupload';
151
        $cleanupTargetDir = true; // Remove old files
152
        $maxFileAge = 5 * 60 * 60; // Temp file age in seconds
153
154
        // Create target dir
155
        if (!\file_exists($targetDir)) {
156
            @\mkdir($targetDir);
157
        }
158
159
        // Get a file name
160
        if ($request->request->has('name')) {
161
            $fileName = $request->request->get('name');
162
        } elseif (0 !== $request->files->count()) {
163
            $fileName = $request->files->get('file')['name'];
164
        } else {
165
            $fileName = \uniqid('file_', false);
166
        }
167
        $filePath = $targetDir . DIRECTORY_SEPARATOR . $fileName;
168
169
        $chunk = 0;
170
        $chunks = 0;
171
        // Chunking might be enabled
172
        if ($request->request->has('chunk')) {
173
            $chunk = $request->request->getInt('chunk');
174
        }
175
        if ($request->request->has('chunks')) {
176
            $chunks = $request->request->getInt('chunks');
177
        }
178
179
        // Remove old temp files
180
        if ($cleanupTargetDir) {
181
            if (!\is_dir($targetDir) || !$dir = \opendir($targetDir)) {
182
                return $this->returnJsonError('100', 'Failed to open temp directory.');
183
            }
184
185
            while (($file = \readdir($dir)) !== false) {
186
                $tmpFilePath = $targetDir . DIRECTORY_SEPARATOR . $file;
187
188
                // If temp file is current file proceed to the next
189
                if ($tmpFilePath === "{$filePath}.part") {
190
                    continue;
191
                }
192
193
                // Remove temp file if it is older than the max age and is not the current file
194
                if (\preg_match('/\.part$/', $file) && (\filemtime($tmpFilePath) < \time() - $maxFileAge)) {
195
                    $success = @\unlink($tmpFilePath);
196
                    if ($success !== true) {
197
                        return $this->returnJsonError('106', 'Could not remove temp file: ' . $filePath);
198
                    }
199
                }
200
            }
201
            \closedir($dir);
202
        }
203
204
        // Open temp file
205
        if (!$out = @\fopen("{$filePath}.part", $chunks ? 'ab' : 'wb')) {
206
            return $this->returnJsonError('102', 'Failed to open output stream.');
207
        }
208
209
        if (0 !== $request->files->count()) {
210
            $_file = $request->files->get('file');
211
            if ($_file->getError() > 0 || !\is_uploaded_file($_file->getRealPath())) {
212
                return $this->returnJsonError('103', 'Failed to move uploaded file.');
213
            }
214
215
            // Read binary input stream and append it to temp file
216
            if (!$input = @\fopen($_file->getRealPath(), 'rb')) {
217
                return $this->returnJsonError('101', 'Failed to open input stream.');
218
            }
219
        } else {
220
            if (!$input = @\fopen('php://input', 'rb')) {
221
                return $this->returnJsonError('101', 'Failed to open input stream.');
222
            }
223
        }
224
225
        while ($buff = \fread($input, 4096)) {
226
            \fwrite($out, $buff);
227
        }
228
229
        @\fclose($out);
230
        @\fclose($input);
231
232
        // Check if file has been uploaded
233
        if (!$chunks || $chunk === $chunks - 1) {
234
            // Strip the temp .part suffix off
235
            \rename("{$filePath}.part", $filePath);
236
        }
237
238
        $em = $this->getDoctrine()->getManager();
239
        /* @var Folder $folder */
240
        $folder = $em->getRepository(Folder::class)->getFolder($folderId);
241
        $file = new File($filePath);
242
243
        try {
244
            /* @var Media $media */
245
            $media = $this->get('kunstmaan_media.media_manager')->getHandler($file)->createNew($file);
246
            $media->setFolder($folder);
247
            $em->getRepository(Media::class)->save($media);
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Doctrine\Persistence\ObjectRepository as the method save() does only exist in the following implementations of said interface: Kunstmaan\MediaBundle\Repository\FolderRepository, Kunstmaan\MediaBundle\Repository\MediaRepository.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
248
        } catch (Exception $e) {
249
            return $this->returnJsonError('104', 'Failed performing save on media-manager');
250
        }
251
252
        $success = \unlink($filePath);
253
        if ($success !== true) {
254
            return $this->returnJsonError('105', 'Could not remove temp file: ' . $filePath);
255
        }
256
257
        // Send headers making sure that the file is not cached (as it happens for example on iOS devices)
258
        $response = new JsonResponse(
259
            [
260
                'jsonrpc' => '2.0',
261
                'result' => '',
262
                'id' => 'id',
263
            ], JsonResponse::HTTP_OK, [
264
                'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT',
265
                'Last-Modified' => \gmdate('D, d M Y H:i:s') . ' GMT',
266
                'Cache-Control' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0',
267
                'Pragma' => 'no-cache',
268
            ]
269
        );
270
271
        return $response;
272
    }
273
274
    private function returnJsonError($code, $message)
275
    {
276
        return new JsonResponse(
277
            [
278
                'jsonrpc' => '2.0',
279
                'error ' => [
280
                    'code' => $code,
281
                    'message' => $message,
282
                ],
283
                'id' => 'id',
284
            ]
285
        );
286
    }
287
288
    /**
289
     * @param int $folderId
290
     *
291
     * @Route("drop/{folderId}", requirements={"folderId" = "\d+"}, name="KunstmaanMediaBundle_media_drop_upload", methods={"GET", "POST"})
292
     *
293
     * @return JsonResponse
294
     */
295
    public function dropAction(Request $request, $folderId)
296
    {
297
        $em = $this->getDoctrine()->getManager();
298
299
        /* @var Folder $folder */
300
        $folder = $em->getRepository(Folder::class)->getFolder($folderId);
301
302
        $drop = null;
303
304
        if ($request->files->has('files') && $request->files->get('files')['error'] === 0) {
305
            $drop = $request->files->get('files');
306
        } else {
307
            if ($request->files->get('file')) {
308
                $drop = $request->files->get('file');
309
            } else {
310
                $drop = $request->get('text');
311
            }
312
        }
313
        $media = $this->get('kunstmaan_media.media_manager')->createNew($drop);
314
        if ($media) {
315
            $media->setFolder($folder);
316
            $em->getRepository(Media::class)->save($media);
317
318
            return new JsonResponse(['status' => $this->get('translator')->trans('kuma_admin.media.flash.drop_success')]);
319
        }
320
321
        $request->getSession()->getFlashBag()->add(
322
            FlashTypes::DANGER,
323
            $this->get('translator')->trans('kuma_admin.media.flash.drop_unrecognized')
324
        );
325
326
        return new JsonResponse(['status' => $this->get('translator')->trans('kuma_admin.media.flash.drop_unrecognized')]);
327
    }
328
329
    /**
330
     * @param int    $folderId The folder id
331
     * @param string $type     The type
332
     *
333
     * @Route("create/{folderId}/{type}", requirements={"folderId" = "\d+", "type" = ".+"}, name="KunstmaanMediaBundle_media_create", methods={"GET", "POST"})
334
     * @Template("@KunstmaanMedia/Media/create.html.twig")
335
     *
336
     * @return array|RedirectResponse
337
     */
338
    public function createAction(Request $request, $folderId, $type)
339
    {
340
        return $this->createAndRedirect($request, $folderId, $type, 'KunstmaanMediaBundle_folder_show');
341
    }
342
343
    /**
344
     * @param int    $folderId    The folder Id
345
     * @param string $type        The type
346
     * @param string $redirectUrl The url where we want to redirect to on success
347
     * @param array  $extraParams The extra parameters that will be passed wen redirecting
348
     *
349
     * @return array|RedirectResponse
350
     */
351
    private function createAndRedirect(Request $request, $folderId, $type, $redirectUrl, $extraParams = [], $isInModal = false)
352
    {
353
        $em = $this->getDoctrine()->getManager();
354
355
        /* @var Folder $folder */
356
        $folder = $em->getRepository(Folder::class)->getFolder($folderId);
357
358
        /* @var MediaManager $mediaManager */
359
        $mediaManager = $this->get('kunstmaan_media.media_manager');
360
        $handler = $mediaManager->getHandlerForType($type);
361
        $media = new Media();
362
        $helper = $handler->getFormHelper($media);
363
364
        $form = $this->createForm($handler->getFormType(), $helper, $handler->getFormTypeOptions());
365
366
        if ($request->isMethod('POST')) {
367
            $params = ['folderId' => $folder->getId()];
368
            $params = \array_merge($params, $extraParams);
369
370
            $form->handleRequest($request);
371
372
            if ($form->isSubmitted() && $form->isValid()) {
373
                $media = $helper->getMedia();
374
                $media->setFolder($folder);
375
                $em->getRepository(Media::class)->save($media);
376
377
                $this->addFlash(
378
                    FlashTypes::SUCCESS,
379
                    $this->get('translator')->trans(
380
                        'media.flash.created',
381
                        [
382
                            '%medianame%' => $media->getName(),
383
                        ]
384
                    )
385
                );
386
387
                return new RedirectResponse($this->generateUrl($redirectUrl, $params));
388
            }
389
390
            if ($isInModal) {
391
                $this->addFlash(
392
                    FlashTypes::DANGER,
393
                    $this->get('translator')->trans(
394
                        'media.flash.not_created',
395
                        [
396
                            '%mediaerrors%' => $form->getErrors(true, true),
397
                        ]
398
                    )
399
                );
400
401
                return new RedirectResponse($this->generateUrl($redirectUrl, $params));
402
            }
403
        }
404
405
        return [
406
            'type' => $type,
407
            'form' => $form->createView(),
408
            'folder' => $folder,
409
        ];
410
    }
411
412
    /**
413
     * @param int    $folderId The folder id
414
     * @param string $type     The type
415
     *
416
     * @Route("create/modal/{folderId}/{type}", requirements={"folderId" = "\d+", "type" = ".+"}, name="KunstmaanMediaBundle_media_modal_create", methods={"POST"})
417
     *
418
     * @return array|RedirectResponse
419
     */
420
    public function createModalAction(Request $request, $folderId, $type)
421
    {
422
        $cKEditorFuncNum = $request->get('CKEditorFuncNum');
423
        $linkChooser = $request->get('linkChooser');
424
425
        $extraParams = [];
426
        if (!empty($cKEditorFuncNum)) {
427
            $extraParams['CKEditorFuncNum'] = $cKEditorFuncNum;
428
        }
429
        if (!empty($linkChooser)) {
430
            $extraParams['linkChooser'] = $linkChooser;
431
        }
432
433
        return $this->createAndRedirect(
434
            $request,
435
            $folderId,
436
            $type,
437
            'KunstmaanMediaBundle_chooser_show_folder',
438
            $extraParams,
439
            true
440
        );
441
    }
442
443
    /**
444
     * @Route("move/", name="KunstmaanMediaBundle_media_move", methods={"POST"})
445
     *
446
     * @return string
447
     */
448
    public function moveMedia(Request $request)
449
    {
450
        @trigger_error(sprintf('The "%s" controller action is deprecated in KunstmaanMediaBundle 5.1 and will be removed in KunstmaanMediaBundle 6.0.', __METHOD__), E_USER_DEPRECATED);
451
452
        $mediaId = $request->request->get('mediaId');
453
        $folderId = $request->request->get('folderId');
454
455
        if (empty($mediaId) || empty($folderId)) {
456
            return new JsonResponse(['error' => ['title' => 'Missing media id or folder id']], 400);
457
        }
458
459
        $em = $this->getDoctrine()->getManager();
460
        $mediaRepo = $em->getRepository(Media::class);
461
462
        $media = $mediaRepo->getMedia($mediaId);
463
        $folder = $em->getRepository(Folder::class)->getFolder($folderId);
464
465
        $media->setFolder($folder);
466
        $mediaRepo->save($media);
467
468
        return new JsonResponse();
469
    }
470
471
    /**
472
     * @Route("/bulk-move", name="KunstmaanMediaBundle_media_bulk_move")
473
     *
474
     * @return JsonResponse|Response
475
     *
476
     * @throws \Doctrine\DBAL\DBALException
477
     */
478
    public function bulkMoveAction(Request $request)
479
    {
480
        $em = $this->getDoctrine()->getManager();
481
        $mediaRepo = $em->getRepository(Media::class);
482
        $form = $this->createForm(BulkMoveMediaType::class);
483
484
        $form->handleRequest($request);
485
486
        if ($form->isSubmitted() && $form->isValid()) {
487
            /** @var Folder $folder */
488
            $folder = $form->getData()['folder'];
489
            $mediaIds = explode(',', $form->getData()['media']);
490
491
            $mediaRepo->createQueryBuilder('m')
492
                ->update()
493
                ->set('m.folder', $folder->getId())
494
                ->where('m.id in (:mediaIds)')
495
                ->setParameter('mediaIds', $mediaIds)
496
                ->getQuery()
497
                ->execute();
498
499
            $this->addFlash(FlashTypes::SUCCESS, $this->get('translator')->trans('media.folder.bulk_move.success.text'));
500
501
            return new JsonResponse(
502
                [
503
                    'Success' => 'The media is moved',
504
                ]
505
            );
506
        }
507
508
        return $this->render(
509
            '@KunstmaanMedia/Folder/bulk-move-modal_form.html.twig',
510
            [
511
                'form' => $form->createView(),
512
            ]
513
        );
514
    }
515
}
516