Completed
Push — master ( 849f7f...d5f83d )
by Nikola
03:25
created

Configuration::getRatesDefinition()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 37
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 37
ccs 29
cts 29
cp 1
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 30
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 11
    public function getConfigTreeBuilder()
31
    {
32 11
        $treeBuilder = new TreeBuilder();
33
34 11
        $rootNode = $treeBuilder->root('run_open_code_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
            ->end()
62 11
        ->end();
63
64 11
        return $treeBuilder;
65
    }
66
67
    /**
68
     * Build configuration tree for rates.
69
     *
70
     * @return ArrayNodeDefinition
71
     */
72 11
    protected function getRatesDefinition()
73
    {
74 11
        $node = new ArrayNodeDefinition('rates');
75
76
        $node
77 11
            ->beforeNormalization()
78
                ->ifTrue(function ($value) {
79 11
                    return array_key_exists('rate', $value);
80 11
                })
81 11
                ->then(function ($value) {
82 2
                    return $value['rate'];
83 11
                })
84 11
            ->end();
85
86
        $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...
87 11
            ->fixXmlConfig('rate')
88 11
            ->info('Configuration of each individual rate with which you intend to work with.')
89 11
            ->requiresAtLeastOneElement()
90 11
                ->prototype('array')
91 11
                    ->children()
92 11
                        ->scalarNode('currency_code')->isRequired()->end()
93 11
                        ->scalarNode('rate_type')->isRequired()->end()
94 11
                        ->scalarNode('source')->isRequired()->end()
95 11
                        ->arrayNode('extra')
96 11
                            ->useAttributeAsKey('name')
97 11
                            ->prototype('array')
98 11
                                ->children()
99 11
                                    ->variableNode('value')->isRequired()->end()
100 11
                                ->end()
101 11
                            ->end()
102 11
                        ->end()
103 11
                    ->end()
104 11
                ->end()
105 11
            ->end();
106
107 11
        return $node;
108
    }
109
110
    /**
111
     * Build configuration tree for file repository.
112
     *
113
     * @return ArrayNodeDefinition
114
     */
115 11
    protected function getFileRepositoryDefinition()
116
    {
117 11
        $node = new ArrayNodeDefinition('file_repository');
118
119
        $node
120 11
            ->info('Configuration for file repository (if used).')
121 11
            ->addDefaultsIfNotSet()
122 11
            ->children()
123 11
                ->scalarNode('path')
124 11
                    ->info('Absolute path to file where database file will be stored.')
125 11
                    ->defaultValue('%kernel.root_dir%/../var/db/exchange_rates.dat')
126 11
                ->end()
127 11
            ->end()
128 11
        ->end();
129
130 11
        return $node;
131
    }
132
133
    /**
134
     * Build configuration tree for Doctrine Dbal repository.
135
     *
136
     * @return ArrayNodeDefinition
137
     */
138 11
    protected function getDoctrineDbalRepositoryDefinition()
139
    {
140 11
        $node = new ArrayNodeDefinition('doctrine_dbal_repository');
141
142
        $node
143 11
            ->info('Configuration for Doctrine Dbla repository (if used).')
144 11
            ->addDefaultsIfNotSet()
145 11
            ->children()
146 11
                ->scalarNode('connection')
147 11
                    ->info('Which database connection to use.')
148 11
                    ->defaultValue('doctrine.dbal.default_connection')
149 11
                ->end()
150 11
                ->scalarNode('table_name')
151 11
                    ->info('Which table name to use for storing exchange rates.')
152 11
                    ->defaultValue('runopencode_exchange_rate')
153 11
                ->end()            
154 11
            ->end()
155 11
        ->end();
156
157 11
        return $node;
158
    }
159
160
    /**
161
     * Build configuration tree for simple sources.
162
     *
163
     * @return ArrayNodeDefinition
164
     */
165 11
    protected function getSourcesDefinition()
166
    {
167 11
        $node = new ArrayNodeDefinition('sources');
168
169
        $node
170 11
            ->info('Add sources to sources registry without registering them into service container.')
171 11
            ->useAttributeAsKey('name')
172 11
            ->prototype('scalar')->end()
173 11
        ->end();
174
175 11
        return $node;
176
    }
177
178
    /**
179
     * Build configuration tree for access roles.
180
     *
181
     * @return ArrayNodeDefinition
182
     */
183 11
    protected function getAccessRolesDefinition()
184
    {
185 11
        $node = new ArrayNodeDefinition('security');
186
187
        $node
188 11
            ->info('Configuration of security voter access roles.')
189 11
            ->addDefaultsIfNotSet()
190 11
            ->children()
191 11
                ->booleanNode('enabled')
192 11
                    ->info('Enables or disables access controll.')
193 11
                    ->defaultTrue()
194 11
                ->end()
195 11
                ->arrayNode(AccessVoter::VIEW)
196 11
                    ->defaultValue(array(Role::MANAGE_RATE, Role::VIEW_RATE))
197 11
                    ->prototype('scalar')->end()
198 11
                ->end()
199 11
                ->arrayNode(AccessVoter::CREATE)
200 11
                    ->defaultValue(array(Role::MANAGE_RATE, Role::CREATE_RATE))
201 11
                    ->prototype('scalar')->end()
202 11
                ->end()
203 11
                ->arrayNode(AccessVoter::EDIT)
204 11
                    ->defaultValue(array(Role::MANAGE_RATE, Role::EDIT_RATE))
205 11
                    ->prototype('scalar')->end()
206 11
                ->end()
207 11
                ->arrayNode(AccessVoter::DELETE)
208 11
                    ->defaultValue(array(Role::MANAGE_RATE, Role::DELETE_RATE))
209 11
                    ->prototype('scalar')->end()
210 11
                ->end()
211 11
            ->end()
212 11
        ->end();
213
214
215 11
        return $node;
216
    }
217
218
    /**
219
     * Build configuration tree for "RunOpenCode\Bundle\ExchangeRate\Form\Type\SourceType" default settings.
220
     *
221
     * @return ArrayNodeDefinition
222
     */
223 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...
224
    {
225 11
        $node = new ArrayNodeDefinition('source_type');
226
227
        $node
228 11
            ->info('Modify default "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\SourceType" settings.')
229 11
            ->addDefaultsIfNotSet()
230 11
            ->children()
231 11
                ->scalarNode('choice_translation_domain')->defaultValue('roc_exchange_rate')->end()
232 11
                ->arrayNode('preferred_choices')->prototype('scalar')->end()->end()
233 11
            ->end()
234 11
        ->end();
235
236 11
        return $node;
237
    }
238
239
    /**
240
     * Build configuration tree for "RunOpenCode\Bundle\ExchangeRate\Form\Type\RateTypeType" default settings.
241
     *
242
     * @return ArrayNodeDefinition
243
     */
244 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...
245
    {
246 11
        $node = new ArrayNodeDefinition('rate_type_type');
247
248
        $node
249 11
            ->info('Modify default "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\RateTypeType" settings.')
250 11
            ->addDefaultsIfNotSet()
251 11
            ->children()
252 11
                ->scalarNode('choice_translation_domain')->defaultValue('roc_exchange_rate')->end()
253 11
                ->arrayNode('preferred_choices')->prototype('scalar')->end()->end()
254 11
            ->end()
255 11
        ->end();
256
257 11
        return $node;
258
    }
259
260
    /**
261
     * Build configuration tree for "RunOpenCode\Bundle\ExchangeRate\Form\Type\CurrencyCodeType" default settings.
262
     *
263
     * @return ArrayNodeDefinition
264
     */
265 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...
266
    {
267 11
        $node = new ArrayNodeDefinition('currency_code_type');
268
269
        $node
270 11
            ->info('Modify default "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\CurrencyCodeType" settings.')
271 11
            ->addDefaultsIfNotSet()
272 11
            ->children()
273 11
                ->scalarNode('choice_translation_domain')->defaultValue('roc_exchange_rate')->end()
274 11
                ->arrayNode('preferred_choices')->prototype('scalar')->end()->end()
275 11
            ->end()
276 11
        ->end();
277
278 11
        return $node;
279
    }
280
281
    /**
282
     * Build configuration tree for "RunOpenCode\Bundle\ExchangeRate\Form\Type\ForeignCurrencyCodeType" default settings.
283
     *
284
     * @return ArrayNodeDefinition
285
     */
286 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...
287
    {
288 11
        $node = new ArrayNodeDefinition('foreign_currency_code_type');
289
290
        $node
291 11
            ->info('Modify default "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\ForeignCurrencyCodeType" settings.')
292 11
            ->addDefaultsIfNotSet()
293 11
            ->children()
294 11
                ->scalarNode('choice_translation_domain')->defaultValue('roc_exchange_rate')->end()
295 11
                ->arrayNode('preferred_choices')->prototype('scalar')->end()->end()
296 11
            ->end()
297 11
        ->end();
298
299 11
        return $node;
300
    }
301
302
    /**
303
     * Build configuration tree for "RunOpenCode\Bundle\ExchangeRate\Form\Type\RateType" default settings.
304
     *
305
     * @return ArrayNodeDefinition
306
     */
307 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...
308
    {
309 11
        $node = new ArrayNodeDefinition('rate_type');
310
311
        $node
312 11
            ->info('Modify default "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\RateType" settings.')
313 11
            ->addDefaultsIfNotSet()
314 11
            ->children()
315 11
                ->scalarNode('choice_translation_domain')->defaultValue('roc_exchange_rate')->end()
316 11
                ->arrayNode('preferred_choices')->prototype('scalar')->end()->end()
317 11
            ->end()
318 11
        ->end();
319
320 11
        return $node;
321
    }
322
}
323