Completed
Push — master ( 5b557d...3742bc )
by Julito
12:11
created

ResourceRepository::getResourcesByCourse()   B

Complexity

Conditions 6
Paths 24

Size

Total Lines 61
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 6
eloc 38
c 2
b 0
f 0
nc 24
nop 3
dl 0
loc 61
rs 8.6897

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
namespace Chamilo\CoreBundle\Repository;
5
6
use APY\DataGridBundle\Grid\Action\RowAction;
7
use APY\DataGridBundle\Grid\Row;
8
use Chamilo\CoreBundle\Entity\Course;
9
use Chamilo\CoreBundle\Entity\Resource\AbstractResource;
10
use Chamilo\CoreBundle\Entity\Resource\ResourceFile;
11
use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
12
use Chamilo\CoreBundle\Entity\Resource\ResourceNode;
13
use Chamilo\CoreBundle\Entity\Resource\ResourceRight;
14
use Chamilo\CoreBundle\Entity\Resource\ResourceType;
15
use Chamilo\CoreBundle\Entity\Session;
16
use Chamilo\CoreBundle\Entity\Tool;
17
use Chamilo\CoreBundle\Entity\Usergroup;
18
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
19
use Chamilo\CourseBundle\Entity\CGroupInfo;
20
use Chamilo\UserBundle\Entity\User;
21
use Doctrine\ORM\EntityManager;
22
use Doctrine\ORM\Query\Expr\Join;
23
use Doctrine\ORM\QueryBuilder;
24
use League\Flysystem\FilesystemInterface;
25
use League\Flysystem\MountManager;
26
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository;
27
use Symfony\Component\HttpFoundation\File\UploadedFile;
28
use Symfony\Component\Routing\RouterInterface;
29
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
30
31
/**
32
 * Class ResourceRepository.
33
 */
34
class ResourceRepository extends EntityRepository
35
{
36
    /**
37
     * @var EntityRepository
38
     */
39
    protected $repository;
40
41
    /**
42
     * @var FilesystemInterface
43
     */
44
    protected $fs;
45
46
    /**
47
     * @var EntityManager
48
     */
49
    protected $entityManager;
50
51
    /**
52
     * The entity class FQN.
53
     *
54
     * @var string
55
     */
56
    protected $className;
57
58
    /** @var RouterInterface */
59
    protected $router;
60
61
    protected $resourceNodeRepository;
62
63
    /**
64
     * @var AuthorizationCheckerInterface
65
     */
66
    protected $authorizationChecker;
67
68
    /**
69
     * ResourceRepository constructor.
70
     */
71
    public function __construct(AuthorizationCheckerInterface $authorizationChecker, EntityManager $entityManager, MountManager $mountManager, RouterInterface $router, string $className)
72
    {
73
        $this->repository = $entityManager->getRepository($className);
74
        // Flysystem mount name is saved in config/packages/oneup_flysystem.yaml @todo add it as a service.
75
        $this->fs = $mountManager->getFilesystem('resources_fs');
76
        $this->router = $router;
77
        $this->resourceNodeRepository = $entityManager->getRepository('ChamiloCoreBundle:Resource\ResourceNode');
78
        $this->authorizationChecker = $authorizationChecker;
79
    }
80
81
    /**
82
     * @return AuthorizationCheckerInterface
83
     */
84
    public function getAuthorizationChecker(): AuthorizationCheckerInterface
85
    {
86
        return $this->authorizationChecker;
87
    }
88
89
    /**
90
     * @return mixed
91
     */
92
    public function create()
93
    {
94
        return new $this->className();
95
    }
96
97
    /**
98
     * @return RouterInterface
99
     */
100
    public function getRouter(): RouterInterface
101
    {
102
        return $this->router;
103
    }
104
105
    /**
106
     * @return EntityRepository
107
     */
108
    public function getResourceNodeRepository()
109
    {
110
        return $this->resourceNodeRepository;
111
    }
112
113
    /**
114
     * @return FilesystemInterface
115
     */
116
    public function getFileSystem()
117
    {
118
        return $this->fs;
119
    }
120
121
    /**
122
     * @return EntityManager
123
     */
124
    public function getEntityManager(): EntityManager
125
    {
126
        return $this->getRepository()->getEntityManager();
127
    }
128
129
    /**
130
     * @return EntityRepository
131
     */
132
    public function getRepository()
133
    {
134
        return $this->repository;
135
    }
136
137
    /**
138
     * @param mixed $id
139
     * @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...
140
     * @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...
141
     */
142
    public function find($id, $lockMode = null, $lockVersion = null): ?AbstractResource
143
    {
144
        return $this->getRepository()->find($id);
145
    }
146
147
    /**
148
     * @return AbstractResource
149
     */
150
    public function findOneBy(array $criteria, array $orderBy = null): ?AbstractResource
151
    {
152
        return $this->getRepository()->findOneBy($criteria, $orderBy);
153
    }
154
155
    /**
156
     * @return ResourceFile
157
     */
158
    public function addFile(ResourceNode $resourceNode, UploadedFile $file): ?ResourceFile
159
    {
160
        $resourceFile = $resourceNode->getResourceFile();
161
        if ($resourceFile === null) {
162
            $resourceFile = new ResourceFile();
163
        }
164
165
        $em = $this->getEntityManager();
166
167
        $resourceFile->setFile($file);
168
        $resourceFile->setName($resourceNode->getName());
169
        $em->persist($resourceFile);
170
        $resourceNode->setResourceFile($resourceFile);
171
        $em->persist($resourceNode);
172
        $em->flush();
173
174
        return $resourceFile;
175
    }
176
177
    /**
178
     * Creates a ResourceNode.
179
     *
180
     * @param AbstractResource $parent
181
     */
182
    public function addResourceNode(AbstractResource $resource, User $creator, AbstractResource $parent = null): ResourceNode
183
    {
184
        $em = $this->getEntityManager();
185
186
        $resourceType = $this->getResourceType();
187
188
        $resourceNode = new ResourceNode();
189
        $resourceNode
190
            ->setName($resource->getResourceName())
191
            ->setCreator($creator)
192
            ->setResourceType($resourceType)
193
        ;
194
195
        if ($parent !== null) {
196
            $resourceNode->setParent($parent->getResourceNode());
197
        }
198
199
        $resource->setResourceNode($resourceNode);
200
201
        $em->persist($resourceNode);
202
        $em->persist($resource);
203
        $em->flush();
204
205
        return $resourceNode;
206
    }
207
208
    /**
209
     * @param Session    $session
210
     * @param CGroupInfo $group
211
     */
212
    public function addResourceToCourse(AbstractResource $resource, int $visibility, User $creator, Course $course, Session $session = null, CGroupInfo $group = null)
213
    {
214
        $node = $this->addResourceNode($resource, $creator, $course);
215
        $this->addResourceNodeToCourse($node, $visibility, $course, $session, $group);
216
    }
217
218
    /**
219
     * @param int        $visibility
220
     * @param Course     $course
221
     * @param Session    $session
222
     * @param CGroupInfo $group
223
     */
224
    public function addResourceNodeToCourse(ResourceNode $resourceNode, $visibility, $course, $session, $group): void
225
    {
226
        $visibility = (int) $visibility;
227
        if (empty($visibility)) {
228
            $visibility = ResourceLink::VISIBILITY_PUBLISHED;
229
        }
230
231
        $link = new ResourceLink();
232
        $link
233
            ->setCourse($course)
234
            ->setSession($session)
235
            ->setGroup($group)
236
            //->setUser($toUser)
237
            ->setResourceNode($resourceNode)
238
            ->setVisibility($visibility)
239
        ;
240
241
        $rights = [];
242
        switch ($visibility) {
243
            case ResourceLink::VISIBILITY_PENDING:
244
            case ResourceLink::VISIBILITY_DRAFT:
245
                $editorMask = ResourceNodeVoter::getEditorMask();
246
                $resourceRight = new ResourceRight();
247
                $resourceRight
248
                    ->setMask($editorMask)
249
                    ->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)
250
                ;
251
                $rights[] = $resourceRight;
252
                break;
253
        }
254
255
        if (!empty($rights)) {
256
            foreach ($rights as $right) {
257
                $link->addResourceRight($right);
258
            }
259
        }
260
261
        $em = $this->getEntityManager();
262
        $em->persist($link);
263
        $em->flush();
264
    }
265
266
    /**
267
     * @return ResourceType
268
     */
269
    public function getResourceType()
270
    {
271
        $em = $this->getEntityManager();
272
        $entityName = $this->getRepository()->getClassMetadata()->getReflectionClass()->getShortName();
273
274
        return $em->getRepository('ChamiloCoreBundle:Resource\ResourceType')->findOneBy(
275
            ['name' => $entityName]
276
        );
277
    }
278
279
    public function addResourceToMe(ResourceNode $resourceNode): ResourceLink
280
    {
281
        $resourceLink = new ResourceLink();
282
        $resourceLink
283
            ->setResourceNode($resourceNode)
284
            ->setPrivate(true);
0 ignored issues
show
Bug introduced by
The method setPrivate() does not exist on Chamilo\CoreBundle\Entity\Resource\ResourceLink. ( Ignorable by Annotation )

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

284
            ->/** @scrutinizer ignore-call */ setPrivate(true);

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...
285
286
        $this->getEntityManager()->persist($resourceLink);
287
        $this->getEntityManager()->flush();
288
289
        return $resourceLink;
290
    }
291
292
    public function addResourceToEveryone(ResourceNode $resourceNode, ResourceRight $right): ResourceLink
293
    {
294
        $resourceLink = new ResourceLink();
295
        $resourceLink
296
            ->setResourceNode($resourceNode)
297
            ->addResourceRight($right)
298
        ;
299
300
        $this->getEntityManager()->persist($resourceLink);
301
        $this->getEntityManager()->flush();
302
303
        return $resourceLink;
304
    }
305
306
    public function addResourceToCourse2(ResourceNode $resourceNode, Course $course, ResourceRight $right): ResourceLink
307
    {
308
        $resourceLink = new ResourceLink();
309
        $resourceLink
310
            ->setResourceNode($resourceNode)
311
            ->setCourse($course)
312
            ->addResourceRight($right);
313
        $this->getEntityManager()->persist($resourceLink);
314
        $this->getEntityManager()->flush();
315
316
        return $resourceLink;
317
    }
318
319
    public function addResourceToUser(ResourceNode $resourceNode, User $toUser): ResourceLink
320
    {
321
        $resourceLink = $this->addResourceNodeToUser($resourceNode, $toUser);
322
        $this->getEntityManager()->persist($resourceLink);
323
324
        return $resourceLink;
325
    }
326
327
    public function addResourceNodeToUser(ResourceNode $resourceNode, User $toUser): ResourceLink
328
    {
329
        $resourceLink = new ResourceLink();
330
        $resourceLink
331
            ->setResourceNode($resourceNode)
332
            ->setUser($toUser);
333
334
        return $resourceLink;
335
    }
336
337
    public function addResourceToSession(
338
        ResourceNode $resourceNode,
339
        Course $course,
340
        Session $session,
341
        ResourceRight $right
342
    ) {
343
        $resourceLink = $this->addResourceToCourse(
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $resourceLink is correct as $this->addResourceToCour...eNode, $course, $right) targeting Chamilo\CoreBundle\Repos...::addResourceToCourse() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
The call to Chamilo\CoreBundle\Repos...::addResourceToCourse() has too few arguments starting with course. ( Ignorable by Annotation )

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

343
        /** @scrutinizer ignore-call */ 
344
        $resourceLink = $this->addResourceToCourse(

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
344
            $resourceNode,
345
            $course,
346
            $right
347
        );
348
        $resourceLink->setSession($session);
349
        $this->getEntityManager()->persist($resourceLink);
350
351
        return $resourceLink;
352
    }
353
354
    /**
355
     * @return ResourceLink
356
     */
357
    public function addResourceToCourseGroup(
358
        ResourceNode $resourceNode,
359
        Course $course,
360
        CGroupInfo $group,
361
        ResourceRight $right
362
    ) {
363
        $resourceLink = $this->addResourceToCourse(
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $resourceLink is correct as $this->addResourceToCour...eNode, $course, $right) targeting Chamilo\CoreBundle\Repos...::addResourceToCourse() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
The call to Chamilo\CoreBundle\Repos...::addResourceToCourse() has too few arguments starting with course. ( Ignorable by Annotation )

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

363
        /** @scrutinizer ignore-call */ 
364
        $resourceLink = $this->addResourceToCourse(

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
364
            $resourceNode,
365
            $course,
366
            $right
367
        );
368
        $resourceLink->setGroup($group);
369
        $this->getEntityManager()->persist($resourceLink);
370
371
        return $resourceLink;
372
    }
373
374
    /**
375
     * @return ResourceLink
376
     */
377
    public function addResourceToGroup(
378
        ResourceNode $resourceNode,
379
        Usergroup $group,
380
        ResourceRight $right
381
    ) {
382
        $resourceLink = new ResourceLink();
383
        $resourceLink
384
            ->setResourceNode($resourceNode)
385
            ->setUserGroup($group)
386
            ->addResourceRight($right);
387
388
        return $resourceLink;
389
    }
390
391
    /**
392
     * @param array $userList User id list
393
     */
394
    public function addResourceToUserList(ResourceNode $resourceNode, array $userList)
395
    {
396
        $em = $this->getEntityManager();
397
398
        if (!empty($userList)) {
399
            foreach ($userList as $userId) {
400
                $toUser = $em->getRepository('ChamiloUserBundle:User')->find($userId);
401
402
                $resourceLink = $this->addResourceNodeToUser($resourceNode, $toUser);
403
                $em->persist($resourceLink);
404
            }
405
        }
406
    }
407
408
    /**
409
     * @param Course          $course
410
     * @param Session|null    $session
411
     * @param CGroupInfo|null $group
412
     *
413
     * @return QueryBuilder
414
     */
415
    public function getResourcesByCourse(Course $course, Session $session = null, CGroupInfo $group = null)
416
    {
417
        $repo = $this->getRepository();
418
        $className = $repo->getClassName();
419
420
        // Check if this resource type requires to load the base course resources when using a session
421
        $loadBaseSessionContent = $repo->getClassMetadata()->getReflectionClass()->hasProperty(
422
            'loadCourseResourcesInSession'
423
        );
424
        $type = $this->getResourceType();
425
426
        $qb = $repo->getEntityManager()->createQueryBuilder()
427
            ->select('resource')
428
            ->from($className, 'resource')
429
            ->innerJoin(
430
                ResourceNode::class,
431
                'node',
432
                Join::WITH,
433
                'resource.resourceNode = node.id'
434
            )
435
            ->innerJoin('node.resourceLinks', 'links')
436
            ->where('node.resourceType = :type')
437
            ->andWhere('links.course = :course')
438
            ->setParameters(
439
                [
440
                    'type' => $type,
441
                    'course' => $course,
442
                ]
443
            );
444
445
        $checker = $this->getAuthorizationChecker();
446
        $isAdmin = $checker->isGranted('ROLE_ADMIN') ||
447
            $checker->isGranted('ROLE_CURRENT_COURSE_TEACHER');
448
449
        if ($isAdmin === false) {
450
            $qb
451
                ->andWhere('links.visibility = :visibility')
452
                ->setParameter('visibility', ResourceLink::VISIBILITY_PUBLISHED)
453
            ;
454
            // @todo Add start/end visibility restrictrions
455
        }
456
457
        if ($session === null) {
458
            $qb->andWhere('links.session IS NULL');
459
        } else {
460
            if ($loadBaseSessionContent) {
461
                // Load course base content.
462
                $qb->andWhere('links.session = :session OR links.session IS NULL');
463
                $qb->setParameter('session', $session);
464
            } else {
465
                // Load only session resources.
466
                $qb->andWhere('links.session = :session');
467
                $qb->setParameter('session', $session);
468
            }
469
        }
470
471
        if ($group === null) {
472
            $qb->andWhere('links.group IS NULL');
473
        }
474
475
        return $qb;
476
    }
477
478
    /**
479
     * @param RowAction $action
480
     * @param Row       $row
481
     * @param Session   $session
482
     *
483
     * @return RowAction|null
484
     */
485
    public function rowCanBeEdited(RowAction $action, Row $row, Session $session = null)
486
    {
487
        if (!empty($session)) {
488
            /** @var AbstractResource $entity */
489
            $entity = $row->getEntity();
490
            $hasSession = $entity->getResourceNode()->hasSession($session);
491
            if ($hasSession->count() > 0) {
492
                return $action;
493
            }
494
495
            return null;
496
        }
497
498
        return $action;
499
    }
500
501
    /**
502
     * @param string $tool
503
     *
504
     * @return Tool|null
505
     */
506
    private function getTool($tool)
0 ignored issues
show
Unused Code introduced by
The method getTool() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
507
    {
508
        return $this
509
            ->getEntityManager()
510
            ->getRepository('ChamiloCoreBundle:Tool')
511
            ->findOneBy(['name' => $tool]);
512
    }
513
514
    /**
515
     * Deletes several entities: AbstractResource (Ex: CDocument, CQuiz), ResourceNode,
516
     * ResourceLinks and ResourceFile (including files via Flysystem).
517
     */
518
    public function hardDelete(AbstractResource $resource)
519
    {
520
        $em = $this->getEntityManager();
521
        $em->remove($resource);
522
        $em->flush();
523
    }
524
525
    /**
526
     * Change all links visibility to DELETED.
527
     */
528
    public function softDelete(AbstractResource $resource)
529
    {
530
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_DELETED);
531
    }
532
533
    /**
534
     * @param AbstractResource $resource
535
     */
536
    public function setVisibilityPublished(AbstractResource $resource)
537
    {
538
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_PUBLISHED);
539
    }
540
541
    /**
542
     * @param AbstractResource $resource
543
     */
544
    public function setVisibilityDraft(AbstractResource $resource)
545
    {
546
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_DRAFT);
547
    }
548
549
    /**
550
     * @param AbstractResource $resource
551
     */
552
    public function setVisibilityPending(AbstractResource $resource)
553
    {
554
        $this->setLinkVisibility($resource, ResourceLink::VISIBILITY_PENDING);
555
    }
556
557
    /**
558
     * @param AbstractResource $resource
559
     * @param                  $visibility
560
     * @param bool             $recursive
561
     *
562
     * @return bool
563
     */
564
    private function setLinkVisibility(AbstractResource $resource, $visibility, $recursive = true)
565
    {
566
        $resourceNode = $resource->getResourceNode();
567
568
        if ($resourceNode === null){
569
            return false;
570
        }
571
572
        $em = $this->getEntityManager();
573
        if ($recursive) {
574
            $children = $resourceNode->getChildren();
575
            if (!empty($children)) {
576
                /** @var ResourceNode $child */
577
                foreach ($children as $child) {
578
                    $criteria = ['resourceNode' => $child];
579
                    $childDocument = $this->getRepository()->findOneBy($criteria);
580
                    if ($childDocument) {
581
                        $this->setLinkVisibility($childDocument, $visibility);
582
                    }
583
                }
584
            }
585
        }
586
587
        $links = $resourceNode->getResourceLinks();
588
589
        if (!empty($links)) {
590
            /** @var ResourceLink $link */
591
            foreach ($links as $link) {
592
                $link->setVisibility($visibility);
593
                if ($visibility === ResourceLink::VISIBILITY_DRAFT) {
594
                    $editorMask = ResourceNodeVoter::getEditorMask();
595
                    $rights = [];
596
                    $resourceRight = new ResourceRight();
597
                    $resourceRight
598
                        ->setMask($editorMask)
599
                        ->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)
600
                        ->setResourceLink($link)
601
                    ;
602
                    $rights[] = $resourceRight;
603
604
                    if (!empty($rights)) {
605
                        $link->setResourceRight($rights);
606
                    }
607
                } else {
608
                    $link->setResourceRight([]);
609
                }
610
                $em->merge($link);
611
            }
612
        }
613
        $em->flush();
614
615
        return true;
616
    }
617
}
618