Completed
Push — master ( 013881...fadbba )
by Keith
06:26
created

Configuration::getSubscribersNode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
ccs 17
cts 17
cp 1
cc 1
eloc 18
nc 1
nop 0
crap 1
1
<?php
2
3
/**
4
 * Copyright 2014 Underground Elephant
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 *
18
 * @package     qpush-bundle
19
 * @copyright   Underground Elephant 2014
20
 * @license     Apache License, Version 2.0
21
 */
22
23
namespace Uecode\Bundle\QPushBundle\DependencyInjection;
24
25
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
26
use Symfony\Component\Config\Definition\ConfigurationInterface;
27
28
/**
29
 * @author Keith Kirk <[email protected]>
30
 */
31
class Configuration implements ConfigurationInterface
32
{
33 1
    public function getConfigTreeBuilder()
34
    {
35 1
        $treeBuilder = new TreeBuilder();
36 1
        $rootNode    = $treeBuilder->root('uecode_qpush');
37
38
        $rootNode
39 1
            ->addDefaultsIfNotSet()
40 1
            ->children()
41 1
                ->scalarNode('cache_service')
42 1
                    ->defaultNull()
43 1
                ->end()
44 1
                ->booleanNode('logging_enabled')
45 1
                    ->defaultTrue()
46 1
                ->end()
47 1
                ->append($this->getProvidersNode())
48 1
                ->append($this->getQueuesNode())
49 1
            ->end()
50
        ;
51
52 1
        return $treeBuilder;
53
    }
54
55 1
    private function getProvidersNode()
56
    {
57 1
        $treeBuilder    = new TreeBuilder();
58 1
        $node           = $treeBuilder->root('providers');
59
        $requirements   = [
60 1
            'aws' => [],
61
            'ironmq' => ['token', 'project_id'],
62
            'sync' => [],
63
            'custom' => ['service'],
64
            'file' => ['path']
65
        ];
66
67
        $node
68 1
            ->useAttributeAsKey('name')
69 1
            ->prototype('array')
70 1
                ->treatNullLike([])
71 1
                ->children()
72 1
                    ->enumNode('driver')
73 1
                        ->isRequired()
74 1
                        ->values(array_keys($requirements))
75 1
                    ->end()
76
                    // IronMQ
77 1
                    ->scalarNode('token')->end()
78 1
                    ->scalarNode('project_id')->end()
79 1
                    ->scalarNode('service')->end()
80 1
                    ->enumNode('host')
81 1
                        ->defaultValue('mq-aws-eu-west-1-1')
82 1
                        ->values([
83 1
                            'mq-aws-eu-west-1-1',
84
                            'mq-aws-us-east-1-1',
85
                        ])
86 1
                    ->end()
87 1
                    ->scalarNode('port')
88 1
                        ->defaultValue('443')
89 1
                    ->end()
90 1
                    ->scalarNode('api_version')
91 1
                        ->defaultValue(3)
92 1
                    ->end()
93
                    // AWS
94 1
                    ->scalarNode('key')->end()
95 1
                    ->scalarNode('secret')->end()
96 1
                    ->scalarNode('region')
97 1
                        ->defaultValue('us-east-1')
98 1
                    ->end()
99
                    // File
100 1
                    ->scalarNode('path')->end()
101 1
                ->end()
102
103 1
                ->validate()
104 1
                ->always()
105 1
                ->then(function (array $provider) use ($node, $requirements) {
106 1
                    foreach ($requirements[$provider['driver']] as $requirement) {
107 1
                        if (empty($provider[$requirement])) {
108
                            throw new \InvalidArgumentException(
109 1
                                sprintf('%s queue providers must have a %s; none provided', $provider['driver'], $requirement)
110
                            );
111
                        }
112
                    }
113
114 1
                    return $provider;
115 1
                })
116 1
            ->end()
117
        ;
118
119 1
        return $node;
120
    }
121
122 1
    private function getQueuesNode()
123
    {
124 1
        $treeBuilder = new TreeBuilder();
125 1
        $node        = $treeBuilder->root('queues');
126
127
        $node
0 ignored issues
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...
128 1
            ->requiresAtLeastOneElement()
129 1
            ->useAttributeAsKey('name')
130 1
            ->prototype('array')
131 1
                ->children()
132 1
                    ->scalarNode('provider')
133 1
                        ->isRequired()
134 1
                        ->info('The Queue Provider to use')
135 1
                    ->end()
136 1
                    ->arrayNode('options')
137 1
                        ->children()
138 1
                            ->scalarNode('queue_name')
139 1
                                ->defaultNull()
140 1
                                ->info('The actual name of the queue')
141 1
                            ->end()
142 1
                            ->booleanNode('push_notifications')
143 1
                                ->defaultFalse()
144 1
                                ->info('Whether notifications are sent to the subscribers')
145 1
                            ->end()
146 1
                            ->scalarNode('push_type')
147 1
                                ->defaultValue('multicast')
148 1
                                ->info('Whether the push queue is multicast or unicast')
149 1
                                ->example('unicast')
150 1
                            ->end()
151 1
                            ->scalarNode('notification_retries')
152 1
                                ->defaultValue(3)
153 1
                                ->info('How many attempts the Push Notifications are retried if the Subscriber returns an error')
154 1
                                ->example(3)
155 1
                            ->end()
156 1
                            ->scalarNode('notification_retries_delay')
157 1
                                ->defaultValue(60)
158 1
                                ->info('Delay between each Push Notification retry in seconds')
159 1
                                ->example(3)
160 1
                                ->end()
161 1
                            ->scalarNode('message_delay')
162 1
                                ->defaultValue(0)
163 1
                                ->info('How many seconds before messages are inititally visible in the Queue')
164 1
                                ->example(0)
165 1
                            ->end()
166 1
                            ->scalarNode('message_timeout')
167 1
                                ->defaultValue(30)
168 1
                                ->info('How many seconds the Queue hides a message while its being processed')
169 1
                                ->example(30)
170 1
                            ->end()
171 1
                            ->scalarNode('message_expiration')
172 1
                                ->defaultValue(604800)
173 1
                                ->info('How many seconds a message is kept in Queue, the default is 7 days (604800 seconds)')
174 1
                                ->example(604800)
175 1
                            ->end()
176 1
                            ->scalarNode('messages_to_receive')
177 1
                                ->defaultValue(1)
178 1
                                ->info('Max amount of messages to receive at once - an event will be fired for each individually')
179 1
                                ->example(1)
180 1
                            ->end()
181 1
                            ->scalarNode('receive_wait_time')
182 1
                                ->defaultValue(0)
183 1
                                ->info('How many seconds to Long Poll when requesting messages - if supported')
184 1
                                ->example(3)
185 1
                            ->end()
186 1
                            ->scalarNode('rate_limit')
187 1
                                ->defaultValue(-1)
188 1
                                ->info('How many push requests per second will be triggered. -1 for unlimited, 0 disables push')
189 1
                                ->example(1)
190 1
                            ->end()
191 1
                            ->booleanNode('fifo')
192 1
                                ->defaultFalse()
193 1
                                ->info('If the queue is FIFO (aws)')
194 1
                            ->end()
195 1
                            ->booleanNode('content_based_deduplication')
196 1
                                ->defaultFalse()
197 1
                                ->info('If the FIFO queue has content based deduplication (aws)')
198 1
                            ->end()
199 1
                            ->append($this->getSubscribersNode())
200 1
                        ->end()
201 1
                    ->end()
202 1
                ->end()
203 1
            ->end()
204
        ;
205
206 1
        return $node;
207
    }
208
209 1
    private function getSubscribersNode()
210
    {
211 1
        $treeBuilder = new TreeBuilder();
212 1
        $node        = $treeBuilder->root('subscribers');
213
214
        $node
0 ignored issues
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...
215 1
            ->prototype('array')
216 1
                ->children()
217 1
                    ->scalarNode('endpoint')
218 1
                        ->info('The url or email address to notify')
219 1
                        ->example('http://foo.bar/qpush/')
220 1
                    ->end()
221 1
                    ->enumNode('protocol')
222 1
                        ->values(['email', 'http', 'https'])
223 1
                        ->info('The endpoint type')
224 1
                        ->example('http')
225 1
                    ->end()
226 1
                ->end()
227 1
            ->end()
228
        ;
229
230 1
        return $node;
231
    }
232
}
233