Passed
Push — master ( c5f69b...918276 )
by Julito
25:10
created

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

384
        return $this->toolChain->/** @scrutinizer ignore-call */ getResourceTypeNameFromRepository(get_class($this));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

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

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

689
                        return $this->router->/** @scrutinizer ignore-call */ generate('chamilo_core_resource_download', $params, $referenceType);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

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

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