Passed
Push — master ( 6f8b91...26ffea )
by Julito
10:53
created

addCourseSessionGroupQueryBuilder()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 39
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 23
nc 6
nop 4
dl 0
loc 39
rs 9.552
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Repository;
8
9
use Chamilo\CoreBundle\Component\Resource\Settings;
10
use Chamilo\CoreBundle\Component\Resource\Template;
11
use Chamilo\CoreBundle\Entity\AbstractResource;
12
use Chamilo\CoreBundle\Entity\Course;
13
use Chamilo\CoreBundle\Entity\ResourceFile;
14
use Chamilo\CoreBundle\Entity\ResourceInterface;
15
use Chamilo\CoreBundle\Entity\ResourceLink;
16
use Chamilo\CoreBundle\Entity\ResourceNode;
17
use Chamilo\CoreBundle\Entity\ResourceRight;
18
use Chamilo\CoreBundle\Entity\ResourceType;
19
use Chamilo\CoreBundle\Entity\Session;
20
use Chamilo\CoreBundle\Entity\User;
21
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
22
use Chamilo\CourseBundle\Entity\CGroup;
23
use Chamilo\CourseBundle\Traits\NonResourceRepository;
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\Form\FormFactory;
34
use Symfony\Component\Form\FormInterface;
35
use Symfony\Component\HttpFoundation\File\UploadedFile;
36
use Throwable;
37
38
/**
39
 * Extends EntityRepository is needed to process settings.
40
 */
41
abstract class ResourceRepository extends ServiceEntityRepository
42
{
43
    use NonResourceRepository;
44
45
    protected Settings $settings;
46
    protected Template $templates;
47
    protected ?ResourceType $resourceType = null;
48
49
    public function setSettings(Settings $settings): self
50
    {
51
        $this->settings = $settings;
52
53
        return $this;
54
    }
55
56
    public function setTemplates(Template $templates): self
57
    {
58
        $this->templates = $templates;
59
60
        return $this;
61
    }
62
63
    public function getResourceSettings(): Settings
64
    {
65
        return $this->settings;
66
    }
67
68
    public function getTemplates(): Template
69
    {
70
        return $this->templates;
71
    }
72
73
    public function getClassName(): string
74
    {
75
        $class = static::class;
76
        //Chamilo\CoreBundle\Repository\Node\IllustrationRepository
77
        $class = str_replace('\\Repository\\', '\\Entity\\', $class);
78
        $class = str_replace('Repository', '', $class);
79
        if (!class_exists($class)) {
80
            throw new Exception(sprintf('Repo: %s not found ', $class));
81
        }
82
83
        return $class;
84
    }
85
86
    public function getCount(QueryBuilder $qb): int
87
    {
88
        $qb->select('count(resource)');
89
        $qb->setMaxResults(1);
90
91
        return (int) $qb->getQuery()->getSingleScalarResult();
92
    }
93
94
    /**
95
     * @return FormInterface
96
     */
97
    public function getForm(FormFactory $formFactory, ResourceInterface $resource = null, array $options = [])
98
    {
99
        $formType = $this->getResourceFormType();
100
101
        if (null === $resource) {
102
            $className = $this->repository->getClassName();
103
            $resource = new $className();
104
        }
105
106
        return $formFactory->create($formType, $resource, $options);
107
    }
108
109
    public function getResourceByResourceNode(ResourceNode $resourceNode): ?ResourceInterface
110
    {
111
        return $this->findOneBy([
112
            'resourceNode' => $resourceNode,
113
        ]);
114
    }
115
116
    /*public function findOneBy(array $criteria, array $orderBy = null)
117
    {
118
        return $this->findOneBy($criteria, $orderBy);
119
    }*/
120
121
    /*public function updateResource(AbstractResource $resource)
122
    {
123
        $em = $this->getEntityManager();
124
125
        $resourceNode = $resource->getResourceNode();
126
        $resourceNode->setTitle($resource->getResourceName());
127
128
        $links = $resource->getResourceLinkEntityList();
129
        if ($links) {
130
            foreach ($links as $link) {
131
                $link->setResourceNode($resourceNode);
132
133
                $rights = [];
134
                switch ($link->getVisibility()) {
135
                    case ResourceLink::VISIBILITY_PENDING:
136
                    case ResourceLink::VISIBILITY_DRAFT:
137
                        $editorMask = ResourceNodeVoter::getEditorMask();
138
                        $resourceRight = new ResourceRight();
139
                        $resourceRight
140
                            ->setMask($editorMask)
141
                            ->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)
142
                        ;
143
                        $rights[] = $resourceRight;
144
145
                        break;
146
                }
147
148
                if (!empty($rights)) {
149
                    foreach ($rights as $right) {
150
                        $link->addResourceRight($right);
151
                    }
152
                }
153
                $em->persist($link);
154
            }
155
        }
156
157
        $em->persist($resourceNode);
158
        $em->persist($resource);
159
        $em->flush();
160
    }*/
161
162
    public function create(AbstractResource $resource): void
163
    {
164
        $this->getEntityManager()->persist($resource);
165
        $this->getEntityManager()->flush();
166
    }
167
168
    public function update(AbstractResource $resource, bool $andFlush = true): void
169
    {
170
        if (!$resource->hasResourceNode()) {
171
            throw new Exception('Resource needs a resource node');
172
        }
173
174
        $resource->getResourceNode()->setUpdatedAt(new DateTime());
175
        $resource->getResourceNode()->setTitle($resource->getResourceName());
176
        $this->getEntityManager()->persist($resource);
177
178
        if ($andFlush) {
179
            $this->getEntityManager()->flush();
180
        }
181
    }
182
183
    public function updateNodeForResource(ResourceInterface $resource): ResourceNode
184
    {
185
        $em = $this->getEntityManager();
186
187
        $resourceNode = $resource->getResourceNode();
188
        $resourceName = $resource->getResourceName();
189
190
        if ($resourceNode->hasResourceFile()) {
191
            $resourceFile = $resourceNode->getResourceFile();
192
            if (null !== $resourceFile) {
193
                $originalName = $resourceFile->getOriginalName();
194
                $originalExtension = pathinfo($originalName, PATHINFO_EXTENSION);
195
196
                //$originalBasename = \basename($resourceName, $originalExtension);
197
                /*$slug = sprintf(
198
                    '%s.%s',
199
                    $this->slugify->slugify($originalBasename),
200
                    $this->slugify->slugify($originalExtension)
201
                );*/
202
203
                $newOriginalName = sprintf('%s.%s', $resourceName, $originalExtension);
204
                $resourceFile->setOriginalName($newOriginalName);
205
206
                $em->persist($resourceFile);
207
            }
208
        }
209
        //$slug = $this->slugify->slugify($resourceName);
210
211
        $resourceNode->setTitle($resourceName);
212
        //$resourceNode->setSlug($slug);
213
214
        $em->persist($resourceNode);
215
        $em->persist($resource);
216
217
        $em->flush();
218
219
        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...
220
    }
221
222
    public function findCourseResourceByTitle(
223
        string $title,
224
        ResourceNode $parentNode,
225
        Course $course,
226
        Session $session = null,
227
        CGroup $group = null
228
    ): ?ResourceInterface {
229
        $qb = $this->getResourcesByCourse($course, $session, $group, $parentNode);
230
        $this->addTitleQueryBuilder($title, $qb);
231
        $qb->setMaxResults(1);
232
233
        return $qb->getQuery()->getOneOrNullResult();
234
    }
235
236
    public function findCourseResourcesByTitle(
237
        string $title,
238
        ResourceNode $parentNode,
239
        Course $course,
240
        Session $session = null,
241
        CGroup $group = null
242
    ) {
243
        $qb = $this->getResourcesByCourse($course, $session, $group, $parentNode);
244
        $this->addTitleQueryBuilder($title, $qb);
245
246
        return $qb->getQuery()->getResult();
247
    }
248
249
    /**
250
     * @todo clean path
251
     */
252
    public function addFileFromPath(ResourceInterface $resource, string $fileName, string $path, bool $flush = true)
253
    {
254
        if (!empty($path) && file_exists($path) && !is_dir($path)) {
255
            $mimeType = mime_content_type($path);
256
            $file = new UploadedFile($path, $fileName, $mimeType, null, true);
257
258
            return $this->addFile($resource, $file, '', $flush);
259
        }
260
261
        return null;
262
    }
263
264
    public function addFileFromString(ResourceInterface $resource, string $fileName, string $mimeType, string $content, bool $flush = true): ?ResourceFile
265
    {
266
        $handle = tmpfile();
267
        fwrite($handle, $content);
268
        $meta = stream_get_meta_data($handle);
269
        $file = new UploadedFile($meta['uri'], $fileName, $mimeType, null, true);
270
271
        return $this->addFile($resource, $file, '', $flush);
272
    }
273
274
    public function addFileFromFileRequest(ResourceInterface $resource, string $fileKey, bool $flush = true): ?ResourceFile
275
    {
276
        $request = $this->getRequest();
277
        if ($request->files->has($fileKey)) {
278
            $file = $request->files->get($fileKey);
279
            if (null !== $file) {
280
                $resourceFile = $this->addFile($resource, $file);
281
                if ($flush) {
282
                    $this->getEntityManager()->flush();
283
                }
284
285
                return $resourceFile;
286
            }
287
        }
288
289
        return null;
290
    }
291
292
    public function addFile(ResourceInterface $resource, UploadedFile $file, string $description = '', bool $flush = false): ?ResourceFile
293
    {
294
        $resourceNode = $resource->getResourceNode();
295
296
        if (null === $resourceNode) {
297
            throw new LogicException('Resource node is null');
298
        }
299
300
        $resourceFile = $resourceNode->getResourceFile();
301
        if (null === $resourceFile) {
302
            $resourceFile = new ResourceFile();
303
        }
304
305
        $em = $this->getEntityManager();
306
        $resourceFile
307
            ->setFile($file)
308
            ->setDescription($description)
309
            ->setName($resource->getResourceName())
310
            ->setResourceNode($resourceNode)
311
        ;
312
        $em->persist($resourceFile);
313
        $resourceNode->setResourceFile($resourceFile);
314
        $em->persist($resourceNode);
315
316
        if ($flush) {
317
            $em->flush();
318
        }
319
320
        return $resourceFile;
321
    }
322
323
    public function getResourceType(): ?ResourceType
324
    {
325
        $name = $this->getResourceTypeName();
326
        $repo = $this->getEntityManager()->getRepository(ResourceType::class);
327
        $this->resourceType = $repo->findOneBy([
328
            'name' => $name,
329
        ]);
330
331
        return $this->resourceType;
332
    }
333
334
    public function getResourceTypeName(): string
335
    {
336
        return $this->toolChain->getResourceTypeNameFromRepository(static::class);
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

336
        return $this->toolChain->/** @scrutinizer ignore-call */ getResourceTypeNameFromRepository(static::class);

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...
337
    }
338
339
    public function addVisibilityQueryBuilder(QueryBuilder $qb = null): QueryBuilder
340
    {
341
        $qb = $this->getOrCreateQueryBuilder($qb);
342
343
        $checker = $this->getAuthorizationChecker();
344
        $isAdmin =
345
            $checker->isGranted('ROLE_ADMIN') ||
346
            $checker->isGranted('ROLE_CURRENT_COURSE_TEACHER');
347
348
        // Do not show deleted resources.
349
        $qb
350
            ->andWhere('links.visibility != :visibilityDeleted')
351
            ->setParameter('visibilityDeleted', ResourceLink::VISIBILITY_DELETED, Types::INTEGER)
352
        ;
353
354
        if (!$isAdmin) {
355
            $qb
356
                ->andWhere('links.visibility = :visibility')
357
                ->setParameter('visibility', ResourceLink::VISIBILITY_PUBLISHED, Types::INTEGER)
358
            ;
359
            // @todo Add start/end visibility restrictions.
360
        }
361
362
        return $qb;
363
    }
364
365
    public function addCourseQueryBuilder(Course $course, QueryBuilder $qb): QueryBuilder
366
    {
367
        $qb
368
            ->andWhere('links.course = :course')
369
            ->setParameter('course', $course)
370
        ;
371
372
        return $qb;
373
    }
374
375
    public function addCourseSessionGroupQueryBuilder(Course $course, Session $session = null, CGroup $group = null, QueryBuilder $qb = null): QueryBuilder
376
    {
377
        $reflectionClass = $this->getClassMetadata()->getReflectionClass();
378
379
        // Check if this resource type requires to load the base course resources when using a session
380
        $loadBaseSessionContent = $reflectionClass->hasProperty('loadCourseResourcesInSession');
381
382
        $this->addCourseQueryBuilder($course, $qb);
383
384
        if (null === $session) {
385
            $qb->andWhere(
386
                $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

386
                $qb->/** @scrutinizer ignore-call */ 
387
                     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...
387
                    $qb->expr()->isNull('links.session'),
388
                    $qb->expr()->eq('links.session', 0)
389
                )
390
            );
391
        } elseif ($loadBaseSessionContent) {
392
            // Load course base content.
393
            $qb->andWhere('links.session = :session OR links.session IS NULL');
394
            $qb->setParameter('session', $session);
395
        } else {
396
            // Load only session resources.
397
            $qb->andWhere('links.session = :session');
398
            $qb->setParameter('session', $session);
399
        }
400
401
        if (null === $group) {
402
            $qb->andWhere(
403
                $qb->expr()->orX(
404
                    $qb->expr()->isNull('links.group'),
405
                    $qb->expr()->eq('links.group', 0)
406
                )
407
            );
408
        } else {
409
            $qb->andWhere('links.group = :group');
410
            $qb->setParameter('group', $group);
411
        }
412
413
        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...
414
    }
415
416
    public function getResources(ResourceNode $parentNode = null): QueryBuilder
417
    {
418
        $resourceTypeName = $this->getResourceTypeName();
419
420
        $qb = $this->createQueryBuilder('resource')
421
            ->select('resource')
422
            ->innerJoin('resource.resourceNode', 'node')
423
            ->innerJoin('node.resourceLinks', 'links')
424
            ->innerJoin('node.resourceType', 'type')
425
            ->leftJoin('node.resourceFile', 'file')
426
            ->where('type.name = :type')
427
            ->setParameter('type', $resourceTypeName, Types::STRING)
428
            ->addSelect('node')
429
            ->addSelect('links')
430
            ->addSelect('type')
431
            ->addSelect('file')
432
        ;
433
434
        if (null !== $parentNode) {
435
            $qb->andWhere('node.parent = :parentNode');
436
            $qb->setParameter('parentNode', $parentNode);
437
        }
438
439
        return $qb;
440
    }
441
442
    public function getResourcesByCourse(Course $course, Session $session = null, CGroup $group = null, ResourceNode $parentNode = null): QueryBuilder
443
    {
444
        $qb = $this->getResources($parentNode);
445
        $this->addVisibilityQueryBuilder($qb);
446
        $this->addCourseSessionGroupQueryBuilder($course, $session, $group, $qb);
447
448
        return $qb;
449
    }
450
451
    /**
452
     * Get resources only from the base course.
453
     */
454
    public function getResourcesByCourseOnly(Course $course, ResourceNode $parentNode = null): QueryBuilder
455
    {
456
        $qb = $this->getResources($parentNode);
457
        $this->addCourseQueryBuilder($course, $qb);
458
        $this->addVisibilityQueryBuilder($qb);
459
460
        return $qb;
461
    }
462
463
    public function getResourceByCreatorFromTitle(
464
        string $title,
465
        User $user,
466
        ResourceNode $parentNode
467
    ): ?ResourceInterface {
468
        $qb = $this->getResourcesByCreator($user, $parentNode);
469
        $this->addTitleQueryBuilder($title, $qb);
470
        $qb->setMaxResults(1);
471
472
        return $qb->getQuery()->getOneOrNullResult();
473
    }
474
475
    public function getResourcesByCreator(User $user, ResourceNode $parentNode = null): QueryBuilder
476
    {
477
        $qb = $this->createQueryBuilder('resource')
478
            ->select('resource')
479
            ->innerJoin('resource.resourceNode', 'node')
480
        ;
481
482
        if (null !== $parentNode) {
483
            $qb->andWhere('node.parent = :parentNode');
484
            $qb->setParameter('parentNode', $parentNode);
485
        }
486
487
        $this->addCreatorQueryBuilder($user, $qb);
488
489
        return $qb;
490
    }
491
492
    public function getResourcesByCourseLinkedToUser(
493
        User $user,
494
        Course $course,
495
        Session $session = null,
496
        CGroup $group = null,
497
        ResourceNode $parentNode = null
498
    ): QueryBuilder {
499
        $qb = $this->getResourcesByCourse($course, $session, $group, $parentNode);
500
        $qb->andWhere('node.creator = :user OR (links.user = :user OR links.user IS NULL)');
501
        $qb->setParameter('user', $user);
502
503
        return $qb;
504
    }
505
506
    public function getResourcesByLinkedUser(User $user, ResourceNode $parentNode = null): QueryBuilder
507
    {
508
        $qb = $this->getResources($parentNode);
509
        $qb
510
            ->andWhere('links.user = :user')
511
            ->setParameter('user', $user)
512
        ;
513
514
        $this->addVisibilityQueryBuilder($qb);
515
516
        return $qb;
517
    }
518
519
    public function getResourceFromResourceNode(int $resourceNodeId): ?ResourceInterface
520
    {
521
        $qb = $this->createQueryBuilder('resource')
522
            ->select('resource')
523
            ->addSelect('node')
524
            ->addSelect('links')
525
            ->innerJoin('resource.resourceNode', 'node')
526
        //    ->innerJoin('node.creator', 'userCreator')
527
            ->innerJoin('node.resourceLinks', 'links')
528
//            ->leftJoin('node.resourceFile', 'file')
529
            ->where('node.id = :id')
530
            ->setParameters([
531
                'id' => $resourceNodeId,
532
            ])
533
            //->addSelect('node')
534
        ;
535
536
        return $qb->getQuery()->getOneOrNullResult();
537
    }
538
539
    public function delete(ResourceInterface $resource): void
540
    {
541
        $children = $resource->getResourceNode()->getChildren();
542
        foreach ($children as $child) {
543
            if ($child->hasResourceFile()) {
544
                $this->getEntityManager()->remove($child->getResourceFile());
545
            }
546
            $resourceNode = $this->getResourceFromResourceNode($child->getId());
547
            if (null !== $resourceNode) {
548
                $this->delete($resourceNode);
549
            }
550
        }
551
        $this->getEntityManager()->remove($resource);
552
        $this->getEntityManager()->flush();
553
    }
554
555
    /**
556
     * Deletes several entities: AbstractResource (Ex: CDocument, CQuiz), ResourceNode,
557
     * ResourceLinks and ResourceFile (including files via Flysystem).
558
     */
559
    public function hardDelete(AbstractResource $resource): void
560
    {
561
        $em = $this->getEntityManager();
562
        $em->remove($resource);
563
        $em->flush();
564
    }
565
566
    public function getResourceFileContent(AbstractResource $resource): string
567
    {
568
        try {
569
            $resourceNode = $resource->getResourceNode();
570
571
            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

571
            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...
572
        } catch (Throwable $throwable) {
573
            throw new FileNotFoundException($resource->getResourceName());
574
        }
575
    }
576
577
    public function getResourceNodeFileContent(ResourceNode $resourceNode): string
578
    {
579
        return $this->resourceNodeRepository->getResourceNodeFileContent($resourceNode);
580
    }
581
582
    public function getResourceNodeFileStream(ResourceNode $resourceNode)
583
    {
584
        return $this->resourceNodeRepository->getResourceNodeFileStream($resourceNode);
585
    }
586
587
    public function getResourceFileDownloadUrl(AbstractResource $resource, array $extraParams = [], $referenceType = null): string
588
    {
589
        $extraParams['mode'] = 'download';
590
591
        return $this->getResourceFileUrl($resource, $extraParams, $referenceType);
592
    }
593
594
    public function getResourceFileUrl(AbstractResource $resource, array $extraParams = [], $referenceType = null): string
595
    {
596
        return $this->getResourceNodeRepository()->getResourceFileUrl(
597
            $resource->getResourceNode(),
598
            $extraParams,
599
            $referenceType
600
        );
601
    }
602
603
    /**
604
     * @return bool
605
     */
606
    public function updateResourceFileContent(AbstractResource $resource, string $content)
607
    {
608
        error_log('updateResourceFileContent');
609
610
        $resourceNode = $resource->getResourceNode();
611
        if ($resourceNode->hasResourceFile()) {
612
            $resourceNode->setContent($content);
613
            error_log('updated');
614
            $resourceNode->getResourceFile()->setSize(\strlen($content));
615
            /*
616
            error_log('has file');
617
            $resourceFile = $resourceNode->getResourceFile();
618
            if ($resourceFile) {
619
                error_log('$resourceFile');
620
                $title = $resource->getResourceName();
621
                $handle = tmpfile();
622
                fwrite($handle, $content);
623
                error_log($title);
624
                error_log($content);
625
                $meta = stream_get_meta_data($handle);
626
                $file = new UploadedFile($meta['uri'], $title, 'text/html', null, true);
627
                $resource->setUploadFile($file);
628
629
                return true;
630
            }*/
631
        }
632
        error_log('false');
633
634
        return false;
635
    }
636
637
    public function setResourceName(AbstractResource $resource, $title): void
638
    {
639
        $resource->setResourceName($title);
640
        $resourceNode = $resource->getResourceNode();
641
        $resourceNode->setTitle($title);
642
        if ($resourceNode->hasResourceFile()) {
643
            //$resourceNode->getResourceFile()->getFile()->
644
            //$resourceNode->getResourceFile()->setName($title);
645
            //$resourceFile->setName($title);
646
647
            /*$fileName = $this->getResourceNodeRepository()->getFilename($resourceFile);
648
            error_log('$fileName');
649
            error_log($fileName);
650
            error_log($title);
651
            $this->getResourceNodeRepository()->getFileSystem()->rename($fileName, $title);
652
            $resourceFile->setName($title);
653
            $resourceFile->setOriginalName($title);*/
654
        }
655
    }
656
657
    /**
658
     * Change all links visibility to DELETED.
659
     */
660
    public function softDelete(AbstractResource $resource): void
661
    {
662
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_DELETED);
663
    }
664
665
    public function setVisibilityPublished(AbstractResource $resource): void
666
    {
667
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_PUBLISHED);
668
    }
669
670
    public function setVisibilityDeleted(AbstractResource $resource): void
671
    {
672
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_DELETED);
673
    }
674
675
    public function setVisibilityDraft(AbstractResource $resource): void
676
    {
677
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_DRAFT);
678
    }
679
680
    public function setVisibilityPending(AbstractResource $resource): void
681
    {
682
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_PENDING);
683
    }
684
685
    public function addResourceNode(ResourceInterface $resource, User $creator, ResourceInterface $parentResource): ResourceNode
686
    {
687
        $parentResourceNode = $parentResource->getResourceNode();
688
689
        return $this->createNodeForResource($resource, $creator, $parentResourceNode);
690
    }
691
692
    /**
693
     * @todo remove this function and merge it with addResourceNode()
694
     */
695
    public function createNodeForResource(ResourceInterface $resource, User $creator, ResourceNode $parentNode, UploadedFile $file = null): ResourceNode
696
    {
697
        $em = $this->getEntityManager();
698
699
        $resourceType = $this->getResourceType();
700
        $resourceName = $resource->getResourceName();
701
        $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

701
        /** @scrutinizer ignore-call */ 
702
        $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...
702
703
        if (empty($extension)) {
704
            $slug = $this->slugify->slugify($resourceName);
705
        } else {
706
            $originalExtension = pathinfo($resourceName, PATHINFO_EXTENSION);
707
            $originalBasename = basename($resourceName, $originalExtension);
708
            $slug = sprintf('%s.%s', $this->slugify->slugify($originalBasename), $originalExtension);
709
        }
710
711
        $resourceNode = new ResourceNode();
712
        $resourceNode
713
            ->setTitle($resourceName)
714
            ->setSlug($slug)
715
            ->setCreator($creator)
716
            ->setResourceType($resourceType)
717
        ;
718
719
        if (null !== $parentNode) {
720
            $resourceNode->setParent($parentNode);
721
        }
722
723
        $resource->setResourceNode($resourceNode);
724
        $em->persist($resourceNode);
725
        $em->persist($resource);
726
727
        if (null !== $file) {
728
            $this->addFile($resource, $file);
729
        }
730
731
        return $resourceNode;
732
    }
733
734
    /**
735
     * This is only used during installation for the special nodes (admin and AccessUrl).
736
     */
737
    public function createNodeForResourceWithNoParent(ResourceInterface $resource, User $creator): ResourceNode
738
    {
739
        $em = $this->getEntityManager();
740
741
        $resourceType = $this->getResourceType();
742
        $resourceName = $resource->getResourceName();
743
        $slug = $this->slugify->slugify($resourceName);
744
        $resourceNode = new ResourceNode();
745
        $resourceNode
746
            ->setTitle($resourceName)
747
            ->setSlug($slug)
748
            ->setCreator($creator)
749
            ->setResourceType($resourceType)
750
        ;
751
        $resource->setResourceNode($resourceNode);
752
        $em->persist($resourceNode);
753
        $em->persist($resource);
754
755
        return $resourceNode;
756
    }
757
758
    public function getTotalSpaceByCourse(Course $course, CGroup $group = null, Session $session = null): int
759
    {
760
        $qb = $this->createQueryBuilder('resource');
761
        $qb
762
            ->select('SUM(file.size) as total')
763
            ->innerJoin('resource.resourceNode', 'node')
764
            ->innerJoin('node.resourceLinks', 'l')
765
            ->innerJoin('node.resourceFile', 'file')
766
            ->where('l.course = :course')
767
            ->andWhere('l.visibility <> :visibility')
768
            ->andWhere('file IS NOT NULL')
769
            ->setParameters(
770
                [
771
                    'course' => $course,
772
                    'visibility' => ResourceLink::VISIBILITY_DELETED,
773
                ]
774
            )
775
        ;
776
777
        if (null === $group) {
778
            $qb->andWhere('l.group IS NULL');
779
        } else {
780
            $qb
781
                ->andWhere('l.group = :group')
782
                ->setParameter('group', $group)
783
            ;
784
        }
785
786
        if (null === $session) {
787
            $qb->andWhere('l.session IS NULL');
788
        } else {
789
            $qb
790
                ->andWhere('l.session = :session')
791
                ->setParameter('session', $session)
792
            ;
793
        }
794
795
        $query = $qb->getQuery();
796
797
        return (int) $query->getSingleScalarResult();
798
    }
799
800
    public function addTitleDecoration(AbstractResource $resource, Course $course, Session $session = null): string
801
    {
802
        if (null === $session) {
803
            return '';
804
        }
805
806
        $link = $resource->getFirstResourceLinkFromCourseSession($course, $session);
807
        if (null === $link) {
808
            return '';
809
        }
810
811
        return '<img title="'.$session->getName().'" src="/img/icons/22/star.png" />';
812
    }
813
814
    public function isGranted(string $subject, AbstractResource $resource): bool
815
    {
816
        return $this->getAuthorizationChecker()->isGranted($subject, $resource->getResourceNode());
817
    }
818
819
    /**
820
     * Changes the visibility of the children that matches the exact same link.
821
     */
822
    public function copyVisibilityToChildren(ResourceNode $resourceNode, ResourceLink $link): bool
823
    {
824
        $children = $resourceNode->getChildren();
825
826
        if (0 === $children->count()) {
827
            return false;
828
        }
829
830
        $em = $this->getEntityManager();
831
832
        /** @var ResourceNode $child */
833
        foreach ($children as $child) {
834
            if ($child->getChildren()->count() > 0) {
835
                $this->copyVisibilityToChildren($child, $link);
836
            }
837
838
            $links = $child->getResourceLinks();
839
            foreach ($links as $linkItem) {
840
                if ($linkItem->getUser() === $link->getUser() &&
841
                    $linkItem->getSession() === $link->getSession() &&
842
                    $linkItem->getCourse() === $link->getCourse() &&
843
                    $linkItem->getUserGroup() === $link->getUserGroup()
844
                ) {
845
                    $linkItem->setVisibility($link->getVisibility());
846
                    $em->persist($linkItem);
847
                }
848
            }
849
        }
850
851
        $em->flush();
852
853
        return true;
854
    }
855
856
    public function saveUpload(UploadedFile $file): ResourceInterface
857
    {
858
        throw new Exception('Implement saveUpload');
859
    }
860
861
    public function getResourceFormType(): string
862
    {
863
        throw new Exception('Implement getResourceFormType');
864
    }
865
866
    protected function getOrCreateQueryBuilder(QueryBuilder $qb = null, string $alias = 'resource'): QueryBuilder
867
    {
868
        return $qb ?: $this->createQueryBuilder($alias);
869
    }
870
871
    protected function addTitleQueryBuilder(?string $title, QueryBuilder $qb = null): QueryBuilder
872
    {
873
        $qb = $this->getOrCreateQueryBuilder($qb);
874
        if (null === $title) {
875
            return $qb;
876
        }
877
878
        $qb
879
            ->andWhere('node.title = :title')
880
            ->setParameter('title', $title)
881
        ;
882
883
        return $qb;
884
    }
885
886
    protected function addCreatorQueryBuilder(?User $user, QueryBuilder $qb = null): QueryBuilder
887
    {
888
        $qb = $this->getOrCreateQueryBuilder($qb);
889
        if (null === $user) {
890
            return $qb;
891
        }
892
893
        $qb
894
            ->andWhere('node.creator = :creator')
895
            ->setParameter('creator', $user)
896
        ;
897
898
        return $qb;
899
    }
900
901
    private function setLinkVisibility(AbstractResource $resource, int $visibility, bool $recursive = true): bool
902
    {
903
        $resourceNode = $resource->getResourceNode();
904
905
        if (null === $resourceNode) {
906
            return false;
907
        }
908
909
        $em = $this->getEntityManager();
910
        if ($recursive) {
911
            $children = $resourceNode->getChildren();
912
            if (!empty($children)) {
913
                /** @var ResourceNode $child */
914
                foreach ($children as $child) {
915
                    $criteria = [
916
                        'resourceNode' => $child,
917
                    ];
918
                    $childDocument = $this->findOneBy($criteria);
919
                    if ($childDocument) {
920
                        $this->setLinkVisibility($childDocument, $visibility);
921
                    }
922
                }
923
            }
924
        }
925
926
        $links = $resourceNode->getResourceLinks();
927
928
        if (!empty($links)) {
929
            /** @var ResourceLink $link */
930
            foreach ($links as $link) {
931
                $link->setVisibility($visibility);
932
                if (ResourceLink::VISIBILITY_DRAFT === $visibility) {
933
                    $editorMask = ResourceNodeVoter::getEditorMask();
934
                    //$rights = [];
935
                    $resourceRight = new ResourceRight();
936
                    $resourceRight
937
                        ->setMask($editorMask)
938
                        ->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)
939
                        ->setResourceLink($link)
940
                    ;
941
                    $link->addResourceRight($resourceRight);
942
                } else {
943
                    $link->setResourceRights(new ArrayCollection());
944
                }
945
                $em->persist($link);
946
            }
947
        }
948
        $em->flush();
949
950
        return true;
951
    }
952
}
953