Passed
Push — master ( e72130...d886e7 )
by Julito
16:11
created

ResourceRepository::getResourcesByCourseOnly()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 42
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 25
nc 8
nop 2
dl 0
loc 42
rs 9.52
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Repository;
8
9
use Chamilo\CoreBundle\Component\Resource\Settings;
10
use Chamilo\CoreBundle\Component\Resource\Template;
11
use Chamilo\CoreBundle\Entity\AbstractResource;
12
use Chamilo\CoreBundle\Entity\Course;
13
use Chamilo\CoreBundle\Entity\ResourceFile;
14
use Chamilo\CoreBundle\Entity\ResourceInterface;
15
use Chamilo\CoreBundle\Entity\ResourceLink;
16
use Chamilo\CoreBundle\Entity\ResourceNode;
17
use Chamilo\CoreBundle\Entity\ResourceRight;
18
use Chamilo\CoreBundle\Entity\ResourceType;
19
use Chamilo\CoreBundle\Entity\Session;
20
use Chamilo\CoreBundle\Entity\User;
21
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
22
use Chamilo\CoreBundle\ToolChain;
23
use Chamilo\CourseBundle\Entity\CDocument;
24
use Chamilo\CourseBundle\Entity\CGroup;
25
use Cocur\Slugify\SlugifyInterface;
26
use DateTime;
27
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
28
use Doctrine\DBAL\Types\Types;
29
use Doctrine\ORM\EntityManager;
30
use Doctrine\ORM\EntityRepository;
31
use Doctrine\ORM\QueryBuilder;
32
use Exception;
33
use League\Flysystem\FilesystemInterface;
34
use LogicException;
35
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
36
use Symfony\Component\Form\FormFactory;
37
use Symfony\Component\Form\FormInterface;
38
use Symfony\Component\HttpFoundation\File\UploadedFile;
39
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
40
use Symfony\Component\Routing\RouterInterface;
41
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
42
use Throwable;
43
44
/**
45
 * Class ResourceRepository.
46
 * Extends EntityRepository is needed to process settings.
47
 */
48
abstract class ResourceRepository extends ServiceEntityRepository
49
{
50
    protected EntityRepository $repository;
51
52
    protected FilesystemInterface $fs;
53
54
    protected EntityManager $entityManager;
55
56
    protected ?RouterInterface $router = null;
57
58
    protected ?ResourceNodeRepository $resourceNodeRepository = null;
59
60
    protected ?AuthorizationCheckerInterface $authorizationChecker = null;
61
62
    protected ?SlugifyInterface $slugify = null;
63
64
    protected ?ToolChain $toolChain = null;
65
66
    /**
67
     * The entity class FQN.
68
     */
69
    protected string $className;
70
71
    protected Settings $settings;
72
    protected Template $templates;
73
    protected ?ResourceType $resourceType = null;
74
75
    /*public function __construct(
76
        AuthorizationCheckerInterface $authorizationChecker,
77
        EntityManager $entityManager,
78
        RouterInterface $router,
79
        SlugifyInterface $slugify,
80
        ToolChain $toolChain,
81
        ResourceNodeRepository $resourceNodeRepository
82
    ) {
83
        $className = $this->getClassName();
84
        $this->repository = $entityManager->getRepository($className);
85
        $this->authorizationChecker = $authorizationChecker;
86
        $this->router = $router;
87
        $this->resourceNodeRepository = $resourceNodeRepository;
88
        $this->slugify = $slugify;
89
        $this->toolChain = $toolChain;
90
        $this->settings = new Settings();
91
        $this->templates = new Template();
92
    }*/
93
94
    public function setResourceNodeRepository(ResourceNodeRepository $resourceNodeRepository): self
95
    {
96
        $this->resourceNodeRepository = $resourceNodeRepository;
97
98
        return $this;
99
    }
100
101
    public function setRouter(RouterInterface $router): self
102
    {
103
        $this->router = $router;
104
105
        return $this;
106
    }
107
108
    public function setAuthorizationChecker(AuthorizationCheckerInterface $authorizationChecker): self
109
    {
110
        $this->authorizationChecker = $authorizationChecker;
111
112
        return $this;
113
    }
114
115
    public function setSlugify(SlugifyInterface $slugify): self
116
    {
117
        $this->slugify = $slugify;
118
119
        return $this;
120
    }
121
122
    public function setToolChain(ToolChain $toolChain): self
123
    {
124
        $this->toolChain = $toolChain;
125
126
        return $this;
127
    }
128
129
    public function setSettings(Settings $settings): self
130
    {
131
        $this->settings = $settings;
132
133
        return $this;
134
    }
135
136
    public function setTemplates(Template $templates): self
137
    {
138
        $this->templates = $templates;
139
140
        return $this;
141
    }
142
143
    public function findResourceByTitle(
144
        string $title,
145
        ResourceNode $parentNode,
146
        Course $course,
147
        Session $session = null,
148
        CGroup $group = null
149
    ): ?ResourceInterface {
150
        $qb = $this->getResourcesByCourse($course, $session, $group, $parentNode);
151
        $qb
152
            ->andWhere('node.title = :title')
153
            ->setParameter('title', $title, Types::STRING)
154
            ->setMaxResults(1)
155
        ;
156
157
        return $qb->getQuery()->getOneOrNullResult();
158
    }
159
160
    public function getClassName(): string
161
    {
162
        $class = get_class($this);
163
        //Chamilo\CoreBundle\Repository\Node\IllustrationRepository
164
        $class = str_replace('\\Repository\\', '\\Entity\\', $class);
165
        $class = str_replace('Repository', '', $class);
166
        if (!class_exists($class)) {
167
            throw new Exception("Repo: {$class} not found ");
168
        }
169
170
        return $class;
171
    }
172
173
    public function getAuthorizationChecker(): AuthorizationCheckerInterface
174
    {
175
        return $this->authorizationChecker;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->authorizationChecker could return the type null which is incompatible with the type-hinted return Symfony\Component\Securi...izationCheckerInterface. Consider adding an additional type-check to rule them out.
Loading history...
176
    }
177
178
    public function getRouter(): RouterInterface
179
    {
180
        return $this->router;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->router could return the type null which is incompatible with the type-hinted return Symfony\Component\Routing\RouterInterface. Consider adding an additional type-check to rule them out.
Loading history...
181
    }
182
183
    /**
184
     * @return ResourceNodeRepository
185
     */
186
    public function getResourceNodeRepository()
187
    {
188
        return $this->resourceNodeRepository;
189
    }
190
191
    /**
192
     * @return FormInterface
193
     */
194
    public function getForm(FormFactory $formFactory, ResourceInterface $resource = null, array $options = [])
195
    {
196
        $formType = $this->getResourceFormType();
197
198
        if (null === $resource) {
199
            $className = $this->repository->getClassName();
200
            $resource = new $className();
201
        }
202
203
        return $formFactory->create($formType, $resource, $options);
204
    }
205
206
    public function getResourceByResourceNode(ResourceNode $resourceNode): ?ResourceInterface
207
    {
208
        return $this->findOneBy([
209
            'resourceNode' => $resourceNode,
210
        ]);
211
    }
212
213
    /*public function findOneBy(array $criteria, array $orderBy = null)
214
    {
215
        return $this->findOneBy($criteria, $orderBy);
216
    }*/
217
218
    /*public function updateResource(AbstractResource $resource)
219
    {
220
        $em = $this->getEntityManager();
221
222
        $resourceNode = $resource->getResourceNode();
223
        $resourceNode->setTitle($resource->getResourceName());
224
225
        $links = $resource->getResourceLinkEntityList();
226
        if ($links) {
227
            foreach ($links as $link) {
228
                $link->setResourceNode($resourceNode);
229
230
                $rights = [];
231
                switch ($link->getVisibility()) {
232
                    case ResourceLink::VISIBILITY_PENDING:
233
                    case ResourceLink::VISIBILITY_DRAFT:
234
                        $editorMask = ResourceNodeVoter::getEditorMask();
235
                        $resourceRight = new ResourceRight();
236
                        $resourceRight
237
                            ->setMask($editorMask)
238
                            ->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)
239
                        ;
240
                        $rights[] = $resourceRight;
241
242
                        break;
243
                }
244
245
                if (!empty($rights)) {
246
                    foreach ($rights as $right) {
247
                        $link->addResourceRight($right);
248
                    }
249
                }
250
                $em->persist($link);
251
            }
252
        }
253
254
        $em->persist($resourceNode);
255
        $em->persist($resource);
256
        $em->flush();
257
    }*/
258
259
    public function create(AbstractResource $resource): void
260
    {
261
        $this->getEntityManager()->persist($resource);
262
        $this->getEntityManager()->flush();
263
    }
264
265
    public function update(AbstractResource $resource, bool $andFlush = true): void
266
    {
267
        $resource->getResourceNode()->setUpdatedAt(new DateTime());
268
        $resource->getResourceNode()->setTitle($resource->getResourceName());
269
        $this->getEntityManager()->persist($resource);
270
271
        if ($andFlush) {
272
            $this->getEntityManager()->flush();
273
        }
274
    }
275
276
    public function updateNodeForResource(ResourceInterface $resource): ResourceNode
277
    {
278
        $em = $this->getEntityManager();
279
280
        $resourceNode = $resource->getResourceNode();
281
        $resourceName = $resource->getResourceName();
282
283
        if ($resourceNode->hasResourceFile()) {
284
            $resourceFile = $resourceNode->getResourceFile();
285
            if (null !== $resourceFile) {
286
                $originalName = $resourceFile->getOriginalName();
287
                $originalExtension = pathinfo($originalName, PATHINFO_EXTENSION);
288
289
                //$originalBasename = \basename($resourceName, $originalExtension);
290
                /*$slug = sprintf(
291
                    '%s.%s',
292
                    $this->slugify->slugify($originalBasename),
293
                    $this->slugify->slugify($originalExtension)
294
                );*/
295
296
                $newOriginalName = sprintf('%s.%s', $resourceName, $originalExtension);
297
                $resourceFile->setOriginalName($newOriginalName);
298
299
                $em->persist($resourceFile);
300
            }
301
        }
302
        //$slug = $this->slugify->slugify($resourceName);
303
304
        $resourceNode->setTitle($resourceName);
305
        //$resourceNode->setSlug($slug);
306
307
        $em->persist($resourceNode);
308
        $em->persist($resource);
309
310
        $em->flush();
311
312
        return $resourceNode;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $resourceNode could return the type null which is incompatible with the type-hinted return Chamilo\CoreBundle\Entity\ResourceNode. Consider adding an additional type-check to rule them out.
Loading history...
313
    }
314
315
    public function addFile(ResourceInterface $resource, UploadedFile $file, string $description = ''): ?ResourceFile
316
    {
317
        $resourceNode = $resource->getResourceNode();
318
319
        if (null === $resourceNode) {
320
            throw new LogicException('Resource node is null');
321
        }
322
323
        $resourceFile = $resourceNode->getResourceFile();
324
        if (null === $resourceFile) {
325
            $resourceFile = new ResourceFile();
326
        }
327
328
        $em = $this->getEntityManager();
329
        $resourceFile
330
            ->setFile($file)
331
            ->setDescription($description)
332
            ->setName($resource->getResourceName())
333
        ;
334
        $em->persist($resourceFile);
335
        $resourceNode->setResourceFile($resourceFile);
336
        $em->persist($resourceNode);
337
338
        return $resourceFile;
339
    }
340
341
    public function addResourceNode(ResourceInterface $resource, User $creator, ResourceInterface $parent = null): ResourceNode
342
    {
343
        if (null !== $parent) {
344
            $parent = $parent->getResourceNode();
345
        }
346
347
        return $this->createNodeForResource($resource, $creator, $parent);
348
    }
349
350
    public function getResourceType(): ?ResourceType
351
    {
352
        $name = $this->getResourceTypeName();
353
        $repo = $this->getEntityManager()->getRepository(ResourceType::class);
354
        $this->resourceType = $repo->findOneBy([
355
            'name' => $name,
356
        ]);
357
358
        return $this->resourceType;
359
    }
360
361
    public function getResourceTypeName(): string
362
    {
363
        return $this->toolChain->getResourceTypeNameFromRepository(get_class($this));
0 ignored issues
show
Bug introduced by
The method getResourceTypeNameFromRepository() 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

363
        return $this->toolChain->/** @scrutinizer ignore-call */ getResourceTypeNameFromRepository(get_class($this));

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...
364
    }
365
366
    public function getResourcesByCourse(Course $course, Session $session = null, CGroup $group = null, ResourceNode $parentNode = null): QueryBuilder
367
    {
368
        $checker = $this->getAuthorizationChecker();
369
        $reflectionClass = $this->getClassMetadata()->getReflectionClass();
370
371
        // Check if this resource type requires to load the base course resources when using a session
372
        $loadBaseSessionContent = $reflectionClass->hasProperty('loadCourseResourcesInSession');
373
        //$loadBaseSessionContent = true;
374
        $resourceTypeName = $this->getResourceTypeName();
375
        $qb = $this->createQueryBuilder('resource')
376
            ->select('resource')
377
            //->from($className, 'resource')
378
            ->innerJoin('resource.resourceNode', 'node')
379
            ->innerJoin('node.resourceLinks', 'links')
380
            ->innerJoin('node.resourceType', 'type')
381
            ->leftJoin('node.resourceFile', 'file')
382
383
            ->where('type.name = :type')
384
            ->setParameter('type', $resourceTypeName, Types::STRING)
385
            ->andWhere('links.course = :course')
386
            ->setParameter('course', $course)
387
            ->addSelect('node')
388
            ->addSelect('links')
389
            //->addSelect('course')
390
            ->addSelect('type')
391
            ->addSelect('file')
392
        ;
393
394
        $isAdmin =
395
            $checker->isGranted('ROLE_ADMIN') ||
396
            $checker->isGranted('ROLE_CURRENT_COURSE_TEACHER');
397
398
        // Do not show deleted resources.
399
        $qb
400
            ->andWhere('links.visibility != :visibilityDeleted')
401
            ->setParameter('visibilityDeleted', ResourceLink::VISIBILITY_DELETED, Types::INTEGER)
402
        ;
403
404
        if (!$isAdmin) {
405
            $qb
406
                ->andWhere('links.visibility = :visibility')
407
                ->setParameter('visibility', ResourceLink::VISIBILITY_PUBLISHED, Types::INTEGER)
408
            ;
409
            // @todo Add start/end visibility restrictions.
410
        }
411
412
        if (null === $session) {
413
            $qb->andWhere(
414
                $qb->expr()->orX(
415
                    $qb->expr()->isNull('links.session'),
416
                    $qb->expr()->eq('links.session', 0)
417
                )
418
            );
419
        } elseif ($loadBaseSessionContent) {
420
            // Load course base content.
421
            $qb->andWhere('links.session = :session OR links.session IS NULL');
422
            $qb->setParameter('session', $session);
423
        } else {
424
            // Load only session resources.
425
            $qb->andWhere('links.session = :session');
426
            $qb->setParameter('session', $session);
427
        }
428
429
        if (null !== $parentNode) {
430
            $qb->andWhere('node.parent = :parentNode');
431
            $qb->setParameter('parentNode', $parentNode);
432
        }
433
434
        if (null === $group) {
435
            $qb->andWhere(
436
                $qb->expr()->orX(
437
                    $qb->expr()->isNull('links.group'),
438
                    $qb->expr()->eq('links.group', 0)
439
                )
440
            );
441
        } else {
442
            $qb->andWhere('links.group = :group');
443
            $qb->setParameter('group', $group);
444
        }
445
446
        return $qb;
447
    }
448
449
    public function getResourcesByCourseOnly(Course $course, ResourceNode $parentNode = null): QueryBuilder
450
    {
451
        $checker = $this->getAuthorizationChecker();
452
        $resourceTypeName = $this->getResourceTypeName();
453
454
        $qb = $this->createQueryBuilder('resource')
455
            ->select('resource')
456
            //->from($className, 'resource')
457
            ->innerJoin(
458
                'resource.resourceNode',
459
                'node'
460
            )
461
            ->innerJoin('node.resourceLinks', 'links')
462
            ->innerJoin('node.resourceType', 'type')
463
            ->where('type.name = :type')
464
            ->setParameter('type', $resourceTypeName, Types::STRING)
465
            ->andWhere('links.course = :course')
466
            ->setParameter('course', $course)
467
        ;
468
469
        $isAdmin = $checker->isGranted('ROLE_ADMIN') || $checker->isGranted('ROLE_CURRENT_COURSE_TEACHER');
470
471
        // Do not show deleted resources
472
        $qb
473
            ->andWhere('links.visibility != :visibilityDeleted')
474
            ->setParameter('visibilityDeleted', ResourceLink::VISIBILITY_DELETED, Types::INTEGER)
475
        ;
476
477
        if (!$isAdmin) {
478
            $qb
479
                ->andWhere('links.visibility = :visibility')
480
                ->setParameter('visibility', ResourceLink::VISIBILITY_PUBLISHED, Types::INTEGER)
481
            ;
482
            // @todo Add start/end visibility restrictions
483
        }
484
485
        if (null !== $parentNode) {
486
            $qb->andWhere('node.parent = :parentNode');
487
            $qb->setParameter('parentNode', $parentNode);
488
        }
489
490
        return $qb;
491
    }
492
493
    public function getResourcesByCreator(User $user, ResourceNode $parentNode = null): QueryBuilder
494
    {
495
        $qb = $this->createQueryBuilder('resource')
496
            ->select('resource')
497
            //->from($className, 'resource')
498
            ->innerJoin('resource.resourceNode', 'node')
499
            //->innerJoin('node.resourceLinks', 'links')
500
            //->where('node.resourceType = :type')
501
            //->setParameter('type',$type)
502
            ;
503
        /*$qb
504
            ->andWhere('links.visibility = :visibility')
505
            ->setParameter('visibility', ResourceLink::VISIBILITY_PUBLISHED)
506
        ;*/
507
508
        if (null !== $parentNode) {
509
            $qb->andWhere('node.parent = :parentNode');
510
            $qb->setParameter('parentNode', $parentNode);
511
        }
512
513
        $qb->andWhere('node.creator = :creator');
514
        $qb->setParameter('creator', $user);
515
516
        return $qb;
517
    }
518
519
    public function getResourcesByCourseLinkedToUser(
520
        User $user,
521
        Course $course,
522
        Session $session = null,
523
        CGroup $group = null,
524
        ResourceNode $parentNode = null
525
    ): QueryBuilder {
526
        $qb = $this->getResourcesByCourse($course, $session, $group, $parentNode);
527
        $qb->andWhere('node.creator = :user OR (links.user = :user OR links.user IS NULL)');
528
        $qb->setParameter('user', $user);
529
530
        return $qb;
531
    }
532
533
    public function getResourcesByLinkedUser(User $user, ResourceNode $parentNode = null): QueryBuilder
534
    {
535
        $checker = $this->getAuthorizationChecker();
536
        $resourceTypeName = $this->getResourceTypeName();
537
538
        $qb = $this->createQueryBuilder('resource')
539
            ->select('resource')
540
            ->innerJoin(
541
                'resource.resourceNode',
542
                'node'
543
            )
544
            ->innerJoin('node.resourceLinks', 'links')
545
            ->innerJoin('node.resourceType', 'type')
546
            ->where('type.name = :type')
547
            ->setParameter('type', $resourceTypeName, Types::STRING)
548
            ->andWhere('links.user = :user')
549
            ->setParameter('user', $user)
550
        ;
551
552
        $isAdmin = $checker->isGranted('ROLE_ADMIN') ||
553
            $checker->isGranted('ROLE_CURRENT_COURSE_TEACHER');
554
555
        // Do not show deleted resources
556
        $qb
557
            ->andWhere('links.visibility != :visibilityDeleted')
558
            ->setParameter('visibilityDeleted', ResourceLink::VISIBILITY_DELETED)
559
        ;
560
561
        if (!$isAdmin) {
562
            $qb
563
                ->andWhere('links.visibility = :visibility')
564
                ->setParameter('visibility', ResourceLink::VISIBILITY_PUBLISHED)
565
            ;
566
            // @todo Add start/end visibility restrictrions
567
        }
568
569
        if (null !== $parentNode) {
570
            $qb->andWhere('node.parent = :parentNode');
571
            $qb->setParameter('parentNode', $parentNode);
572
        }
573
574
        return $qb;
575
    }
576
577
    public function getResourceFromResourceNode(int $resourceNodeId): ?ResourceInterface
578
    {
579
        // Include links
580
        $qb = $this->createQueryBuilder('resource')
581
            ->select('resource')
582
            ->addSelect('node')
583
            ->addSelect('links')
584
            ->innerJoin('resource.resourceNode', 'node')
585
        //    ->innerJoin('node.creator', 'userCreator')
586
            ->innerJoin('node.resourceLinks', 'links')
587
//            ->leftJoin('node.resourceFile', 'file')
588
            ->where('node.id = :id')
589
            ->setParameters([
590
                'id' => $resourceNodeId,
591
            ])
592
            //->addSelect('node')
593
        ;
594
595
        return $qb->getQuery()->getOneOrNullResult();
596
    }
597
598
    public function delete(ResourceInterface $resource): void
599
    {
600
        $children = $resource->getResourceNode()->getChildren();
601
        foreach ($children as $child) {
602
            if ($child->hasResourceFile()) {
603
                $this->getEntityManager()->remove($child->getResourceFile());
604
            }
605
            $resourceNode = $this->getResourceFromResourceNode($child->getId());
606
            if (null !== $resourceNode) {
607
                $this->delete($resourceNode);
608
            }
609
        }
610
        $this->getEntityManager()->remove($resource);
611
        $this->getEntityManager()->flush();
612
    }
613
614
    /**
615
     * Deletes several entities: AbstractResource (Ex: CDocument, CQuiz), ResourceNode,
616
     * ResourceLinks and ResourceFile (including files via Flysystem).
617
     */
618
    public function hardDelete(AbstractResource $resource): void
619
    {
620
        $em = $this->getEntityManager();
621
        $em->remove($resource);
622
        $em->flush();
623
    }
624
625
    public function getResourceFileContent(AbstractResource $resource): string
626
    {
627
        try {
628
            $resourceNode = $resource->getResourceNode();
629
630
            return $this->resourceNodeRepository->getResourceNodeFileContent($resourceNode);
0 ignored issues
show
Bug introduced by
The method getResourceNodeFileContent() 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

630
            return $this->resourceNodeRepository->/** @scrutinizer ignore-call */ getResourceNodeFileContent($resourceNode);

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...
631
        } catch (Throwable $exception) {
632
            throw new FileNotFoundException($resource->getResourceName());
633
        }
634
    }
635
636
    public function getResourceNodeFileContent(ResourceNode $resourceNode): string
637
    {
638
        return $this->resourceNodeRepository->getResourceNodeFileContent($resourceNode);
639
    }
640
641
    public function getResourceNodeFileStream(ResourceNode $resourceNode)
642
    {
643
        return $this->resourceNodeRepository->getResourceNodeFileStream($resourceNode);
644
    }
645
646
    public function getResourceFileDownloadUrl(AbstractResource $resource, array $extraParams = [], $referenceType = null): string
647
    {
648
        $extraParams['mode'] = 'download';
649
650
        return $this->getResourceFileUrl($resource, $extraParams, $referenceType);
651
    }
652
653
    public function getResourceFileUrl(AbstractResource $resource, array $extraParams = [], $referenceType = null): string
654
    {
655
        try {
656
            $resourceNode = $resource->getResourceNode();
657
            if ($resourceNode->hasResourceFile()) {
658
                $params = [
659
                    'tool' => $resourceNode->getResourceType()->getTool(),
660
                    'type' => $resourceNode->getResourceType(),
661
                    'id' => $resourceNode->getId(),
662
                ];
663
664
                if (!empty($extraParams)) {
665
                    $params = array_merge($params, $extraParams);
666
                }
667
668
                $referenceType ??= UrlGeneratorInterface::ABSOLUTE_PATH;
669
670
                $mode = $params['mode'] ?? 'view';
671
                // Remove mode from params and sent directly to the controller.
672
                unset($params['mode']);
673
674
                switch ($mode) {
675
                    case 'download':
676
                        return $this->router->generate('chamilo_core_resource_download', $params, $referenceType);
0 ignored issues
show
Bug introduced by
The method generate() 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

676
                        return $this->router->/** @scrutinizer ignore-call */ generate('chamilo_core_resource_download', $params, $referenceType);

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...
677
                    case 'view':
678
                        return $this->router->generate('chamilo_core_resource_view', $params, $referenceType);
679
                }
680
            }
681
682
            return '';
683
        } catch (Throwable $exception) {
684
            throw new FileNotFoundException($resource->getResourceName());
685
        }
686
    }
687
688
    public function getResourceSettings(): Settings
689
    {
690
        return $this->settings;
691
    }
692
693
    public function getTemplates(): Template
694
    {
695
        return $this->templates;
696
    }
697
698
    /**
699
     * @param string $content
700
     *
701
     * @return bool
702
     */
703
    public function updateResourceFileContent(AbstractResource $resource, $content)
704
    {
705
        error_log('updateResourceFileContent');
706
707
        $resourceNode = $resource->getResourceNode();
708
        if ($resourceNode->hasResourceFile()) {
709
            $resourceNode->setContent($content);
710
            error_log('updated');
711
            $resourceNode->getResourceFile()->setSize(strlen($content));
712
            /*
713
            error_log('has file');
714
            $resourceFile = $resourceNode->getResourceFile();
715
            if ($resourceFile) {
716
                error_log('$resourceFile');
717
                $title = $resource->getResourceName();
718
                $handle = tmpfile();
719
                fwrite($handle, $content);
720
                error_log($title);
721
                error_log($content);
722
                $meta = stream_get_meta_data($handle);
723
                $file = new UploadedFile($meta['uri'], $title, 'text/html', null, true);
724
                $resource->setUploadFile($file);
725
726
                return true;
727
            }*/
728
        }
729
        error_log('false');
730
731
        return false;
732
    }
733
734
    public function setResourceName(AbstractResource $resource, $title): void
735
    {
736
        $resource->setResourceName($title);
737
        $resourceNode = $resource->getResourceNode();
738
        $resourceNode->setTitle($title);
739
        if ($resourceNode->hasResourceFile()) {
740
            //$resourceNode->getResourceFile()->getFile()->
741
            //$resourceNode->getResourceFile()->setName($title);
742
            //$resourceFile->setName($title);
743
744
            /*$fileName = $this->getResourceNodeRepository()->getFilename($resourceFile);
745
            error_log('$fileName');
746
            error_log($fileName);
747
            error_log($title);
748
            $this->getResourceNodeRepository()->getFileSystem()->rename($fileName, $title);
749
            $resourceFile->setName($title);
750
            $resourceFile->setOriginalName($title);*/
751
        }
752
    }
753
754
    /**
755
     * Change all links visibility to DELETED.
756
     */
757
    public function softDelete(AbstractResource $resource): void
758
    {
759
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_DELETED);
760
    }
761
762
    public function setVisibilityPublished(AbstractResource $resource): void
763
    {
764
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_PUBLISHED);
765
    }
766
767
    public function setVisibilityDeleted(AbstractResource $resource): void
768
    {
769
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_DELETED);
770
    }
771
772
    public function setVisibilityDraft(AbstractResource $resource): void
773
    {
774
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_DRAFT);
775
    }
776
777
    public function setVisibilityPending(AbstractResource $resource): void
778
    {
779
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_PENDING);
780
    }
781
782
    public function createNodeForResource(ResourceInterface $resource, User $creator, ResourceNode $parentNode = null, UploadedFile $file = null): ResourceNode
783
    {
784
        $em = $this->getEntityManager();
785
786
        $resourceType = $this->getResourceType();
787
        $resourceName = $resource->getResourceName();
788
        $extension = $this->slugify->slugify(pathinfo($resourceName, PATHINFO_EXTENSION));
0 ignored issues
show
Bug introduced by
The method slugify() 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

788
        /** @scrutinizer ignore-call */ 
789
        $extension = $this->slugify->slugify(pathinfo($resourceName, PATHINFO_EXTENSION));

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...
789
790
        if (empty($extension)) {
791
            $slug = $this->slugify->slugify($resourceName);
792
        } else {
793
            $originalExtension = pathinfo($resourceName, PATHINFO_EXTENSION);
794
            $originalBasename = \basename($resourceName, $originalExtension);
795
            $slug = sprintf('%s.%s', $this->slugify->slugify($originalBasename), $originalExtension);
796
        }
797
798
        $resourceNode = new ResourceNode();
799
        $resourceNode
800
            ->setTitle($resourceName)
801
            ->setSlug($slug)
802
            ->setCreator($creator)
803
            ->setResourceType($resourceType)
804
        ;
805
806
        if (null !== $parentNode) {
807
            $resourceNode->setParent($parentNode);
808
        }
809
810
        $resource->setResourceNode($resourceNode);
811
        $em->persist($resourceNode);
812
        $em->persist($resource);
813
814
        if (null !== $file) {
815
            $this->addFile($resource, $file);
816
        }
817
818
        return $resourceNode;
819
    }
820
821
    public function getTotalSpaceByCourse(Course $course, CGroup $group = null, Session $session = null): int
822
    {
823
        $qb = $this->createQueryBuilder('resource');
824
        $qb
825
            ->select('SUM(file.size) as total')
826
            ->innerJoin('resource.resourceNode', 'node')
827
            ->innerJoin('node.resourceLinks', 'l')
828
            ->innerJoin('node.resourceFile', 'file')
829
            ->where('l.course = :course')
830
            ->andWhere('l.visibility <> :visibility')
831
            ->andWhere('file IS NOT NULL')
832
            ->setParameters(
833
                [
834
                    'course' => $course,
835
                    'visibility' => ResourceLink::VISIBILITY_DELETED,
836
                ]
837
            )
838
        ;
839
840
        if (null === $group) {
841
            $qb->andWhere('l.group IS NULL');
842
        } else {
843
            $qb
844
                ->andWhere('l.group = :group')
845
                ->setParameter('group', $group)
846
            ;
847
        }
848
849
        if (null === $session) {
850
            $qb->andWhere('l.session IS NULL');
851
        } else {
852
            $qb
853
                ->andWhere('l.session = :session')
854
                ->setParameter('session', $session)
855
            ;
856
        }
857
858
        $query = $qb->getQuery();
859
860
        return (int) $query->getSingleScalarResult();
861
    }
862
863
    public function isGranted(string $subject, AbstractResource $resource): bool
864
    {
865
        return $this->getAuthorizationChecker()->isGranted($subject, $resource->getResourceNode());
866
    }
867
868
    /**
869
     * Changes the visibility of the children that matches the exact same link.
870
     */
871
    public function copyVisibilityToChildren(ResourceNode $resourceNode, ResourceLink $link): bool
872
    {
873
        $children = $resourceNode->getChildren();
874
875
        if (0 === $children->count()) {
876
            return false;
877
        }
878
879
        $em = $this->getEntityManager();
880
881
        /** @var ResourceNode $child */
882
        foreach ($children as $child) {
883
            if ($child->getChildren()->count() > 0) {
884
                $this->copyVisibilityToChildren($child, $link);
885
            }
886
887
            $links = $child->getResourceLinks();
888
            foreach ($links as $linkItem) {
889
                if ($linkItem->getUser() === $link->getUser() &&
890
                    $linkItem->getSession() === $link->getSession() &&
891
                    $linkItem->getCourse() === $link->getCourse() &&
892
                    $linkItem->getUserGroup() === $link->getUserGroup()
893
                ) {
894
                    $linkItem->setVisibility($link->getVisibility());
895
                    $em->persist($linkItem);
896
                }
897
            }
898
        }
899
900
        $em->flush();
901
902
        return true;
903
    }
904
905
    public function saveUpload(UploadedFile $file): ResourceInterface
906
    {
907
        throw new Exception('Implement saveUpload');
908
    }
909
910
    public function getResourceFormType(): string
911
    {
912
        throw new Exception('Implement getResourceFormType');
913
    }
914
915
    protected function getOrCreateQueryBuilder(QueryBuilder $qb = null, string $alias = 'resource'): QueryBuilder
916
    {
917
        return $qb ?: $this->createQueryBuilder($alias);
918
    }
919
920
    private function setLinkVisibility(AbstractResource $resource, int $visibility, bool $recursive = true): bool
921
    {
922
        $resourceNode = $resource->getResourceNode();
923
924
        if (null === $resourceNode) {
925
            return false;
926
        }
927
928
        $em = $this->getEntityManager();
929
        if ($recursive) {
930
            $children = $resourceNode->getChildren();
931
            if (!empty($children)) {
932
                /** @var ResourceNode $child */
933
                foreach ($children as $child) {
934
                    $criteria = [
935
                        'resourceNode' => $child,
936
                    ];
937
                    $childDocument = $this->findOneBy($criteria);
938
                    if ($childDocument) {
939
                        $this->setLinkVisibility($childDocument, $visibility);
940
                    }
941
                }
942
            }
943
        }
944
945
        $links = $resourceNode->getResourceLinks();
946
947
        if (!empty($links)) {
948
            /** @var ResourceLink $link */
949
            foreach ($links as $link) {
950
                $link->setVisibility($visibility);
951
                if (ResourceLink::VISIBILITY_DRAFT === $visibility) {
952
                    $editorMask = ResourceNodeVoter::getEditorMask();
953
                    $rights = [];
954
                    $resourceRight = new ResourceRight();
955
                    $resourceRight
956
                        ->setMask($editorMask)
957
                        ->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)
958
                        ->setResourceLink($link)
959
                    ;
960
                    $rights[] = $resourceRight;
961
962
                    if (!empty($rights)) {
963
                        $link->setResourceRights($rights);
964
                    }
965
                } else {
966
                    $link->setResourceRights([]);
967
                }
968
                $em->persist($link);
969
            }
970
        }
971
        $em->flush();
972
973
        return true;
974
    }
975
}
976