Completed
Push — master ( fea95a...cb6bda )
by Olivier
06:35
created

Configuration::getExchangesConfiguration()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 13
rs 9.4285
ccs 13
cts 13
cp 1
cc 1
eloc 10
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Ola\RabbitMqAdminToolkitBundle\DependencyInjection;
4
5
use Ola\RabbitMqAdminToolkitBundle\Manager\QueueManager;
6
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
7
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
8
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
9
use Symfony\Component\Config\Definition\ConfigurationInterface;
10
11
class Configuration implements ConfigurationInterface
12
{
13
    /**
14 4
     * {@inheritdoc}
15
     */
16 4
    public function getConfigTreeBuilder()
17 4
    {
18
        $treeBuilder = new TreeBuilder();
19 4
        $rootNode = $treeBuilder->root('ola_rabbit_mq_admin_toolkit');
20 4
21 4
        $rootNode
22 3
            ->addDefaultsIfNotSet()
23 2
            ->children()
24 1
                ->scalarNode('default_vhost')->defaultValue('default')->end()
25 1
                ->scalarNode('delete_allowed')->defaultFalse()->end()
26
                ->scalarNode('silent_failure')->defaultFalse()->end()
27
                ->arrayNode('connections')
28 1
                    ->prototype('scalar')
29
                    ->end()
30
                ->end()
31
                ->arrayNode('vhosts')
32 2
                    ->prototype('array')
33 2
                        ->children()
34 2
                            ->scalarNode('name')->end()
35 2
                            ->scalarNode('connection')->defaultValue('default')->end()
36
                            ->scalarNode('delete_allowed')->end()
37
                            ->append($this->getPermissionsConfiguration())
38
                            ->append($this->getExchangesConfiguration())
39 2
                            ->append($this->getQueuesConfiguration())
40 3
                        ->end()
41
                    ->end()
42
                ->end()
43
            ->end()
44 4
        ;
45
        return $treeBuilder;
46
    }
47 4
48 4
    /**
49 4
     * @return NodeDefinition
50 4
     */
51 4
    private function getPermissionsConfiguration()
52 4
    {
53 4
        $node = new ArrayNodeDefinition('permissions');
54 4
55 4
        return $node
1 ignored issue
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Symfony\Component\Config...\Builder\NodeDefinition as the method children() does only exist in the following sub-classes of Symfony\Component\Config...\Builder\NodeDefinition: Symfony\Component\Config...der\ArrayNodeDefinition. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
56 4
            ->prototype('array')
57 4
                ->children()
58 4
                    ->scalarNode('configure')->defaultValue('.*')->end()
59 4
                    ->scalarNode('read')->defaultValue('.*')->end()
60 4
                    ->scalarNode('write')->defaultValue('.*')->end()
61 4
                ->end()
62 4
            ->end();
63 4
    }
64 4
65 4
    /**
66 4
     * @return NodeDefinition
67 4
     */
68 4
    private function getExchangesConfiguration()
69 4
    {
70 4
        $node = new ArrayNodeDefinition('exchanges');
71 4
72 4
        return $node
1 ignored issue
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Symfony\Component\Config...\Builder\NodeDefinition as the method children() does only exist in the following sub-classes of Symfony\Component\Config...\Builder\NodeDefinition: Symfony\Component\Config...der\ArrayNodeDefinition. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
73 4
            ->prototype('array')
74 4
                ->children()
75 4
                    ->scalarNode('name')->end()
76 4
                    ->scalarNode('type')->defaultValue('topic')->end()
77 4
                    ->scalarNode('durable')->defaultTrue()->end()
78 4
                ->end()
79 4
            ->end();
80 4
    }
81 4
82 4
    /**
83 4
     * @return NodeDefinition
84 4
     */
85 4
    private function getQueuesConfiguration()
86 4
    {
87 4
        $modulusValidation = function($v) {
88 4
89 4
            $hasModulus = function($string) {
90 4
                return strpos($string, QueueManager::MODULUS_PLACEHOLDER) !== false;
91 4
            };
92 4
93 4
            foreach ($v as $name => $queue) {
94 4
                if (isset($queue['modulus']) && is_int($queue['modulus'])) {
95 4
                    if (!$hasModulus($name) || (!$hasModulus($name) && isset($queue['name']) && !$hasModulus($queue['name']))) {
96 4
                        return true;
97 4
                    }
98 4
99 4
                    $bindingsHaveModulus = false;
100 4
                    foreach ($queue['bindings'] as $binding) {
101 4
                        $bindingsHaveModulus = $hasModulus($binding['routing_key']);
102 4
                    }
103 4
104 4
                    if (!$bindingsHaveModulus) {
105 4
                        return true;
106 4
                    }
107
                }
108 4
            }
109
        };
110
111
        $node = new ArrayNodeDefinition('queues');
112
113
        return $node
114
            ->validate()
115
                ->ifTrue($modulusValidation)
116
                ->thenInvalid('If queue.modulus is defined queue.name & at least one associated routing_key should contain a {modulus} part')
117
            ->end()
118
            ->prototype('array')
119
                ->children()
120
                    ->scalarNode('name')->end()
121
                    ->scalarNode('durable')->defaultTrue()->end()
122
                    ->scalarNode('modulus')->defaultNull()->end()
123
                    ->arrayNode('bindings')
124
                        ->prototype('array')
125
                            ->children()
126
                                ->scalarNode('exchange')->end()
127
                                ->scalarNode('routing_key')->end()
128
                            ->end()
129
                        ->end()
130
                    ->end()
131
                ->end()
132
            ->end();
133
    }
134
}
135