Completed
Push — master ( 667dde...0fb228 )
by Julito
13:48
created

ResourceController::deleteMassAction()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 35
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 3
eloc 23
nc 3
nop 3
dl 0
loc 35
rs 9.552
c 1
b 0
f 1
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 Doctrine\Common\Collections\ArrayCollection;
21
use Doctrine\Common\Collections\Criteria;
22
use Doctrine\ORM\QueryBuilder;
23
use FOS\CKEditorBundle\Form\Type\CKEditorType;
24
use League\Flysystem\Filesystem;
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
 *
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
        $grid = $this->getGrid($request, $grid);
64
65
        $breadcrumb = $this->getBreadCrumb();
66
        $breadcrumb->addChild(
67
            $this->trans($tool),
68
            [
69
                'uri' => '#',
70
            ]
71
        );
72
73
        // The base resource node is the course.
74
        $id = $this->getCourse()->getResourceNode()->getId();
75
76
        return $grid->getGridResponse(
77
            '@ChamiloTheme/Resource/index.html.twig',
78
            ['tool' => $tool, 'type' => $type, 'id' => $id]
79
        );
80
    }
81
82
    /**
83
     * @param int $resourceNodeId
84
     *
85
     * @return Grid
86
     */
87
    public function getGrid(Request $request, Grid $grid, $resourceNodeId = 0)
88
    {
89
        $tool = $request->get('tool');
90
        $type = $request->get('type');
91
        $id = (int) $request->get('id');
92
93
        $repository = $this->getRepositoryFromRequest($request);
94
        $class = $repository->getRepository()->getClassName();
95
96
        // The group 'resource' is set in the @GRID\Source annotation in the entity.
97
        $source = new Entity($class, 'resource');
98
99
        $course = $this->getCourse();
100
        $session = $this->getSession();
101
102
        $parent = $course->getResourceNode();
103
        if (!empty($resourceNodeId)) {
104
            $parent = $repository->getResourceNodeRepository()->find($resourceNodeId);
105
        }
106
107
        $qb = $repository->getResourcesByCourse($course, $session, null, $parent);
108
109
        // 3. Set QueryBuilder to the source.
110
        $source->initQueryBuilder($qb);
111
        $grid->setSource($source);
112
113
        $courseParams = $this->getCourseParams();
114
115
        $params = $courseParams;
116
        $params['tool'] = $tool;
117
        $params['type'] = $type;
118
        $params['id'] = $id;
119
120
        $grid->setRouteUrl($this->generateUrl('chamilo_core_resource_list', $params));
121
122
        //$grid->hideFilters();
123
        //$grid->setLimits(20);
124
        //$grid->isReadyForRedirect();
125
        //$grid->setMaxResults(1);
126
        //$grid->setLimits(2);
127
128
        //$grid->setColumns($columns);
129
130
        $routeParams = $courseParams;
131
        $routeParams['tool'] = $tool;
132
        $routeParams['type'] = $type;
133
        $routeParams['id'] = null;
134
135
        $titleColumn = $repository->getTitleColumn($grid);
136
        $titleColumn->setSafe(false); // allows links in the title
137
138
        // Title link.
139
        $titleColumn->setTitle($this->trans('Name'));
140
141
        //$repository->formatGrid();
142
143
        /*if ($grid->hasColumn('filetype')) {
144
            $grid->getColumn('filetype')->setTitle($this->trans('Type'));
145
        }*/
146
147
        $titleColumn->manipulateRenderCell(
148
            function ($value, Row $row, $router) use ($routeParams) {
149
                /** @var Router $router */
150
                /** @var AbstractResource $entity */
151
                $entity = $row->getEntity();
152
                $resourceNode = $entity->getResourceNode();
153
                $id = $resourceNode->getId();
154
155
                $myParams = $routeParams;
156
                $myParams['id'] = $id;
157
                unset($myParams[0]);
158
159
                $icon = $resourceNode->getIcon().' &nbsp;';
160
                if ($resourceNode->hasResourceFile()) {
161
                    /*$url = $router->generate(
162
                        'chamilo_core_resource_show',
163
                        $myParams
164
                    );*/
165
                    if ($resourceNode->isResourceFileAnImage()) {
166
                        $url = $router->generate(
167
                            'chamilo_core_resource_view',
168
                            $myParams
169
                        );
170
171
                        return $icon.'<a data-fancybox="gallery" href="'.$url.'">'.$value.'</a>';
172
                    }
173
174
                    if ($resourceNode->isResourceFileAVideo()) {
175
                        $url = $router->generate(
176
                            'chamilo_core_resource_view',
177
                            $myParams
178
                        );
179
180
                        return '
181
                        <video width="640" height="320" controls id="video'.$id.'" controls preload="metadata" style="display:none;">
182
                            <source src="'.$url.'" type="video/mp4">
183
                            Your browser doesn\'t support HTML5 video tag.
184
                        </video>
185
                        '.$icon.' <a data-fancybox="gallery"  data-width="640" data-height="360" href="#video'.$id.'">'.$value.'</a>';
186
                    }
187
188
                    $url = $router->generate(
189
                        'chamilo_core_resource_preview',
190
                        $myParams
191
                    );
192
193
                    return $icon.'<a data-fancybox="gallery" data-type="iframe" data-src="'.$url.'" href="javascript:;" >'.$value.'</a>';
194
                } else {
195
                    $url = $router->generate(
196
                        'chamilo_core_resource_list',
197
                        $myParams
198
                    );
199
200
                    return $icon.'<a href="'.$url.'">'.$value.'</a>';
201
                }
202
            }
203
        );
204
205
        if ($grid->hasColumn('filetype')) {
206
            $grid->getColumn('filetype')->manipulateRenderCell(
207
                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

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

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
831
832
        $response = new StreamedResponse(function () use ($rootNodePath, $zipName, $children, $fileSystem) {
0 ignored issues
show
Unused Code introduced by
$response = new Symfony\...ion(...) { /* ... */ }) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
833
            // Define suitable options for ZipStream Archive.
834
            $options = new Archive();
835
            $options->setContentType('application/octet-stream');
836
            //initialise zipstream with output zip filename and options.
837
            $zip = new ZipStream($zipName, $options);
838
839
            /** @var ResourceNode $node */
840
            foreach ($children as $node) {
841
                $resourceFile = $node->getResourceFile();
842
                $systemName = $resourceFile->getFile()->getPathname();
843
                $stream = $fileSystem->readStream($systemName);
844
                //error_log($node->getPathForDisplay());
845
                $fileToDisplay = str_replace($rootNodePath, '', $node->getPathForDisplay());
846
                $zip->addFileFromStream($fileToDisplay, $stream);
847
            }
848
            //$data = $repo->getDocumentContent($not_deleted_file['id']);
849
            //$zip->addFile($not_deleted_file['path'], $data);
850
            $zip->finish();
851
        });
852
853
        $disposition = $response->headers->makeDisposition(
854
            ResponseHeaderBag::DISPOSITION_ATTACHMENT,
855
            Transliterator::transliterate($zipName)
856
        );
857
        $response->headers->set('Content-Disposition', $disposition);
858
        $response->headers->set('Content-Type', 'application/octet-stream');
859
860
        return $response;
861
    }
862
863
    /**
864
     * Upload form.
865
     *
866
     * @Route("/{tool}/{type}/{id}/upload", name="chamilo_core_resource_upload", methods={"GET", "POST"},
867
     *                                      options={"expose"=true})
868
     */
869
    public function uploadAction(Request $request, $tool, $type, $id): Response
870
    {
871
        $repository = $this->getRepositoryFromRequest($request);
872
        $resourceNode = $repository->getResourceNodeRepository()->find($id);
873
874
        $this->denyAccessUnlessGranted(
875
            ResourceNodeVoter::EDIT,
876
            $resourceNode,
877
            $this->trans('Unauthorised access to resource')
878
        );
879
880
        $this->setBreadCrumb($request);
881
882
        $routeParams = $this->getCourseParams();
883
        $routeParams['tool'] = $tool;
884
        $routeParams['type'] = $type;
885
        $routeParams['id'] = $id;
886
887
        return $this->render(
888
            '@ChamiloTheme/Resource/upload.html.twig',
889
            $routeParams
890
        );
891
    }
892
893
    public function setBreadCrumb(Request $request)
894
    {
895
        $tool = $request->get('tool');
896
        $type = $request->get('type');
897
        $resourceNodeId = $request->get('id');
898
899
        $routeParams = $this->getCourseParams();
900
        $routeParams['tool'] = $tool;
901
        $routeParams['type'] = $type;
902
903
        if (!empty($resourceNodeId)) {
904
            $breadcrumb = $this->getBreadCrumb();
905
906
            // Root tool link
907
            $breadcrumb->addChild(
908
                $this->trans($tool),
909
                [
910
                    'uri' => $this->generateUrl(
911
                        'chamilo_core_resource_index',
912
                        $routeParams
913
                    ),
914
                ]
915
            );
916
917
            $repo = $this->getRepositoryFromRequest($request);
918
919
            /** @var AbstractResource $parent */
920
            $originalResource = $repo->findOneBy(['resourceNode' => $resourceNodeId]);
921
            if ($originalResource === null) {
922
                return;
923
            }
924
            $parent = $originalParent = $originalResource->getResourceNode();
925
926
            $parentList = [];
927
            while ($parent !== null) {
928
                if ($type !== $parent->getResourceType()->getName()) {
929
                    break;
930
                }
931
                $parent = $parent->getParent();
932
                if ($parent) {
933
                    $resource = $repo->findOneBy(['resourceNode' => $parent->getId()]);
934
                    if ($resource) {
935
                        $parentList[] = $resource;
936
                    }
937
                }
938
            }
939
940
            $parentList = array_reverse($parentList);
941
            /** @var AbstractResource $item */
942
            foreach ($parentList as $item) {
943
                $params = $routeParams;
944
                $params['id'] = $item->getResourceNode()->getId();
945
                $breadcrumb->addChild(
946
                    $item->getResourceName(),
947
                    [
948
                        'uri' => $this->generateUrl(
949
                            'chamilo_core_resource_list',
950
                            $params
951
                        ),
952
                    ]
953
                );
954
            }
955
956
            $params = $routeParams;
957
            $params['id'] = $originalParent->getId();
958
959
            $breadcrumb->addChild(
960
                $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

960
                $originalResource->/** @scrutinizer ignore-call */ 
961
                                   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...
961
                [
962
                    'uri' => $this->generateUrl(
963
                        'chamilo_core_resource_list',
964
                        $params
965
                    ),
966
                ]
967
            );
968
        }
969
    }
970
971
    /**
972
     * @param string $mode   show or download
973
     * @param string $filter
974
     *
975
     * @return mixed|StreamedResponse
976
     */
977
    private function showFile(Request $request, ResourceNode $resourceNode, $mode = 'show', Glide $glide = null, $filter = '')
978
    {
979
        $this->denyAccessUnlessGranted(
980
            ResourceNodeVoter::VIEW,
981
            $resourceNode,
982
            $this->trans('Unauthorised access to resource')
983
        );
984
        $resourceFile = $resourceNode->getResourceFile();
985
986
        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...
987
            throw new NotFoundHttpException();
988
        }
989
990
        //$fileName = $resourceFile->getOriginalName();
991
        $fileName = $resourceNode->getSlug();
992
        $filePath = $resourceFile->getFile()->getPathname();
993
        $mimeType = $resourceFile->getMimeType();
994
995
        switch ($mode) {
996
            case 'download':
997
                $forceDownload = true;
998
                break;
999
            case 'show':
1000
            default:
1001
                $forceDownload = false;
1002
                // If it's an image then send it to Glide.
1003
                if (strpos($mimeType, 'image') !== false) {
1004
                    $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

1004
                    /** @scrutinizer ignore-call */ 
1005
                    $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...
1005
                    $params = $request->query->all();
1006
1007
                    // The filter overwrites the params from get
1008
                    if (!empty($filter)) {
1009
                        $params = $glide->getFilters()[$filter] ?? [];
1010
                    }
1011
1012
                    // The image was cropped manually by the user, so we force to render this version,
1013
                    // no matter other crop parameters.
1014
                    $crop = $resourceFile->getCrop();
1015
                    if (!empty($crop)) {
1016
                        $params['crop'] = $crop;
1017
                    }
1018
1019
                    return $server->getImageResponse($filePath, $params);
1020
                }
1021
                break;
1022
        }
1023
1024
        $stream = $this->fs->readStream($filePath);
1025
        $response = new StreamedResponse(function () use ($stream): void {
1026
            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

1026
            stream_copy_to_stream($stream, /** @scrutinizer ignore-type */ fopen('php://output', 'wb'));
Loading history...
1027
        });
1028
        $disposition = $response->headers->makeDisposition(
1029
            $forceDownload ? ResponseHeaderBag::DISPOSITION_ATTACHMENT : ResponseHeaderBag::DISPOSITION_INLINE,
1030
            $fileName
1031
            //Transliterator::transliterate($fileName)
1032
        );
1033
        $response->headers->set('Content-Disposition', $disposition);
1034
        $response->headers->set('Content-Type', $mimeType ?: 'application/octet-stream');
1035
1036
        return $response;
1037
    }
1038
1039
    /**
1040
     * @param string $fileType
1041
     *
1042
     * @return RedirectResponse|Response
1043
     */
1044
    private function createResource(Request $request, $fileType = 'file')
1045
    {
1046
        $tool = $request->get('tool');
1047
        $type = $request->get('type');
1048
        $resourceNodeParentId = $request->get('id');
1049
1050
        $repository = $this->getRepositoryFromRequest($request);
1051
        $form = $repository->getForm($this->container->get('form.factory'));
1052
1053
        $courseParams = $this->getCourseParams();
1054
1055
        if ($fileType === 'file') {
1056
            $params = $courseParams;
1057
            $params['tool'] = $tool;
1058
            $params['type'] = $type;
1059
            $params['id'] = $resourceNodeParentId;
1060
1061
            $form->add(
1062
                'content',
1063
                CKEditorType::class,
1064
                [
1065
                    'mapped' => false,
1066
                    'config' => [
1067
                        'filebrowserImageBrowseRoute' => 'resources_filemanager',
1068
                        'filebrowserImageBrowseRouteParameters' => $params,
1069
                    ],
1070
                ]
1071
            );
1072
        }
1073
1074
        $course = $this->getCourse();
1075
        $session = $this->getSession();
1076
        // Default parent node is course.
1077
        $parentNode = $course->getResourceNode();
1078
        if (!empty($resourceNodeParentId)) {
1079
            // Get parent node.
1080
            $parentNode = $repository->getResourceNodeRepository()->find($resourceNodeParentId);
1081
        }
1082
1083
        $form->handleRequest($request);
1084
        if ($form->isSubmitted() && $form->isValid()) {
1085
            $em = $this->getDoctrine()->getManager();
1086
1087
            /** @var AbstractResource $newResource */
1088
            $newResource = $repository->saveResource($form, $course, $session, $fileType);
1089
1090
            $file = null;
1091
            if ($fileType === 'file') {
1092
                $content = $form->get('content')->getViewData();
1093
                $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

1093
                $newResource->/** @scrutinizer ignore-call */ 
1094
                              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

1093
                $newResource->setTitle($newResource->/** @scrutinizer ignore-call */ getTitle().'.html');
Loading history...
1094
                $fileName = $newResource->getTitle();
1095
1096
                $handle = tmpfile();
1097
                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

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

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