Abac::processExtraData()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 24
ccs 13
cts 13
cp 1
rs 9.536
c 0
b 0
f 0
cc 4
nc 4
nop 3
crap 4
1
<?php
2
3
namespace PhpAbac;
4
5
use PhpAbac\Manager\{
6
    AttributeManager,
7
    CacheManager,
8
    ComparisonManager,
9
    PolicyRuleManager
10
};
11
use PhpAbac\Model\PolicyRuleAttribute;
12
13
final class Abac
14
{
15
    /** @var PolicyRuleManager **/
16
    private $policyRuleManager;
17
    /** @var AttributeManager **/
18
    private $attributeManager;
19
    /** @var CacheManager **/
20
    private $cacheManager;
21
    /** @var ComparisonManager **/
22
    private $comparisonManager;
23
    /** @var array **/
24
    private $errors;
25
    
26 4
    public function __construct(PolicyRuleManager $policyRuleManager, AttributeManager $attributeManager, ComparisonManager $comparisonManager, CacheManager $cacheManager)
27
    {
28 4
        $this->attributeManager = $attributeManager;
0 ignored issues
show
Documentation Bug introduced by
It seems like $attributeManager of type object<PhpAbac\Manager\AttributeManager> is incompatible with the declared type object<AttributeManager> of property $attributeManager.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
29 4
        $this->policyRuleManager = $policyRuleManager;
0 ignored issues
show
Documentation Bug introduced by
It seems like $policyRuleManager of type object<PhpAbac\Manager\PolicyRuleManager> is incompatible with the declared type object<PolicyRuleManager> of property $policyRuleManager.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
30 4
        $this->cacheManager = $cacheManager;
0 ignored issues
show
Documentation Bug introduced by
It seems like $cacheManager of type object<PhpAbac\Manager\CacheManager> is incompatible with the declared type object<CacheManager> of property $cacheManager.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
31 4
        $this->comparisonManager = $comparisonManager;
0 ignored issues
show
Documentation Bug introduced by
It seems like $comparisonManager of type object<PhpAbac\Manager\ComparisonManager> is incompatible with the declared type object<ComparisonManager> of property $comparisonManager.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
32 4
    }
33
    
34
    /**
35
     * Return true if both user and object respects all the rules conditions
36
     * If the objectId is null, policy rules about its attributes will be ignored
37
     * In case of mismatch between attributes and expected values,
38
     * an array with the concerned attributes slugs will be returned.
39
     *
40
     * Available options are :
41
     * * dynamic_attributes: array
42
     * * cache_result: boolean
43
     * * cache_ttl: integer
44
     * * cache_driver: string
45
     *
46
     * Available cache drivers are :
47
     * * memory
48
     */
49 4
    public function enforce(string $ruleName, $user, $resource = null, array $options = []): bool
50
    {
51 4
        $this->errors = [];
52
        // If there is dynamic attributes, we pass them to the comparison manager
53
        // When a comparison will be performed, the passed values will be retrieved and used
54 4
        if (isset($options[ 'dynamic_attributes' ])) {
55 1
            $this->comparisonManager->setDynamicAttributes($options[ 'dynamic_attributes' ]);
56
        }
57
        // Retrieve cache value for the current rule and values if cache item is valid
58 4
        if (($cacheResult = isset($options[ 'cache_result' ]) && $options[ 'cache_result' ] === true) === true) {
0 ignored issues
show
Comprehensibility introduced by
Consider adding parentheses for clarity. Current Interpretation: $cacheResult = (isset($o...ache_result'] === true), Probably Intended Meaning: ($cacheResult = isset($o...cache_result'] === true
Loading history...
59
            $cacheItem = $this->cacheManager->getItem("$ruleName-{$user->getId()}-" . (($resource !== null) ? $resource->getId() : ''), (isset($options[ 'cache_driver' ])) ? $options[ 'cache_driver' ] : null, (isset($options[ 'cache_ttl' ])) ? $options[ 'cache_ttl' ] : null);
60
            // We check if the cache value s valid before returning it
61
            if (($cacheValue = $cacheItem->get()) !== null) {
62
                return $cacheValue;
63
            }
64
        }
65 4
        $policyRules = $this->policyRuleManager->getRule($ruleName, $user, $resource);
66
        
67 4
        foreach ($policyRules as $policyRule) {
68
            // For each policy rule attribute, we retrieve the attribute value and proceed configured extra data
69 4
            foreach ($policyRule->getPolicyRuleAttributes() as $pra) {
70
                /** @var PolicyRuleAttribute $pra */
71 4
                $attribute = $pra->getAttribute();
72
                
73 4
                $getter_params = $this->prepareGetterParams($pra->getGetterParams(), $user, $resource);
74 4
                $attribute->setValue($this->attributeManager->retrieveAttribute($attribute, $user, $resource, $getter_params));
75 4
                if (count($pra->getExtraData()) > 0) {
76 3
                    $this->processExtraData($pra, $user, $resource);
77
                }
78 4
                $this->comparisonManager->compare($pra);
79
            }
80
            // The given result could be an array of rejected attributes or true
81
            // True means that the rule is correctly enforced for the given user and resource
82 4
            $this->errors = $this->comparisonManager->getResult();
83 4
            if (count($this->errors) === 0) {
84 4
                break;
85
            }
86
        }
87 4
        if ($cacheResult) {
88
            $cacheItem->set((count($this->errors) > 0) ? $this->errors : true);
0 ignored issues
show
Bug introduced by
The variable $cacheItem does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
89
            $this->cacheManager->save($cacheItem);
90
        }
91 4
        return count($this->errors) === 0;
92
    }
93
    
94 4
    public function getErrors(): array
95
    {
96 4
        return $this->errors;
97
    }
98
    
99
    /**
100
     * Function to prepare Getter Params when getter require parameters ( this parameters must be specified in configuration file)
101
     *
102
     * @param $getter_params
103
     * @param $user
104
     * @param $resource
105
     *
106
     * @return array
107
     */
108 4
    private function prepareGetterParams($getter_params, $user, $resource)
109
    {
110 4
        if (empty($getter_params)) {
111 4
            return [];
112
        }
113 2
        $values = [];
114 2
        foreach ($getter_params as $getter_name=>$params) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space before "=>"; 0 found
Loading history...
Coding Style introduced by
Expected 1 space after "=>"; 0 found
Loading history...
115 2
            foreach ($params as $param) {
116 2
                if ('@' !== $param[ 'param_name' ][ 0 ]) {
117
                    $values[$getter_name][] = $param[ 'param_value' ];
118
                } else {
119 2
                    $values[$getter_name][] = $this->attributeManager->retrieveAttribute($this->attributeManager->getAttribute($param[ 'param_value' ]), $user, $resource);
120
                }
121
            }
122
        }
123 2
        return $values;
124
    }
125
    
126 3
    private function processExtraData(PolicyRuleAttribute $pra, $user, $resource)
127
    {
128 3
        foreach ($pra->getExtraData() as $key => $data) {
129
            switch ($key) {
130 3
                case 'with':
131
                    // This data has to be removed for it will be stored elsewhere
132
                    // in the policy rule attribute
133 3
                    $pra->removeExtraData('with');
134
                    // The "with" extra data is an array of attributes, which are objects
135
                    // Once we process it as policy rule attributes, we set it as the main policy rule attribute value
136 3
                    $subPolicyRuleAttributes = [];
137
                    
138 3
                    foreach ($this->policyRuleManager->processRuleAttributes($data, $user, $resource) as $subPolicyRuleAttribute) {
139 3
                        $subPolicyRuleAttributes[] = $subPolicyRuleAttribute;
140
                    }
141 3
                    $pra->setValue($subPolicyRuleAttributes);
142
                    // This data can be used in complex comparisons
143 3
                    $pra->addExtraData('attribute', $pra->getAttribute());
144 3
                    $pra->addExtraData('user', $user);
145 3
                    $pra->addExtraData('resource', $resource);
146 3
                    break;
147
            }
148
        }
149 3
    }
150
}
151