Passed
Push — master ( da0304...c9db81 )
by Julito
09:10
created

ResourceRepository::getResourceNodeFileStream()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
namespace Chamilo\CoreBundle\Repository;
6
7
use Chamilo\CoreBundle\Component\Resource\Settings;
8
use Chamilo\CoreBundle\Component\Resource\Template;
9
use Chamilo\CoreBundle\Entity\AbstractResource;
10
use Chamilo\CoreBundle\Entity\Course;
11
use Chamilo\CoreBundle\Entity\ResourceFile;
12
use Chamilo\CoreBundle\Entity\ResourceInterface;
13
use Chamilo\CoreBundle\Entity\ResourceLink;
14
use Chamilo\CoreBundle\Entity\ResourceNode;
15
use Chamilo\CoreBundle\Entity\ResourceRight;
16
use Chamilo\CoreBundle\Entity\ResourceType;
17
use Chamilo\CoreBundle\Entity\Session;
18
use Chamilo\CoreBundle\Entity\User;
19
use Chamilo\CoreBundle\Form\Resource\PersonalFileType;
20
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
21
use Chamilo\CoreBundle\ToolChain;
22
use Chamilo\CourseBundle\Entity\CGroup;
23
use Cocur\Slugify\SlugifyInterface;
24
use Doctrine\ORM\EntityManager;
25
use Doctrine\ORM\EntityRepository;
26
use Doctrine\ORM\QueryBuilder;
27
use League\Flysystem\FilesystemInterface;
28
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
29
use Symfony\Component\Form\FormFactory;
30
use Symfony\Component\Form\FormInterface;
31
use Symfony\Component\HttpFoundation\File\UploadedFile;
32
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
33
use Symfony\Component\Routing\RouterInterface;
34
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
35
36
/**
37
 * Class ResourceRepository.
38
 * Extends EntityRepository is needed to process settings.
39
 */
40
class ResourceRepository extends EntityRepository
41
{
42
    /**
43
     * @var EntityRepository
44
     */
45
    protected $repository;
46
47
    /**
48
     * @var FilesystemInterface
49
     */
50
    protected $fs;
51
52
    /**
53
     * @var EntityManager
54
     */
55
    protected $entityManager;
56
57
    /**
58
     * The entity class FQN.
59
     *
60
     * @var string
61
     */
62
    protected $className;
63
64
    /** @var RouterInterface */
65
    protected $router;
66
67
    /** @var ResourceNodeRepository */
68
    protected $resourceNodeRepository;
69
70
    /**
71
     * @var AuthorizationCheckerInterface
72
     */
73
    protected $authorizationChecker;
74
75
    /** @var SlugifyInterface */
76
    protected $slugify;
77
78
    /** @var ToolChain */
79
    protected $toolChain;
80
    protected $settings;
81
    protected $templates;
82
    protected $resourceType;
83
84
    /**
85
     * ResourceRepository constructor.
86
     */
87
    public function __construct(
88
        AuthorizationCheckerInterface $authorizationChecker,
89
        EntityManager $entityManager,
90
        RouterInterface $router,
91
        SlugifyInterface $slugify,
92
        ToolChain $toolChain,
93
        ResourceNodeRepository $resourceNodeRepository
94
    ) {
95
        $className = $this->getClassName();
96
        $this->repository = $entityManager->getRepository($className);
97
        $this->authorizationChecker = $authorizationChecker;
98
        $this->router = $router;
99
        $this->resourceNodeRepository = $resourceNodeRepository;
100
        $this->slugify = $slugify;
101
        $this->toolChain = $toolChain;
102
        $this->settings = new Settings();
103
        $this->templates = new Template();
104
    }
105
106
    public function getClassName()
107
    {
108
        $class = get_class($this);
109
        //Chamilo\CoreBundle\Repository\IllustrationRepository
110
        $class = str_replace('\\Repository\\', '\\Entity\\', $class);
111
        $class = str_replace('Repository', '', $class);
112
        if (false === class_exists($class)) {
113
            throw new \Exception("Repo: $class not found ");
114
        }
115
116
        return $class;
117
    }
118
119
    public function getAuthorizationChecker(): AuthorizationCheckerInterface
120
    {
121
        return $this->authorizationChecker;
122
    }
123
124
    /**
125
     * @return AbstractResource
126
     */
127
    public function create()
128
    {
129
        $class = $this->repository->getClassName();
130
131
        return new $class();
132
    }
133
134
    public function getRouter(): RouterInterface
135
    {
136
        return $this->router;
137
    }
138
139
    /**
140
     * @return ResourceNodeRepository
141
     */
142
    public function getResourceNodeRepository()
143
    {
144
        return $this->resourceNodeRepository;
145
    }
146
147
    public function getEntityManager(): EntityManager
148
    {
149
        return $this->getRepository()->getEntityManager();
150
    }
151
152
    /**
153
     * @return EntityRepository
154
     */
155
    public function getRepository()
156
    {
157
        return $this->repository;
158
    }
159
160
    /**
161
     * @return FormInterface
162
     */
163
    public function getForm(FormFactory $formFactory, AbstractResource $resource = null, $options = [])
164
    {
165
        $formType = $this->getResourceFormType();
166
167
        if (null === $resource) {
168
            $className = $this->repository->getClassName();
169
            $resource = new $className();
170
        }
171
172
        return $formFactory->create($formType, $resource, $options);
173
    }
174
175
    /**
176
     * @param null $lockMode
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $lockMode is correct as it would always require null to be passed?
Loading history...
177
     * @param null $lockVersion
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $lockVersion is correct as it would always require null to be passed?
Loading history...
178
     *
179
     * @return ResourceInterface
180
     */
181
    public function find($id, $lockMode = null, $lockVersion = null)
182
    {
183
        return $this->getRepository()->find($id, $lockMode, $lockVersion);
184
    }
185
186
    public function getResourceByResourceNode(ResourceNode $resourceNode)
187
    {
188
        return $this->getRepository()->findOneBy(['resourceNode' => $resourceNode]);
189
    }
190
191
    public function findOneBy(array $criteria, array $orderBy = null)
192
    {
193
        return $this->getRepository()->findOneBy($criteria, $orderBy);
194
    }
195
196
    public function updateNodeForResource(ResourceInterface $resource): ResourceNode
197
    {
198
        $em = $this->getEntityManager();
199
200
        $resourceNode = $resource->getResourceNode();
201
        $resourceName = $resource->getResourceName();
202
203
        if ($resourceNode->hasResourceFile()) {
204
            $resourceFile = $resourceNode->getResourceFile();
205
            if ($resourceFile) {
0 ignored issues
show
introduced by
$resourceFile is of type Chamilo\CoreBundle\Entity\ResourceFile, thus it always evaluated to true.
Loading history...
206
                $originalName = $resourceFile->getOriginalName();
207
                $originalExtension = pathinfo($originalName, PATHINFO_EXTENSION);
208
209
                //$originalBasename = \basename($resourceName, $originalExtension);
210
                /*$slug = sprintf(
211
                    '%s.%s',
212
                    $this->slugify->slugify($originalBasename),
213
                    $this->slugify->slugify($originalExtension)
214
                );*/
215
216
                $newOriginalName = sprintf('%s.%s', $resourceName, $originalExtension);
217
                $resourceFile->setOriginalName($newOriginalName);
218
219
                $em->persist($resourceFile);
220
            }
221
        } else {
222
            //$slug = $this->slugify->slugify($resourceName);
223
        }
224
225
        $resourceNode->setTitle($resourceName);
226
        //$resourceNode->setSlug($slug);
227
228
        $em->persist($resourceNode);
229
        $em->persist($resource);
230
231
        $em->flush();
232
233
        return $resourceNode;
234
    }
235
236
    public function addFile(ResourceInterface $resource, UploadedFile $file): ?ResourceFile
237
    {
238
        $resourceNode = $resource->getResourceNode();
239
240
        if (null === $resourceNode) {
241
            throw new \LogicException('Resource node is null');
242
        }
243
244
        $resourceFile = $resourceNode->getResourceFile();
245
        if (null === $resourceFile) {
246
            $resourceFile = new ResourceFile();
247
        }
248
249
        $em = $this->getEntityManager();
250
        $resourceFile->setFile($file);
251
        $resourceFile->setName($resource->getResourceName());
252
        $em->persist($resourceFile);
253
254
        $resourceNode->setResourceFile($resourceFile);
255
        $em->persist($resourceNode);
256
257
        return $resourceFile;
258
    }
259
260
    public function addResourceNode(AbstractResource $resource, User $creator, AbstractResource $parent = null): ResourceNode
261
    {
262
        if (null !== $parent) {
263
            $parent = $parent->getResourceNode();
264
        }
265
266
        return $this->createNodeForResource($resource, $creator, $parent);
267
    }
268
269
    /**
270
     * @return ResourceType
271
     */
272
    public function getResourceType()
273
    {
274
        $name = $this->getResourceTypeName();
275
        $repo = $this->getEntityManager()->getRepository(ResourceType::class);
276
        $this->resourceType = $repo->findOneBy(['name' => $name]);
277
278
        return $this->resourceType;
279
    }
280
281
    public function getResourceTypeName(): string
282
    {
283
        return $this->toolChain->getResourceTypeNameFromRepository(get_class($this));
284
    }
285
286
    public function getResourcesByCourse(Course $course, Session $session = null, CGroup $group = null, ResourceNode $parentNode = null): QueryBuilder
287
    {
288
        $repo = $this->getRepository();
289
        $className = $repo->getClassName();
290
        $checker = $this->getAuthorizationChecker();
291
        $reflectionClass = $repo->getClassMetadata()->getReflectionClass();
292
293
        // Check if this resource type requires to load the base course resources when using a session
294
        $loadBaseSessionContent = $reflectionClass->hasProperty('loadCourseResourcesInSession');
295
        $resourceTypeName = $this->getResourceTypeName();
296
297
        $qb = $repo->getEntityManager()->createQueryBuilder()
298
            ->select('resource')
299
            ->from($className, 'resource')
300
            ->innerJoin('resource.resourceNode', 'node')
301
            ->innerJoin('node.resourceLinks', 'links')
302
            ->innerJoin('node.resourceType', 'type')
303
            ->leftJoin('node.resourceFile', 'file')
304
305
            ->where('type.name = :type')
306
            ->setParameter('type', $resourceTypeName)
307
            ->andWhere('links.course = :course')
308
            ->setParameter('course', $course)
309
            ->addSelect('node')
310
            ->addSelect('links')
311
            //->addSelect('course')
312
            ->addSelect('type')
313
            ->addSelect('file')
314
        ;
315
316
        $isAdmin =
317
            $checker->isGranted('ROLE_ADMIN') ||
318
            $checker->isGranted('ROLE_CURRENT_COURSE_TEACHER');
319
320
        // Do not show deleted resources.
321
        $qb
322
            ->andWhere('links.visibility != :visibilityDeleted')
323
            ->setParameter('visibilityDeleted', ResourceLink::VISIBILITY_DELETED)
324
        ;
325
326
        if (false === $isAdmin) {
327
            $qb
328
                ->andWhere('links.visibility = :visibility')
329
                ->setParameter('visibility', ResourceLink::VISIBILITY_PUBLISHED)
330
            ;
331
            // @todo Add start/end visibility restrictions.
332
        }
333
334
        if (null === $session) {
335
            $qb->andWhere(
336
                $qb->expr()->orX(
337
                    $qb->expr()->isNull('links.session'),
338
                    $qb->expr()->eq('links.session', 0)
339
                )
340
            );
341
        } else {
342
            if ($loadBaseSessionContent) {
343
                // Load course base content.
344
                $qb->andWhere('links.session = :session OR links.session IS NULL');
345
                $qb->setParameter('session', $session);
346
            } else {
347
                // Load only session resources.
348
                $qb->andWhere('links.session = :session');
349
                $qb->setParameter('session', $session);
350
            }
351
        }
352
353
        if (null !== $parentNode) {
354
            $qb->andWhere('node.parent = :parentNode');
355
            $qb->setParameter('parentNode', $parentNode);
356
        }
357
358
        if (null === $group) {
359
            $qb->andWhere(
360
                $qb->expr()->orX(
361
                    $qb->expr()->isNull('links.group'),
362
                    $qb->expr()->eq('links.group', 0)
363
                )
364
            );
365
        } else {
366
            $qb->andWhere('links.group = :group');
367
            $qb->setParameter('group', $group);
368
        }
369
370
        return $qb;
371
    }
372
373
    public function getResourcesByCourseOnly(Course $course, ResourceNode $parentNode = null)
374
    {
375
        $repo = $this->getRepository();
376
        $className = $repo->getClassName();
377
        $checker = $this->getAuthorizationChecker();
378
        $resourceTypeName = $this->getResourceTypeName();
379
380
        $qb = $repo->getEntityManager()->createQueryBuilder()
381
            ->select('resource')
382
            ->from($className, 'resource')
383
            ->innerJoin(
384
                'resource.resourceNode',
385
                'node'
386
            )
387
            ->innerJoin('node.resourceLinks', 'links')
388
            ->innerJoin('node.resourceType', 'type')
389
            ->where('type.name = :type')
390
            ->setParameter('type', $resourceTypeName)
391
            ->andWhere('links.course = :course')
392
            ->setParameter('course', $course)
393
        ;
394
395
        $isAdmin = $checker->isGranted('ROLE_ADMIN') ||
396
            $checker->isGranted('ROLE_CURRENT_COURSE_TEACHER');
397
398
        // Do not show deleted resources
399
        $qb
400
            ->andWhere('links.visibility != :visibilityDeleted')
401
            ->setParameter('visibilityDeleted', ResourceLink::VISIBILITY_DELETED)
402
        ;
403
404
        if (false === $isAdmin) {
405
            $qb
406
                ->andWhere('links.visibility = :visibility')
407
                ->setParameter('visibility', ResourceLink::VISIBILITY_PUBLISHED)
408
            ;
409
            // @todo Add start/end visibility restrictrions
410
        }
411
412
        if (null !== $parentNode) {
413
            $qb->andWhere('node.parent = :parentNode');
414
            $qb->setParameter('parentNode', $parentNode);
415
        }
416
417
        return $qb;
418
    }
419
420
    /**
421
     * @return QueryBuilder
422
     */
423
    public function getResourcesByCreator(User $user, ResourceNode $parentNode = null)
424
    {
425
        $repo = $this->getRepository();
426
        $className = $repo->getClassName();
427
428
        $qb = $repo->getEntityManager()->createQueryBuilder()
429
            ->select('resource')
430
            ->from($className, 'resource')
431
            ->innerJoin(
432
                'resource.resourceNode',
433
                'node'
434
            )
435
            //->innerJoin('node.resourceLinks', 'links')
436
            //->where('node.resourceType = :type')
437
            //->setParameter('type',$type)
438
            ;
439
        /*$qb
440
            ->andWhere('links.visibility = :visibility')
441
            ->setParameter('visibility', ResourceLink::VISIBILITY_PUBLISHED)
442
        ;*/
443
444
        if (null !== $parentNode) {
445
            $qb->andWhere('node.parent = :parentNode');
446
            $qb->setParameter('parentNode', $parentNode);
447
        }
448
449
        $qb->andWhere('node.creator = :creator');
450
        $qb->setParameter('creator', $user);
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
464
        $qb
465
            ->andWhere('links.user = :user')
466
            ->setParameter('user', $user);
467
468
        return $qb;
469
    }
470
471
    public function getResourcesByLinkedUser(User $user, ResourceNode $parentNode = null): QueryBuilder
472
    {
473
        $repo = $this->getRepository();
474
        $className = $repo->getClassName();
475
        $checker = $this->getAuthorizationChecker();
476
        $resourceTypeName = $this->getResourceTypeName();
477
478
        $qb = $repo->getEntityManager()->createQueryBuilder()
479
            ->select('resource')
480
            ->from($className, 'resource')
481
            ->innerJoin(
482
                'resource.resourceNode',
483
                'node'
484
            )
485
            ->innerJoin('node.resourceLinks', 'links')
486
            ->innerJoin('node.resourceType', 'type')
487
            ->where('type.name = :type')
488
            ->setParameter('type', $resourceTypeName)
489
            ->andWhere('links.user = :user')
490
            ->setParameter('user', $user)
491
        ;
492
493
        $isAdmin = $checker->isGranted('ROLE_ADMIN') ||
494
            $checker->isGranted('ROLE_CURRENT_COURSE_TEACHER');
495
496
        // Do not show deleted resources
497
        $qb
498
            ->andWhere('links.visibility != :visibilityDeleted')
499
            ->setParameter('visibilityDeleted', ResourceLink::VISIBILITY_DELETED)
500
        ;
501
502
        if (false === $isAdmin) {
503
            $qb
504
                ->andWhere('links.visibility = :visibility')
505
                ->setParameter('visibility', ResourceLink::VISIBILITY_PUBLISHED)
506
            ;
507
            // @todo Add start/end visibility restrictrions
508
        }
509
510
        if (null !== $parentNode) {
511
            $qb->andWhere('node.parent = :parentNode');
512
            $qb->setParameter('parentNode', $parentNode);
513
        }
514
515
        return $qb;
516
    }
517
518
    public function getResourceFromResourceNode(int $resourceNodeId): ?AbstractResource
519
    {
520
        // Include links
521
        $qb = $this->getRepository()->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(['id' => $resourceNodeId])
531
            //->addSelect('node')
532
        ;
533
534
        return $qb->getQuery()->getOneOrNullResult();
535
    }
536
537
    public function delete(AbstractResource $resource)
538
    {
539
        $children = $resource->getResourceNode()->getChildren();
540
        foreach ($children as $child) {
541
            if ($child->hasResourceFile()) {
542
                $this->getEntityManager()->remove($child->getResourceFile());
543
            }
544
            $resourceNode = $this->getResourceFromResourceNode($child->getId());
545
            if ($resourceNode) {
546
                $this->delete($resourceNode);
547
            }
548
        }
549
        $this->getEntityManager()->remove($resource);
550
        $this->getEntityManager()->flush();
551
    }
552
553
    /**
554
     * Deletes several entities: AbstractResource (Ex: CDocument, CQuiz), ResourceNode,
555
     * ResourceLinks and ResourceFile (including files via Flysystem).
556
     */
557
    public function hardDelete(AbstractResource $resource)
558
    {
559
        $em = $this->getEntityManager();
560
        $em->remove($resource);
561
        $em->flush();
562
    }
563
564
    public function getResourceFileContent(AbstractResource $resource): string
565
    {
566
        try {
567
            $resourceNode = $resource->getResourceNode();
568
569
            return $this->resourceNodeRepository->getResourceNodeFileContent($resourceNode);
570
        } catch (\Throwable $exception) {
571
            throw new FileNotFoundException($resource);
572
        }
573
    }
574
575
    public function getResourceNodeFileContent(ResourceNode $resourceNode): string
576
    {
577
        return $this->resourceNodeRepository->getResourceNodeFileContent($resourceNode);
578
    }
579
580
    public function getResourceNodeFileStream(ResourceNode $resourceNode)
581
    {
582
        return $this->resourceNodeRepository->getResourceNodeFileStream($resourceNode);
583
    }
584
585
    public function getResourceFileDownloadUrl(AbstractResource $resource, array $extraParams = [], $referenceType = null): string
586
    {
587
        $extraParams['mode'] = 'download';
588
589
        return $this->getResourceFileUrl($resource, $extraParams, $referenceType);
590
    }
591
592
    public function getResourceFileUrl(AbstractResource $resource, array $extraParams = [], $referenceType = null): string
593
    {
594
        try {
595
            $resourceNode = $resource->getResourceNode();
596
            if ($resourceNode->hasResourceFile()) {
597
                $params = [
598
                    'tool' => $resourceNode->getResourceType()->getTool(),
599
                    'type' => $resourceNode->getResourceType(),
600
                    'id' => $resourceNode->getId(),
601
                ];
602
603
                if (!empty($extraParams)) {
604
                    $params = array_merge($params, $extraParams);
605
                }
606
607
                $referenceType = $referenceType ?? UrlGeneratorInterface::ABSOLUTE_PATH;
608
609
                return $this->router->generate('chamilo_core_resource_view', $params, $referenceType);
610
            }
611
612
            return '';
613
        } catch (\Throwable $exception) {
614
            throw new FileNotFoundException($resource);
615
        }
616
    }
617
618
    public function getResourceSettings(): Settings
619
    {
620
        return $this->settings;
621
    }
622
623
    public function getTemplates(): Template
624
    {
625
        return $this->templates;
626
    }
627
628
    /**
629
     * @param string $content
630
     *
631
     * @return bool
632
     */
633
    public function updateResourceFileContent(AbstractResource $resource, $content)
634
    {
635
        error_log('updateResourceFileContent');
636
637
        $resourceNode = $resource->getResourceNode();
638
        if ($resourceNode->hasResourceFile()) {
639
            error_log('has file');
640
            $resourceFile = $resourceNode->getResourceFile();
641
            if ($resourceFile) {
0 ignored issues
show
introduced by
$resourceFile is of type Chamilo\CoreBundle\Entity\ResourceFile, thus it always evaluated to true.
Loading history...
642
                error_log('$resourceFile');
643
                $title = $resource->getResourceName();
644
                $handle = tmpfile();
645
                fwrite($handle, $content);
646
                error_log($title);
647
                error_log($content);
648
                $meta = stream_get_meta_data($handle);
649
                $file = new UploadedFile($meta['uri'], $title, 'text/html', null, true);
650
                $resource->setUploadFile($file);
651
652
                return true;
653
            }
654
        }
655
        error_log('false');
656
657
        return false;
658
    }
659
660
    public function setResourceName(AbstractResource $resource, $title)
661
    {
662
        $resource->setResourceName($title);
663
        $resourceNode = $resource->getResourceNode();
664
        $resourceNode->setTitle($title);
665
        if ($resourceNode->hasResourceFile()) {
666
            //$resourceNode->getResourceFile()->getFile()->
667
            //$resourceNode->getResourceFile()->setName($title);
668
            //$resourceFile->setName($title);
669
670
            /*$fileName = $this->getResourceNodeRepository()->getFilename($resourceFile);
671
            error_log('$fileName');
672
            error_log($fileName);
673
            error_log($title);
674
            $this->getResourceNodeRepository()->getFileSystem()->rename($fileName, $title);
675
            $resourceFile->setName($title);
676
            $resourceFile->setOriginalName($title);*/
677
        }
678
    }
679
680
    /**
681
     * Change all links visibility to DELETED.
682
     */
683
    public function softDelete(AbstractResource $resource)
684
    {
685
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_DELETED);
686
    }
687
688
    public function setVisibilityPublished(AbstractResource $resource)
689
    {
690
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_PUBLISHED);
691
    }
692
693
    public function setVisibilityDeleted(AbstractResource $resource)
694
    {
695
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_DELETED);
696
    }
697
698
    public function setVisibilityDraft(AbstractResource $resource)
699
    {
700
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_DRAFT);
701
    }
702
703
    public function setVisibilityPending(AbstractResource $resource)
704
    {
705
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_PENDING);
706
    }
707
708
    public function createNodeForResource(ResourceInterface $resource, User $creator, ResourceNode $parentNode = null, UploadedFile $file = null): ResourceNode
709
    {
710
        $em = $this->getEntityManager();
711
712
        $resourceType = $this->getResourceType();
713
        $resourceName = $resource->getResourceName();
714
        $extension = $this->slugify->slugify(pathinfo($resourceName, PATHINFO_EXTENSION));
715
716
        if (empty($extension)) {
717
            $slug = $this->slugify->slugify($resourceName);
718
        } else {
719
            $originalExtension = pathinfo($resourceName, PATHINFO_EXTENSION);
720
            $originalBasename = \basename($resourceName, $originalExtension);
721
            $slug = sprintf('%s.%s', $this->slugify->slugify($originalBasename), $originalExtension);
722
        }
723
724
        $resourceNode = new ResourceNode();
725
        $resourceNode
726
            ->setTitle($resourceName)
727
            ->setSlug($slug)
728
            ->setCreator($creator)
729
            ->setResourceType($resourceType)
730
        ;
731
732
        if (null !== $parentNode) {
733
            $resourceNode->setParent($parentNode);
734
        }
735
736
        $resource->setResourceNode($resourceNode);
737
        $em->persist($resourceNode);
738
        $em->persist($resource);
739
740
        if (null !== $file) {
741
            $this->addFile($resource, $file);
742
        }
743
744
        return $resourceNode;
745
    }
746
747
    private function setLinkVisibility(AbstractResource $resource, int $visibility, bool $recursive = true): bool
748
    {
749
        $resourceNode = $resource->getResourceNode();
750
751
        if (null === $resourceNode) {
752
            return false;
753
        }
754
755
        $em = $this->getEntityManager();
756
        if ($recursive) {
757
            $children = $resourceNode->getChildren();
758
            if (!empty($children)) {
759
                /** @var ResourceNode $child */
760
                foreach ($children as $child) {
761
                    $criteria = ['resourceNode' => $child];
762
                    $childDocument = $this->getRepository()->findOneBy($criteria);
763
                    if ($childDocument) {
764
                        $this->setLinkVisibility($childDocument, $visibility);
765
                    }
766
                }
767
            }
768
        }
769
770
        $links = $resourceNode->getResourceLinks();
771
772
        if (!empty($links)) {
773
            /** @var ResourceLink $link */
774
            foreach ($links as $link) {
775
                $link->setVisibility($visibility);
776
                if (ResourceLink::VISIBILITY_DRAFT === $visibility) {
777
                    $editorMask = ResourceNodeVoter::getEditorMask();
778
                    $rights = [];
779
                    $resourceRight = new ResourceRight();
780
                    $resourceRight
781
                        ->setMask($editorMask)
782
                        ->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)
783
                        ->setResourceLink($link)
784
                    ;
785
                    $rights[] = $resourceRight;
786
787
                    if (!empty($rights)) {
788
                        $link->setResourceRight($rights);
789
                    }
790
                } else {
791
                    $link->setResourceRight([]);
792
                }
793
                $em->persist($link);
794
            }
795
        }
796
        $em->flush();
797
798
        return true;
799
    }
800
801
    public function getTotalSpaceByCourse(Course $course, CGroup $group = null, Session $session = null): int
802
    {
803
        $repo = $this->getRepository();
804
805
        $qb = $repo->createQueryBuilder('resource');
806
        $qb
807
            ->select('SUM(file.size) as total')
808
            ->innerJoin('resource.resourceNode', 'node')
809
            ->innerJoin('node.resourceLinks', 'l')
810
            ->innerJoin('node.resourceFile', 'file')
811
            ->where('l.course = :course')
812
            ->andWhere('l.visibility <> :visibility')
813
            ->andWhere('file IS NOT NULL')
814
            ->setParameters(
815
                [
816
                    'course' => $course,
817
                    'visibility' => ResourceLink::VISIBILITY_DELETED,
818
                ]
819
            );
820
821
        if (null === $group) {
822
            $qb->andWhere('l.group IS NULL');
823
        } else {
824
            $qb
825
                ->andWhere('l.group = :group')
826
                ->setParameter('group', $group);
827
        }
828
829
        if (null === $session) {
830
            $qb->andWhere('l.session IS NULL');
831
        } else {
832
            $qb
833
                ->andWhere('l.session = :session')
834
                ->setParameter('session', $session);
835
        }
836
837
        $query = $qb->getQuery();
838
839
        return (int) $query->getSingleScalarResult();
840
    }
841
}
842