Configuration::getFileRepositoryDefinition()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 12
cts 12
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 13
nc 1
nop 0
crap 1
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 12
    public function getConfigTreeBuilder()
31
    {
32 12
        $treeBuilder = new TreeBuilder();
33
34 12
        $rootNode = $treeBuilder->root('runopencode_exchange_rate');
35
36
        $rootNode
37 12
            ->fixXmlConfig('source', 'sources')
38 12
            ->children()
39 12
                ->scalarNode('base_currency')
40 12
                    ->isRequired()
41 12
                    ->info('Set base currency in which you are doing your business activities.')
42 12
                ->end()
43 12
                ->scalarNode('repository')
44 12
                    ->defaultValue('file')
45 12
                    ->info('Service ID which is in charge for rates persistence.')
46 12
                ->end()
47 12
                ->append($this->getRatesDefinition())
48 12
                ->append($this->getFileRepositoryDefinition())
49 12
                ->append($this->getDoctrineDbalRepositoryDefinition())
50 12
                ->append($this->getSourcesDefinition())
51 12
                ->append($this->getAccessRolesDefinition())
52 12
                ->arrayNode('form_types')
53 12
                    ->addDefaultsIfNotSet()
54 12
                    ->children()
55 12
                        ->append($this->getSourceTypeDefinition())
56 12
                        ->append($this->getRateTypeTypeDefinition())
57 12
                        ->append($this->getCurrencyCodeTypeDefinition())
58 12
                        ->append($this->getForeignCurrencyCodeTypeDefinition())
59 12
                        ->append($this->getRateTypeDefinition())
60 12
                    ->end()
61 12
                ->end()
62 12
                ->append($this->getNotificationsDefinition())
63 12
            ->end()
64 12
        ->end();
65
66 12
        return $treeBuilder;
67
    }
68
69
    /**
70
     * Build configuration tree for rates.
71
     *
72
     * @return ArrayNodeDefinition
73
     */
74 12
    protected function getRatesDefinition()
75
    {
76 12
        $node = new ArrayNodeDefinition('rates');
77
78
        $node
79 12
            ->beforeNormalization()
80 12
                ->ifTrue(function ($value) {
81 12
                    return array_key_exists('rate', $value);
82 12
                })
83 12
                ->then(function ($value) {
84 2
                    return $value['rate'];
85 12
                })
86 12
            ->end();
87
88
        $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...
89 12
            ->fixXmlConfig('rate')
90 12
            ->info('Configuration of each individual rate with which you intend to work with.')
91 12
            ->requiresAtLeastOneElement()
92 12
                ->prototype('array')
93 12
                    ->children()
94 12
                        ->scalarNode('currency_code')->isRequired()->end()
95 12
                        ->scalarNode('rate_type')->isRequired()->end()
96 12
                        ->scalarNode('source')->isRequired()->end()
97 12
                        ->arrayNode('extra')
98 12
                            ->useAttributeAsKey('name')
99 12
                            ->prototype('array')
100 12
                                ->children()
101 12
                                    ->variableNode('value')->isRequired()->end()
102 12
                                ->end()
103 12
                            ->end()
104 12
                        ->end()
105 12
                    ->end()
106 12
                ->end()
107 12
            ->end();
108
109 12
        return $node;
110
    }
111
112
    /**
113
     * Build configuration tree for file repository.
114
     *
115
     * @return ArrayNodeDefinition
116
     */
117 12
    protected function getFileRepositoryDefinition()
118
    {
119 12
        $node = new ArrayNodeDefinition('file_repository');
120
121
        $node
122 12
            ->info('Configuration for file repository (if used).')
123 12
            ->addDefaultsIfNotSet()
124 12
            ->children()
125 12
                ->scalarNode('path')
126 12
                    ->info('Absolute path to file where database file will be stored.')
127 12
                    ->defaultValue('%kernel.root_dir%/../var/db/exchange_rates.dat')
128 12
                ->end()
129 12
            ->end()
130 12
        ->end();
131
132 12
        return $node;
133
    }
134
135
    /**
136
     * Build configuration tree for Doctrine Dbal repository.
137
     *
138
     * @return ArrayNodeDefinition
139
     */
140 12
    protected function getDoctrineDbalRepositoryDefinition()
141
    {
142 12
        $node = new ArrayNodeDefinition('doctrine_dbal_repository');
143
144
        $node
145 12
            ->info('Configuration for Doctrine Dbla repository (if used).')
146 12
            ->addDefaultsIfNotSet()
147 12
            ->children()
148 12
                ->scalarNode('connection')
149 12
                    ->info('Which database connection to use.')
150 12
                    ->defaultValue('doctrine.dbal.default_connection')
151 12
                ->end()
152 12
                ->scalarNode('table_name')
153 12
                    ->info('Which table name to use for storing exchange rates.')
154 12
                    ->defaultValue('runopencode_exchange_rate')
155 12
                ->end()            
156 12
            ->end()
157 12
        ->end();
158
159 12
        return $node;
160
    }
161
162
    /**
163
     * Build configuration tree for simple sources.
164
     *
165
     * @return ArrayNodeDefinition
166
     */
167 12
    protected function getSourcesDefinition()
168
    {
169 12
        $node = new ArrayNodeDefinition('sources');
170
171
        $node
172 12
            ->info('Add sources to sources registry without registering them into service container.')
173 12
            ->prototype('scalar')->end()
174 12
        ->end();
175
176 12
        return $node;
177
    }
178
179
    /**
180
     * Build configuration tree for access roles.
181
     *
182
     * @return ArrayNodeDefinition
183
     */
184 12
    protected function getAccessRolesDefinition()
185
    {
186 12
        $node = new ArrayNodeDefinition('security');
187
188
        $node
189 12
            ->info('Configuration of security voter access roles.')
190 12
            ->addDefaultsIfNotSet()
191 12
            ->children()
192 12
                ->booleanNode('enabled')
193 12
                    ->info('Enables or disables access controll.')
194 12
                    ->defaultTrue()
195 12
                ->end()
196 12
                ->arrayNode(AccessVoter::VIEW)
197 12
                    ->defaultValue(array(Role::MANAGE_RATE, Role::VIEW_RATE))
198 12
                    ->prototype('scalar')->end()
199 12
                ->end()
200 12
                ->arrayNode(AccessVoter::CREATE)
201 12
                    ->defaultValue(array(Role::MANAGE_RATE, Role::CREATE_RATE))
202 12
                    ->prototype('scalar')->end()
203 12
                ->end()
204 12
                ->arrayNode(AccessVoter::EDIT)
205 12
                    ->defaultValue(array(Role::MANAGE_RATE, Role::EDIT_RATE))
206 12
                    ->prototype('scalar')->end()
207 12
                ->end()
208 12
                ->arrayNode(AccessVoter::DELETE)
209 12
                    ->defaultValue(array(Role::MANAGE_RATE, Role::DELETE_RATE))
210 12
                    ->prototype('scalar')->end()
211 12
                ->end()
212 12
            ->end()
213 12
        ->end();
214
215
216 12
        return $node;
217
    }
218
219
    /**
220
     * Build configuration tree for "RunOpenCode\Bundle\ExchangeRate\Form\Type\SourceType" default settings.
221
     *
222
     * @return ArrayNodeDefinition
223
     */
224 12 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 12
        $node = new ArrayNodeDefinition('source_type');
227
228
        $node
229 12
            ->info('Modify default "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\SourceType" settings.')
230 12
            ->addDefaultsIfNotSet()
231 12
            ->children()
232 12
                ->scalarNode('choice_translation_domain')->defaultValue('runopencode_exchange_rate')->end()
233 12
                ->arrayNode('preferred_choices')->prototype('scalar')->end()->end()
234 12
            ->end()
235 12
        ->end();
236
237 12
        return $node;
238
    }
239
240
    /**
241
     * Build configuration tree for "RunOpenCode\Bundle\ExchangeRate\Form\Type\RateTypeType" default settings.
242
     *
243
     * @return ArrayNodeDefinition
244
     */
245 12 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 12
        $node = new ArrayNodeDefinition('rate_type_type');
248
249
        $node
250 12
            ->info('Modify default "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\RateTypeType" settings.')
251 12
            ->addDefaultsIfNotSet()
252 12
            ->children()
253 12
                ->scalarNode('choice_translation_domain')->defaultValue('runopencode_exchange_rate')->end()
254 12
                ->arrayNode('preferred_choices')->prototype('scalar')->end()->end()
255 12
            ->end()
256 12
        ->end();
257
258 12
        return $node;
259
    }
260
261
    /**
262
     * Build configuration tree for "RunOpenCode\Bundle\ExchangeRate\Form\Type\CurrencyCodeType" default settings.
263
     *
264
     * @return ArrayNodeDefinition
265
     */
266 12 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 12
        $node = new ArrayNodeDefinition('currency_code_type');
269
270
        $node
271 12
            ->info('Modify default "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\CurrencyCodeType" settings.')
272 12
            ->addDefaultsIfNotSet()
273 12
            ->children()
274 12
                ->scalarNode('choice_translation_domain')->defaultValue('runopencode_exchange_rate')->end()
275 12
                ->arrayNode('preferred_choices')->prototype('scalar')->end()->end()
276 12
            ->end()
277 12
        ->end();
278
279 12
        return $node;
280
    }
281
282
    /**
283
     * Build configuration tree for "RunOpenCode\Bundle\ExchangeRate\Form\Type\ForeignCurrencyCodeType" default settings.
284
     *
285
     * @return ArrayNodeDefinition
286
     */
287 12 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 12
        $node = new ArrayNodeDefinition('foreign_currency_code_type');
290
291
        $node
292 12
            ->info('Modify default "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\ForeignCurrencyCodeType" settings.')
293 12
            ->addDefaultsIfNotSet()
294 12
            ->children()
295 12
                ->scalarNode('choice_translation_domain')->defaultValue('runopencode_exchange_rate')->end()
296 12
                ->arrayNode('preferred_choices')->prototype('scalar')->end()->end()
297 12
            ->end()
298 12
        ->end();
299
300 12
        return $node;
301
    }
302
303
    /**
304
     * Build configuration tree for "RunOpenCode\Bundle\ExchangeRate\Form\Type\RateType" default settings.
305
     *
306
     * @return ArrayNodeDefinition
307
     */
308 12 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 12
        $node = new ArrayNodeDefinition('rate_type');
311
312
        $node
313 12
            ->info('Modify default "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\RateType" settings.')
314 12
            ->addDefaultsIfNotSet()
315 12
            ->children()
316 12
                ->scalarNode('choice_translation_domain')->defaultValue('runopencode_exchange_rate')->end()
317 12
                ->arrayNode('preferred_choices')->prototype('scalar')->end()->end()
318 12
            ->end()
319 12
        ->end();
320
321 12
        return $node;
322
    }
323
324
    /**
325
     * Build configuration tree for notifications.
326
     *
327
     * @return ArrayNodeDefinition
328
     */
329 12
    protected function getNotificationsDefinition()
330
    {
331 12
        $node = new ArrayNodeDefinition('notifications');
332
333
        $node
334 12
            ->beforeNormalization()
335 12
                ->always(function ($value) {
336
337 2
                    if (isset($value['email'])) {
338 2
                        return ['e_mail' => $value['email']];
339
                    }
340
341 1
                    return $value;
342 12
                })
343 12
            ->end()
344 12
            ->info('Enable and configure notifications, or disable them.')
345 12
            ->addDefaultsIfNotSet()
346 12
            ->children()
347 12
                ->arrayNode('e_mail')
348 12
                    ->fixXmlConfig('recipient', 'recipients')
349 12
                    ->addDefaultsIfNotSet()
350 12
                    ->children()
351 12
                        ->booleanNode('enabled')
352 12
                            ->info('Denotes if e-mail notifications are enabled.')
353 12
                            ->defaultFalse()
354 12
                        ->end()
355 12
                        ->arrayNode('recipients')
356 12
                            ->beforeNormalization()
357 12
                                ->ifString()
358 12
                                ->then(function ($value) {
359
                                    return [$value];
360 12
                                })
361
                            ->end()
362
                            ->info('E-mail addresses where notifications should be sent.')
363
                            ->prototype('scalar')->end()
364
                        ->end()
365
                    ->end()
366
                ->end()
367
            ->end()
368
        ->end();    
369
370
        return $node;
371
    }
372
}
373