Passed
Push — master ( 7abcd4...1a3e0d )
by Julito
08:38
created

ResourceRepository::copyVisibilityToChildren()   B

Complexity

Conditions 9
Paths 8

Size

Total Lines 32
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 17
nc 8
nop 2
dl 0
loc 32
rs 8.0555
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Repository;
8
9
use Chamilo\CoreBundle\Component\Resource\Settings;
10
use Chamilo\CoreBundle\Component\Resource\Template;
11
use Chamilo\CoreBundle\Entity\AbstractResource;
12
use Chamilo\CoreBundle\Entity\Course;
13
use Chamilo\CoreBundle\Entity\ResourceFile;
14
use Chamilo\CoreBundle\Entity\ResourceInterface;
15
use Chamilo\CoreBundle\Entity\ResourceLink;
16
use Chamilo\CoreBundle\Entity\ResourceNode;
17
use Chamilo\CoreBundle\Entity\ResourceRight;
18
use Chamilo\CoreBundle\Entity\ResourceType;
19
use Chamilo\CoreBundle\Entity\Session;
20
use Chamilo\CoreBundle\Entity\User;
21
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
22
use Chamilo\CoreBundle\Traits\NonResourceRepository;
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\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 create(AbstractResource $resource): void
117
    {
118
        $this->getEntityManager()->persist($resource);
119
        $this->getEntityManager()->flush();
120
    }
121
122
    public function update(AbstractResource $resource, bool $andFlush = true): void
123
    {
124
        if (!$resource->hasResourceNode()) {
125
            throw new Exception('Resource needs a resource node');
126
        }
127
128
        $resource->getResourceNode()->setUpdatedAt(new DateTime());
129
        $resource->getResourceNode()->setTitle($resource->getResourceName());
130
        $this->getEntityManager()->persist($resource);
131
132
        if ($andFlush) {
133
            $this->getEntityManager()->flush();
134
        }
135
    }
136
137
    public function updateNodeForResource(ResourceInterface $resource): ResourceNode
138
    {
139
        $em = $this->getEntityManager();
140
141
        $resourceNode = $resource->getResourceNode();
142
        $resourceName = $resource->getResourceName();
143
144
        if ($resourceNode->hasResourceFile()) {
145
            $resourceFile = $resourceNode->getResourceFile();
146
            if (null !== $resourceFile) {
147
                $originalName = $resourceFile->getOriginalName();
148
                $originalExtension = pathinfo($originalName, PATHINFO_EXTENSION);
149
150
                //$originalBasename = \basename($resourceName, $originalExtension);
151
                /*$slug = sprintf(
152
                    '%s.%s',
153
                    $this->slugify->slugify($originalBasename),
154
                    $this->slugify->slugify($originalExtension)
155
                );*/
156
157
                $newOriginalName = sprintf('%s.%s', $resourceName, $originalExtension);
158
                $resourceFile->setOriginalName($newOriginalName);
159
160
                $em->persist($resourceFile);
161
            }
162
        }
163
        //$slug = $this->slugify->slugify($resourceName);
164
165
        $resourceNode->setTitle($resourceName);
166
        //$resourceNode->setSlug($slug);
167
168
        $em->persist($resourceNode);
169
        $em->persist($resource);
170
171
        $em->flush();
172
173
        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...
174
    }
175
176
    public function findCourseResourceByTitle(
177
        string $title,
178
        ResourceNode $parentNode,
179
        Course $course,
180
        Session $session = null,
181
        CGroup $group = null
182
    ): ?ResourceInterface {
183
        $qb = $this->getResourcesByCourse($course, $session, $group, $parentNode);
184
        $this->addTitleQueryBuilder($title, $qb);
185
        $qb->setMaxResults(1);
186
187
        return $qb->getQuery()->getOneOrNullResult();
188
    }
189
190
    public function findCourseResourcesByTitle(
191
        string $title,
192
        ResourceNode $parentNode,
193
        Course $course,
194
        Session $session = null,
195
        CGroup $group = null
196
    ) {
197
        $qb = $this->getResourcesByCourse($course, $session, $group, $parentNode);
198
        $this->addTitleQueryBuilder($title, $qb);
199
200
        return $qb->getQuery()->getResult();
201
    }
202
203
    /**
204
     * @todo clean path
205
     */
206
    public function addFileFromPath(ResourceInterface $resource, string $fileName, string $path, bool $flush = true)
207
    {
208
        if (!empty($path) && file_exists($path) && !is_dir($path)) {
209
            $mimeType = mime_content_type($path);
210
            $file = new UploadedFile($path, $fileName, $mimeType, null, true);
211
212
            return $this->addFile($resource, $file, '', $flush);
213
        }
214
215
        return null;
216
    }
217
218
    public function createTempUploadedFile(string $fileName, string $mimeType, string $content): UploadedFile
219
    {
220
        /*$handle = tmpfile();
221
        fwrite($handle, $content);
222
        $meta = stream_get_meta_data($handle);*/
223
224
        $tmpFilename = tempnam(sys_get_temp_dir(), 'resource_file_');
225
        file_put_contents($tmpFilename, $content);
226
227
        return new UploadedFile($tmpFilename, $fileName, $mimeType, null, true);
228
    }
229
230
    public function addFileFromString(ResourceInterface $resource, string $fileName, string $mimeType, string $content, bool $flush = true): ?ResourceFile
231
    {
232
        $file = $this->createTempUploadedFile($fileName, $mimeType, $content);
233
234
        return $this->addFile($resource, $file, '', $flush);
235
    }
236
237
    public function addFileFromFileRequest(ResourceInterface $resource, string $fileKey, bool $flush = true): ?ResourceFile
238
    {
239
        $request = $this->getRequest();
240
        if ($request->files->has($fileKey)) {
241
            $file = $request->files->get($fileKey);
242
            if (null !== $file) {
243
                $resourceFile = $this->addFile($resource, $file);
244
                if ($flush) {
245
                    $this->getEntityManager()->flush();
246
                }
247
248
                return $resourceFile;
249
            }
250
        }
251
252
        return null;
253
    }
254
255
    public function addFile(ResourceInterface $resource, UploadedFile $file, string $description = '', bool $flush = false): ?ResourceFile
256
    {
257
        $resourceNode = $resource->getResourceNode();
258
259
        if (null === $resourceNode) {
260
            throw new LogicException('Resource node is null');
261
        }
262
263
        $resourceFile = $resourceNode->getResourceFile();
264
        if (null === $resourceFile) {
265
            $resourceFile = new ResourceFile();
266
        }
267
268
        $em = $this->getEntityManager();
269
        $resourceFile
270
            ->setFile($file)
271
            ->setDescription($description)
272
            ->setName($resource->getResourceName())
273
            ->setResourceNode($resourceNode)
274
        ;
275
        $em->persist($resourceFile);
276
        $resourceNode->setResourceFile($resourceFile);
277
        $em->persist($resourceNode);
278
279
        if ($flush) {
280
            $em->flush();
281
        }
282
283
        return $resourceFile;
284
    }
285
286
    public function getResourceType(): ?ResourceType
287
    {
288
        $name = $this->getResourceTypeName();
289
        $repo = $this->getEntityManager()->getRepository(ResourceType::class);
290
        $this->resourceType = $repo->findOneBy([
291
            'name' => $name,
292
        ]);
293
294
        return $this->resourceType;
295
    }
296
297
    public function getResourceTypeName(): string
298
    {
299
        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

299
        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...
300
    }
301
302
    public function addVisibilityQueryBuilder(QueryBuilder $qb = null): QueryBuilder
303
    {
304
        $qb = $this->getOrCreateQueryBuilder($qb);
305
306
        $checker = $this->getAuthorizationChecker();
307
        $isAdmin =
308
            $checker->isGranted('ROLE_ADMIN') ||
309
            $checker->isGranted('ROLE_CURRENT_COURSE_TEACHER');
310
311
        // Do not show deleted resources.
312
        $qb
313
            ->andWhere('links.visibility != :visibilityDeleted')
314
            ->setParameter('visibilityDeleted', ResourceLink::VISIBILITY_DELETED, Types::INTEGER)
315
        ;
316
317
        if (!$isAdmin) {
318
            $qb
319
                ->andWhere('links.visibility = :visibility')
320
                ->setParameter('visibility', ResourceLink::VISIBILITY_PUBLISHED, Types::INTEGER)
321
            ;
322
            // @todo Add start/end visibility restrictions.
323
        }
324
325
        return $qb;
326
    }
327
328
    public function addCourseQueryBuilder(Course $course, QueryBuilder $qb): QueryBuilder
329
    {
330
        $qb
331
            ->andWhere('links.course = :course')
332
            ->setParameter('course', $course)
333
        ;
334
335
        return $qb;
336
    }
337
338
    public function addCourseSessionGroupQueryBuilder(Course $course, Session $session = null, CGroup $group = null, QueryBuilder $qb = null): QueryBuilder
339
    {
340
        $reflectionClass = $this->getClassMetadata()->getReflectionClass();
341
342
        // Check if this resource type requires to load the base course resources when using a session
343
        $loadBaseSessionContent = $reflectionClass->hasProperty('loadCourseResourcesInSession');
344
345
        $this->addCourseQueryBuilder($course, $qb);
346
347
        if (null === $session) {
348
            $qb->andWhere(
349
                $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

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

534
            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...
535
        } catch (Throwable $throwable) {
536
            throw new FileNotFoundException($resource->getResourceName());
537
        }
538
    }
539
540
    public function getResourceNodeFileContent(ResourceNode $resourceNode): string
541
    {
542
        return $this->resourceNodeRepository->getResourceNodeFileContent($resourceNode);
543
    }
544
545
    public function getResourceNodeFileStream(ResourceNode $resourceNode)
546
    {
547
        return $this->resourceNodeRepository->getResourceNodeFileStream($resourceNode);
548
    }
549
550
    public function getResourceFileDownloadUrl(AbstractResource $resource, array $extraParams = [], $referenceType = null): string
551
    {
552
        $extraParams['mode'] = 'download';
553
554
        return $this->getResourceFileUrl($resource, $extraParams, $referenceType);
555
    }
556
557
    public function getResourceFileUrl(AbstractResource $resource, array $extraParams = [], $referenceType = null): string
558
    {
559
        return $this->getResourceNodeRepository()->getResourceFileUrl(
560
            $resource->getResourceNode(),
561
            $extraParams,
562
            $referenceType
563
        );
564
    }
565
566
    /**
567
     * @return bool
568
     */
569
    public function updateResourceFileContent(AbstractResource $resource, string $content)
570
    {
571
        error_log('updateResourceFileContent');
572
573
        $resourceNode = $resource->getResourceNode();
574
        if ($resourceNode->hasResourceFile()) {
575
            $resourceNode->setContent($content);
576
            $resourceNode->getResourceFile()->setSize(\strlen($content));
577
        }
578
579
        return false;
580
    }
581
582
    public function setResourceName(AbstractResource $resource, $title): void
583
    {
584
        if (!empty($title)) {
585
            $resource->setResourceName($title);
586
            $resourceNode = $resource->getResourceNode();
587
            $resourceNode->setTitle($title);
588
        }
589
590
        //if ($resourceNode->hasResourceFile()) {
591
            //$resourceNode->getResourceFile()->getFile()->
592
            //$resourceNode->getResourceFile()->setName($title);
593
            //$resourceFile->setName($title);
594
595
            /*$fileName = $this->getResourceNodeRepository()->getFilename($resourceFile);
596
            error_log('$fileName');
597
            error_log($fileName);
598
            error_log($title);
599
            $this->getResourceNodeRepository()->getFileSystem()->rename($fileName, $title);
600
            $resourceFile->setName($title);
601
            $resourceFile->setOriginalName($title);*/
602
        //}
603
    }
604
605
    /**
606
     * Change all links visibility to DELETED.
607
     */
608
    public function softDelete(AbstractResource $resource): void
609
    {
610
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_DELETED);
611
    }
612
613
    public function setVisibilityPublished(AbstractResource $resource): void
614
    {
615
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_PUBLISHED);
616
    }
617
618
    public function setVisibilityDeleted(AbstractResource $resource): void
619
    {
620
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_DELETED);
621
    }
622
623
    public function setVisibilityDraft(AbstractResource $resource): void
624
    {
625
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_DRAFT);
626
    }
627
628
    public function setVisibilityPending(AbstractResource $resource): void
629
    {
630
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_PENDING);
631
    }
632
633
    public function addResourceNode(ResourceInterface $resource, User $creator, ResourceInterface $parentResource): ResourceNode
634
    {
635
        $parentResourceNode = $parentResource->getResourceNode();
636
637
        return $this->createNodeForResource($resource, $creator, $parentResourceNode);
638
    }
639
640
    /**
641
     * @todo remove this function and merge it with addResourceNode()
642
     */
643
    public function createNodeForResource(ResourceInterface $resource, User $creator, ResourceNode $parentNode, UploadedFile $file = null): ResourceNode
644
    {
645
        $em = $this->getEntityManager();
646
647
        $resourceType = $this->getResourceType();
648
        $resourceName = $resource->getResourceName();
649
        $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

649
        /** @scrutinizer ignore-call */ 
650
        $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...
650
651
        if (empty($extension)) {
652
            $slug = $this->slugify->slugify($resourceName);
653
        } else {
654
            $originalExtension = pathinfo($resourceName, PATHINFO_EXTENSION);
655
            $originalBasename = basename($resourceName, $originalExtension);
656
            $slug = sprintf('%s.%s', $this->slugify->slugify($originalBasename), $originalExtension);
657
        }
658
659
        $resourceNode = new ResourceNode();
660
        $resourceNode
661
            ->setTitle($resourceName)
662
            ->setSlug($slug)
663
            ->setCreator($creator)
664
            ->setResourceType($resourceType)
665
        ;
666
667
        if (null !== $parentNode) {
668
            $resourceNode->setParent($parentNode);
669
        }
670
671
        $resource->setResourceNode($resourceNode);
672
        $em->persist($resourceNode);
673
        $em->persist($resource);
674
675
        if (null !== $file) {
676
            $this->addFile($resource, $file);
677
        }
678
679
        return $resourceNode;
680
    }
681
682
    /**
683
     * This is only used during installation for the special nodes (admin and AccessUrl).
684
     */
685
    public function createNodeForResourceWithNoParent(ResourceInterface $resource, User $creator): ResourceNode
686
    {
687
        $em = $this->getEntityManager();
688
689
        $resourceType = $this->getResourceType();
690
        $resourceName = $resource->getResourceName();
691
        $slug = $this->slugify->slugify($resourceName);
692
        $resourceNode = new ResourceNode();
693
        $resourceNode
694
            ->setTitle($resourceName)
695
            ->setSlug($slug)
696
            ->setCreator($creator)
697
            ->setResourceType($resourceType)
698
        ;
699
        $resource->setResourceNode($resourceNode);
700
        $em->persist($resourceNode);
701
        $em->persist($resource);
702
703
        return $resourceNode;
704
    }
705
706
    public function getTotalSpaceByCourse(Course $course, CGroup $group = null, Session $session = null): int
707
    {
708
        $qb = $this->createQueryBuilder('resource');
709
        $qb
710
            ->select('SUM(file.size) as total')
711
            ->innerJoin('resource.resourceNode', 'node')
712
            ->innerJoin('node.resourceLinks', 'l')
713
            ->innerJoin('node.resourceFile', 'file')
714
            ->where('l.course = :course')
715
            ->andWhere('l.visibility <> :visibility')
716
            ->andWhere('file IS NOT NULL')
717
            ->setParameters(
718
                [
719
                    'course' => $course,
720
                    'visibility' => ResourceLink::VISIBILITY_DELETED,
721
                ]
722
            )
723
        ;
724
725
        if (null === $group) {
726
            $qb->andWhere('l.group IS NULL');
727
        } else {
728
            $qb
729
                ->andWhere('l.group = :group')
730
                ->setParameter('group', $group)
731
            ;
732
        }
733
734
        if (null === $session) {
735
            $qb->andWhere('l.session IS NULL');
736
        } else {
737
            $qb
738
                ->andWhere('l.session = :session')
739
                ->setParameter('session', $session)
740
            ;
741
        }
742
743
        $query = $qb->getQuery();
744
745
        return (int) $query->getSingleScalarResult();
746
    }
747
748
    public function addTitleDecoration(AbstractResource $resource, Course $course, Session $session = null): string
749
    {
750
        if (null === $session) {
751
            return '';
752
        }
753
754
        $link = $resource->getFirstResourceLinkFromCourseSession($course, $session);
755
        if (null === $link) {
756
            return '';
757
        }
758
759
        return '<img title="'.$session->getName().'" src="/img/icons/22/star.png" />';
760
    }
761
762
    public function isGranted(string $subject, AbstractResource $resource): bool
763
    {
764
        return $this->getAuthorizationChecker()->isGranted($subject, $resource->getResourceNode());
765
    }
766
767
    /**
768
     * Changes the visibility of the children that matches the exact same link.
769
     */
770
    public function copyVisibilityToChildren(ResourceNode $resourceNode, ResourceLink $link): bool
771
    {
772
        $children = $resourceNode->getChildren();
773
774
        if (0 === $children->count()) {
775
            return false;
776
        }
777
778
        $em = $this->getEntityManager();
779
780
        /** @var ResourceNode $child */
781
        foreach ($children as $child) {
782
            if ($child->getChildren()->count() > 0) {
783
                $this->copyVisibilityToChildren($child, $link);
784
            }
785
786
            $links = $child->getResourceLinks();
787
            foreach ($links as $linkItem) {
788
                if ($linkItem->getUser() === $link->getUser() &&
789
                    $linkItem->getSession() === $link->getSession() &&
790
                    $linkItem->getCourse() === $link->getCourse() &&
791
                    $linkItem->getUserGroup() === $link->getUserGroup()
792
                ) {
793
                    $linkItem->setVisibility($link->getVisibility());
794
                    $em->persist($linkItem);
795
                }
796
            }
797
        }
798
799
        $em->flush();
800
801
        return true;
802
    }
803
804
    public function saveUpload(UploadedFile $file): ResourceInterface
805
    {
806
        throw new Exception('Implement saveUpload');
807
    }
808
809
    public function getResourceFormType(): string
810
    {
811
        throw new Exception('Implement getResourceFormType');
812
    }
813
814
    protected function getOrCreateQueryBuilder(QueryBuilder $qb = null, string $alias = 'resource'): QueryBuilder
815
    {
816
        return $qb ?: $this->createQueryBuilder($alias);
817
    }
818
819
    protected function addTitleQueryBuilder(?string $title, QueryBuilder $qb = null): QueryBuilder
820
    {
821
        $qb = $this->getOrCreateQueryBuilder($qb);
822
        if (null === $title) {
823
            return $qb;
824
        }
825
826
        $qb
827
            ->andWhere('node.title = :title')
828
            ->setParameter('title', $title)
829
        ;
830
831
        return $qb;
832
    }
833
834
    protected function addCreatorQueryBuilder(?User $user, QueryBuilder $qb = null): QueryBuilder
835
    {
836
        $qb = $this->getOrCreateQueryBuilder($qb);
837
        if (null === $user) {
838
            return $qb;
839
        }
840
841
        $qb
842
            ->andWhere('node.creator = :creator')
843
            ->setParameter('creator', $user)
844
        ;
845
846
        return $qb;
847
    }
848
849
    private function setLinkVisibility(AbstractResource $resource, int $visibility, bool $recursive = true): bool
850
    {
851
        $resourceNode = $resource->getResourceNode();
852
853
        if (null === $resourceNode) {
854
            return false;
855
        }
856
857
        $em = $this->getEntityManager();
858
        if ($recursive) {
859
            $children = $resourceNode->getChildren();
860
            if (!empty($children)) {
861
                /** @var ResourceNode $child */
862
                foreach ($children as $child) {
863
                    $criteria = [
864
                        'resourceNode' => $child,
865
                    ];
866
                    $childDocument = $this->findOneBy($criteria);
867
                    if ($childDocument) {
868
                        $this->setLinkVisibility($childDocument, $visibility);
869
                    }
870
                }
871
            }
872
        }
873
874
        $links = $resourceNode->getResourceLinks();
875
876
        if (!empty($links)) {
877
            /** @var ResourceLink $link */
878
            foreach ($links as $link) {
879
                $link->setVisibility($visibility);
880
                if (ResourceLink::VISIBILITY_DRAFT === $visibility) {
881
                    $editorMask = ResourceNodeVoter::getEditorMask();
882
                    //$rights = [];
883
                    $resourceRight = new ResourceRight();
884
                    $resourceRight
885
                        ->setMask($editorMask)
886
                        ->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)
887
                        ->setResourceLink($link)
888
                    ;
889
                    $link->addResourceRight($resourceRight);
890
                } else {
891
                    $link->setResourceRights(new ArrayCollection());
892
                }
893
                $em->persist($link);
894
            }
895
        }
896
        $em->flush();
897
898
        return true;
899
    }
900
}
901