Completed
Push — master ( 81469d...e47b50 )
by Nikola
03:24
created

AccessVoter::voteOnAttribute()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 0
cts 3
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 3
crap 2
1
<?php
2
/*
3
 * This file is part of the Exchange Rate Bundle, an RunOpenCode project.
4
 *
5
 * (c) 2017 RunOpenCode
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace RunOpenCode\Bundle\ExchangeRate\Security;
11
12
use RunOpenCode\ExchangeRate\Contract\RateInterface;
13
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
14
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
15
use Symfony\Component\Security\Core\Role\RoleInterface;
16
17
/**
18
 * Class AccessVoter
19
 *
20
 * @package RunOpenCode\Bundle\ExchangeRate\Security
21
 */
22
class AccessVoter extends Voter
23
{
24
    /**
25
     * View action for exchange rate
26
     */
27
    const VIEW = 'view';
28
29
    /**
30
     * Create new exchange rate action
31
     */
32
    const CREATE = 'create';
33
34
    /**
35
     * Edit exchange rate action
36
     */
37
    const EDIT = 'edit';
38
39
    /**
40
     * Delete exchange rate action
41
     */
42
    const DELETE = 'delete';
43
44
    /**
45
     * @var array
46
     */
47
    protected $roles;
48
49
    public function __construct(array $roles = [])
50
    {
51
        $this->roles = array_merge([
52
            self::VIEW => [],
53
            self::CREATE => [],
54
            self::EDIT => [],
55
            self::DELETE => [],
56
        ], $roles);
57
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62
    protected function supports($attribute, $subject)
63
    {
64
        $attribute = strtolower($attribute);
65
66
        if (in_array($attribute, [ self::EDIT, self::DELETE ], true)) {
67
            return $subject instanceof RateInterface;
68
        }
69
70
        if (self::VIEW === $attribute && $subject instanceof RateInterface) {
71
            return true;
72
        }
73
74
        if (
75
            in_array($attribute, [ self::VIEW, self::CREATE], true)
76
            &&
77
            is_string($subject)
78
            &&
79
            class_exists($subject)
80
        ) {
81
            return (new \ReflectionClass($subject))->implementsInterface(RateInterface::class);
82
        }
83
84
        return false;
85
    }
86
87
    /**
88
     * {@inheritdoc}
89
     */
90
    protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
91
    {
92
        $attribute = strtolower($attribute);
93
94
        return $this->hasAnyRole($token, $this->roles[$attribute]);
95
    }
96
97
    /**
98
     * Check if token has any of given roles.
99
     *
100
     * @param TokenInterface $token
101
     * @param array $roles
102
     *
103
     * @return bool
104
     */
105
    private function hasAnyRole(TokenInterface $token, array $roles)
106
    {
107
        $tokenRoles = array_filter(array_map(function(RoleInterface $role) {
108
            return $role->getRole() ?? false;
109
        }, $token->getRoles()));
110
111
        foreach ($tokenRoles as $tokenRole) {
112
            foreach ($roles as $role) {
113
                if (strtolower($tokenRole) === strtolower($role)) {
114
                    return true;
115
                }
116
            }
117
        }
118
119
        return false;
120
    }
121
}
122