Completed
Push — master ( 4e378a...cfdcd7 )
by Yann
05:10
created

replaceWithReference()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
1
<?php
2
3
namespace Yokai\SecurityExtraBundle\DependencyInjection;
4
5
use Symfony\Component\DependencyInjection\ContainerBuilder;
6
use Symfony\Component\DependencyInjection\Definition;
7
use Symfony\Component\DependencyInjection\Reference;
8
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
9
use Yokai\SecurityExtraBundle\Callback\HasRoles;
10
use Yokai\SecurityExtraBundle\Voter\CallableCollectionVoter;
11
12
/**
13
 * @author Yann Eugoné <[email protected]>
14
 */
15
class YokaiSecurityExtraExtension extends Extension
16
{
17
    /**
18
     * @inheritdoc
19
     */
20
    public function load(array $configs, ContainerBuilder $container)
21
    {
22
        $config = $this->processConfiguration(new Configuration(), $configs);
23
24
        foreach ($config['permissions'] as $permission) {
25
            $callables = $this->buildCallables($container, $permission['roles'], $permission['callables']);
26
27
            $voterDefinition = (new Definition(CallableCollectionVoter::class))
28
                ->setArguments([$permission['attributes'], $permission['subjects'], $callables])
29
                ->addTag('security.voter')
30
                ->setPublic(false)
31
            ;
32
33
            $container->setDefinition($this->uniqueVoterId(), $voterDefinition);
34
        }
35
    }
36
37
    /**
38
     * @param ContainerBuilder $container
39
     * @param array            $roles
40
     * @param array            $callables
41
     *
42
     * @return array
43
     */
44
    private function buildCallables(ContainerBuilder $container, array $roles, array $callables)
45
    {
46
        $return = [];
47
48
        if (count($roles) > 0) {
49
            $callbackDefinition = (new Definition(HasRoles::class))
50
                ->setArguments([new Reference('security.role_hierarchy'), $roles])
51
                ->setPublic(false)
52
            ;
53
54
            $container->setDefinition($callbackId = $this->uniqueCallbackId(), $callbackDefinition);
55
56
            $return[] = new Reference($callbackId);
57
        }
58
59
        foreach ($callables as $callable) {
60
            if (is_array($callable) && isset($callable[0])) {
61
                $callable[0] = $this->replaceWithReference($callable[0]);
62
            }
63
64
            if (is_string($callable)) {
65
                $callable = $this->replaceWithReference($callable);
66
            }
67
68
            $return[] = $callable;
69
        }
70
71
        return $return;
72
    }
73
74
    /**
75
     * @return string
76
     */
77
    private function uniqueVoterId()
78
    {
79
        return uniqid('app.security.voter.configurable.', true);
80
    }
81
82
    /**
83
     * @return string
84
     */
85
    private function uniqueCallbackId()
86
    {
87
        return uniqid('app.security.voter.callback.', true);
88
    }
89
90
    /**
91
     * @param string $string
92
     *
93
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|Reference?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
94
     */
95
    private function replaceWithReference(string $string)
96
    {
97
        if (strpos($string, '@') !== 0) {
98
            return $string;
99
        }
100
101
        return new Reference(substr($string, 1));
102
    }
103
}
104