Passed
Push — master ( 0f66d0...a5c111 )
by Gabor
16:59 queued 08:35
created

IsAllowedHelper::__invoke()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 27
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 27
ccs 13
cts 13
cp 1
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 13
nc 3
nop 0
crap 3
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\Adapter\Acl\AclAdapterInterface;
17
use WebHemi\Adapter\Auth\AuthAdapterInterface;
18
use WebHemi\Adapter\Renderer\RendererHelperInterface;
19
use WebHemi\Application\EnvironmentManager;
20
use WebHemi\Config\ConfigInterface;
21
use WebHemi\Data\Entity\AccessManagement\ResourceEntity;
22
use WebHemi\Data\Entity\ApplicationEntity;
23
use WebHemi\Data\Entity\User\UserEntity;
24
use WebHemi\Data\Storage\AccessManagement\ResourceStorage;
25
use WebHemi\Data\Storage\ApplicationStorage;
26
27
/**
28
 * Class IsAllowedHelper
29
 */
30
class IsAllowedHelper implements RendererHelperInterface
31
{
32
    /** @var ConfigInterface */
33
    private $configuration;
34
    /** @var EnvironmentManager */
35
    private $environmentManager;
36
    /** @var AclAdapterInterface */
37
    private $aclAdapter;
38
    /** @var AuthAdapterInterface */
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 'isAllowed(string resourceName = null, string applicationName = null) : bool';
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
     * IsAllowedHelper constructor.
80
     *
81
     * @param ConfigInterface $configuration
82
     * @param EnvironmentManager $environmentManager
83
     * @param AclAdapterInterface $aclAdapter
84
     * @param AuthAdapterInterface $authAdapter
85
     * @param ResourceStorage $resourceStorage
86
     * @param ApplicationStorage $applicationStorage
87
     */
88 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...
89
        ConfigInterface $configuration,
90
        EnvironmentManager $environmentManager,
91
        AclAdapterInterface $aclAdapter,
92
        AuthAdapterInterface $authAdapter,
93
        ResourceStorage $resourceStorage,
94
        ApplicationStorage $applicationStorage
95
    ) {
96 3
        $this->configuration = $configuration;
97 3
        $this->environmentManager = $environmentManager;
98 3
        $this->aclAdapter = $aclAdapter;
99 3
        $this->authAdapter = $authAdapter;
100 3
        $this->resourceStorage = $resourceStorage;
101 3
        $this->applicationStorage = $applicationStorage;
102 3
    }
103
104
    /**
105
     * A renderer helper should be called with its name.
106
     *
107
     * @return bool
108
     */
109 3
    public function __invoke() : bool
110
    {
111
        /** @var UserEntity $userEntity */
112 3
        $userEntity = $this->authAdapter->getIdentity();
113
        // Without user, access should be denied.
114 3
        if (!$userEntity) {
115 1
            return false;
116
        }
117
118 2
        $arguments = func_get_args();
119
120 2
        $applicationName = $arguments[1] ?? $this->environmentManager->getSelectedApplication();
121
        /** @var null|ApplicationEntity $applicationEntity */
122 2
        $applicationEntity = $this->applicationStorage->getApplicationByName($applicationName);
123
124
        // For invalid applications the path will be checked against the current (valid) application
125 2
        if (!$applicationEntity instanceof ApplicationEntity) {
126 2
            $applicationName = $this->environmentManager->getSelectedApplication();
127
        }
128
129 2
        $resourceName = $arguments[0] ?? '';
130 2
        $this->checkResourceNameAgainstRouting($resourceName, $applicationName);
131
        /** @var null|ResourceEntity $resourceEntity */
132 2
        $resourceEntity = $this->resourceStorage->getResourceByName($resourceName);
133
134 2
        return $this->aclAdapter->isAllowed($userEntity, $resourceEntity, $applicationEntity);
135
    }
136
137
    /**
138
     * Matches the given resource name against router URLs and if found, changes it to the assigned middleware name.
139
     * @TODO: make sure it is NOT possible to give a custom resource with a name that can match against a router path.
140
     *
141
     * @param string $resourceName
142
     * @param string $applicationName
143
     */
144 2
    private function checkResourceNameAgainstRouting(string &$resourceName, string $applicationName) : void
145
    {
146 2
        $applicationConfig = $this->configuration
147 2
            ->getData('applications/'.$applicationName);
148
149 2
        $applicationRouteConfig = $this->configuration
150 2
            ->getData('router/'.$applicationConfig['module']);
151
152 2
        $tempName = $resourceName;
153 2
        $tempName = '/'.trim($tempName, '/');
154
155 2
        foreach ($applicationRouteConfig as $route) {
156 2
            if ($route['path'] == $tempName) {
157 1
                $resourceName = $route['middleware'];
158 2
                break;
159
            }
160
        }
161 2
    }
162
}
163