Completed
Push — master ( 9d81b9...1cdf8a )
by Nikola
12:36
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 ($subject instanceof RateInterface && in_array($attribute, [ self::EDIT, self::DELETE, self::VIEW ], true)) {
67
            return true;
68
        }
69
70
        if (
71
            in_array($attribute, [ self::VIEW, self::CREATE], true)
72
            &&
73
            is_string($subject)
74
            &&
75
            class_exists($subject)
76
        ) {
77
            return (new \ReflectionClass($subject))->implementsInterface(RateInterface::class);
78
        }
79
80
        return false;
81
    }
82
83
    /**
84
     * {@inheritdoc}
85
     */
86
    protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
87
    {
88
        $attribute = strtolower($attribute);
89
90
        return $this->hasAnyRole($token, $this->roles[$attribute]);
91
    }
92
93
    /**
94
     * Check if token has any of given roles.
95
     *
96
     * @param TokenInterface $token
97
     * @param array $roles
98
     *
99
     * @return bool
100
     */
101
    private function hasAnyRole(TokenInterface $token, array $roles)
102
    {
103
        $tokenRoles = array_filter(array_map(function(RoleInterface $role) {
104
            return $role->getRole() ?? false;
105
        }, $token->getRoles()));
106
107
        foreach ($tokenRoles as $tokenRole) {
108
            foreach ($roles as $role) {
109
                if (strtolower($tokenRole) === strtolower($role)) {
110
                    return true;
111
                }
112
            }
113
        }
114
115
        return false;
116
    }
117
}
118