Completed
Push — master ( fc1588...7621d0 )
by Julito
16:55
created

ResourceController::getParentResourceNode()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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

245
                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...
246
                    /** @var AbstractResource $entity */
247
                    $entity = $row->getEntity();
248
                    $resourceNode = $entity->getResourceNode();
249
250
                    if ($resourceNode->hasResourceFile()) {
251
                        $file = $resourceNode->getResourceFile();
252
253
                        return $file->getMimeType();
254
                    }
255
256
                    return $this->trans('Folder');
257
                }
258
            );
259
        }
260
261
        if ($grid->hasColumn('iid')) {
262
            $grid->setHiddenColumns(['iid']);
263
        }
264
265
        // Delete mass action.
266
        if ($this->isGranted(ResourceNodeVoter::DELETE, $this->getCourse())) {
267
            $deleteMassAction = new MassAction(
268
                'Delete',
269
                'ChamiloCoreBundle:Resource:deleteMass',
270
                true,
271
                $routeParams
272
            );
273
            $grid->addMassAction($deleteMassAction);
274
        }
275
276
        // Info action.
277
        $myRowAction = new RowAction(
278
            $this->trans('Info'),
279
            'chamilo_core_resource_info',
280
            false,
281
            '_self',
282
            [
283
                'class' => 'btn btn-secondary info_action',
284
                'icon' => 'fa-info-circle',
285
                'iframe' => false,
286
            ]
287
        );
288
289
        $setNodeParameters = function (RowAction $action, Row $row) use ($routeParams) {
290
            $id = $row->getEntity()->getResourceNode()->getId();
291
            $routeParams['id'] = $id;
292
            $action->setRouteParameters($routeParams);
293
            $attributes = $action->getAttributes();
294
            $attributes['data-action'] = $action->getRoute();
295
            $attributes['data-action-id'] = $action->getRoute().'_'.$id;
296
            $attributes['data-node-id'] = $id;
297
298
            $action->setAttributes($attributes);
299
300
            return $action;
301
        };
302
303
        $myRowAction->addManipulateRender($setNodeParameters);
304
        $grid->addRowAction($myRowAction);
305
306
        // Download action
307
        $myRowAction = new RowAction(
308
            $this->trans('Download'),
309
            'chamilo_core_resource_download',
310
            false,
311
            '_self',
312
            [
313
                'class' => 'btn btn-secondary download_action',
314
                'icon' => 'fa-download',
315
            ]
316
        );
317
318
        $setNodeParameters = function (RowAction $action, Row $row) use ($routeParams) {
319
            $id = $row->getEntity()->getResourceNode()->getId();
320
            $routeParams['id'] = $id;
321
322
            $action->setRouteParameters($routeParams);
323
            $attributes = $action->getAttributes();
324
            //$attributes['data-action'] = $action->getRoute();
325
            //$attributes['data-action-id'] = $action->getRoute().'_'.$id;
326
            //$attributes['data-node-id'] = $id;
327
            $action->setAttributes($attributes);
328
329
            return $action;
330
        };
331
332
        $myRowAction->addManipulateRender($setNodeParameters);
333
        $grid->addRowAction($myRowAction);
334
335
        if ($this->isGranted(ResourceNodeVoter::EDIT, $this->getCourse())) {
336
            // Enable/Disable
337
            $myRowAction = new RowAction(
338
                '',
339
                'chamilo_core_resource_change_visibility',
340
                false,
341
                '_self'
342
            );
343
344
            $setVisibleParameters = function (RowAction $action, Row $row) use ($routeParams) {
345
                /** @var AbstractResource $resource */
346
                $resource = $row->getEntity();
347
                $id = $resource->getResourceNode()->getId();
348
349
                $icon = 'fa-eye-slash';
350
                $link = $resource->getCourseSessionResourceLink($this->getCourse(), $this->getSession());
351
352
                if ($link === null) {
353
                    return null;
354
                }
355
                if ($link->getVisibility() === ResourceLink::VISIBILITY_PUBLISHED) {
356
                    $icon = 'fa-eye';
357
                }
358
                $routeParams['id'] = $id;
359
                $action->setRouteParameters($routeParams);
360
                $attributes = [
361
                    'class' => 'btn btn-secondary change_visibility',
362
                    'data-id' => $id,
363
                    'icon' => $icon,
364
                ];
365
                $action->setAttributes($attributes);
366
367
                return $action;
368
            };
369
370
            $myRowAction->addManipulateRender($setVisibleParameters);
371
            $grid->addRowAction($myRowAction);
372
373
            // Edit action.
374
            $myRowAction = new RowAction(
375
                $this->trans('Edit'),
376
                'chamilo_core_resource_edit',
377
                false,
378
                '_self',
379
                ['class' => 'btn btn-secondary', 'icon' => 'fa fa-pen']
380
            );
381
            $myRowAction->addManipulateRender($setNodeParameters);
382
            $grid->addRowAction($myRowAction);
383
384
            // More action.
385
            $myRowAction = new RowAction(
386
                $this->trans('More'),
387
                'chamilo_core_resource_preview',
388
                false,
389
                '_self',
390
                ['class' => 'btn btn-secondary edit_resource', 'icon' => 'fa fa-ellipsis-h']
391
            );
392
393
            $myRowAction->addManipulateRender($setNodeParameters);
394
            $grid->addRowAction($myRowAction);
395
396
            // Delete action.
397
            $myRowAction = new RowAction(
398
                $this->trans('Delete'),
399
                'chamilo_core_resource_delete',
400
                true,
401
                '_self',
402
                ['class' => 'btn btn-danger', 'data_hidden' => true]
403
            );
404
            $myRowAction->addManipulateRender($setNodeParameters);
405
            $grid->addRowAction($myRowAction);
406
        }
407
408
        /*$grid->addExport(new CSVExport($this->trans('CSV export'), 'export', ['course' => $courseIdentifier]));
409
        $grid->addExport(
410
            new ExcelExport(
411
                $this->trans('Excel export'),
412
                'export',
413
                ['course' => $courseIdentifier]
414
            )
415
        );*/
416
417
        return $grid;
418
    }
419
420
    /**
421
     * @Route("/{tool}/{type}/{id}/new_folder", methods={"GET", "POST"}, name="chamilo_core_resource_new_folder")
422
     */
423
    public function newFolderAction(Request $request): Response
424
    {
425
        $this->setBreadCrumb($request);
426
427
        return $this->createResource($request, 'folder');
428
    }
429
430
    /**
431
     * @Route("/{tool}/{type}/{id}/new", methods={"GET", "POST"}, name="chamilo_core_resource_new")
432
     */
433
    public function newAction(Request $request): Response
434
    {
435
        $this->setBreadCrumb($request);
436
437
        return $this->createResource($request, 'file');
438
    }
439
440
    /**
441
     * @Route("/{tool}/{type}/{id}/edit", methods={"GET", "POST"})
442
     */
443
    public function editAction(Request $request): Response
444
    {
445
        $tool = $request->get('tool');
446
        $type = $request->get('type');
447
        $resourceNodeId = $request->get('id');
448
449
        $this->setBreadCrumb($request);
450
        $repository = $this->getRepositoryFromRequest($request);
451
        /** @var AbstractResource $resource */
452
        $resource = $repository->getRepository()->findOneBy(['resourceNode' => $resourceNodeId]);
453
        $resourceNode = $resource->getResourceNode();
454
455
        $this->denyAccessUnlessGranted(
456
            ResourceNodeVoter::EDIT,
457
            $resourceNode,
458
            $this->trans('Unauthorised access to resource')
459
        );
460
461
        $resourceNodeParentId = $resourceNode->getId();
462
463
        $routeParams = $this->getResourceParams($request);
464
        $routeParams['id'] = $resourceNodeParentId;
465
466
        $form = $repository->getForm($this->container->get('form.factory'), $resource);
467
468
        if ($resourceNode->hasEditableContent()) {
469
            $form->add(
470
                'content',
471
                CKEditorType::class,
472
                [
473
                    'mapped' => false,
474
                    'config' => [
475
                        'filebrowserImageBrowseRoute' => 'resources_filemanager',
476
                        'filebrowserImageBrowseRouteParameters' => $routeParams,
477
                    ],
478
                ]
479
            );
480
            $content = $repository->getResourceNodeFileContent($resourceNode);
481
            $form->get('content')->setData($content);
482
        }
483
484
        $form->handleRequest($request);
485
486
        if ($form->isSubmitted() && $form->isValid()) {
487
            /** @var AbstractResource $newResource */
488
            $newResource = $form->getData();
489
490
            if ($form->has('content')) {
491
                $data = $form->get('content')->getData();
492
                $repository->updateResourceFileContent($newResource, $data);
493
            }
494
495
            //$newResource->setTitle($form->get('title')->getData()); // already set in $form->getData()
496
            $repository->updateNodeForResource($newResource);
497
498
            $this->addFlash('success', $this->trans('Updated'));
499
500
            if ($newResource->getResourceNode()->hasResourceFile()) {
501
                //$resourceNodeParentId = $newResource->getResourceNode()->getParent()->getId();
502
            }
503
504
            return $this->redirectToRoute('chamilo_core_resource_list', $routeParams);
505
        }
506
507
        return $this->render(
508
            '@ChamiloTheme/Resource/edit.html.twig',
509
            [
510
                'form' => $form->createView(),
511
                'parent' => $resourceNodeParentId,
512
            ]
513
        );
514
    }
515
516
    /**
517
     * Shows a resource information.
518
     *
519
     * @Route("/{tool}/{type}/{id}/info", methods={"GET"}, name="chamilo_core_resource_info")
520
     */
521
    public function infoAction(Request $request): Response
522
    {
523
        $this->setBreadCrumb($request);
524
        $nodeId = $request->get('id');
525
526
        $repository = $this->getRepositoryFromRequest($request);
527
528
        /** @var AbstractResource $resource */
529
        $resource = $repository->getRepository()->findOneBy(['resourceNode' => $nodeId]);
530
531
        if (null === $resource) {
532
            throw new NotFoundHttpException();
533
        }
534
535
        $resourceNode = $resource->getResourceNode();
536
537
        if (null === $resourceNode) {
538
            throw new NotFoundHttpException();
539
        }
540
541
        $this->denyAccessUnlessGranted(
542
            ResourceNodeVoter::VIEW,
543
            $resourceNode,
544
            $this->trans('Unauthorised access to resource')
545
        );
546
547
        $tool = $request->get('tool');
548
        $type = $request->get('type');
549
550
        $params = [
551
            'resource' => $resource,
552
            'tool' => $tool,
553
            'type' => $type,
554
        ];
555
556
        return $this->render('@ChamiloTheme/Resource/show.html.twig', $params);
557
    }
558
559
    /**
560
     * Preview a file. Mostly used when using a modal.
561
     *
562
     * @Route("/{tool}/{type}/{id}/preview", methods={"GET"}, name="chamilo_core_resource_preview")
563
     */
564
    public function previewAction(Request $request): Response
565
    {
566
        $this->setBreadCrumb($request);
567
        $nodeId = $request->get('id');
568
569
        $repository = $this->getRepositoryFromRequest($request);
570
571
        /** @var AbstractResource $resource */
572
        $resource = $repository->getRepository()->findOneBy(['resourceNode' => $nodeId]);
573
574
        if (null === $resource) {
575
            throw new NotFoundHttpException();
576
        }
577
578
        $resourceNode = $resource->getResourceNode();
579
580
        if (null === $resourceNode) {
581
            throw new NotFoundHttpException();
582
        }
583
584
        $this->denyAccessUnlessGranted(
585
            ResourceNodeVoter::VIEW,
586
            $resourceNode,
587
            $this->trans('Unauthorised access to resource')
588
        );
589
590
        $tool = $request->get('tool');
591
        $type = $request->get('type');
592
593
        $params = [
594
            'resource' => $resource,
595
            'tool' => $tool,
596
            'type' => $type,
597
        ];
598
599
        return $this->render('@ChamiloTheme/Resource/preview.html.twig', $params);
600
    }
601
602
    /**
603
     * @Route("/{tool}/{type}/{id}/change_visibility", name="chamilo_core_resource_change_visibility")
604
     */
605
    public function changeVisibilityAction(Request $request): Response
606
    {
607
        $id = $request->get('id');
608
609
        $repository = $this->getRepositoryFromRequest($request);
610
611
        /** @var AbstractResource $resource */
612
        $resource = $repository->getRepository()->findOneBy(['resourceNode' => $id]);
613
614
        if (null === $resource) {
615
            throw new NotFoundHttpException();
616
        }
617
618
        $resourceNode = $resource->getResourceNode();
619
620
        $this->denyAccessUnlessGranted(
621
            ResourceNodeVoter::EDIT,
622
            $resourceNode,
623
            $this->trans('Unauthorised access to resource')
624
        );
625
626
        /** @var ResourceLink $link */
627
        $link = $resource->getCourseSessionResourceLink($this->getCourse(), $this->getSession());
628
629
        $icon = 'fa-eye';
630
        // Use repository to change settings easily.
631
        if ($link && $link->getVisibility() === ResourceLink::VISIBILITY_PUBLISHED) {
632
            $repository->setVisibilityDraft($resource);
633
            $icon = 'fa-eye-slash';
634
        } else {
635
            $repository->setVisibilityPublished($resource);
636
        }
637
638
        $result = ['icon' => $icon];
639
640
        return new JsonResponse($result);
641
    }
642
643
    /**
644
     * @Route("/{tool}/{type}/{id}", name="chamilo_core_resource_delete")
645
     */
646
    public function deleteAction(Request $request): Response
647
    {
648
        $tool = $request->get('tool');
649
        $type = $request->get('type');
650
651
        $em = $this->getDoctrine()->getManager();
652
653
        $id = $request->get('id');
654
        $resourceNode = $this->getDoctrine()->getRepository('ChamiloCoreBundle:Resource\ResourceNode')->find($id);
655
        $parentId = $resourceNode->getParent()->getId();
656
657
        if (null === $resourceNode) {
658
            throw new NotFoundHttpException();
659
        }
660
661
        $this->denyAccessUnlessGranted(
662
            ResourceNodeVoter::DELETE,
663
            $resourceNode,
664
            $this->trans('Unauthorised access to resource')
665
        );
666
667
        $em->remove($resourceNode);
668
        $this->addFlash('success', $this->trans('Deleted'));
669
        $em->flush();
670
671
        $routeParams = $this->getResourceParams($request);
672
        $routeParams['id'] = $parentId;
673
674
        return $this->redirectToRoute(
675
            'chamilo_core_resource_list',
676
            $routeParams
677
        );
678
    }
679
680
    /**
681
     * @Route("/{tool}/{type}/{id}", methods={"DELETE"}, name="chamilo_core_resource_delete_mass")
682
     */
683
    public function deleteMassAction($primaryKeys, $allPrimaryKeys, Request $request): Response
684
    {
685
        $tool = $request->get('tool');
686
        $type = $request->get('type');
687
        $em = $this->getDoctrine()->getManager();
688
        $repo = $this->getRepositoryFromRequest($request);
689
690
        $parentId = 0;
691
        foreach ($primaryKeys as $id) {
692
            $resource = $repo->find($id);
693
            $resourceNode = $resource->getResourceNode();
694
695
            if (null === $resourceNode) {
696
                continue;
697
            }
698
699
            $this->denyAccessUnlessGranted(
700
                ResourceNodeVoter::DELETE,
701
                $resourceNode,
702
                $this->trans('Unauthorised access to resource')
703
            );
704
705
            $parentId = $resourceNode->getParent()->getId();
706
            $em->remove($resource);
707
        }
708
709
        $this->addFlash('success', $this->trans('Deleted'));
710
        $em->flush();
711
712
        $routeParams = $this->getResourceParams($request);
713
        $routeParams['id'] = $parentId;
714
715
        return $this->redirectToRoute('chamilo_core_resource_list', $routeParams);
716
    }
717
718
    /**
719
     * Shows the associated resource file.
720
     *
721
     * @Route("/{tool}/{type}/{id}/view", methods={"GET"}, name="chamilo_core_resource_view")
722
     */
723
    public function viewAction(Request $request, Glide $glide): Response
724
    {
725
        $id = $request->get('id');
726
        $filter = $request->get('filter');
727
        $mode = $request->get('mode');
728
        $em = $this->getDoctrine();
729
        $resourceNode = $em->getRepository('ChamiloCoreBundle:Resource\ResourceNode')->find($id);
730
731
        if ($resourceNode === null) {
732
            throw new FileNotFoundException('Resource not found');
733
        }
734
735
        return $this->showFile($request, $resourceNode, $mode, $glide, $filter);
736
    }
737
738
    /**
739
     * Gets a document when calling route resources_document_get_file
740
     * @deprecated
741
     *
742
     * @throws \League\Flysystem\FileNotFoundException
743
     */
744
    public function getDocumentAction(Request $request, Glide $glide): Response
745
    {
746
        /*$file = $request->get('file');
747
        $mode = $request->get('mode');
748
749
        // see list of filters in config/services.yaml
750
        $filter = $request->get('filter');
751
        $mode = !empty($mode) ? $mode : 'show';
752
753
        $repository = $this->getRepository('document', 'files');
754
        $nodeRepository = $repository->getResourceNodeRepository();
755
756
        $title = basename($file);
757
        // @todo improve criteria to avoid giving the wrong file.
758
        $criteria = ['slug' => $title];
759
760
        $resourceNode = $nodeRepository->findOneBy($criteria);
761
762
        if (null === $resourceNode) {
763
            throw new NotFoundHttpException();
764
        }
765
766
        return $this->showFile($request, $resourceNode, $mode, $glide,$filter);*/
767
    }
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...
768
769
    /**
770
     * @Route("/{tool}/{type}/{id}/download", methods={"GET"}, name="chamilo_core_resource_download")
771
     */
772
    public function downloadAction(Request $request)
773
    {
774
        $resourceNodeId = (int) $request->get('id');
775
        $courseNode = $this->getCourse()->getResourceNode();
776
777
        $repo = $this->getRepositoryFromRequest($request);
778
779
        if (empty($resourceNodeId)) {
780
            $resourceNode = $courseNode;
781
        } else {
782
            $resourceNode = $repo->getResourceNodeRepository()->find($resourceNodeId);
783
        }
784
785
        $type = $repo->getResourceType();
786
787
        if (null === $resourceNode) {
788
            throw new NotFoundHttpException();
789
        }
790
791
        $this->denyAccessUnlessGranted(
792
            ResourceNodeVoter::VIEW,
793
            $resourceNode,
794
            $this->trans('Unauthorised access to resource')
795
        );
796
797
        // If resource node has a file just download it. Don't download the children.
798
        if ($resourceNode->hasResourceFile()) {
799
            // Redirect to download single file.
800
            return $this->showFile($request, $resourceNode, 'download');
801
        }
802
803
        $zipName = $resourceNode->getSlug().'.zip';
804
        $rootNodePath = $resourceNode->getPathForDisplay();
805
806
        $resourceNodeRepo = $repo->getResourceNodeRepository();
807
808
        $criteria = Criteria::create()
809
            ->where(Criteria::expr()->neq('resourceFile', null)) // must have a file
810
           // ->andWhere(Criteria::expr()->eq('resourceType', $type))
811
        ;
812
813
        /** @var ArrayCollection|ResourceNode[] $children */
814
        /** @var QueryBuilder $children */
815
        $qb = $resourceNodeRepo->getChildrenQueryBuilder($resourceNode);
816
        $qb->addCriteria($criteria);
817
        $children = $qb->getQuery()->getResult();
818
819
        $response = new StreamedResponse(function () use ($rootNodePath, $zipName, $children, $repo) {
820
            // Define suitable options for ZipStream Archive.
821
            $options = new Archive();
822
            $options->setContentType('application/octet-stream');
823
            //initialise zipstream with output zip filename and options.
824
            $zip = new ZipStream($zipName, $options);
825
826
            /** @var ResourceNode $node */
827
            foreach ($children as $node) {
828
                $resourceFile = $node->getResourceFile();
829
                $systemName = $resourceFile->getFile()->getPathname();
830
                $stream = $repo->getResourceNodeFileStream($node);
831
                //error_log($node->getPathForDisplay());
832
                $fileToDisplay = str_replace($rootNodePath, '', $node->getPathForDisplay());
833
                $zip->addFileFromStream($fileToDisplay, $stream);
834
            }
835
            $zip->finish();
836
        });
837
838
        $disposition = $response->headers->makeDisposition(
839
            ResponseHeaderBag::DISPOSITION_ATTACHMENT,
840
            Transliterator::transliterate($zipName)
841
        );
842
        $response->headers->set('Content-Disposition', $disposition);
843
        $response->headers->set('Content-Type', 'application/octet-stream');
844
845
        return $response;
846
    }
847
848
    /**
849
     * Upload form.
850
     *
851
     * @Route("/{tool}/{type}/{id}/upload", name="chamilo_core_resource_upload", methods={"GET", "POST"},
852
     *                                      options={"expose"=true})
853
     */
854
    public function uploadAction(Request $request, $tool, $type, $id): Response
855
    {
856
        $repository = $this->getRepositoryFromRequest($request);
857
        $resourceNode = $repository->getResourceNodeRepository()->find($id);
858
859
        $this->denyAccessUnlessGranted(
860
            ResourceNodeVoter::EDIT,
861
            $resourceNode,
862
            $this->trans('Unauthorised access to resource')
863
        );
864
865
        $this->setBreadCrumb($request);
866
867
        $routeParams = $this->getResourceParams($request);
868
        $routeParams['tool'] = $tool;
869
        $routeParams['type'] = $type;
870
        $routeParams['id'] = $id;
871
872
        return $this->render(
873
            '@ChamiloTheme/Resource/upload.html.twig',
874
            $routeParams
875
        );
876
    }
877
878
    public function setBreadCrumb(Request $request)
879
    {
880
        $tool = $request->get('tool');
881
        $type = $request->get('type');
882
        $resourceNodeId = $request->get('id');
883
884
        $routeParams = $this->getResourceParams($request);
885
886
        if (!empty($resourceNodeId)) {
887
            $breadcrumb = $this->getBreadCrumb();
888
889
            // Root tool link
890
            $breadcrumb->addChild(
891
                $this->trans($tool),
892
                [
893
                    'uri' => $this->generateUrl(
894
                        'chamilo_core_resource_index',
895
                        $routeParams
896
                    ),
897
                ]
898
            );
899
900
            $repo = $this->getRepositoryFromRequest($request);
901
902
            /** @var AbstractResource $parent */
903
            $originalResource = $repo->findOneBy(['resourceNode' => $resourceNodeId]);
904
            if ($originalResource === null) {
905
                return;
906
            }
907
            $parent = $originalParent = $originalResource->getResourceNode();
908
909
            $parentList = [];
910
            while ($parent !== null) {
911
                if ($type !== $parent->getResourceType()->getName()) {
912
                    break;
913
                }
914
                $parent = $parent->getParent();
915
                if ($parent) {
916
                    $resource = $repo->findOneBy(['resourceNode' => $parent->getId()]);
917
                    if ($resource) {
918
                        $parentList[] = $resource;
919
                    }
920
                }
921
            }
922
923
            $parentList = array_reverse($parentList);
924
            /** @var AbstractResource $item */
925
            foreach ($parentList as $item) {
926
                $params = $routeParams;
927
                $params['id'] = $item->getResourceNode()->getId();
928
                $breadcrumb->addChild(
929
                    $item->getResourceName(),
930
                    [
931
                        'uri' => $this->generateUrl(
932
                            'chamilo_core_resource_list',
933
                            $params
934
                        ),
935
                    ]
936
                );
937
            }
938
939
            $params = $routeParams;
940
            $params['id'] = $originalParent->getId();
941
942
            $breadcrumb->addChild(
943
                $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

943
                $originalResource->/** @scrutinizer ignore-call */ 
944
                                   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...
944
                [
945
                    'uri' => $this->generateUrl(
946
                        'chamilo_core_resource_list',
947
                        $params
948
                    ),
949
                ]
950
            );
951
        }
952
    }
953
954
    /**
955
     * @param Request      $request
956
     * @param ResourceNode $resourceNode
957
     * @param string       $mode
958
     * @param Glide|null   $glide
959
     * @param string       $filter
960
     *
961
     * @return mixed|StreamedResponse
962
     */
963
    private function showFile(Request $request, ResourceNode $resourceNode, $mode = 'show', Glide $glide = null, $filter = '')
964
    {
965
        $this->denyAccessUnlessGranted(
966
            ResourceNodeVoter::VIEW,
967
            $resourceNode,
968
            $this->trans('Unauthorised access to resource')
969
        );
970
971
        $repo = $this->getRepositoryFromRequest($request);
972
        $resourceFile = $resourceNode->getResourceFile();
973
974
        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...
975
            throw new NotFoundHttpException($this->trans('File not found for resource'));
976
        }
977
978
        //$fileName = $resourceFile->getOriginalName();
979
        $fileName = $resourceNode->getSlug();
980
        $filePath = $resourceFile->getFile()->getPathname();
981
        $mimeType = $resourceFile->getMimeType();
982
983
        switch ($mode) {
984
            case 'download':
985
                $forceDownload = true;
986
                break;
987
            case 'show':
988
            default:
989
                $forceDownload = false;
990
                // If it's an image then send it to Glide.
991
                if (strpos($mimeType, 'image') !== false) {
992
                    $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

992
                    /** @scrutinizer ignore-call */ 
993
                    $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...
993
                    $params = $request->query->all();
994
995
                    // The filter overwrites the params from get
996
                    if (!empty($filter)) {
997
                        $params = $glide->getFilters()[$filter] ?? [];
998
                    }
999
1000
                    // The image was cropped manually by the user, so we force to render this version,
1001
                    // no matter other crop parameters.
1002
                    $crop = $resourceFile->getCrop();
1003
                    if (!empty($crop)) {
1004
                        $params['crop'] = $crop;
1005
                    }
1006
1007
                    return $server->getImageResponse($filePath, $params);
1008
                }
1009
                break;
1010
        }
1011
1012
        $stream = $repo->getResourceNodeFileStream($resourceNode);
1013
1014
        //$stream = $this->fs->readStream($resourceNode);
1015
        $response = new StreamedResponse(function () use ($stream): void {
1016
            stream_copy_to_stream($stream, fopen('php://output', 'wb'));
0 ignored issues
show
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

1016
            stream_copy_to_stream($stream, /** @scrutinizer ignore-type */ fopen('php://output', 'wb'));
Loading history...
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

1016
            stream_copy_to_stream(/** @scrutinizer ignore-type */ $stream, fopen('php://output', 'wb'));
Loading history...
1017
        });
1018
        $disposition = $response->headers->makeDisposition(
1019
            $forceDownload ? ResponseHeaderBag::DISPOSITION_ATTACHMENT : ResponseHeaderBag::DISPOSITION_INLINE,
1020
            $fileName
1021
            //Transliterator::transliterate($fileName)
1022
        );
1023
        $response->headers->set('Content-Disposition', $disposition);
1024
        $response->headers->set('Content-Type', $mimeType ?: 'application/octet-stream');
1025
1026
        return $response;
1027
    }
1028
1029
    /**
1030
     * @param string $fileType
1031
     *
1032
     * @return RedirectResponse|Response
1033
     */
1034
    private function createResource(Request $request, $fileType = 'file')
1035
    {
1036
        $resourceNodeParentId = $request->get('id');
1037
1038
        $repository = $this->getRepositoryFromRequest($request);
1039
1040
        $course = $this->getCourse();
1041
        $session = $this->getSession();
1042
        // Default parent node is course.
1043
        $parentNode = $this->getParentResourceNode($request);
1044
1045
        $this->denyAccessUnlessGranted(
1046
            ResourceNodeVoter::CREATE,
1047
            $parentNode,
1048
            $this->trans('Unauthorised access to resource')
1049
        );
1050
1051
        $form = $repository->getForm($this->container->get('form.factory'));
1052
1053
        $courseParams = $this->getResourceParams($request);
1054
1055
        if ($fileType === 'file') {
1056
            $params = $courseParams;
1057
            $params['id'] = $resourceNodeParentId;
1058
1059
            $form->add(
1060
                'content',
1061
                CKEditorType::class,
1062
                [
1063
                    'mapped' => false,
1064
                    'config' => [
1065
                        'filebrowserImageBrowseRoute' => 'resources_filemanager',
1066
                        'filebrowserImageBrowseRouteParameters' => $params,
1067
                    ],
1068
                ]
1069
            );
1070
        }
1071
1072
        $form->handleRequest($request);
1073
        if ($form->isSubmitted() && $form->isValid()) {
1074
            $em = $this->getDoctrine()->getManager();
1075
1076
            /** @var AbstractResource $newResource */
1077
            $newResource = $repository->saveResource($form, $course, $session, $fileType);
1078
1079
            $file = null;
1080
            if ($fileType === 'file') {
1081
                $content = $form->get('content')->getViewData();
1082
                $newResource->setTitle($newResource->getTitle().'.html');
0 ignored issues
show
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

1082
                $newResource->setTitle($newResource->/** @scrutinizer ignore-call */ getTitle().'.html');
Loading history...
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

1082
                $newResource->/** @scrutinizer ignore-call */ 
1083
                              setTitle($newResource->getTitle().'.html');
Loading history...
1083
                $fileName = $newResource->getTitle();
1084
1085
                $handle = tmpfile();
1086
                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

1086
                fwrite(/** @scrutinizer ignore-type */ $handle, $content);
Loading history...
1087
                $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

1087
                $meta = stream_get_meta_data(/** @scrutinizer ignore-type */ $handle);
Loading history...
1088
                $file = new UploadedFile($meta['uri'], $fileName, null, null, true);
1089
                $em->persist($newResource);
1090
            }
1091
1092
            $resourceNode = $repository->createNodeForResource($newResource, $this->getUser(), $parentNode, $file);
1093
            $em->persist($resourceNode);
1094
1095
            $repository->addResourceNodeToCourse(
1096
                $resourceNode,
1097
                ResourceLink::VISIBILITY_PUBLISHED,
1098
                $course,
1099
                $session,
1100
                null
1101
            );
1102
1103
            $em->flush();
1104
1105
            // Loops all sharing options
1106
            /*foreach ($shareList as $share) {
1107
                $idList = [];
1108
                if (isset($share['search'])) {
1109
                    $idList = explode(',', $share['search']);
1110
                }
1111
1112
                $resourceRight = null;
1113
                if (isset($share['mask'])) {
1114
                    $resourceRight = new ResourceRight();
1115
                    $resourceRight
1116
                        ->setMask($share['mask'])
1117
                        ->setRole($share['role'])
1118
                    ;
1119
                }
1120
1121
                // Build links
1122
                switch ($share['sharing']) {
1123
                    case 'everyone':
1124
                        $repository->addResourceToEveryone(
1125
                            $resourceNode,
1126
                            $resourceRight
1127
                        );
1128
                        break;
1129
                    case 'course':
1130
                        $repository->addResourceToCourse(
1131
                            $resourceNode,
1132
                            $course,
1133
                            $resourceRight
1134
                        );
1135
                        break;
1136
                    case 'session':
1137
                        $repository->addResourceToSession(
1138
                            $resourceNode,
1139
                            $course,
1140
                            $session,
1141
                            $resourceRight
1142
                        );
1143
                        break;
1144
                    case 'user':
1145
                        // Only for me
1146
                        if (isset($share['only_me'])) {
1147
                            $repository->addResourceOnlyToMe($resourceNode);
1148
                        } else {
1149
                            // To other users
1150
                            $repository->addResourceToUserList($resourceNode, $idList);
1151
                        }
1152
                        break;
1153
                    case 'group':
1154
                        // @todo
1155
                        break;
1156
                }*/
1157
            //}
1158
            $em->flush();
1159
            $this->addFlash('success', $this->trans('Saved'));
1160
1161
            $params = $this->getResourceParams($request);
1162
            $params['id'] = $resourceNodeParentId;
1163
1164
            return $this->redirectToRoute(
1165
                'chamilo_core_resource_list',
1166
                $params
1167
            );
1168
        }
1169
1170
        switch ($fileType) {
1171
            case 'folder':
1172
                $template = '@ChamiloTheme/Resource/new_folder.html.twig';
1173
                break;
1174
            case 'file':
1175
                $template = '@ChamiloTheme/Resource/new.html.twig';
1176
                break;
1177
        }
1178
1179
        return $this->render(
1180
            $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...
1181
            [
1182
                'form' => $form->createView(),
1183
                'parent' => $resourceNodeParentId,
1184
                'file_type' => $fileType,
1185
            ]
1186
        );
1187
    }
1188
}
1189