AccessControlPipe   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 114
Duplicated Lines 0 %

Test Coverage

Coverage 86.67%

Importance

Changes 0
Metric Value
wmc 16
eloc 38
dl 0
loc 114
ccs 39
cts 45
cp 0.8667
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 2
A getProperties() 0 5 2
A pipe() 0 5 1
A addGuard() 0 3 1
A assertCanAccess() 0 20 4
A getCurrentPathSchemaProperties() 0 5 1
A pick() 0 5 1
A getPathSchema() 0 7 1
A arrayGet() 0 11 3
1
<?php
2
3
namespace Lneicelis\Transformer\Pipe;
4
5
use Lneicelis\Transformer\Contract\CanGuard;
6
use Lneicelis\Transformer\Contract\CanPipe;
7
use Lneicelis\Transformer\Contract\HasAccessConfig;
8
use Lneicelis\Transformer\Exception\AccessDeniedException;
9
use Lneicelis\Transformer\Exception\TransformerNotFoundException;
10
use Lneicelis\Transformer\TransformerRegistry;
11
use Lneicelis\Transformer\ValueObject\Context;
12
use Lneicelis\Transformer\ValueObject\Path;
13
14
class AccessControlPipe implements CanPipe
15
{
16
    /** @var TransformerRegistry */
17
    private $transformerRepository;
18
19
    /** @var CanGuard[] */
20
    private $guardByName = [];
21
22
    /**
23
     * @param TransformerRegistry $transformerRepository
24
     * @param array $guards
25
     */
26 5
    public function __construct(TransformerRegistry $transformerRepository, array $guards = [])
27
    {
28 5
        $this->transformerRepository = $transformerRepository;
29
30 5
        foreach ($guards as $guard) {
31
            $this->addGuard($guard);
32
        }
33 5
    }
34
35 4
    public function addGuard(CanGuard $guard): void
36
    {
37 4
        $this->guardByName[$guard->getName()] = $guard;
38 4
    }
39
40
    /**
41
     * @param object $resource
42
     * @param Context $context
43
     * @param $data
44
     * @param Path $path
45
     * @return mixed
46
     * @throws TransformerNotFoundException
47
     * @throws AccessDeniedException
48
     */
49 5
    public function pipe($resource, Context $context, Path $path, $data)
50
    {
51 5
        $this->assertCanAccess($resource, $context, $path);
52
53 4
        return $data;
54
    }
55
56
    /**
57
     * @param $resource
58
     * @param Context $context
59
     * @param Path $path
60
     * @throws TransformerNotFoundException
61
     * @throws AccessDeniedException
62
     */
63 5
    private function assertCanAccess($resource, Context $context, Path $path): void {
64 5
        $transformer = $this->transformerRepository->getTransformer($resource);
65
66 5
        if (! $transformer instanceof HasAccessConfig) {
67
            return;
68
        }
69
70 5
        $optionalProps = $this->getCurrentPathSchemaProperties($path, $context->getSchema());
71 5
        $accessConfig = $transformer->getAccessConfig();
72 5
        $defaultAccessGroups = $accessConfig->getDefaultGroups();
73 5
        $accessGroupsByProperty = $accessConfig->getGroupsByProperty();
74
75 5
        $optionalPropsAcl = $this->pick($accessGroupsByProperty, $optionalProps);
76 5
        $allAcl = array_unique(array_merge($defaultAccessGroups, ...array_values($optionalPropsAcl)));
77
78 5
        foreach ($allAcl as $acl) {
79 3
            $guard = $this->guardByName[$acl];
80
81 3
            if (! $guard->canAccess($resource, $context)) {
82 3
                throw new AccessDeniedException('test');
83
            }
84
        }
85 4
    }
86
87
    private function pick(array $array, array $keys)
88
    {
89 5
        return array_filter($array, function (string $key) use ($keys): bool {
90 2
            return in_array($key, $keys, true);
91 5
        }, ARRAY_FILTER_USE_KEY);
92
    }
93
94 5
    private function getCurrentPathSchemaProperties(Path $path, array $schema)
95
    {
96 5
        $schema = $this->getPathSchema($path, $schema);
97
98 5
        return $this->getProperties($schema);
99
    }
100
101
    private function getProperties(array $schema): array
102
    {
103 5
        return array_map(function ($value, $key) {
104 1
            return is_string($value) ? $value : $key;
105 5
        }, $schema, array_keys($schema));
106
    }
107
108
    private function getPathSchema(Path $path, array $schema): array
109
    {
110 5
        $segments = array_filter($path->getSegments(), function ($segment) {
111
            return ! is_numeric($segment);
112 5
        });
113
114 5
        return $this->arrayGet($schema, $segments, []);
115
    }
116
117 5
    private function arrayGet(array $array, array $path, $default): array
118
    {
119 5
        foreach ($path as $key) {
120
            if (! array_key_exists($key, $array)) {
121
                return $default;
122
            }
123
124
            $array = $array[$key];
125
        }
126
127 5
        return $array;
128
    }
129
}
130