Passed
Push — master ( 9b28ce...1fed75 )
by Julito
11:04
created

ResourceController::editAction()   B

Complexity

Conditions 8
Paths 14

Size

Total Lines 72
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 35
nc 14
nop 2
dl 0
loc 72
rs 8.1155
c 0
b 0
f 0

How to fix   Long Method   

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
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Controller;
8
9
use Chamilo\CoreBundle\Entity\AbstractResource;
10
use Chamilo\CoreBundle\Entity\ResourceLink;
11
use Chamilo\CoreBundle\Entity\ResourceNode;
12
use Chamilo\CoreBundle\Form\Type\ResourceCommentType;
13
use Chamilo\CoreBundle\Repository\ResourceWithLinkInterface;
14
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
15
use Chamilo\CoreBundle\Traits\ControllerTrait;
16
use Chamilo\CoreBundle\Traits\CourseControllerTrait;
17
use Chamilo\CoreBundle\Traits\ResourceControllerTrait;
18
use Chamilo\CourseBundle\Controller\CourseControllerInterface;
19
use Doctrine\Common\Collections\ArrayCollection;
20
use Doctrine\Common\Collections\Criteria;
21
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
22
use Symfony\Component\HttpFoundation\JsonResponse;
23
use Symfony\Component\HttpFoundation\RedirectResponse;
24
use Symfony\Component\HttpFoundation\Request;
25
use Symfony\Component\HttpFoundation\Response;
26
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
27
use Symfony\Component\HttpFoundation\StreamedResponse;
28
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
29
use Symfony\Component\Routing\Annotation\Route;
30
use Symfony\Component\Routing\RouterInterface;
31
use ZipStream\Option\Archive;
32
use ZipStream\ZipStream;
33
34
/**
35
 * Class ResourceController.
36
 *
37
 * @Route("/r")
38
 *
39
 * @author Julio Montoya <[email protected]>.
40
 */
41
class ResourceController extends AbstractResourceController implements CourseControllerInterface
42
{
43
    use CourseControllerTrait;
44
    use ResourceControllerTrait;
45
    use ControllerTrait;
46
47
    private string $fileContentName = 'file_content';
0 ignored issues
show
introduced by
The private property $fileContentName is not used, and could be removed.
Loading history...
48
49
    /**
50
     * @Route("/{tool}/{type}/{id}/disk_space", methods={"GET", "POST"}, name="chamilo_core_resource_disk_space")
51
     */
52
    public function diskSpaceAction(Request $request): Response
53
    {
54
        $nodeId = $request->get('id');
55
        $repository = $this->getRepositoryFromRequest($request);
56
57
        /** @var ResourceNode $resourceNode */
58
        $resourceNode = $repository->getResourceNodeRepository()->find($nodeId);
59
60
        $this->denyAccessUnlessGranted(
61
            ResourceNodeVoter::VIEW,
62
            $resourceNode,
63
            $this->trans('Unauthorised access to resource')
64
        );
65
66
        $this->setBreadCrumb($request, $resourceNode);
67
68
        $course = $this->getCourse();
69
        $totalSize = 0;
70
        if (null !== $course) {
71
            $totalSize = $course->getDiskQuota();
72
        }
73
74
        $size = $repository->getResourceNodeRepository()->getSize(
75
            $resourceNode,
76
            $repository->getResourceType(),
77
            $course
78
        );
79
80
        $labels[] = $course->getTitle();
0 ignored issues
show
Comprehensibility Best Practice introduced by
$labels was never initialized. Although not strictly required by PHP, it is generally a good practice to add $labels = array(); before regardless.
Loading history...
81
        $data[] = $size;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$data was never initialized. Although not strictly required by PHP, it is generally a good practice to add $data = array(); before regardless.
Loading history...
82
        $sessions = $course->getSessions();
83
84
        foreach ($sessions as $sessionRelCourse) {
85
            $session = $sessionRelCourse->getSession();
86
87
            $labels[] = $course->getTitle().' - '.$session->getName();
88
            $size = $repository->getResourceNodeRepository()->getSize(
89
                $resourceNode,
90
                $repository->getResourceType(),
91
                $course,
92
                $session
93
            );
94
            $data[] = $size;
95
        }
96
97
        /*$groups = $course->getGroups();
98
        foreach ($groups as $group) {
99
            $labels[] = $course->getTitle().' - '.$group->getName();
100
            $size = $repository->getResourceNodeRepository()->getSize(
101
                $resourceNode,
102
                $repository->getResourceType(),
103
                $course,
104
                null,
105
                $group
106
            );
107
            $data[] = $size;
108
        }*/
109
110
        $used = array_sum($data);
111
        $labels[] = $this->trans('Free');
112
        $data[] = $totalSize - $used;
113
114
        return $this->render(
115
            $repository->getTemplates()->getFromAction(__FUNCTION__),
116
            [
117
                'resourceNode' => $resourceNode,
118
                'labels' => $labels,
119
                'data' => $data,
120
            ]
121
        );
122
    }
123
124
    /**
125
     * Shows resource information.
126
     *
127
     * @Route("/{tool}/{type}/{id}/info", methods={"GET", "POST"}, name="chamilo_core_resource_info")
128
     */
129
    public function infoAction(Request $request): Response
130
    {
131
        $nodeId = (int) $request->get('id');
132
        $repository = $this->getRepositoryFromRequest($request);
133
134
        $resource = $repository->getResourceFromResourceNode($nodeId);
135
        $this->denyAccessUnlessValidResource($resource);
136
137
        $resourceNode = $resource->getResourceNode();
138
139
        $this->denyAccessUnlessGranted(
140
            ResourceNodeVoter::VIEW,
141
            $resourceNode,
142
            $this->trans(sprintf('Unauthorised access to resource #%s', $nodeId))
143
        );
144
145
        $this->setBreadCrumb($request, $resourceNode);
146
147
        $tool = $request->get('tool');
148
        $type = $request->get('type');
149
150
        $form = $this->createForm(ResourceCommentType::class, null);
151
152
        $params = [
153
            'resource' => $resource,
154
            'course' => $this->getCourse(),
155
            'tool' => $tool,
156
            'type' => $type,
157
            'comment_form' => $form->createView(),
158
        ];
159
160
        return $this->render(
161
            $repository->getTemplates()->getFromAction(__FUNCTION__, $request->isXmlHttpRequest()),
162
            $params
163
        );
164
    }
165
166
    /**
167
     * Preview a file. Mostly used when using a modal.
168
     *
169
     * @Route("/{tool}/{type}/{id}/preview", methods={"GET"}, name="chamilo_core_resource_preview")
170
     */
171
    /*public function previewAction(Request $request): Response
172
    {
173
        $nodeId = $request->get('id');
174
        $repository = $this->getRepositoryFromRequest($request);
175
176
        $resource = $repository->getResourceFromResourceNode($nodeId);
177
        $this->denyAccessUnlessValidResource($resource);
178
179
        $resourceNode = $resource->getResourceNode();
180
        $this->denyAccessUnlessGranted(
181
            ResourceNodeVoter::VIEW,
182
            $resourceNode,
183
            $this->trans('Unauthorised access to resource')
184
        );
185
186
        $this->setBreadCrumb($request, $resourceNode);
187
188
        $tool = $request->get('tool');
189
        $type = $request->get('type');
190
191
        $params = [
192
            'resource' => $resource,
193
            'tool' => $tool,
194
            'type' => $type,
195
        ];
196
197
        return $this->render($repository->getTemplates()->getFromAction(__FUNCTION__), $params);
198
    }*/
199
200
    /**
201
     * @deprecated use vue
202
     *
203
     * @Route("/{tool}/{type}/{id}/change_visibility", name="chamilo_core_resource_change_visibility")
204
     */
205
    public function changeVisibilityAction(Request $request): Response
206
    {
207
        $id = (int) $request->get('id');
208
209
        $repository = $this->getRepositoryFromRequest($request);
210
211
        $resource = $repository->getResourceFromResourceNode($id);
212
        $this->denyAccessUnlessValidResource($resource);
213
        /** @var AbstractResource $resource */
214
        $resourceNode = $resource->getResourceNode();
215
216
        $this->denyAccessUnlessGranted(
217
            ResourceNodeVoter::EDIT,
218
            $resourceNode,
219
            $this->trans('Unauthorised access to resource')
220
        );
221
222
        if ($this->hasCourse()) {
223
            $link = $resource->getFirstResourceLinkFromCourseSession($this->getCourse(), $this->getSession());
224
        } else {
225
            $link = $resource->getFirstResourceLink();
226
        }
227
228
        // Use repository to change settings easily.
229
        if ($link && ResourceLink::VISIBILITY_PUBLISHED === $link->getVisibility()) {
230
            $repository->setVisibilityDraft($resource);
231
        } else {
232
            $repository->setVisibilityPublished($resource);
233
        }
234
235
        $result = [
236
            'visibility' => $link->getVisibility(),
237
            'ok' => true,
238
        ];
239
240
        return new JsonResponse($result);
241
    }
242
243
    /**
244
     * @deprecated Use Vue + api platform
245
     *
246
     * @Route("/{tool}/{type}/{id}/delete", name="chamilo_core_resource_delete")
247
     */
248
    public function deleteAction(Request $request): Response
249
    {
250
        $em = $this->getDoctrine()->getManager();
251
252
        $id = $request->get('id');
253
        $resourceNode = $this->getDoctrine()->getRepository(ResourceNode::class)->find($id);
254
        $parentId = $resourceNode->getParent()->getId();
255
256
        $this->denyAccessUnlessGranted(
257
            ResourceNodeVoter::DELETE,
258
            $resourceNode,
259
            $this->trans('Unauthorised access to resource')
260
        );
261
262
        $children = $resourceNode->getChildren();
263
264
        if (!empty($children)) {
265
            /** @var ResourceNode $child */
266
            foreach ($children as $child) {
267
                $em->remove($child);
268
            }
269
        }
270
271
        $em->remove($resourceNode);
272
        $this->addFlash('success', $this->trans('Deleted').': '.$resourceNode->getSlug());
273
        $em->flush();
274
275
        $routeParams = $this->getResourceParams($request);
276
        $routeParams['id'] = $parentId;
277
278
        return $this->redirectToRoute('chamilo_core_resource_list', $routeParams);
279
    }
280
281
    /**
282
     * Shows the associated resource file.
283
     *
284
     * @deprecated use vue
285
     *
286
     * @Route("/{tool}/{type}/{id}/view_resource", methods={"GET"}, name="chamilo_core_resource_view_resource")
287
     */
288
    /*public function viewResourceAction(Request $request, RouterInterface $router): Response
289
    {
290
        $id = $request->get('id');
291
292
        $resourceNode = $this->getResourceNodeRepository()->find($id);
293
294
        if (null === $resourceNode) {
295
            throw new FileNotFoundException('Resource not found');
296
        }
297
298
        $this->denyAccessUnlessGranted(
299
            ResourceNodeVoter::VIEW,
300
            $resourceNode,
301
            $this->trans('Unauthorised access to resource')
302
        );
303
304
        $repository = $this->getRepositoryFromRequest($request);
305
306
        $resource = $repository->getResourceFromResourceNode($id);
307
308
        $tool = $request->get('tool');
309
        $type = $request->get('type');
310
        $this->setBreadCrumb($request, $resourceNode);
311
312
        $params = [
313
            'resource' => $resource,
314
            'tool' => $tool,
315
            'type' => $type,
316
        ];
317
318
        return $this->render($repository->getTemplates()->getFromAction(__FUNCTION__), $params);
319
    }*/
320
321
    /**
322
     * View file of a resource node.
323
     *
324
     * @Route("/{tool}/{type}/{id}/view", methods={"GET"}, name="chamilo_core_resource_view")
325
     */
326
    public function viewAction(Request $request): Response
327
    {
328
        $id = $request->get('id');
329
        $filter = (string) $request->get('filter'); // See filters definitions in /config/services.yml.
330
        $resourceNode = $this->getResourceNodeRepository()->find($id);
331
332
        if (null === $resourceNode) {
333
            throw new FileNotFoundException('Resource not found');
334
        }
335
336
        return $this->processFile($request, $resourceNode, 'show', $filter);
337
    }
338
339
    /**
340
     * Redirect resource to link.
341
     *
342
     * @Route("/{tool}/{type}/{id}/link", methods={"GET"}, name="chamilo_core_resource_link")
343
     *
344
     * @return RedirectResponse|void
345
     */
346
    public function linkAction(Request $request, RouterInterface $router)
347
    {
348
        $id = $request->get('id');
349
        $resourceNode = $this->getResourceNodeRepository()->find($id);
350
351
        if (null === $resourceNode) {
352
            throw new FileNotFoundException('Resource not found');
353
        }
354
355
        $repo = $this->getRepositoryFromRequest($request);
356
        if ($repo instanceof ResourceWithLinkInterface) {
357
            $resource = $repo->getResourceFromResourceNode($resourceNode->getId());
358
            $url = $repo->getLink($resource, $router, $this->getCourseUrlQueryToArray());
359
360
            return $this->redirect($url);
361
        }
362
363
        $this->abort('No redirect');
364
    }
365
366
    /**
367
     * Download file of a resource node.
368
     *
369
     * @Route("/{tool}/{type}/{id}/download", methods={"GET"}, name="chamilo_core_resource_download")
370
     *
371
     * @return RedirectResponse|StreamedResponse
372
     */
373
    public function downloadAction(Request $request)
374
    {
375
        $id = (int) $request->get('id');
376
        $resourceNode = $this->getResourceNodeRepository()->find($id);
377
378
        if (null === $resourceNode) {
379
            throw new FileNotFoundException('Resource not found');
380
        }
381
382
        $repo = $this->getRepositoryFromRequest($request);
383
384
        $this->denyAccessUnlessGranted(
385
            ResourceNodeVoter::VIEW,
386
            $resourceNode,
387
            $this->trans('Unauthorised access to resource')
388
        );
389
390
        // If resource node has a file just download it. Don't download the children.
391
        if ($resourceNode->hasResourceFile()) {
392
            // Redirect to download single file.
393
            return $this->processFile($request, $resourceNode, 'download');
394
        }
395
396
        $zipName = $resourceNode->getSlug().'.zip';
397
        //$rootNodePath = $resourceNode->getPathForDisplay();
398
        $resourceNodeRepo = $repo->getResourceNodeRepository();
399
        $type = $repo->getResourceType();
400
401
        $criteria = Criteria::create()
402
            ->where(Criteria::expr()->neq('resourceFile', null)) // must have a file
403
            ->andWhere(Criteria::expr()->eq('resourceType', $type)) // only download same type
404
        ;
405
406
        $qb = $resourceNodeRepo->getChildrenQueryBuilder($resourceNode);
407
        $qb->addCriteria($criteria);
408
        /** @var ArrayCollection|ResourceNode[] $children */
409
        $children = $qb->getQuery()->getResult();
410
        $count = \count($children);
411
        if (0 === $count) {
412
            $params = $this->getResourceParams($request);
413
            $params['id'] = $id;
414
415
            $this->addFlash('warning', $this->trans('No files'));
416
417
            return $this->redirectToRoute('chamilo_core_resource_list', $params);
418
        }
419
420
        $response = new StreamedResponse(
421
            function () use ($zipName, $children, $repo): void {
422
                // Define suitable options for ZipStream Archive.
423
                $options = new Archive();
424
                $options->setContentType('application/octet-stream');
425
                //initialise zipstream with output zip filename and options.
426
                $zip = new ZipStream($zipName, $options);
427
428
                /** @var ResourceNode $node */
429
                foreach ($children as $node) {
430
                    $stream = $repo->getResourceNodeFileStream($node);
431
                    $fileName = $node->getResourceFile()->getOriginalName();
432
                    //$fileToDisplay = basename($node->getPathForDisplay());
433
                    //$fileToDisplay = str_replace($rootNodePath, '', $node->getPathForDisplay());
434
                    //error_log($fileToDisplay);
435
                    $zip->addFileFromStream($fileName, $stream);
436
                }
437
                $zip->finish();
438
            }
439
        );
440
441
        $disposition = $response->headers->makeDisposition(
442
            ResponseHeaderBag::DISPOSITION_ATTACHMENT,
443
            $zipName //Transliterator::transliterate($zipName)
444
        );
445
        $response->headers->set('Content-Disposition', $disposition);
446
        $response->headers->set('Content-Type', 'application/octet-stream');
447
448
        return $response;
449
    }
450
451
    /**
452
     * @return mixed|StreamedResponse
453
     */
454
    private function processFile(Request $request, ResourceNode $resourceNode, string $mode = 'show', string $filter = '')
455
    {
456
        $this->denyAccessUnlessGranted(
457
            ResourceNodeVoter::VIEW,
458
            $resourceNode,
459
            $this->trans('Unauthorised view access to resource')
460
        );
461
462
        $resourceFile = $resourceNode->getResourceFile();
463
464
        if (null === $resourceFile) {
465
            throw new NotFoundHttpException($this->trans('File not found for resource'));
466
        }
467
468
        $fileName = $resourceNode->getResourceFile()->getOriginalName();
469
        $mimeType = $resourceFile->getMimeType();
470
        $resourceNodeRepo = $this->getResourceNodeRepository();
471
472
        switch ($mode) {
473
            case 'download':
474
                $forceDownload = true;
475
476
                break;
477
            case 'show':
478
            default:
479
                $forceDownload = false;
480
                // If it's an image then send it to Glide.
481
                if (str_contains($mimeType, 'image')) {
482
                    $glide = $this->getGlide();
483
                    $server = $glide->getServer();
484
                    $params = $request->query->all();
485
486
                    // The filter overwrites the params from GET.
487
                    if (!empty($filter)) {
488
                        $params = $glide->getFilters()[$filter] ?? [];
489
                    }
490
491
                    // The image was cropped manually by the user, so we force to render this version,
492
                    // no matter other crop parameters.
493
                    $crop = $resourceFile->getCrop();
494
                    if (!empty($crop)) {
495
                        $params['crop'] = $crop;
496
                    }
497
498
                    $fileName = $resourceNodeRepo->getFilename($resourceFile);
499
500
                    return $server->getImageResponse($fileName, $params);
501
                }
502
503
                // Modify the HTML content before displaying it.
504
                if (str_contains($mimeType, 'html')) {
505
                    $content = $resourceNodeRepo->getResourceNodeFileContent($resourceNode);
506
507
                    $response = new Response();
508
                    $disposition = $response->headers->makeDisposition(
509
                        ResponseHeaderBag::DISPOSITION_INLINE,
510
                        $fileName
511
                    );
512
                    $response->headers->set('Content-Disposition', $disposition);
513
                    $response->headers->set('Content-Type', 'text/html');
514
515
                    // @todo move into a function/class
516
                    if ('true' === $this->getSettingsManager()->getSetting('editor.translate_html')) {
517
                        $user = $this->getUser();
518
                        if (null !== $user) {
519
                            // Overwrite user_json, otherwise it will be loaded by the TwigListener.php
520
                            $userJson = json_encode(['locale' => $user->getLocale()]);
521
                            $js = $this->renderView(
522
                                '@ChamiloCore/Layout/document.html.twig',
523
                                ['breadcrumb' => '', 'user_json' => $userJson]
524
                            );
525
                            // Insert inside the head tag.
526
                            $content = str_replace('</head>', $js.'</head>', $content);
527
                        }
528
                    }
529
530
                    $response->setContent($content);
531
                    /*$contents = $this->renderView('@ChamiloCore/Resource/view_html.twig', [
532
                        'category' => '...',
533
                    ]);*/
534
535
                    return $response;
536
                }
537
538
                break;
539
        }
540
541
        $stream = $resourceNodeRepo->getResourceNodeFileStream($resourceNode);
542
543
        $response = new StreamedResponse(
544
            function () use ($stream): void {
545
                stream_copy_to_stream($stream, fopen('php://output', 'wb'));
546
            }
547
        );
548
549
        //Transliterator::transliterate($fileName)
550
        $disposition = $response->headers->makeDisposition(
551
            $forceDownload ? ResponseHeaderBag::DISPOSITION_ATTACHMENT : ResponseHeaderBag::DISPOSITION_INLINE,
552
            $fileName
553
        );
554
        $response->headers->set('Content-Disposition', $disposition);
555
        $response->headers->set('Content-Type', $mimeType ?: 'application/octet-stream');
556
557
        return $response;
558
    }
559
}
560