Passed
Push — master ( f8f106...a015d1 )
by Julito
08:38
created

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

240
        /** @scrutinizer ignore-call */ 
241
        $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...
241
242
        $repo = $this->getEntityManager()->getRepository(ResourceType::class);
243
244
        return $repo->findOneBy([
245
            'name' => $resourceTypeName,
246
        ]);
247
    }
248
249
    public function addVisibilityQueryBuilder(QueryBuilder $qb = null): QueryBuilder
250
    {
251
        $qb = $this->getOrCreateQueryBuilder($qb);
252
253
        $checker = $this->getAuthorizationChecker();
254
        $isAdmin =
255
            $checker->isGranted('ROLE_ADMIN') ||
256
            $checker->isGranted('ROLE_CURRENT_COURSE_TEACHER');
257
258
        // Do not show deleted resources.
259
        $qb
260
            ->andWhere('links.visibility != :visibilityDeleted')
261
            ->setParameter('visibilityDeleted', ResourceLink::VISIBILITY_DELETED, Types::INTEGER)
262
        ;
263
264
        if (!$isAdmin) {
265
            $qb
266
                ->andWhere('links.visibility = :visibility')
267
                ->setParameter('visibility', ResourceLink::VISIBILITY_PUBLISHED, Types::INTEGER)
268
            ;
269
            // @todo Add start/end visibility restrictions.
270
        }
271
272
        return $qb;
273
    }
274
275
    public function addCourseQueryBuilder(Course $course, QueryBuilder $qb): QueryBuilder
276
    {
277
        $qb
278
            ->andWhere('links.course = :course')
279
            ->setParameter('course', $course)
280
        ;
281
282
        return $qb;
283
    }
284
285
    public function addCourseSessionGroupQueryBuilder(Course $course, Session $session = null, CGroup $group = null, QueryBuilder $qb = null): QueryBuilder
286
    {
287
        $reflectionClass = $this->getClassMetadata()->getReflectionClass();
288
289
        // Check if this resource type requires to load the base course resources when using a session
290
        $loadBaseSessionContent = $reflectionClass->hasProperty('loadCourseResourcesInSession');
291
292
        $this->addCourseQueryBuilder($course, $qb);
293
294
        if (null === $session) {
295
            $qb->andWhere(
296
                $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

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

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

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