Passed
Push — master ( a121f5...3ea3fd )
by Julito
08:38
created

ResourceRepository::getTemplates()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
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\Utils\CreateUploadedFile;
10
use Chamilo\CoreBundle\Entity\AbstractResource;
11
use Chamilo\CoreBundle\Entity\Course;
12
use Chamilo\CoreBundle\Entity\ResourceFile;
13
use Chamilo\CoreBundle\Entity\ResourceInterface;
14
use Chamilo\CoreBundle\Entity\ResourceLink;
15
use Chamilo\CoreBundle\Entity\ResourceNode;
16
use Chamilo\CoreBundle\Entity\ResourceRight;
17
use Chamilo\CoreBundle\Entity\ResourceType;
18
use Chamilo\CoreBundle\Entity\Session;
19
use Chamilo\CoreBundle\Entity\User;
20
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
21
use Chamilo\CoreBundle\Traits\NonResourceRepository;
22
use Chamilo\CoreBundle\Traits\Repository\RepositoryQueryBuilderTrait;
23
use Chamilo\CourseBundle\Entity\CGroup;
24
use DateTime;
25
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
26
use Doctrine\Common\Collections\ArrayCollection;
27
use Doctrine\DBAL\Types\Types;
28
use Doctrine\ORM\EntityRepository;
29
use Doctrine\ORM\QueryBuilder;
30
use Exception;
31
use LogicException;
32
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
33
use Symfony\Component\HttpFoundation\File\UploadedFile;
34
use Throwable;
35
36
/**
37
 * Extends Resource EntityRepository.
38
 */
39
abstract class ResourceRepository extends ServiceEntityRepository
40
{
41
    use NonResourceRepository;
42
    use RepositoryQueryBuilderTrait;
43
44
    protected ?ResourceType $resourceType = null;
45
46
    public function getCount(QueryBuilder $qb): int
47
    {
48
        $qb->select('count(resource)');
49
        $qb->setMaxResults(1);
50
51
        return (int) $qb->getQuery()->getSingleScalarResult();
52
    }
53
54
    public function getResourceByResourceNode(ResourceNode $resourceNode): ?ResourceInterface
55
    {
56
        return $this->findOneBy([
57
            'resourceNode' => $resourceNode,
58
        ]);
59
    }
60
61
    public function create(AbstractResource $resource): void
62
    {
63
        $this->getEntityManager()->persist($resource);
64
        $this->getEntityManager()->flush();
65
    }
66
67
    public function update(AbstractResource | User $resource, bool $andFlush = true): void
68
    {
69
        if (!$resource->hasResourceNode()) {
70
            throw new Exception('Resource needs a resource node');
71
        }
72
73
        $em = $this->getEntityManager();
74
75
        $resource->getResourceNode()->setUpdatedAt(new DateTime());
76
        $resource->getResourceNode()->setTitle($resource->getResourceName());
77
        $em->persist($resource);
78
79
        if ($andFlush) {
80
            $em->flush();
81
        }
82
    }
83
84
    public function updateNodeForResource(ResourceInterface $resource): ResourceNode
85
    {
86
        $em = $this->getEntityManager();
87
88
        $resourceNode = $resource->getResourceNode();
89
        $resourceName = $resource->getResourceName();
90
91
        if ($resourceNode->hasResourceFile()) {
92
            $resourceFile = $resourceNode->getResourceFile();
93
            if (null !== $resourceFile) {
94
                $originalName = $resourceFile->getOriginalName();
95
                $originalExtension = pathinfo($originalName, PATHINFO_EXTENSION);
96
97
                //$originalBasename = \basename($resourceName, $originalExtension);
98
                /*$slug = sprintf(
99
                    '%s.%s',
100
                    $this->slugify->slugify($originalBasename),
101
                    $this->slugify->slugify($originalExtension)
102
                );*/
103
104
                $newOriginalName = sprintf('%s.%s', $resourceName, $originalExtension);
105
                $resourceFile->setOriginalName($newOriginalName);
106
107
                $em->persist($resourceFile);
108
            }
109
        }
110
        //$slug = $this->slugify->slugify($resourceName);
111
112
        $resourceNode->setTitle($resourceName);
113
        //$resourceNode->setSlug($slug);
114
115
        $em->persist($resourceNode);
116
        $em->persist($resource);
117
118
        $em->flush();
119
120
        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...
121
    }
122
123
    public function findCourseResourceByTitle(
124
        string $title,
125
        ResourceNode $parentNode,
126
        Course $course,
127
        Session $session = null,
128
        CGroup $group = null
129
    ): ?ResourceInterface {
130
        $qb = $this->getResourcesByCourse($course, $session, $group, $parentNode);
131
        $this->addTitleQueryBuilder($title, $qb);
132
        $qb->setMaxResults(1);
133
134
        return $qb->getQuery()->getOneOrNullResult();
135
    }
136
137
    /**
138
     * @return ResourceInterface[]
139
     */
140
    public function findCourseResourcesByTitle(
141
        string $title,
142
        ResourceNode $parentNode,
143
        Course $course,
144
        Session $session = null,
145
        CGroup $group = null
146
    ) {
147
        $qb = $this->getResourcesByCourse($course, $session, $group, $parentNode);
148
        $this->addTitleQueryBuilder($title, $qb);
149
150
        return $qb->getQuery()->getResult();
151
    }
152
153
    /**
154
     * @todo clean path
155
     */
156
    public function addFileFromPath(ResourceInterface $resource, string $fileName, string $path, bool $flush = true): ?ResourceFile
157
    {
158
        if (!empty($path) && file_exists($path) && !is_dir($path)) {
159
            $mimeType = mime_content_type($path);
160
            $file = new UploadedFile($path, $fileName, $mimeType, null, true);
161
162
            return $this->addFile($resource, $file, '', $flush);
163
        }
164
165
        return null;
166
    }
167
168
    public function addFileFromString(ResourceInterface $resource, string $fileName, string $mimeType, string $content, bool $flush = true): ?ResourceFile
169
    {
170
        $file = CreateUploadedFile::fromString($fileName, $mimeType, $content);
171
172
        return $this->addFile($resource, $file, '', $flush);
173
    }
174
175
    public function addFileFromFileRequest(ResourceInterface $resource, string $fileKey, bool $flush = true): ?ResourceFile
176
    {
177
        $request = $this->getRequest();
178
        if ($request->files->has($fileKey)) {
179
            $file = $request->files->get($fileKey);
180
            if (null !== $file) {
181
                $resourceFile = $this->addFile($resource, $file);
182
                if ($flush) {
183
                    $this->getEntityManager()->flush();
184
                }
185
186
                return $resourceFile;
187
            }
188
        }
189
190
        return null;
191
    }
192
193
    public function addFile(ResourceInterface $resource, UploadedFile $file, string $description = '', bool $flush = false): ?ResourceFile
194
    {
195
        $resourceNode = $resource->getResourceNode();
196
197
        if (null === $resourceNode) {
198
            throw new LogicException('Resource node is null');
199
        }
200
201
        $resourceFile = $resourceNode->getResourceFile();
202
        if (null === $resourceFile) {
203
            $resourceFile = new ResourceFile();
204
        }
205
206
        $em = $this->getEntityManager();
207
        $resourceFile
208
            ->setFile($file)
209
            ->setDescription($description)
210
            ->setName($resource->getResourceName())
211
            ->setResourceNode($resourceNode)
212
        ;
213
        $em->persist($resourceFile);
214
        $resourceNode->setResourceFile($resourceFile);
215
        $em->persist($resourceNode);
216
217
        if ($flush) {
218
            $em->flush();
219
        }
220
221
        return $resourceFile;
222
    }
223
224
    public function getResourceType(): ResourceType
225
    {
226
        $resourceTypeName = $this->toolChain->getResourceTypeNameByEntity($this->getClassName());
0 ignored issues
show
Bug introduced by
The method getResourceTypeNameByEntity() 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

226
        /** @scrutinizer ignore-call */ 
227
        $resourceTypeName = $this->toolChain->getResourceTypeNameByEntity($this->getClassName());

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...
227
228
        $repo = $this->getEntityManager()->getRepository(ResourceType::class);
229
230
        return $repo->findOneBy([
231
            'name' => $resourceTypeName,
232
        ]);
233
    }
234
235
    public function addVisibilityQueryBuilder(QueryBuilder $qb = null): QueryBuilder
236
    {
237
        $qb = $this->getOrCreateQueryBuilder($qb);
238
239
        $checker = $this->getAuthorizationChecker();
240
        $isAdmin =
241
            $checker->isGranted('ROLE_ADMIN') ||
242
            $checker->isGranted('ROLE_CURRENT_COURSE_TEACHER');
243
244
        // Do not show deleted resources.
245
        $qb
246
            ->andWhere('links.visibility != :visibilityDeleted')
247
            ->setParameter('visibilityDeleted', ResourceLink::VISIBILITY_DELETED, Types::INTEGER)
248
        ;
249
250
        if (!$isAdmin) {
251
            $qb
252
                ->andWhere('links.visibility = :visibility')
253
                ->setParameter('visibility', ResourceLink::VISIBILITY_PUBLISHED, Types::INTEGER)
254
            ;
255
            // @todo Add start/end visibility restrictions.
256
        }
257
258
        return $qb;
259
    }
260
261
    public function addCourseQueryBuilder(Course $course, QueryBuilder $qb): QueryBuilder
262
    {
263
        $qb
264
            ->andWhere('links.course = :course')
265
            ->setParameter('course', $course)
266
        ;
267
268
        return $qb;
269
    }
270
271
    public function addCourseSessionGroupQueryBuilder(Course $course, Session $session = null, CGroup $group = null, QueryBuilder $qb = null): QueryBuilder
272
    {
273
        $reflectionClass = $this->getClassMetadata()->getReflectionClass();
274
275
        // Check if this resource type requires to load the base course resources when using a session
276
        $loadBaseSessionContent = $reflectionClass->hasProperty('loadCourseResourcesInSession');
277
278
        $this->addCourseQueryBuilder($course, $qb);
279
280
        if (null === $session) {
281
            $qb->andWhere(
282
                $qb->expr()->orX(
0 ignored issues
show
Bug introduced by
The method expr() 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

282
                $qb->/** @scrutinizer ignore-call */ 
283
                     expr()->orX(

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...
283
                    $qb->expr()->isNull('links.session'),
284
                    $qb->expr()->eq('links.session', 0)
285
                )
286
            );
287
        } elseif ($loadBaseSessionContent) {
288
            // Load course base content.
289
            $qb->andWhere('links.session = :session OR links.session IS NULL');
290
            $qb->setParameter('session', $session);
291
        } else {
292
            // Load only session resources.
293
            $qb->andWhere('links.session = :session');
294
            $qb->setParameter('session', $session);
295
        }
296
297
        if (null === $group) {
298
            $qb->andWhere(
299
                $qb->expr()->orX(
300
                    $qb->expr()->isNull('links.group'),
301
                    $qb->expr()->eq('links.group', 0)
302
                )
303
            );
304
        } else {
305
            $qb->andWhere('links.group = :group');
306
            $qb->setParameter('group', $group);
307
        }
308
309
        return $qb;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $qb could return the type null which is incompatible with the type-hinted return Doctrine\ORM\QueryBuilder. Consider adding an additional type-check to rule them out.
Loading history...
310
    }
311
312
    public function getResourceTypeName(): string
313
    {
314
        return $this->toolChain->getResourceTypeNameByEntity($this->getClassName());
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->toolChain-...($this->getClassName()) could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
315
    }
316
317
    public function getResources(ResourceNode $parentNode = null): QueryBuilder
318
    {
319
        $resourceTypeName = $this->getResourceTypeName();
320
321
        $qb = $this->createQueryBuilder('resource')
322
            ->select('resource')
323
            ->innerJoin('resource.resourceNode', 'node')
324
            ->innerJoin('node.resourceLinks', 'links')
325
            ->innerJoin('node.resourceType', 'type')
326
            ->leftJoin('node.resourceFile', 'file')
327
            ->where('type.name = :type')
328
            ->setParameter('type', $resourceTypeName, Types::STRING)
329
            ->addSelect('node')
330
            ->addSelect('links')
331
            ->addSelect('type')
332
            ->addSelect('file')
333
        ;
334
335
        if (null !== $parentNode) {
336
            $qb->andWhere('node.parent = :parentNode');
337
            $qb->setParameter('parentNode', $parentNode);
338
        }
339
340
        return $qb;
341
    }
342
343
    public function getResourcesByCourse(Course $course, Session $session = null, CGroup $group = null, ResourceNode $parentNode = null): QueryBuilder
344
    {
345
        $qb = $this->getResources($parentNode);
346
        $this->addVisibilityQueryBuilder($qb);
347
        $this->addCourseSessionGroupQueryBuilder($course, $session, $group, $qb);
348
349
        return $qb;
350
    }
351
352
    /**
353
     * Get resources only from the base course.
354
     */
355
    public function getResourcesByCourseOnly(Course $course, ResourceNode $parentNode = null): QueryBuilder
356
    {
357
        $qb = $this->getResources($parentNode);
358
        $this->addCourseQueryBuilder($course, $qb);
359
        $this->addVisibilityQueryBuilder($qb);
360
361
        return $qb;
362
    }
363
364
    public function getResourceByCreatorFromTitle(
365
        string $title,
366
        User $user,
367
        ResourceNode $parentNode
368
    ): ?ResourceInterface {
369
        $qb = $this->getResourcesByCreator($user, $parentNode);
370
        $this->addTitleQueryBuilder($title, $qb);
371
        $qb->setMaxResults(1);
372
373
        return $qb->getQuery()->getOneOrNullResult();
374
    }
375
376
    public function getResourcesByCreator(User $user, ResourceNode $parentNode = null): QueryBuilder
377
    {
378
        $qb = $this->createQueryBuilder('resource')
379
            ->select('resource')
380
            ->innerJoin('resource.resourceNode', 'node')
381
        ;
382
383
        if (null !== $parentNode) {
384
            $qb->andWhere('node.parent = :parentNode');
385
            $qb->setParameter('parentNode', $parentNode);
386
        }
387
388
        $this->addCreatorQueryBuilder($user, $qb);
389
390
        return $qb;
391
    }
392
393
    public function getResourcesByCourseLinkedToUser(
394
        User $user,
395
        Course $course,
396
        Session $session = null,
397
        CGroup $group = null,
398
        ResourceNode $parentNode = null
399
    ): QueryBuilder {
400
        $qb = $this->getResourcesByCourse($course, $session, $group, $parentNode);
401
        $qb->andWhere('node.creator = :user OR (links.user = :user OR links.user IS NULL)');
402
        $qb->setParameter('user', $user);
403
404
        return $qb;
405
    }
406
407
    public function getResourcesByLinkedUser(User $user, ResourceNode $parentNode = null): QueryBuilder
408
    {
409
        $qb = $this->getResources($parentNode);
410
        $qb
411
            ->andWhere('links.user = :user')
412
            ->setParameter('user', $user)
413
        ;
414
415
        $this->addVisibilityQueryBuilder($qb);
416
417
        return $qb;
418
    }
419
420
    public function getResourceFromResourceNode(int $resourceNodeId): ?ResourceInterface
421
    {
422
        $qb = $this->createQueryBuilder('resource')
423
            ->select('resource')
424
            ->addSelect('node')
425
            ->addSelect('links')
426
            ->innerJoin('resource.resourceNode', 'node')
427
        //    ->innerJoin('node.creator', 'userCreator')
428
            ->leftJoin('node.resourceLinks', 'links')
429
//            ->leftJoin('node.resourceFile', 'file')
430
            ->where('node.id = :id')
431
            ->setParameters([
432
                'id' => $resourceNodeId,
433
            ])
434
        ;
435
436
        return $qb->getQuery()->getOneOrNullResult();
437
    }
438
439
    public function delete(ResourceInterface $resource): void
440
    {
441
        $em = $this->getEntityManager();
442
        $children = $resource->getResourceNode()->getChildren();
443
        foreach ($children as $child) {
444
            if ($child->hasResourceFile()) {
445
                $em->remove($child->getResourceFile());
446
            }
447
            $resourceNode = $this->getResourceFromResourceNode($child->getId());
448
            if (null !== $resourceNode) {
449
                $this->delete($resourceNode);
450
            }
451
        }
452
453
        $em->remove($resource);
454
        $em->flush();
455
    }
456
457
    /**
458
     * Deletes several entities: AbstractResource (Ex: CDocument, CQuiz), ResourceNode,
459
     * ResourceLinks and ResourceFile (including files via Flysystem).
460
     */
461
    public function hardDelete(AbstractResource $resource): void
462
    {
463
        $em = $this->getEntityManager();
464
        $em->remove($resource);
465
        $em->flush();
466
    }
467
468
    public function getResourceFileContent(AbstractResource $resource): string
469
    {
470
        try {
471
            $resourceNode = $resource->getResourceNode();
472
473
            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

473
            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...
474
        } catch (Throwable $throwable) {
475
            throw new FileNotFoundException($resource->getResourceName());
476
        }
477
    }
478
479
    public function getResourceNodeFileContent(ResourceNode $resourceNode): string
480
    {
481
        return $this->resourceNodeRepository->getResourceNodeFileContent($resourceNode);
482
    }
483
484
    /**
485
     * @return false|resource
486
     */
487
    public function getResourceNodeFileStream(ResourceNode $resourceNode)
488
    {
489
        return $this->resourceNodeRepository->getResourceNodeFileStream($resourceNode);
490
    }
491
492
    public function getResourceFileDownloadUrl(AbstractResource $resource, array $extraParams = [], ?int $referenceType = null): string
493
    {
494
        $extraParams['mode'] = 'download';
495
496
        return $this->getResourceFileUrl($resource, $extraParams, $referenceType);
497
    }
498
499
    public function getResourceFileUrl(AbstractResource $resource, array $extraParams = [], ?int $referenceType = null): string
500
    {
501
        return $this->getResourceNodeRepository()->getResourceFileUrl(
502
            $resource->getResourceNode(),
503
            $extraParams,
504
            $referenceType
505
        );
506
    }
507
508
    public function updateResourceFileContent(AbstractResource $resource, string $content): bool
509
    {
510
        $resourceNode = $resource->getResourceNode();
511
        if ($resourceNode->hasResourceFile()) {
512
            $resourceNode->setContent($content);
513
            $resourceNode->getResourceFile()->setSize(\strlen($content));
514
515
            return true;
516
        }
517
518
        return false;
519
    }
520
521
    public function setResourceName(AbstractResource $resource, $title): void
522
    {
523
        if (!empty($title)) {
524
            $resource->setResourceName($title);
525
            $resourceNode = $resource->getResourceNode();
526
            $resourceNode->setTitle($title);
527
        }
528
529
        //if ($resourceNode->hasResourceFile()) {
530
            //$resourceNode->getResourceFile()->getFile()->
531
            //$resourceNode->getResourceFile()->setName($title);
532
            //$resourceFile->setName($title);
533
534
            /*$fileName = $this->getResourceNodeRepository()->getFilename($resourceFile);
535
            error_log('$fileName');
536
            error_log($fileName);
537
            error_log($title);
538
            $this->getResourceNodeRepository()->getFileSystem()->rename($fileName, $title);
539
            $resourceFile->setName($title);
540
            $resourceFile->setOriginalName($title);*/
541
        //}
542
    }
543
544
    /**
545
     * Change all links visibility to DELETED.
546
     */
547
    public function softDelete(AbstractResource $resource): void
548
    {
549
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_DELETED);
550
    }
551
552
    public function setVisibilityPublished(AbstractResource $resource): void
553
    {
554
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_PUBLISHED);
555
    }
556
557
    public function setVisibilityDeleted(AbstractResource $resource): void
558
    {
559
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_DELETED);
560
    }
561
562
    public function setVisibilityDraft(AbstractResource $resource): void
563
    {
564
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_DRAFT);
565
    }
566
567
    public function setVisibilityPending(AbstractResource $resource): void
568
    {
569
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_PENDING);
570
    }
571
572
    public function addResourceNode(ResourceInterface $resource, User $creator, ResourceInterface $parentResource): ResourceNode
573
    {
574
        $parentResourceNode = $parentResource->getResourceNode();
575
576
        return $this->createNodeForResource($resource, $creator, $parentResourceNode);
577
    }
578
579
    /**
580
     * @todo remove this function and merge it with addResourceNode()
581
     */
582
    public function createNodeForResource(ResourceInterface $resource, User $creator, ResourceNode $parentNode, UploadedFile $file = null): ResourceNode
583
    {
584
        $em = $this->getEntityManager();
585
586
        $resourceType = $this->getResourceType();
587
        $resourceName = $resource->getResourceName();
588
        $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

588
        /** @scrutinizer ignore-call */ 
589
        $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...
589
590
        if (empty($extension)) {
591
            $slug = $this->slugify->slugify($resourceName);
592
        } else {
593
            $originalExtension = pathinfo($resourceName, PATHINFO_EXTENSION);
594
            $originalBasename = basename($resourceName, $originalExtension);
595
            $slug = sprintf('%s.%s', $this->slugify->slugify($originalBasename), $originalExtension);
596
        }
597
598
        $resourceNode = new ResourceNode();
599
        $resourceNode
600
            ->setTitle($resourceName)
601
            ->setSlug($slug)
602
            ->setCreator($creator)
603
            ->setResourceType($resourceType)
604
        ;
605
606
        if (null !== $parentNode) {
607
            $resourceNode->setParent($parentNode);
608
        }
609
610
        $resource->setResourceNode($resourceNode);
611
        $em->persist($resourceNode);
612
        $em->persist($resource);
613
614
        if (null !== $file) {
615
            $this->addFile($resource, $file);
616
        }
617
618
        return $resourceNode;
619
    }
620
621
    /**
622
     * This is only used during installation for the special nodes (admin and AccessUrl).
623
     */
624
    public function createNodeForResourceWithNoParent(ResourceInterface $resource, User $creator): ResourceNode
625
    {
626
        $em = $this->getEntityManager();
627
628
        $resourceType = $this->getResourceType();
629
        $resourceName = $resource->getResourceName();
630
        $slug = $this->slugify->slugify($resourceName);
631
        $resourceNode = new ResourceNode();
632
        $resourceNode
633
            ->setTitle($resourceName)
634
            ->setSlug($slug)
635
            ->setCreator($creator)
636
            ->setResourceType($resourceType)
637
        ;
638
        $resource->setResourceNode($resourceNode);
639
        $em->persist($resourceNode);
640
        $em->persist($resource);
641
642
        return $resourceNode;
643
    }
644
645
    public function getTotalSpaceByCourse(Course $course, CGroup $group = null, Session $session = null): int
646
    {
647
        $qb = $this->createQueryBuilder('resource');
648
        $qb
649
            ->select('SUM(file.size) as total')
650
            ->innerJoin('resource.resourceNode', 'node')
651
            ->innerJoin('node.resourceLinks', 'l')
652
            ->innerJoin('node.resourceFile', 'file')
653
            ->where('l.course = :course')
654
            ->andWhere('l.visibility <> :visibility')
655
            ->andWhere('file IS NOT NULL')
656
            ->setParameters(
657
                [
658
                    'course' => $course,
659
                    'visibility' => ResourceLink::VISIBILITY_DELETED,
660
                ]
661
            )
662
        ;
663
664
        if (null === $group) {
665
            $qb->andWhere('l.group IS NULL');
666
        } else {
667
            $qb
668
                ->andWhere('l.group = :group')
669
                ->setParameter('group', $group)
670
            ;
671
        }
672
673
        if (null === $session) {
674
            $qb->andWhere('l.session IS NULL');
675
        } else {
676
            $qb
677
                ->andWhere('l.session = :session')
678
                ->setParameter('session', $session)
679
            ;
680
        }
681
682
        $query = $qb->getQuery();
683
684
        return (int) $query->getSingleScalarResult();
685
    }
686
687
    public function addTitleDecoration(AbstractResource $resource, Course $course, Session $session = null): string
688
    {
689
        if (null === $session) {
690
            return '';
691
        }
692
693
        $link = $resource->getFirstResourceLinkFromCourseSession($course, $session);
694
        if (null === $link) {
695
            return '';
696
        }
697
698
        return '<img title="'.$session->getName().'" src="/img/icons/22/star.png" />';
699
    }
700
701
    public function isGranted(string $subject, AbstractResource $resource): bool
702
    {
703
        return $this->getAuthorizationChecker()->isGranted($subject, $resource->getResourceNode());
704
    }
705
706
    /**
707
     * Changes the visibility of the children that matches the exact same link.
708
     */
709
    public function copyVisibilityToChildren(ResourceNode $resourceNode, ResourceLink $link): bool
710
    {
711
        $children = $resourceNode->getChildren();
712
713
        if (0 === $children->count()) {
714
            return false;
715
        }
716
717
        $em = $this->getEntityManager();
718
719
        /** @var ResourceNode $child */
720
        foreach ($children as $child) {
721
            if ($child->getChildren()->count() > 0) {
722
                $this->copyVisibilityToChildren($child, $link);
723
            }
724
725
            $links = $child->getResourceLinks();
726
            foreach ($links as $linkItem) {
727
                if ($linkItem->getUser() === $link->getUser() &&
728
                    $linkItem->getSession() === $link->getSession() &&
729
                    $linkItem->getCourse() === $link->getCourse() &&
730
                    $linkItem->getUserGroup() === $link->getUserGroup()
731
                ) {
732
                    $linkItem->setVisibility($link->getVisibility());
733
                    $em->persist($linkItem);
734
                }
735
            }
736
        }
737
738
        $em->flush();
739
740
        return true;
741
    }
742
743
    protected function addTitleQueryBuilder(?string $title, QueryBuilder $qb = null): QueryBuilder
744
    {
745
        $qb = $this->getOrCreateQueryBuilder($qb);
746
        if (null === $title) {
747
            return $qb;
748
        }
749
750
        $qb
751
            ->andWhere('node.title = :title')
752
            ->setParameter('title', $title)
753
        ;
754
755
        return $qb;
756
    }
757
758
    protected function addCreatorQueryBuilder(?User $user, QueryBuilder $qb = null): QueryBuilder
759
    {
760
        $qb = $this->getOrCreateQueryBuilder($qb);
761
        if (null === $user) {
762
            return $qb;
763
        }
764
765
        $qb
766
            ->andWhere('node.creator = :creator')
767
            ->setParameter('creator', $user)
768
        ;
769
770
        return $qb;
771
    }
772
773
    private function setLinkVisibility(AbstractResource $resource, int $visibility, bool $recursive = true): bool
774
    {
775
        $resourceNode = $resource->getResourceNode();
776
777
        if (null === $resourceNode) {
778
            return false;
779
        }
780
781
        $em = $this->getEntityManager();
782
        if ($recursive) {
783
            $children = $resourceNode->getChildren();
784
            if (!empty($children)) {
785
                /** @var ResourceNode $child */
786
                foreach ($children as $child) {
787
                    $criteria = [
788
                        'resourceNode' => $child,
789
                    ];
790
                    $childDocument = $this->findOneBy($criteria);
791
                    if ($childDocument) {
792
                        $this->setLinkVisibility($childDocument, $visibility);
793
                    }
794
                }
795
            }
796
        }
797
798
        $links = $resourceNode->getResourceLinks();
799
800
        if (!empty($links)) {
801
            /** @var ResourceLink $link */
802
            foreach ($links as $link) {
803
                $link->setVisibility($visibility);
804
                if (ResourceLink::VISIBILITY_DRAFT === $visibility) {
805
                    $editorMask = ResourceNodeVoter::getEditorMask();
806
                    //$rights = [];
807
                    $resourceRight = new ResourceRight();
808
                    $resourceRight
809
                        ->setMask($editorMask)
810
                        ->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)
811
                        ->setResourceLink($link)
812
                    ;
813
                    $link->addResourceRight($resourceRight);
814
                } else {
815
                    $link->setResourceRights(new ArrayCollection());
816
                }
817
                $em->persist($link);
818
            }
819
        }
820
        $em->flush();
821
822
        return true;
823
    }
824
}
825