Passed
Push — master ( b56fa5...9c4b43 )
by Julito
09:52
created

ResourceRepository::getTotalSpaceByCourse()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 40
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

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