Passed
Push — master ( 3fcb32...49d6fc )
by Julito
09:27
created

ResourceRepository::setTemplates()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
rs 10
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 getResourceSettings(): Settings
144
    {
145
        return $this->settings;
146
    }
147
148
    public function getTemplates(): Template
149
    {
150
        return $this->templates;
151
    }
152
153
    public function getClassName(): string
154
    {
155
        $class = get_class($this);
156
        //Chamilo\CoreBundle\Repository\Node\IllustrationRepository
157
        $class = str_replace('\\Repository\\', '\\Entity\\', $class);
158
        $class = str_replace('Repository', '', $class);
159
        if (!class_exists($class)) {
160
            throw new Exception(sprintf('Repo: %s not found ', $class));
161
        }
162
163
        return $class;
164
    }
165
166
    public function getAuthorizationChecker(): AuthorizationCheckerInterface
167
    {
168
        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...
169
    }
170
171
    public function getRouter(): RouterInterface
172
    {
173
        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...
174
    }
175
176
    /**
177
     * @return ResourceNodeRepository
178
     */
179
    public function getResourceNodeRepository()
180
    {
181
        return $this->resourceNodeRepository;
182
    }
183
184
    /**
185
     * @return FormInterface
186
     */
187
    public function getForm(FormFactory $formFactory, ResourceInterface $resource = null, array $options = [])
188
    {
189
        $formType = $this->getResourceFormType();
190
191
        if (null === $resource) {
192
            $className = $this->repository->getClassName();
193
            $resource = new $className();
194
        }
195
196
        return $formFactory->create($formType, $resource, $options);
197
    }
198
199
    public function getResourceByResourceNode(ResourceNode $resourceNode): ?ResourceInterface
200
    {
201
        return $this->findOneBy([
202
            'resourceNode' => $resourceNode,
203
        ]);
204
    }
205
206
    /*public function findOneBy(array $criteria, array $orderBy = null)
207
    {
208
        return $this->findOneBy($criteria, $orderBy);
209
    }*/
210
211
    /*public function updateResource(AbstractResource $resource)
212
    {
213
        $em = $this->getEntityManager();
214
215
        $resourceNode = $resource->getResourceNode();
216
        $resourceNode->setTitle($resource->getResourceName());
217
218
        $links = $resource->getResourceLinkEntityList();
219
        if ($links) {
220
            foreach ($links as $link) {
221
                $link->setResourceNode($resourceNode);
222
223
                $rights = [];
224
                switch ($link->getVisibility()) {
225
                    case ResourceLink::VISIBILITY_PENDING:
226
                    case ResourceLink::VISIBILITY_DRAFT:
227
                        $editorMask = ResourceNodeVoter::getEditorMask();
228
                        $resourceRight = new ResourceRight();
229
                        $resourceRight
230
                            ->setMask($editorMask)
231
                            ->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)
232
                        ;
233
                        $rights[] = $resourceRight;
234
235
                        break;
236
                }
237
238
                if (!empty($rights)) {
239
                    foreach ($rights as $right) {
240
                        $link->addResourceRight($right);
241
                    }
242
                }
243
                $em->persist($link);
244
            }
245
        }
246
247
        $em->persist($resourceNode);
248
        $em->persist($resource);
249
        $em->flush();
250
    }*/
251
252
    public function create(AbstractResource $resource): void
253
    {
254
        $this->getEntityManager()->persist($resource);
255
        $this->getEntityManager()->flush();
256
    }
257
258
    public function update(AbstractResource $resource, bool $andFlush = true): void
259
    {
260
        $resource->getResourceNode()->setUpdatedAt(new DateTime());
261
        $resource->getResourceNode()->setTitle($resource->getResourceName());
262
        $this->getEntityManager()->persist($resource);
263
264
        if ($andFlush) {
265
            $this->getEntityManager()->flush();
266
        }
267
    }
268
269
    public function updateNodeForResource(ResourceInterface $resource): ResourceNode
270
    {
271
        $em = $this->getEntityManager();
272
273
        $resourceNode = $resource->getResourceNode();
274
        $resourceName = $resource->getResourceName();
275
276
        if ($resourceNode->hasResourceFile()) {
277
            $resourceFile = $resourceNode->getResourceFile();
278
            if (null !== $resourceFile) {
279
                $originalName = $resourceFile->getOriginalName();
280
                $originalExtension = pathinfo($originalName, PATHINFO_EXTENSION);
281
282
                //$originalBasename = \basename($resourceName, $originalExtension);
283
                /*$slug = sprintf(
284
                    '%s.%s',
285
                    $this->slugify->slugify($originalBasename),
286
                    $this->slugify->slugify($originalExtension)
287
                );*/
288
289
                $newOriginalName = sprintf('%s.%s', $resourceName, $originalExtension);
290
                $resourceFile->setOriginalName($newOriginalName);
291
292
                $em->persist($resourceFile);
293
            }
294
        }
295
        //$slug = $this->slugify->slugify($resourceName);
296
297
        $resourceNode->setTitle($resourceName);
298
        //$resourceNode->setSlug($slug);
299
300
        $em->persist($resourceNode);
301
        $em->persist($resource);
302
303
        $em->flush();
304
305
        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...
306
    }
307
308
    public function findResourceByTitle(
309
        string $title,
310
        ResourceNode $parentNode,
311
        Course $course,
312
        Session $session = null,
313
        CGroup $group = null
314
    ): ?ResourceInterface {
315
        $qb = $this->getResourcesByCourse($course, $session, $group, $parentNode);
316
        $this->addTitleQueryBuilder($title, $qb);
317
        $qb->setMaxResults(1);
318
319
        return $qb->getQuery()->getOneOrNullResult();
320
    }
321
322
    public function getCount(QueryBuilder $qb)
323
    {
324
        $qb->select('count(resource)');
325
        $qb->setMaxResults(1);
326
327
        return (int) $qb->getQuery()->getSingleScalarResult();
328
    }
329
330
    public function findResourcesByTitle(
331
        string $title,
332
        ResourceNode $parentNode,
333
        Course $course,
334
        Session $session = null,
335
        CGroup $group = null
336
    ) {
337
        $qb = $this->getResourcesByCourse($course, $session, $group, $parentNode);
338
        $this->addTitleQueryBuilder($title, $qb);
339
340
        return $qb->getQuery()->getResult();
341
    }
342
343
    public function addFile(ResourceInterface $resource, UploadedFile $file, string $description = ''): ?ResourceFile
344
    {
345
        $resourceNode = $resource->getResourceNode();
346
347
        if (null === $resourceNode) {
348
            throw new LogicException('Resource node is null');
349
        }
350
351
        $resourceFile = $resourceNode->getResourceFile();
352
        if (null === $resourceFile) {
353
            $resourceFile = new ResourceFile();
354
        }
355
356
        $em = $this->getEntityManager();
357
        $resourceFile
358
            ->setFile($file)
359
            ->setDescription($description)
360
            ->setName($resource->getResourceName())
361
            ->setResourceNode($resourceNode)
362
        ;
363
        $em->persist($resourceFile);
364
        $resourceNode->setResourceFile($resourceFile);
365
        $em->persist($resourceNode);
366
367
        return $resourceFile;
368
    }
369
370
    public function addResourceNode(ResourceInterface $resource, User $creator, ResourceInterface $parent = null): ResourceNode
371
    {
372
        if (null !== $parent) {
373
            $parent = $parent->getResourceNode();
374
        }
375
376
        return $this->createNodeForResource($resource, $creator, $parent);
377
    }
378
379
    public function getResourceType(): ?ResourceType
380
    {
381
        $name = $this->getResourceTypeName();
382
        $repo = $this->getEntityManager()->getRepository(ResourceType::class);
383
        $this->resourceType = $repo->findOneBy([
384
            'name' => $name,
385
        ]);
386
387
        return $this->resourceType;
388
    }
389
390
    public function getResourceTypeName(): string
391
    {
392
        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

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

651
            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...
652
        } catch (Throwable $throwable) {
653
            throw new FileNotFoundException($resource->getResourceName());
654
        }
655
    }
656
657
    public function getResourceNodeFileContent(ResourceNode $resourceNode): string
658
    {
659
        return $this->resourceNodeRepository->getResourceNodeFileContent($resourceNode);
660
    }
661
662
    public function getResourceNodeFileStream(ResourceNode $resourceNode)
663
    {
664
        return $this->resourceNodeRepository->getResourceNodeFileStream($resourceNode);
665
    }
666
667
    public function getResourceFileDownloadUrl(AbstractResource $resource, array $extraParams = [], $referenceType = null): string
668
    {
669
        $extraParams['mode'] = 'download';
670
671
        return $this->getResourceFileUrl($resource, $extraParams, $referenceType);
672
    }
673
674
    public function getResourceFileUrl(AbstractResource $resource, array $extraParams = [], $referenceType = null): string
675
    {
676
        try {
677
            $resourceNode = $resource->getResourceNode();
678
            if ($resourceNode->hasResourceFile()) {
679
                $params = [
680
                    'tool' => $resourceNode->getResourceType()->getTool(),
681
                    'type' => $resourceNode->getResourceType(),
682
                    'id' => $resourceNode->getId(),
683
                ];
684
685
                if (!empty($extraParams)) {
686
                    $params = array_merge($params, $extraParams);
687
                }
688
689
                $referenceType ??= UrlGeneratorInterface::ABSOLUTE_PATH;
690
691
                $mode = $params['mode'] ?? 'view';
692
                // Remove mode from params and sent directly to the controller.
693
                unset($params['mode']);
694
695
                switch ($mode) {
696
                    case 'download':
697
                        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

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

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