Completed
Push — master ( 5f1c93...626f54 )
by Julito
31:28
created

CourseVoter   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 126
Duplicated Lines 15.87 %

Coupling/Cohesion

Components 0
Dependencies 3

Importance

Changes 2
Bugs 0 Features 0
Metric Value
dl 20
loc 126
rs 10
c 2
b 0
f 0
wmc 16
lcom 0
cbo 3

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A getEntityManager() 0 4 1
A getCourseManager() 0 4 1
A supports() 20 20 3
C voteOnAttribute() 0 57 10

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
namespace Chamilo\CoreBundle\Security\Authorization\Voter;
5
6
use Chamilo\CoreBundle\Entity\Course;
7
use Chamilo\CoreBundle\Entity\Manager\CourseManager;
8
use Chamilo\UserBundle\Entity\User;
9
use Doctrine\ORM\EntityManager;
10
use Symfony\Component\DependencyInjection\ContainerInterface;
11
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
12
use Symfony\Component\Security\Core\Authorization\Voter\Voter as AbstractVoter;
13
use Symfony\Component\Security\Core\User\UserInterface;
14
15
/**
16
 * Class CourseVoter
17
 * @package Chamilo\CoreBundle\Security\Authorization\Voter
18
 */
19
class CourseVoter extends AbstractVoter
20
{
21
    const VIEW = 'VIEW';
22
    const EDIT = 'EDIT';
23
    const DELETE = 'DELETE';
24
25
    private $entityManager;
26
    private $courseManager;
27
    private $container;
28
29
    /**
30
     * @param EntityManager $entityManager
31
     * @param CourseManager $courseManager
32
     * @param ContainerInterface $container
33
     */
34
    public function __construct(
35
        EntityManager $entityManager,
0 ignored issues
show
Bug introduced by
You have injected the EntityManager via parameter $entityManager. This is generally not recommended as it might get closed and become unusable. Instead, it is recommended to inject the ManagerRegistry and retrieve the EntityManager via getManager() each time you need it.

The EntityManager might become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:

function someFunction(ManagerRegistry $registry) {
    $em = $registry->getManager();
    $em->getConnection()->beginTransaction();
    try {
        // Do something.
        $em->getConnection()->commit();
    } catch (\Exception $ex) {
        $em->getConnection()->rollback();
        $em->close();

        throw $ex;
    }
}

If that code throws an exception and the EntityManager is closed. Any other code which depends on the same instance of the EntityManager during this request will fail.

On the other hand, if you instead inject the ManagerRegistry, the getManager() method guarantees that you will always get a usable manager instance.

Loading history...
36
        CourseManager $courseManager,
37
        ContainerInterface $container
38
    ) {
39
        $this->entityManager = $entityManager;
40
        $this->courseManager = $courseManager;
41
        $this->container = $container;
42
    }
43
44
    /**
45
     * @return EntityManager
46
     */
47
    public function getEntityManager()
48
    {
49
        return $this->entityManager;
50
    }
51
52
    /**
53
     * @return CourseManager
54
     */
55
    public function getCourseManager()
56
    {
57
        return $this->courseManager;
58
    }
59
60
    /**
61
     * @inheritdoc
62
     */
63 View Code Duplication
    protected function supports($attribute, $subject)
64
    {
65
        $options = [
66
            self::VIEW,
67
            self::EDIT,
68
            self::DELETE
69
        ];
70
71
        // if the attribute isn't one we support, return false
72
        if (!in_array($attribute, $options)) {
73
            return false;
74
        }
75
76
        // only vote on Post objects inside this voter
77
        if (!$subject instanceof Course) {
78
            return false;
79
        }
80
81
        return true;
82
    }
83
84
    /**
85
     * @inheritdoc
86
     */
87
    protected function voteOnAttribute($attribute, $course, TokenInterface $token)
88
    {
89
        $user = $token->getUser();
90
        // Anons can enter a course depending of the course visibility
91
        /*if (!$user instanceof UserInterface) {
92
            return false;
93
        }*/
94
95
        $authChecker = $this->container->get('security.authorization_checker');
96
97
        // Admins have access to everything
98
        if ($authChecker->isGranted('ROLE_ADMIN')) {
99
100
            return true;
101
        }
102
103
        // Course is active?
104
        if (!$course->isActive()) {
105
106
            return false;
107
        }
108
109
        switch ($attribute) {
110
            case self::VIEW:
111
                // "Open to the world" no need to check if user is registered
112
                if ($course->isPublic()) {
113
114
                    return true;
115
                }
116
117
                // Other course visibility need to have a user set
118
                if (!$user instanceof UserInterface) {
119
                    return false;
120
                }
121
122
                // User is subscribed in the course no matter if is teacher/student
123
                if ($course->hasUser($user)) {
124
125
                    $user->addRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_STUDENT);
126
127
                    return true;
128
                }
129
130
                break;
131
            case self::EDIT:
132
            case self::DELETE:
133
                // Only teacher can edit/delete stuff
134
                if ($course->hasTeacher($user)) {
135
                    $user->addRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER);
136
137
                    return true;
138
                }
139
                break;
140
        }
141
142
        return false;
143
    }
144
}
145