Completed
Push — master ( f67c92...339b0b )
by Julito
15:21
created

ResourceController::createResource()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 151
Code Lines 63

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 7
eloc 63
nc 10
nop 2
dl 0
loc 151
rs 7.8739
c 2
b 0
f 1

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
/* For licensing terms, see /license.txt */
3
4
namespace Chamilo\CoreBundle\Controller;
5
6
use APY\DataGridBundle\Grid\Action\MassAction;
7
use APY\DataGridBundle\Grid\Action\RowAction;
8
use APY\DataGridBundle\Grid\Export\CSVExport;
9
use APY\DataGridBundle\Grid\Export\ExcelExport;
10
use APY\DataGridBundle\Grid\Grid;
11
use APY\DataGridBundle\Grid\Row;
12
use APY\DataGridBundle\Grid\Source\Entity;
13
use Chamilo\CoreBundle\Component\Utils\Glide;
14
use Chamilo\CoreBundle\Entity\Resource\AbstractResource;
15
use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
16
use Chamilo\CoreBundle\Entity\Resource\ResourceNode;
17
use Chamilo\CoreBundle\Repository\ResourceRepository;
18
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
19
use Chamilo\CourseBundle\Controller\CourseControllerInterface;
20
use Chamilo\CourseBundle\Controller\CourseControllerTrait;
21
use Chamilo\UserBundle\Entity\User;
22
use Doctrine\Common\Collections\ArrayCollection;
23
use Doctrine\Common\Collections\Criteria;
24
use Doctrine\ORM\QueryBuilder;
25
use FOS\CKEditorBundle\Form\Type\CKEditorType;
26
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
27
use Symfony\Component\HttpFoundation\File\UploadedFile;
28
use Symfony\Component\HttpFoundation\JsonResponse;
29
use Symfony\Component\HttpFoundation\RedirectResponse;
30
use Symfony\Component\HttpFoundation\Request;
31
use Symfony\Component\HttpFoundation\Response;
32
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
33
use Symfony\Component\HttpFoundation\StreamedResponse;
34
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
35
use Symfony\Component\Routing\Annotation\Route;
36
use Symfony\Component\Routing\Router;
37
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
38
use Vich\UploaderBundle\Util\Transliterator;
39
use ZipStream\Option\Archive;
40
use ZipStream\ZipStream;
41
42
/**
43
 * Class ResourceController.
44
 *
45
 * @todo improve/refactor $this->denyAccessUnlessGranted
46
 * @Route("/resources")
47
 *
48
 * @author Julio Montoya <[email protected]>.
49
 */
50
class ResourceController extends AbstractResourceController implements CourseControllerInterface
51
{
52
    use CourseControllerTrait;
53
54
    /**
55
     * @Route("/{tool}/{type}", name="chamilo_core_resource_index")
56
     *
57
     * Example: /document/files (See the 'tool' and the 'resource_type' DB tables.)
58
     * For the tool value check the Tool entity.
59
     * For the type value check the ResourceType entity.
60
     */
61
    public function indexAction(Request $request, Grid $grid): Response
62
    {
63
        $tool = $request->get('tool');
64
        $type = $request->get('type');
65
66
        $parentResourceNode = $this->getParentResourceNode($request);
67
        $repository = $this->getRepositoryFromRequest($request);
68
        $settings = $repository->getResourceSettings();
69
70
        $grid = $this->getGrid($request, $repository, $grid, $parentResourceNode->getId());
71
72
        $breadcrumb = $this->getBreadCrumb();
73
        $breadcrumb->addChild(
74
            $this->trans($tool),
75
            [
76
                'uri' => '#',
77
            ]
78
        );
79
80
        // The base resource node is the course.
81
        $id = $parentResourceNode->getId();
82
83
84
        return $grid->getGridResponse(
85
            '@ChamiloTheme/Resource/index.html.twig',
86
            [
87
                'tool' => $tool,
88
                'type' => $type,
89
                'id' => $id,
90
                'parent_resource_node' => $parentResourceNode,
91
                'resource_settings' => $settings,
92
            ]
93
        );
94
    }
95
96
    /**
97
     * @Route("/{tool}/{type}/{id}/list", name="chamilo_core_resource_list")
98
     *
99
     * If node has children show it
100
     */
101
    public function listAction(Request $request, Grid $grid): Response
102
    {
103
        $tool = $request->get('tool');
104
        $type = $request->get('type');
105
        $resourceNodeId = $request->get('id');
106
107
        $repository = $this->getRepositoryFromRequest($request);
108
        $settings = $repository->getResourceSettings();
109
110
        $grid = $this->getGrid($request, $repository, $grid, $resourceNodeId);
111
112
        $this->setBreadCrumb($request);
113
        $parentResourceNode = $this->getParentResourceNode($request);
114
115
        return $grid->getGridResponse(
116
            '@ChamiloTheme/Resource/index.html.twig',
117
            [
118
                'parent_id' => $resourceNodeId,
119
                'tool' => $tool,
120
                'type' => $type,
121
                'id' => $resourceNodeId,
122
                'parent_resource_node' => $parentResourceNode,
123
                'resource_settings' => $settings,
124
            ]
125
        );
126
    }
127
128
    public function getGrid(Request $request, ResourceRepository $repository, Grid $grid, $resourceNodeId): Grid
129
    {
130
        $class = $repository->getRepository()->getClassName();
131
132
        // The group 'resource' is set in the @GRID\Source annotation in the entity.
133
        $source = new Entity($class, 'resource');
134
        $parentNode = $repository->getResourceNodeRepository()->find($resourceNodeId);
135
136
        $this->denyAccessUnlessGranted(
137
            ResourceNodeVoter::VIEW,
138
            $parentNode,
139
            $this->trans('Unauthorised access to resource')
140
        );
141
142
        $course = null;
143
        $session = null;
144
        if ($this->hasCourse()) {
145
            $course = $this->getCourse();
146
            $session = $this->getSession();
147
            $qb = $repository->getResourcesByCourse($course, $session, null, $parentNode);
148
        } else {
149
            $qb = $repository->getResourcesByCreator($this->getUser(), $parentNode);
150
        }
151
152
        // 3. Set QueryBuilder to the source.
153
        $source->initQueryBuilder($qb);
154
        $grid->setSource($source);
155
156
        $resourceParams = $this->getResourceParams($request);
157
158
        $grid->setRouteUrl($this->generateUrl('chamilo_core_resource_list', $resourceParams));
159
160
        //$grid->hideFilters();
161
        //$grid->setLimits(20);
162
        //$grid->isReadyForRedirect();
163
        //$grid->setMaxResults(1);
164
        //$grid->setLimits(2);
165
        //$grid->setColumns($columns);
166
        $routeParams = $resourceParams;
167
        $routeParams['id'] = null;
168
169
        $titleColumn = $repository->getTitleColumn($grid);
170
        $titleColumn->setSafe(false); // allows links in the title
171
172
        // Title link.
173
        $titleColumn->setTitle($this->trans('Name'));
174
175
        //$repository->formatGrid();
176
        /*if ($grid->hasColumn('filetype')) {
177
            $grid->getColumn('filetype')->setTitle($this->trans('Type'));
178
        }*/
179
180
        $titleColumn->manipulateRenderCell(
181
            function ($value, Row $row, $router) use ($routeParams) {
182
                /** @var Router $router */
183
                /** @var AbstractResource $entity */
184
                $entity = $row->getEntity();
185
                $resourceNode = $entity->getResourceNode();
186
                $id = $resourceNode->getId();
187
188
                $myParams = $routeParams;
189
                $myParams['id'] = $id;
190
                unset($myParams[0]);
191
192
                $icon = $resourceNode->getIcon().' &nbsp;';
193
                if ($resourceNode->hasResourceFile()) {
194
                    /*$url = $router->generate(
195
                        'chamilo_core_resource_show',
196
                        $myParams
197
                    );*/
198
                    if ($resourceNode->isResourceFileAnImage()) {
199
                        $url = $router->generate(
200
                            'chamilo_core_resource_view',
201
                            $myParams
202
                        );
203
204
                        return $icon.'<a data-fancybox="gallery" href="'.$url.'">'.$value.'</a>';
205
                    }
206
207
                    if ($resourceNode->isResourceFileAVideo()) {
208
                        $url = $router->generate(
209
                            'chamilo_core_resource_view',
210
                            $myParams
211
                        );
212
213
                        return '
214
                        <video width="640" height="320" controls id="video'.$id.'" controls preload="metadata" style="display:none;">
215
                            <source src="'.$url.'" type="video/mp4">
216
                            Your browser doesn\'t support HTML5 video tag.
217
                        </video>
218
                        '.$icon.' <a data-fancybox="gallery"  data-width="640" data-height="360" href="#video'.$id.'">'.$value.'</a>';
219
                    }
220
221
                    $url = $router->generate(
222
                        'chamilo_core_resource_preview',
223
                        $myParams
224
                    );
225
226
                    return $icon.'<a data-fancybox="gallery" data-type="iframe" data-src="'.$url.'" href="javascript:;" >'.$value.'</a>';
227
                } else {
228
                    $url = $router->generate(
229
                        'chamilo_core_resource_list',
230
                        $myParams
231
                    );
232
233
                    return $icon.'<a href="'.$url.'">'.$value.'</a>';
234
                }
235
            }
236
        );
237
238
        if ($grid->hasColumn('filetype')) {
239
            $grid->getColumn('filetype')->manipulateRenderCell(
240
                function ($value, Row $row, $router) use ($routeParams) {
0 ignored issues
show
Unused Code introduced by
The parameter $router is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

240
                function ($value, Row $row, /** @scrutinizer ignore-unused */ $router) use ($routeParams) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The import $routeParams is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
241
                    /** @var AbstractResource $entity */
242
                    $entity = $row->getEntity();
243
                    $resourceNode = $entity->getResourceNode();
244
245
                    if ($resourceNode->hasResourceFile()) {
246
                        $file = $resourceNode->getResourceFile();
247
248
                        return $file->getMimeType();
249
                    }
250
251
                    return $this->trans('Folder');
252
                }
253
            );
254
        }
255
256
        if ($grid->hasColumn('iid')) {
257
            $grid->setHiddenColumns(['iid']);
258
        }
259
260
        // Delete mass action.
261
        if ($this->isGranted(ResourceNodeVoter::DELETE, $this->getCourse())) {
262
            $deleteMassAction = new MassAction(
263
                'Delete',
264
                'ChamiloCoreBundle:Resource:deleteMass',
265
                true,
266
                $routeParams
267
            );
268
            $grid->addMassAction($deleteMassAction);
269
        }
270
271
        // Info action.
272
        $myRowAction = new RowAction(
273
            $this->trans('Info'),
274
            'chamilo_core_resource_info',
275
            false,
276
            '_self',
277
            [
278
                'class' => 'btn btn-secondary info_action',
279
                'icon' => 'fa-info-circle',
280
                'iframe' => false,
281
            ]
282
        );
283
284
        $setNodeParameters = function (RowAction $action, Row $row) use ($routeParams) {
285
            $id = $row->getEntity()->getResourceNode()->getId();
286
            $routeParams['id'] = $id;
287
            $action->setRouteParameters($routeParams);
288
            $attributes = $action->getAttributes();
289
            $attributes['data-action'] = $action->getRoute();
290
            $attributes['data-action-id'] = $action->getRoute().'_'.$id;
291
            $attributes['data-node-id'] = $id;
292
293
            $action->setAttributes($attributes);
294
295
            return $action;
296
        };
297
298
        $myRowAction->addManipulateRender($setNodeParameters);
299
        $grid->addRowAction($myRowAction);
300
301
        // Download action
302
        $myRowAction = new RowAction(
303
            $this->trans('Download'),
304
            'chamilo_core_resource_download',
305
            false,
306
            '_self',
307
            [
308
                'class' => 'btn btn-secondary download_action',
309
                'icon' => 'fa-download',
310
            ]
311
        );
312
313
        $setNodeParameters = function (RowAction $action, Row $row) use ($routeParams) {
314
            $id = $row->getEntity()->getResourceNode()->getId();
315
            $routeParams['id'] = $id;
316
317
            $action->setRouteParameters($routeParams);
318
            $attributes = $action->getAttributes();
319
            //$attributes['data-action'] = $action->getRoute();
320
            //$attributes['data-action-id'] = $action->getRoute().'_'.$id;
321
            //$attributes['data-node-id'] = $id;
322
            $action->setAttributes($attributes);
323
324
            return $action;
325
        };
326
327
        $myRowAction->addManipulateRender($setNodeParameters);
328
        $grid->addRowAction($myRowAction);
329
330
        if ($this->isGranted(ResourceNodeVoter::EDIT, $this->getCourse())) {
331
            // Enable/Disable
332
            $myRowAction = new RowAction(
333
                '',
334
                'chamilo_core_resource_change_visibility',
335
                false,
336
                '_self'
337
            );
338
339
            $setVisibleParameters = function (RowAction $action, Row $row) use ($routeParams) {
340
                /** @var AbstractResource $resource */
341
                $resource = $row->getEntity();
342
                $id = $resource->getResourceNode()->getId();
343
344
                $icon = 'fa-eye-slash';
345
                $link = $resource->getCourseSessionResourceLink($this->getCourse(), $this->getSession());
346
347
                if ($link === null) {
348
                    return null;
349
                }
350
                if ($link->getVisibility() === ResourceLink::VISIBILITY_PUBLISHED) {
351
                    $icon = 'fa-eye';
352
                }
353
                $routeParams['id'] = $id;
354
                $action->setRouteParameters($routeParams);
355
                $attributes = [
356
                    'class' => 'btn btn-secondary change_visibility',
357
                    'data-id' => $id,
358
                    'icon' => $icon,
359
                ];
360
                $action->setAttributes($attributes);
361
362
                return $action;
363
            };
364
365
            $myRowAction->addManipulateRender($setVisibleParameters);
366
            $grid->addRowAction($myRowAction);
367
368
            // Edit action.
369
            $myRowAction = new RowAction(
370
                $this->trans('Edit'),
371
                'chamilo_core_resource_edit',
372
                false,
373
                '_self',
374
                ['class' => 'btn btn-secondary', 'icon' => 'fa fa-pen']
375
            );
376
            $myRowAction->addManipulateRender($setNodeParameters);
377
            $grid->addRowAction($myRowAction);
378
379
            // More action.
380
            $myRowAction = new RowAction(
381
                $this->trans('More'),
382
                'chamilo_core_resource_preview',
383
                false,
384
                '_self',
385
                ['class' => 'btn btn-secondary edit_resource', 'icon' => 'fa fa-ellipsis-h']
386
            );
387
388
            $myRowAction->addManipulateRender($setNodeParameters);
389
            $grid->addRowAction($myRowAction);
390
391
            // Delete action.
392
            $myRowAction = new RowAction(
393
                $this->trans('Delete'),
394
                'chamilo_core_resource_delete',
395
                true,
396
                '_self',
397
                ['class' => 'btn btn-danger', 'data_hidden' => true]
398
            );
399
            $myRowAction->addManipulateRender($setNodeParameters);
400
            $grid->addRowAction($myRowAction);
401
        }
402
403
        /*$grid->addExport(new CSVExport($this->trans('CSV export'), 'export', ['course' => $courseIdentifier]));
404
        $grid->addExport(
405
            new ExcelExport(
406
                $this->trans('Excel export'),
407
                'export',
408
                ['course' => $courseIdentifier]
409
            )
410
        );*/
411
412
        return $grid;
413
    }
414
415
    /**
416
     * @Route("/{tool}/{type}/{id}/new_folder", methods={"GET", "POST"}, name="chamilo_core_resource_new_folder")
417
     */
418
    public function newFolderAction(Request $request): Response
419
    {
420
        $this->setBreadCrumb($request);
421
422
        return $this->createResource($request, 'folder');
423
    }
424
425
    /**
426
     * @Route("/{tool}/{type}/{id}/new", methods={"GET", "POST"}, name="chamilo_core_resource_new")
427
     */
428
    public function newAction(Request $request): Response
429
    {
430
        $this->setBreadCrumb($request);
431
432
        return $this->createResource($request, 'file');
433
    }
434
435
    /**
436
     * @Route("/{tool}/{type}/{id}/edit", methods={"GET", "POST"})
437
     */
438
    public function editAction(Request $request): Response
439
    {
440
        $resourceNodeId = $request->get('id');
441
442
        $this->setBreadCrumb($request);
443
        $repository = $this->getRepositoryFromRequest($request);
444
        /** @var AbstractResource $resource */
445
        $resource = $repository->getRepository()->findOneBy(['resourceNode' => $resourceNodeId]);
446
        $resourceNode = $resource->getResourceNode();
447
448
        $this->denyAccessUnlessGranted(
449
            ResourceNodeVoter::EDIT,
450
            $resourceNode,
451
            $this->trans('Unauthorised access to resource')
452
        );
453
454
        $resourceNodeParentId = $resourceNode->getId();
455
456
        $routeParams = $this->getResourceParams($request);
457
        $routeParams['id'] = $resourceNodeParentId;
458
459
        $form = $repository->getForm($this->container->get('form.factory'), $resource);
460
461
        if ($resourceNode->hasEditableContent()) {
462
            $form->add(
463
                'content',
464
                CKEditorType::class,
465
                [
466
                    'mapped' => false,
467
                    'config' => [
468
                        'filebrowserImageBrowseRoute' => 'resources_filemanager',
469
                        'filebrowserImageBrowseRouteParameters' => $routeParams,
470
                    ],
471
                ]
472
            );
473
            $content = $repository->getResourceNodeFileContent($resourceNode);
474
            $form->get('content')->setData($content);
475
        }
476
477
        $form->handleRequest($request);
478
479
        if ($form->isSubmitted() && $form->isValid()) {
480
            /** @var AbstractResource $newResource */
481
            $newResource = $form->getData();
482
483
            if ($form->has('content')) {
484
                $data = $form->get('content')->getData();
485
                $repository->updateResourceFileContent($newResource, $data);
486
            }
487
488
            //$newResource->setTitle($form->get('title')->getData()); // already set in $form->getData()
489
            $repository->updateNodeForResource($newResource);
490
491
            $this->addFlash('success', $this->trans('Updated'));
492
493
            //if ($newResource->getResourceNode()->hasResourceFile()) {
494
                $resourceNodeParentId = $newResource->getResourceNode()->getParent()->getId();
495
            //}
496
            $routeParams['id'] = $resourceNodeParentId;
497
498
            return $this->redirectToRoute('chamilo_core_resource_list', $routeParams);
499
        }
500
501
        return $this->render(
502
            '@ChamiloTheme/Resource/edit.html.twig',
503
            [
504
                'form' => $form->createView(),
505
                'parent' => $resourceNodeParentId,
506
            ]
507
        );
508
    }
509
510
    /**
511
     * Shows a resource information.
512
     *
513
     * @Route("/{tool}/{type}/{id}/info", methods={"GET"}, name="chamilo_core_resource_info")
514
     */
515
    public function infoAction(Request $request): Response
516
    {
517
        $this->setBreadCrumb($request);
518
        $nodeId = $request->get('id');
519
520
        $repository = $this->getRepositoryFromRequest($request);
521
522
        /** @var AbstractResource $resource */
523
        $resource = $repository->getRepository()->findOneBy(['resourceNode' => $nodeId]);
524
525
        if (null === $resource) {
526
            throw new NotFoundHttpException();
527
        }
528
529
        $resourceNode = $resource->getResourceNode();
530
531
        if (null === $resourceNode) {
532
            throw new NotFoundHttpException();
533
        }
534
535
        $this->denyAccessUnlessGranted(
536
            ResourceNodeVoter::VIEW,
537
            $resourceNode,
538
            $this->trans('Unauthorised access to resource')
539
        );
540
541
        $tool = $request->get('tool');
542
        $type = $request->get('type');
543
544
        $params = [
545
            'resource' => $resource,
546
            'tool' => $tool,
547
            'type' => $type,
548
        ];
549
550
        return $this->render('@ChamiloTheme/Resource/show.html.twig', $params);
551
    }
552
553
    /**
554
     * Preview a file. Mostly used when using a modal.
555
     *
556
     * @Route("/{tool}/{type}/{id}/preview", methods={"GET"}, name="chamilo_core_resource_preview")
557
     */
558
    public function previewAction(Request $request): Response
559
    {
560
        $this->setBreadCrumb($request);
561
        $nodeId = $request->get('id');
562
563
        $repository = $this->getRepositoryFromRequest($request);
564
565
        /** @var AbstractResource $resource */
566
        $resource = $repository->getRepository()->findOneBy(['resourceNode' => $nodeId]);
567
568
        if (null === $resource) {
569
            throw new NotFoundHttpException();
570
        }
571
572
        $resourceNode = $resource->getResourceNode();
573
574
        if (null === $resourceNode) {
575
            throw new NotFoundHttpException();
576
        }
577
578
        $this->denyAccessUnlessGranted(
579
            ResourceNodeVoter::VIEW,
580
            $resourceNode,
581
            $this->trans('Unauthorised access to resource')
582
        );
583
584
        $tool = $request->get('tool');
585
        $type = $request->get('type');
586
587
        $params = [
588
            'resource' => $resource,
589
            'tool' => $tool,
590
            'type' => $type,
591
        ];
592
593
        return $this->render('@ChamiloTheme/Resource/preview.html.twig', $params);
594
    }
595
596
    /**
597
     * @Route("/{tool}/{type}/{id}/change_visibility", name="chamilo_core_resource_change_visibility")
598
     */
599
    public function changeVisibilityAction(Request $request): Response
600
    {
601
        $id = $request->get('id');
602
603
        $repository = $this->getRepositoryFromRequest($request);
604
605
        /** @var AbstractResource $resource */
606
        $resource = $repository->getRepository()->findOneBy(['resourceNode' => $id]);
607
608
        if (null === $resource) {
609
            throw new NotFoundHttpException();
610
        }
611
612
        $resourceNode = $resource->getResourceNode();
613
614
        $this->denyAccessUnlessGranted(
615
            ResourceNodeVoter::EDIT,
616
            $resourceNode,
617
            $this->trans('Unauthorised access to resource')
618
        );
619
620
        /** @var ResourceLink $link */
621
        $link = $resource->getCourseSessionResourceLink($this->getCourse(), $this->getSession());
622
623
        $icon = 'fa-eye';
624
        // Use repository to change settings easily.
625
        if ($link && $link->getVisibility() === ResourceLink::VISIBILITY_PUBLISHED) {
626
            $repository->setVisibilityDraft($resource);
627
            $icon = 'fa-eye-slash';
628
        } else {
629
            $repository->setVisibilityPublished($resource);
630
        }
631
632
        $result = ['icon' => $icon];
633
634
        return new JsonResponse($result);
635
    }
636
637
    /**
638
     * @Route("/{tool}/{type}/{id}", name="chamilo_core_resource_delete")
639
     */
640
    public function deleteAction(Request $request): Response
641
    {
642
        $tool = $request->get('tool');
643
        $type = $request->get('type');
644
645
        $em = $this->getDoctrine()->getManager();
646
647
        $id = $request->get('id');
648
        $resourceNode = $this->getDoctrine()->getRepository('ChamiloCoreBundle:Resource\ResourceNode')->find($id);
649
        $parentId = $resourceNode->getParent()->getId();
650
651
        if (null === $resourceNode) {
652
            throw new NotFoundHttpException();
653
        }
654
655
        $this->denyAccessUnlessGranted(
656
            ResourceNodeVoter::DELETE,
657
            $resourceNode,
658
            $this->trans('Unauthorised access to resource')
659
        );
660
661
        $em->remove($resourceNode);
662
        $this->addFlash('success', $this->trans('Deleted'));
663
        $em->flush();
664
665
        $routeParams = $this->getResourceParams($request);
666
        $routeParams['id'] = $parentId;
667
668
        return $this->redirectToRoute(
669
            'chamilo_core_resource_list',
670
            $routeParams
671
        );
672
    }
673
674
    /**
675
     * @Route("/{tool}/{type}/{id}", methods={"DELETE"}, name="chamilo_core_resource_delete_mass")
676
     */
677
    public function deleteMassAction($primaryKeys, $allPrimaryKeys, Request $request): Response
678
    {
679
        $tool = $request->get('tool');
680
        $type = $request->get('type');
681
        $em = $this->getDoctrine()->getManager();
682
        $repo = $this->getRepositoryFromRequest($request);
683
684
        $parentId = 0;
685
        foreach ($primaryKeys as $id) {
686
            $resource = $repo->find($id);
687
            $resourceNode = $resource->getResourceNode();
688
689
            if (null === $resourceNode) {
690
                continue;
691
            }
692
693
            $this->denyAccessUnlessGranted(
694
                ResourceNodeVoter::DELETE,
695
                $resourceNode,
696
                $this->trans('Unauthorised access to resource')
697
            );
698
699
            $parentId = $resourceNode->getParent()->getId();
700
            $em->remove($resource);
701
        }
702
703
        $this->addFlash('success', $this->trans('Deleted'));
704
        $em->flush();
705
706
        $routeParams = $this->getResourceParams($request);
707
        $routeParams['id'] = $parentId;
708
709
        return $this->redirectToRoute('chamilo_core_resource_list', $routeParams);
710
    }
711
712
    /**
713
     * Shows the associated resource file.
714
     *
715
     * @Route("/{tool}/{type}/{id}/view", methods={"GET"}, name="chamilo_core_resource_view")
716
     */
717
    public function viewAction(Request $request, Glide $glide): Response
718
    {
719
        $id = $request->get('id');
720
        $filter = $request->get('filter');
721
        $mode = $request->get('mode');
722
        $em = $this->getDoctrine();
723
        $resourceNode = $em->getRepository('ChamiloCoreBundle:Resource\ResourceNode')->find($id);
724
725
        if ($resourceNode === null) {
726
            throw new FileNotFoundException('Resource not found');
727
        }
728
729
        return $this->showFile($request, $resourceNode, $mode, $glide, $filter);
730
    }
731
732
    /**
733
     * Gets a document when calling route resources_document_get_file.
734
1     *
735
     * @deprecated
736
     *
737
     * @throws \League\Flysystem\FileNotFoundException
738
     */
739
    public function getDocumentAction(Request $request, Glide $glide): Response
740
    {
741
        /*$file = $request->get('file');
742
        $mode = $request->get('mode');
743
744
        // see list of filters in config/services.yaml
745
        $filter = $request->get('filter');
746
        $mode = !empty($mode) ? $mode : 'show';
747
748
        $repository = $this->getRepository('document', 'files');
749
        $nodeRepository = $repository->getResourceNodeRepository();
750
751
        $title = basename($file);
752
        // @todo improve criteria to avoid giving the wrong file.
753
        $criteria = ['slug' => $title];
754
755
        $resourceNode = $nodeRepository->findOneBy($criteria);
756
757
        if (null === $resourceNode) {
758
            throw new NotFoundHttpException();
759
        }
760
761
        return $this->showFile($request, $resourceNode, $mode, $glide,$filter);*/
762
    }
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return Symfony\Component\HttpFoundation\Response. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
763
764
    /**
765
     * @Route("/{tool}/{type}/{id}/download", methods={"GET"}, name="chamilo_core_resource_download")
766
     */
767
    public function downloadAction(Request $request)
768
    {
769
        $resourceNodeId = (int) $request->get('id');
770
        $courseNode = $this->getCourse()->getResourceNode();
771
772
        $repo = $this->getRepositoryFromRequest($request);
773
774
        if (empty($resourceNodeId)) {
775
            $resourceNode = $courseNode;
776
        } else {
777
            $resourceNode = $repo->getResourceNodeRepository()->find($resourceNodeId);
778
        }
779
780
        $type = $repo->getResourceType();
781
782
        if (null === $resourceNode) {
783
            throw new NotFoundHttpException();
784
        }
785
786
        $this->denyAccessUnlessGranted(
787
            ResourceNodeVoter::VIEW,
788
            $resourceNode,
789
            $this->trans('Unauthorised access to resource')
790
        );
791
792
        // If resource node has a file just download it. Don't download the children.
793
        if ($resourceNode->hasResourceFile()) {
794
            // Redirect to download single file.
795
            return $this->showFile($request, $resourceNode, 'download');
796
        }
797
798
        $zipName = $resourceNode->getSlug().'.zip';
799
        $rootNodePath = $resourceNode->getPathForDisplay();
800
801
        $resourceNodeRepo = $repo->getResourceNodeRepository();
802
803
        $criteria = Criteria::create()
804
            ->where(Criteria::expr()->neq('resourceFile', null)) // must have a file
805
           // ->andWhere(Criteria::expr()->eq('resourceType', $type))
806
        ;
807
808
        /** @var ArrayCollection|ResourceNode[] $children */
809
        /** @var QueryBuilder $children */
810
        $qb = $resourceNodeRepo->getChildrenQueryBuilder($resourceNode);
811
        $qb->addCriteria($criteria);
812
        $children = $qb->getQuery()->getResult();
813
814
        $response = new StreamedResponse(function () use ($rootNodePath, $zipName, $children, $repo) {
815
            // Define suitable options for ZipStream Archive.
816
            $options = new Archive();
817
            $options->setContentType('application/octet-stream');
818
            //initialise zipstream with output zip filename and options.
819
            $zip = new ZipStream($zipName, $options);
820
821
            /** @var ResourceNode $node */
822
            foreach ($children as $node) {
823
                $resourceFile = $node->getResourceFile();
824
                $systemName = $resourceFile->getFile()->getPathname();
825
                $stream = $repo->getResourceNodeFileStream($node);
826
                //error_log($node->getPathForDisplay());
827
                $fileToDisplay = str_replace($rootNodePath, '', $node->getPathForDisplay());
828
                $zip->addFileFromStream($fileToDisplay, $stream);
829
            }
830
            $zip->finish();
831
        });
832
833
        $disposition = $response->headers->makeDisposition(
834
            ResponseHeaderBag::DISPOSITION_ATTACHMENT,
835
            Transliterator::transliterate($zipName)
836
        );
837
        $response->headers->set('Content-Disposition', $disposition);
838
        $response->headers->set('Content-Type', 'application/octet-stream');
839
840
        return $response;
841
    }
842
843
    /**
844
     * Upload form.
845
     *
846
     * @Route("/{tool}/{type}/{id}/upload", name="chamilo_core_resource_upload", methods={"GET", "POST"},
847
     *                                      options={"expose"=true})
848
     */
849
    public function uploadAction(Request $request, $tool, $type, $id): Response
850
    {
851
        $repository = $this->getRepositoryFromRequest($request);
852
        $resourceNode = $repository->getResourceNodeRepository()->find($id);
853
854
        $this->denyAccessUnlessGranted(
855
            ResourceNodeVoter::EDIT,
856
            $resourceNode,
857
            $this->trans('Unauthorised access to resource')
858
        );
859
860
        $this->setBreadCrumb($request);
861
862
        $routeParams = $this->getResourceParams($request);
863
        $routeParams['tool'] = $tool;
864
        $routeParams['type'] = $type;
865
        $routeParams['id'] = $id;
866
867
        return $this->render(
868
            '@ChamiloTheme/Resource/upload.html.twig',
869
            $routeParams
870
        );
871
    }
872
873
    public function setBreadCrumb(Request $request)
874
    {
875
        $tool = $request->get('tool');
876
        $type = $request->get('type');
877
        $resourceNodeId = $request->get('id');
878
879
        $routeParams = $this->getResourceParams($request);
880
881
        if (!empty($resourceNodeId)) {
882
            $breadcrumb = $this->getBreadCrumb();
883
884
            // Root tool link
885
            $breadcrumb->addChild(
886
                $this->trans($tool),
887
                [
888
                    'uri' => $this->generateUrl(
889
                        'chamilo_core_resource_index',
890
                        $routeParams
891
                    ),
892
                ]
893
            );
894
895
            $repo = $this->getRepositoryFromRequest($request);
896
897
            /** @var AbstractResource $parent */
898
            $originalResource = $repo->findOneBy(['resourceNode' => $resourceNodeId]);
899
            if ($originalResource === null) {
900
                return;
901
            }
902
            $parent = $originalParent = $originalResource->getResourceNode();
903
904
            $parentList = [];
905
            while ($parent !== null) {
906
                if ($type !== $parent->getResourceType()->getName()) {
907
                    break;
908
                }
909
                $parent = $parent->getParent();
910
                if ($parent) {
911
                    $resource = $repo->findOneBy(['resourceNode' => $parent->getId()]);
912
                    if ($resource) {
913
                        $parentList[] = $resource;
914
                    }
915
                }
916
            }
917
918
            $parentList = array_reverse($parentList);
919
            /** @var AbstractResource $item */
920
            foreach ($parentList as $item) {
921
                $params = $routeParams;
922
                $params['id'] = $item->getResourceNode()->getId();
923
                $breadcrumb->addChild(
924
                    $item->getResourceName(),
925
                    [
926
                        'uri' => $this->generateUrl(
927
                            'chamilo_core_resource_list',
928
                            $params
929
                        ),
930
                    ]
931
                );
932
            }
933
934
            $params = $routeParams;
935
            $params['id'] = $originalParent->getId();
936
937
            $breadcrumb->addChild(
938
                $originalResource->getResourceName(),
0 ignored issues
show
Bug introduced by
The method getResourceName() does not exist on Chamilo\CoreBundle\Entit...source\AbstractResource. Did you maybe mean getResourceNode()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

938
                $originalResource->/** @scrutinizer ignore-call */ 
939
                                   getResourceName(),

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
939
                [
940
                    'uri' => $this->generateUrl(
941
                        'chamilo_core_resource_list',
942
                        $params
943
                    ),
944
                ]
945
            );
946
        }
947
    }
948
949
    private function getParentResourceNode(Request $request): ResourceNode
950
    {
951
        $parentNodeId = $request->get('id');
952
953
        $parentResourceNode = null;
954
955
        if (empty($parentNodeId)) {
956
            if ($this->hasCourse()) {
957
                $parentResourceNode = $this->getCourse()->getResourceNode();
958
            } else {
959
                if ($this->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
960
                    /** @var User $user */
961
                    $parentResourceNode = $this->getUser()->getResourceNode();
962
                }
963
            }
964
        } else {
965
            $repo = $this->getDoctrine()->getRepository('ChamiloCoreBundle:Resource\ResourceNode');
966
            $parentResourceNode = $repo->find($parentNodeId);
967
        }
968
969
        if (null === $parentResourceNode) {
970
            throw new AccessDeniedException();
971
        }
972
973
        return $parentResourceNode;
974
    }
975
976
    /**
977
     * @param string $mode
978
     * @param string $filter
979
     *
980
     * @return mixed|StreamedResponse
981
     */
982
    private function showFile(Request $request, ResourceNode $resourceNode, $mode = 'show', Glide $glide = null, $filter = '')
983
    {
984
        $this->denyAccessUnlessGranted(
985
            ResourceNodeVoter::VIEW,
986
            $resourceNode,
987
            $this->trans('Unauthorised access to resource')
988
        );
989
990
        $repo = $this->getRepositoryFromRequest($request);
991
        $resourceFile = $resourceNode->getResourceFile();
992
993
        if (!$resourceFile) {
0 ignored issues
show
introduced by
$resourceFile is of type Chamilo\CoreBundle\Entity\Resource\ResourceFile, thus it always evaluated to true.
Loading history...
994
            throw new NotFoundHttpException($this->trans('File not found for resource'));
995
        }
996
997
        //$fileName = $resourceFile->getOriginalName();
998
        $fileName = $resourceNode->getSlug();
999
        $filePath = $resourceFile->getFile()->getPathname();
1000
        $mimeType = $resourceFile->getMimeType();
1001
1002
        switch ($mode) {
1003
            case 'download':
1004
                $forceDownload = true;
1005
                break;
1006
            case 'show':
1007
            default:
1008
                $forceDownload = false;
1009
                // If it's an image then send it to Glide.
1010
                if (strpos($mimeType, 'image') !== false) {
1011
                    $server = $glide->getServer();
0 ignored issues
show
Bug introduced by
The method getServer() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1011
                    /** @scrutinizer ignore-call */ 
1012
                    $server = $glide->getServer();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1012
                    $params = $request->query->all();
1013
1014
                    // The filter overwrites the params from get
1015
                    if (!empty($filter)) {
1016
                        $params = $glide->getFilters()[$filter] ?? [];
1017
                    }
1018
1019
                    // The image was cropped manually by the user, so we force to render this version,
1020
                    // no matter other crop parameters.
1021
                    $crop = $resourceFile->getCrop();
1022
                    if (!empty($crop)) {
1023
                        $params['crop'] = $crop;
1024
                    }
1025
1026
                    return $server->getImageResponse($filePath, $params);
1027
                }
1028
                break;
1029
        }
1030
1031
        $stream = $repo->getResourceNodeFileStream($resourceNode);
1032
1033
        //$stream = $this->fs->readStream($resourceNode);
1034
        $response = new StreamedResponse(function () use ($stream): void {
1035
            stream_copy_to_stream($stream, fopen('php://output', 'wb'));
0 ignored issues
show
Bug introduced by
It seems like $stream can also be of type string; however, parameter $source of stream_copy_to_stream() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1035
            stream_copy_to_stream(/** @scrutinizer ignore-type */ $stream, fopen('php://output', 'wb'));
Loading history...
Bug introduced by
It seems like fopen('php://output', 'wb') can also be of type false; however, parameter $dest of stream_copy_to_stream() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1035
            stream_copy_to_stream($stream, /** @scrutinizer ignore-type */ fopen('php://output', 'wb'));
Loading history...
1036
        });
1037
        $disposition = $response->headers->makeDisposition(
1038
            $forceDownload ? ResponseHeaderBag::DISPOSITION_ATTACHMENT : ResponseHeaderBag::DISPOSITION_INLINE,
1039
            $fileName
1040
            //Transliterator::transliterate($fileName)
1041
        );
1042
        $response->headers->set('Content-Disposition', $disposition);
1043
        $response->headers->set('Content-Type', $mimeType ?: 'application/octet-stream');
1044
1045
        return $response;
1046
    }
1047
1048
    /**
1049
     * @param string $fileType
1050
     *
1051
     * @return RedirectResponse|Response
1052
     */
1053
    private function createResource(Request $request, $fileType = 'file')
1054
    {
1055
        $resourceNodeParentId = $request->get('id');
1056
1057
        $repository = $this->getRepositoryFromRequest($request);
1058
1059
        $course = $this->getCourse();
1060
        $session = $this->getSession();
1061
        // Default parent node is course.
1062
        $parentNode = $this->getParentResourceNode($request);
1063
1064
        $this->denyAccessUnlessGranted(
1065
            ResourceNodeVoter::CREATE,
1066
            $parentNode,
1067
            $this->trans('Unauthorised access to resource')
1068
        );
1069
1070
        $form = $repository->getForm($this->container->get('form.factory'));
1071
1072
        $courseParams = $this->getResourceParams($request);
1073
1074
        if ($fileType === 'file') {
1075
            $params = $courseParams;
1076
            $params['id'] = $resourceNodeParentId;
1077
1078
            $form->add(
1079
                'content',
1080
                CKEditorType::class,
1081
                [
1082
                    'mapped' => false,
1083
                    'config' => [
1084
                        'filebrowserImageBrowseRoute' => 'resources_filemanager',
1085
                        'filebrowserImageBrowseRouteParameters' => $params,
1086
                    ],
1087
                ]
1088
            );
1089
        }
1090
1091
        $form->handleRequest($request);
1092
        if ($form->isSubmitted() && $form->isValid()) {
1093
            $em = $this->getDoctrine()->getManager();
1094
1095
            /** @var AbstractResource $newResource */
1096
            $newResource = $repository->saveResource($form, $course, $session, $fileType);
1097
1098
            $file = null;
1099
            if ($fileType === 'file') {
1100
                $content = $form->get('content')->getViewData();
1101
                $newResource->setTitle($newResource->getTitle().'.html');
0 ignored issues
show
Bug introduced by
The method setTitle() does not exist on Chamilo\CoreBundle\Entit...source\AbstractResource. It seems like you code against a sub-type of Chamilo\CoreBundle\Entit...source\AbstractResource such as Chamilo\CoreBundle\Entity\Course or Chamilo\CourseBundle\Entity\CLink or Chamilo\CourseBundle\Entity\CAnnouncement or Chamilo\CourseBundle\Entity\CQuiz or Chamilo\CourseBundle\Entity\CDocument or Chamilo\CourseBundle\Entity\CQuizQuestionCategory. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1101
                $newResource->/** @scrutinizer ignore-call */ 
1102
                              setTitle($newResource->getTitle().'.html');
Loading history...
Bug introduced by
The method getTitle() does not exist on Chamilo\CoreBundle\Entit...source\AbstractResource. It seems like you code against a sub-type of Chamilo\CoreBundle\Entit...source\AbstractResource such as Chamilo\CoreBundle\Entity\Course or Chamilo\CourseBundle\Entity\CLink or Chamilo\CourseBundle\Entity\CAnnouncement or Chamilo\CourseBundle\Entity\CQuiz or Chamilo\CourseBundle\Entity\CDocument or Chamilo\CourseBundle\Entity\CQuizQuestionCategory. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1101
                $newResource->setTitle($newResource->/** @scrutinizer ignore-call */ getTitle().'.html');
Loading history...
1102
                $fileName = $newResource->getTitle();
1103
1104
                $handle = tmpfile();
1105
                fwrite($handle, $content);
0 ignored issues
show
Bug introduced by
It seems like $handle can also be of type false; however, parameter $handle of fwrite() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1105
                fwrite(/** @scrutinizer ignore-type */ $handle, $content);
Loading history...
1106
                $meta = stream_get_meta_data($handle);
0 ignored issues
show
Bug introduced by
It seems like $handle can also be of type false; however, parameter $stream of stream_get_meta_data() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1106
                $meta = stream_get_meta_data(/** @scrutinizer ignore-type */ $handle);
Loading history...
1107
                $file = new UploadedFile($meta['uri'], $fileName, 'text/html', null, true);
1108
                $em->persist($newResource);
1109
            }
1110
1111
            $resourceNode = $repository->createNodeForResource($newResource, $this->getUser(), $parentNode, $file);
1112
            $em->persist($resourceNode);
1113
1114
            $repository->addResourceNodeToCourse(
1115
                $resourceNode,
1116
                ResourceLink::VISIBILITY_PUBLISHED,
1117
                $course,
1118
                $session,
1119
                null
1120
            );
1121
1122
            $em->flush();
1123
1124
            // Loops all sharing options
1125
            /*foreach ($shareList as $share) {
1126
                $idList = [];
1127
                if (isset($share['search'])) {
1128
                    $idList = explode(',', $share['search']);
1129
                }
1130
1131
                $resourceRight = null;
1132
                if (isset($share['mask'])) {
1133
                    $resourceRight = new ResourceRight();
1134
                    $resourceRight
1135
                        ->setMask($share['mask'])
1136
                        ->setRole($share['role'])
1137
                    ;
1138
                }
1139
1140
                // Build links
1141
                switch ($share['sharing']) {
1142
                    case 'everyone':
1143
                        $repository->addResourceToEveryone(
1144
                            $resourceNode,
1145
                            $resourceRight
1146
                        );
1147
                        break;
1148
                    case 'course':
1149
                        $repository->addResourceToCourse(
1150
                            $resourceNode,
1151
                            $course,
1152
                            $resourceRight
1153
                        );
1154
                        break;
1155
                    case 'session':
1156
                        $repository->addResourceToSession(
1157
                            $resourceNode,
1158
                            $course,
1159
                            $session,
1160
                            $resourceRight
1161
                        );
1162
                        break;
1163
                    case 'user':
1164
                        // Only for me
1165
                        if (isset($share['only_me'])) {
1166
                            $repository->addResourceOnlyToMe($resourceNode);
1167
                        } else {
1168
                            // To other users
1169
                            $repository->addResourceToUserList($resourceNode, $idList);
1170
                        }
1171
                        break;
1172
                    case 'group':
1173
                        // @todo
1174
                        break;
1175
                }*/
1176
            //}
1177
            $em->flush();
1178
            $this->addFlash('success', $this->trans('Saved'));
1179
1180
            $params = $this->getResourceParams($request);
1181
            $params['id'] = $resourceNodeParentId;
1182
1183
            return $this->redirectToRoute(
1184
                'chamilo_core_resource_list',
1185
                $params
1186
            );
1187
        }
1188
1189
        switch ($fileType) {
1190
            case 'folder':
1191
                $template = '@ChamiloTheme/Resource/new_folder.html.twig';
1192
                break;
1193
            case 'file':
1194
                $template = '@ChamiloTheme/Resource/new.html.twig';
1195
                break;
1196
        }
1197
1198
        return $this->render(
1199
            $template,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $template does not seem to be defined for all execution paths leading up to this point.
Loading history...
1200
            [
1201
                'form' => $form->createView(),
1202
                'parent' => $resourceNodeParentId,
1203
                'file_type' => $fileType,
1204
            ]
1205
        );
1206
    }
1207
}
1208