Passed
Push — master ( f47d5f...f7335a )
by Gabor
05:38
created

IsAllowedHelper   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 143
Duplicated Lines 10.49 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 11
lcom 1
cbo 6
dl 15
loc 143
rs 10
c 0
b 0
f 0
ccs 32
cts 32
cp 1

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getName() 0 4 1
A getDefinition() 0 4 1
A getDescription() 0 4 1
A getOptions() 0 4 1
A __construct() 15 15 1
B __invoke() 0 27 3
A checkResourceNameAgainstRouting() 0 17 3

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
/**
3
 * WebHemi.
4
 *
5
 * PHP version 7.1
6
 *
7
 * @copyright 2012 - 2017 Gixx-web (http://www.gixx-web.com)
8
 * @license   https://opensource.org/licenses/MIT The MIT License (MIT)
9
 *
10
 * @link      http://www.gixx-web.com
11
 */
12
declare(strict_types = 1);
13
14
namespace WebHemi\Renderer\Helper;
15
16
use WebHemi\Acl\ServiceInterface as AclInterface;
17
use WebHemi\Auth\ServiceInterface as AuthInterface;
18
use WebHemi\Configuration\ServiceInterface as ConfigurationInterface;
19
use WebHemi\Data\Entity\AccessManagement\ResourceEntity;
20
use WebHemi\Data\Entity\ApplicationEntity;
21
use WebHemi\Data\Entity\User\UserEntity;
22
use WebHemi\Data\Storage\AccessManagement\ResourceStorage;
23
use WebHemi\Data\Storage\ApplicationStorage;
24
use WebHemi\Environment\ServiceInterface as EnvironmentInterface;
25
use WebHemi\Renderer\HelperInterface;
26
27
/**
28
 * Class IsAllowedHelper
29
 */
30
class IsAllowedHelper implements HelperInterface
31
{
32
    /** @var ConfigurationInterface */
33
    private $configuration;
34
    /** @var EnvironmentInterface */
35
    private $environmentManager;
36
    /** @var AclInterface */
37
    private $aclAdapter;
38
    /** @var AuthInterface */
39
    private $authAdapter;
40
    /** @var ResourceStorage */
41
    private $resourceStorage;
42
    /** @var ApplicationStorage */
43
    private $applicationStorage;
44
45
    /**
46
     * Should return the name of the helper.
47
     *
48
     * @return string
49
     * @codeCoverageIgnore - plain text
50
     */
51
    public static function getName() : string
52
    {
53
        return 'isAllowed';
54
    }
55
56
    /**
57
     * Should return the name of the helper.
58
     *
59
     * @return string
60
     * @codeCoverageIgnore - plain text
61
     */
62
    public static function getDefinition() : string
63
    {
64
        return '{% if isAllowed("routeAlias") %}';
65
    }
66
67
    /**
68
     * Should return a description text.
69
     *
70
     * @return string
71
     * @codeCoverageIgnore - plain text
72
     */
73
    public static function getDescription() : string
74
    {
75
        return 'Checks if the given user has access to the given resource in the given application.';
76
    }
77
78
    /**
79
     * Gets helper options for the render.
80
     *
81
     * @return array
82
     * @codeCoverageIgnore - empty array
83
     */
84
    public static function getOptions() : array
85
    {
86
        return [];
87
    }
88
89
    /**
90
     * IsAllowedHelper constructor.
91
     *
92
     * @param ConfigurationInterface $configuration
93
     * @param EnvironmentInterface   $environmentManager
94
     * @param AclInterface           $aclAdapter
95
     * @param AuthInterface          $authAdapter
96
     * @param ResourceStorage        $resourceStorage
97
     * @param ApplicationStorage     $applicationStorage
98
     */
99 3 View Code Duplication
    public function __construct(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
100
        ConfigurationInterface $configuration,
101
        EnvironmentInterface $environmentManager,
102
        AclInterface $aclAdapter,
103
        AuthInterface $authAdapter,
104
        ResourceStorage $resourceStorage,
105
        ApplicationStorage $applicationStorage
106
    ) {
107 3
        $this->configuration = $configuration;
108 3
        $this->environmentManager = $environmentManager;
109 3
        $this->aclAdapter = $aclAdapter;
110 3
        $this->authAdapter = $authAdapter;
111 3
        $this->resourceStorage = $resourceStorage;
112 3
        $this->applicationStorage = $applicationStorage;
113 3
    }
114
115
    /**
116
     * A renderer helper should be called with its name.
117
     *
118
     * @return bool
119
     */
120 3
    public function __invoke() : bool
121
    {
122
        /** @var UserEntity $userEntity */
123 3
        $userEntity = $this->authAdapter->getIdentity();
124
        // Without user, access should be denied.
125 3
        if (!$userEntity) {
126 1
            return false;
127
        }
128
129 2
        $arguments = func_get_args();
130
131 2
        $applicationName = $arguments[1] ?? $this->environmentManager->getSelectedApplication();
132
        /** @var null|ApplicationEntity $applicationEntity */
133 2
        $applicationEntity = $this->applicationStorage->getApplicationByName($applicationName);
134
135
        // For invalid applications the path will be checked against the current (valid) application
136 2
        if (!$applicationEntity instanceof ApplicationEntity) {
137 2
            $applicationName = $this->environmentManager->getSelectedApplication();
138
        }
139
140 2
        $resourceName = $arguments[0] ?? '';
141 2
        $this->checkResourceNameAgainstRouting($resourceName, $applicationName);
142
        /** @var null|ResourceEntity $resourceEntity */
143 2
        $resourceEntity = $this->resourceStorage->getResourceByName($resourceName);
144
145 2
        return $this->aclAdapter->isAllowed($userEntity, $resourceEntity, $applicationEntity);
146
    }
147
148
    /**
149
     * Matches the given resource name against router URLs and if found, changes it to the assigned middleware name.
150
     * @TODO: make sure it is NOT possible to give a custom resource with a name that can match against a router path.
151
     *
152
     * @param string $resourceName
153
     * @param string $applicationName
154
     */
155 2
    private function checkResourceNameAgainstRouting(string&$resourceName, string $applicationName) : void
156
    {
157 2
        $applicationConfig = $this->configuration
158 2
            ->getData('applications/'.$applicationName);
159
160 2
        $applicationRouteConfig = $this->configuration
161 2
            ->getData('router/'.$applicationConfig['module']);
162
163 2
        $tempName = trim($resourceName, '/');
164
165 2
        foreach ($applicationRouteConfig as $routeAlias => $routeData) {
166 2
            if ($routeAlias == $tempName) {
167 1
                $resourceName = $routeData['middleware'];
168 2
                break;
169
            }
170
        }
171 2
    }
172
}
173