Completed
Push — master ( 07ac7e...f5aed6 )
by Nikola
14:36
created

Configuration::getNotificationsDefinition()   B

Complexity

Conditions 2
Paths 1

Size

Total Lines 43
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 33
CRAP Score 2.0001

Importance

Changes 0
Metric Value
dl 0
loc 43
ccs 33
cts 34
cp 0.9706
rs 8.8571
c 0
b 0
f 0
cc 2
eloc 34
nc 1
nop 0
crap 2.0001
1
<?php
2
/*
3
 * This file is part of the Exchange Rate Bundle, an RunOpenCode project.
4
 *
5
 * (c) 2017 RunOpenCode
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace RunOpenCode\Bundle\ExchangeRate\DependencyInjection;
11
12
use RunOpenCode\Bundle\ExchangeRate\Enum\Role;
13
use RunOpenCode\Bundle\ExchangeRate\Security\AccessVoter;
14
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
15
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
16
use Symfony\Component\Config\Definition\ConfigurationInterface;
17
18
/**
19
 * Class Configuration
20
 *
21
 * Configuration tree.
22
 *
23
 * @package RunOpenCode\Bundle\ExchangeRate\DependencyInjection
24
 */
25
class Configuration implements ConfigurationInterface
26
{
27
    /**
28
     * {@inheritdoc}
29
     */
30 11
    public function getConfigTreeBuilder()
31
    {
32 11
        $treeBuilder = new TreeBuilder();
33
34 11
        $rootNode = $treeBuilder->root('runopencode_exchange_rate');
35
36
        $rootNode
37 11
            ->children()
38 11
                ->scalarNode('base_currency')
39 11
                    ->isRequired()
40 11
                    ->info('Set base currency in which you are doing your business activities.')
41 11
                ->end()
42 11
                ->scalarNode('repository')
43 11
                    ->defaultValue('file')
44 11
                    ->info('Service ID which is in charge for rates persistence.')
45 11
                ->end()
46 11
                ->append($this->getRatesDefinition())
47 11
                ->append($this->getFileRepositoryDefinition())
48 11
                ->append($this->getDoctrineDbalRepositoryDefinition())
49 11
                ->append($this->getSourcesDefinition())
50 11
                ->append($this->getAccessRolesDefinition())
51 11
                ->arrayNode('form_types')
52 11
                    ->addDefaultsIfNotSet()
53 11
                    ->children()
54 11
                        ->append($this->getSourceTypeDefinition())
55 11
                        ->append($this->getRateTypeTypeDefinition())
56 11
                        ->append($this->getCurrencyCodeTypeDefinition())
57 11
                        ->append($this->getForeignCurrencyCodeTypeDefinition())
58 11
                        ->append($this->getRateTypeDefinition())
59 11
                    ->end()
60 11
                ->end()
61 11
                ->append($this->getNotificationsDefinition())
62 11
            ->end()
63 11
        ->end();
64
65 11
        return $treeBuilder;
66
    }
67
68
    /**
69
     * Build configuration tree for rates.
70
     *
71
     * @return ArrayNodeDefinition
72
     */
73 11
    protected function getRatesDefinition()
74
    {
75 11
        $node = new ArrayNodeDefinition('rates');
76
77
        $node
78 11
            ->beforeNormalization()
79
                ->ifTrue(function ($value) {
80 11
                    return array_key_exists('rate', $value);
81 11
                })
82
                ->then(function ($value) {
83 2
                    return $value['rate'];
84 11
                })
85 11
            ->end();
86
87
        $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...
88 11
            ->fixXmlConfig('rate')
89 11
            ->info('Configuration of each individual rate with which you intend to work with.')
90 11
            ->requiresAtLeastOneElement()
91 11
                ->prototype('array')
92 11
                    ->children()
93 11
                        ->scalarNode('currency_code')->isRequired()->end()
94 11
                        ->scalarNode('rate_type')->isRequired()->end()
95 11
                        ->scalarNode('source')->isRequired()->end()
96 11
                        ->arrayNode('extra')
97 11
                            ->useAttributeAsKey('name')
98 11
                            ->prototype('array')
99 11
                                ->children()
100 11
                                    ->variableNode('value')->isRequired()->end()
101 11
                                ->end()
102 11
                            ->end()
103 11
                        ->end()
104 11
                    ->end()
105 11
                ->end()
106 11
            ->end();
107
108 11
        return $node;
109
    }
110
111
    /**
112
     * Build configuration tree for file repository.
113
     *
114
     * @return ArrayNodeDefinition
115
     */
116 11
    protected function getFileRepositoryDefinition()
117
    {
118 11
        $node = new ArrayNodeDefinition('file_repository');
119
120
        $node
121 11
            ->info('Configuration for file repository (if used).')
122 11
            ->addDefaultsIfNotSet()
123 11
            ->children()
124 11
                ->scalarNode('path')
125 11
                    ->info('Absolute path to file where database file will be stored.')
126 11
                    ->defaultValue('%kernel.root_dir%/../var/db/exchange_rates.dat')
127 11
                ->end()
128 11
            ->end()
129 11
        ->end();
130
131 11
        return $node;
132
    }
133
134
    /**
135
     * Build configuration tree for Doctrine Dbal repository.
136
     *
137
     * @return ArrayNodeDefinition
138
     */
139 11
    protected function getDoctrineDbalRepositoryDefinition()
140
    {
141 11
        $node = new ArrayNodeDefinition('doctrine_dbal_repository');
142
143
        $node
144 11
            ->info('Configuration for Doctrine Dbla repository (if used).')
145 11
            ->addDefaultsIfNotSet()
146 11
            ->children()
147 11
                ->scalarNode('connection')
148 11
                    ->info('Which database connection to use.')
149 11
                    ->defaultValue('doctrine.dbal.default_connection')
150 11
                ->end()
151 11
                ->scalarNode('table_name')
152 11
                    ->info('Which table name to use for storing exchange rates.')
153 11
                    ->defaultValue('runopencode_exchange_rate')
154 11
                ->end()            
155 11
            ->end()
156 11
        ->end();
157
158 11
        return $node;
159
    }
160
161
    /**
162
     * Build configuration tree for simple sources.
163
     *
164
     * @return ArrayNodeDefinition
165
     */
166 11
    protected function getSourcesDefinition()
167
    {
168 11
        $node = new ArrayNodeDefinition('sources');
169
170
        $node
171 11
            ->info('Add sources to sources registry without registering them into service container.')
172 11
            ->useAttributeAsKey('name')
173 11
            ->prototype('scalar')->end()
174 11
        ->end();
175
176 11
        return $node;
177
    }
178
179
    /**
180
     * Build configuration tree for access roles.
181
     *
182
     * @return ArrayNodeDefinition
183
     */
184 11
    protected function getAccessRolesDefinition()
185
    {
186 11
        $node = new ArrayNodeDefinition('security');
187
188
        $node
189 11
            ->info('Configuration of security voter access roles.')
190 11
            ->addDefaultsIfNotSet()
191 11
            ->children()
192 11
                ->booleanNode('enabled')
193 11
                    ->info('Enables or disables access controll.')
194 11
                    ->defaultTrue()
195 11
                ->end()
196 11
                ->arrayNode(AccessVoter::VIEW)
197 11
                    ->defaultValue(array(Role::MANAGE_RATE, Role::VIEW_RATE))
198 11
                    ->prototype('scalar')->end()
199 11
                ->end()
200 11
                ->arrayNode(AccessVoter::CREATE)
201 11
                    ->defaultValue(array(Role::MANAGE_RATE, Role::CREATE_RATE))
202 11
                    ->prototype('scalar')->end()
203 11
                ->end()
204 11
                ->arrayNode(AccessVoter::EDIT)
205 11
                    ->defaultValue(array(Role::MANAGE_RATE, Role::EDIT_RATE))
206 11
                    ->prototype('scalar')->end()
207 11
                ->end()
208 11
                ->arrayNode(AccessVoter::DELETE)
209 11
                    ->defaultValue(array(Role::MANAGE_RATE, Role::DELETE_RATE))
210 11
                    ->prototype('scalar')->end()
211 11
                ->end()
212 11
            ->end()
213 11
        ->end();
214
215
216 11
        return $node;
217
    }
218
219
    /**
220
     * Build configuration tree for "RunOpenCode\Bundle\ExchangeRate\Form\Type\SourceType" default settings.
221
     *
222
     * @return ArrayNodeDefinition
223
     */
224 11 View Code Duplication
    protected function getSourceTypeDefinition()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
225
    {
226 11
        $node = new ArrayNodeDefinition('source_type');
227
228
        $node
229 11
            ->info('Modify default "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\SourceType" settings.')
230 11
            ->addDefaultsIfNotSet()
231 11
            ->children()
232 11
                ->scalarNode('choice_translation_domain')->defaultValue('runopencode_exchange_rate')->end()
233 11
                ->arrayNode('preferred_choices')->prototype('scalar')->end()->end()
234 11
            ->end()
235 11
        ->end();
236
237 11
        return $node;
238
    }
239
240
    /**
241
     * Build configuration tree for "RunOpenCode\Bundle\ExchangeRate\Form\Type\RateTypeType" default settings.
242
     *
243
     * @return ArrayNodeDefinition
244
     */
245 11 View Code Duplication
    protected function getRateTypeTypeDefinition()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
246
    {
247 11
        $node = new ArrayNodeDefinition('rate_type_type');
248
249
        $node
250 11
            ->info('Modify default "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\RateTypeType" settings.')
251 11
            ->addDefaultsIfNotSet()
252 11
            ->children()
253 11
                ->scalarNode('choice_translation_domain')->defaultValue('runopencode_exchange_rate')->end()
254 11
                ->arrayNode('preferred_choices')->prototype('scalar')->end()->end()
255 11
            ->end()
256 11
        ->end();
257
258 11
        return $node;
259
    }
260
261
    /**
262
     * Build configuration tree for "RunOpenCode\Bundle\ExchangeRate\Form\Type\CurrencyCodeType" default settings.
263
     *
264
     * @return ArrayNodeDefinition
265
     */
266 11 View Code Duplication
    protected function getCurrencyCodeTypeDefinition()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
267
    {
268 11
        $node = new ArrayNodeDefinition('currency_code_type');
269
270
        $node
271 11
            ->info('Modify default "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\CurrencyCodeType" settings.')
272 11
            ->addDefaultsIfNotSet()
273 11
            ->children()
274 11
                ->scalarNode('choice_translation_domain')->defaultValue('runopencode_exchange_rate')->end()
275 11
                ->arrayNode('preferred_choices')->prototype('scalar')->end()->end()
276 11
            ->end()
277 11
        ->end();
278
279 11
        return $node;
280
    }
281
282
    /**
283
     * Build configuration tree for "RunOpenCode\Bundle\ExchangeRate\Form\Type\ForeignCurrencyCodeType" default settings.
284
     *
285
     * @return ArrayNodeDefinition
286
     */
287 11 View Code Duplication
    protected function getForeignCurrencyCodeTypeDefinition()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
288
    {
289 11
        $node = new ArrayNodeDefinition('foreign_currency_code_type');
290
291
        $node
292 11
            ->info('Modify default "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\ForeignCurrencyCodeType" settings.')
293 11
            ->addDefaultsIfNotSet()
294 11
            ->children()
295 11
                ->scalarNode('choice_translation_domain')->defaultValue('runopencode_exchange_rate')->end()
296 11
                ->arrayNode('preferred_choices')->prototype('scalar')->end()->end()
297 11
            ->end()
298 11
        ->end();
299
300 11
        return $node;
301
    }
302
303
    /**
304
     * Build configuration tree for "RunOpenCode\Bundle\ExchangeRate\Form\Type\RateType" default settings.
305
     *
306
     * @return ArrayNodeDefinition
307
     */
308 11 View Code Duplication
    protected function getRateTypeDefinition()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
309
    {
310 11
        $node = new ArrayNodeDefinition('rate_type');
311
312
        $node
313 11
            ->info('Modify default "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\RateType" settings.')
314 11
            ->addDefaultsIfNotSet()
315 11
            ->children()
316 11
                ->scalarNode('choice_translation_domain')->defaultValue('runopencode_exchange_rate')->end()
317 11
                ->arrayNode('preferred_choices')->prototype('scalar')->end()->end()
318 11
            ->end()
319 11
        ->end();
320
321 11
        return $node;
322
    }
323
324
    /**
325
     * Build configuration tree for notifications.
326
     *
327
     * @return ArrayNodeDefinition
328
     */
329 11
    protected function getNotificationsDefinition()
330
    {
331 11
        $node = new ArrayNodeDefinition('notifications');
332
333
        $node
334 11
            ->beforeNormalization()
335
                ->always(function ($value) {
336
337 1
                    if (isset($value['email'])) {
338 1
                        return ['e_mail' => $value['email']];
339
                    }
340
341 1
                    return $value;
342 11
                })
343 11
            ->end()
344 11
            ->info('Enable and configure notifications, or disable them.')
345 11
            ->addDefaultsIfNotSet()
346 11
            ->children()
347 11
                ->arrayNode('e_mail')
348 11
                    ->fixXmlConfig('recipient', 'recipients')
349 11
                    ->addDefaultsIfNotSet()
350 11
                    ->children()
351 11
                        ->booleanNode('enabled')
352 11
                            ->info('Denotes if e-mail notifications are enabled.')
353 11
                            ->defaultFalse()
354 11
                        ->end()
355 11
                        ->arrayNode('recipients')
356 11
                            ->beforeNormalization()
357 11
                                ->ifString()
358 11
                                ->then(function ($value) {
359
                                    return [$value];
360 11
                                })
361 11
                            ->end()
362 11
                            ->info('E-mail addresses where notifications should be sent.')
363 11
                            ->prototype('scalar')->end()
364 11
                        ->end()
365 11
                    ->end()
366 11
                ->end()
367 11
            ->end()
368 11
        ->end();    
369
370 11
        return $node;
371
    }
372
}
373