Completed
Push — master ( 4f28c1...404636 )
by Nikola
05:13
created

Extension::configureAccessVoter()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 25
ccs 12
cts 12
cp 1
rs 8.8571
c 0
b 0
f 0
cc 2
eloc 15
nc 2
nop 2
crap 2
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\DependencyInjection\Configuration as TreeConfiguration;
13
use RunOpenCode\Bundle\ExchangeRate\Security\AccessVoter;
14
use RunOpenCode\ExchangeRate\Configuration;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, RunOpenCode\Bundle\Excha...Injection\Configuration.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
15
use RunOpenCode\ExchangeRate\Utils\CurrencyCodeUtil;
16
use Symfony\Component\Config\FileLocator;
17
use Symfony\Component\DependencyInjection\ContainerBuilder;
18
use Symfony\Component\DependencyInjection\Definition;
19
use Symfony\Component\DependencyInjection\Extension\Extension as BaseExtension;
20
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
21
use Symfony\Component\DependencyInjection\Reference;
22
23
/**
24
 * Class Extension
25
 *
26
 * Bundle extension.
27
 *
28
 * @package RunOpenCode\Bundle\ExchangeRate\DependencyInjection
29
 */
30
class Extension extends BaseExtension
31
{
32
    /**
33
     * {@inheritdoc}
34
     */
35 12
    public function getAlias()
36
    {
37 12
        return "runopencode_exchange_rate";
38
    }
39
40
    /**
41
     * {@inheritdoc}
42
     */
43 12
    public function getNamespace()
44
    {
45 12
        return 'http://www.runopencode.com/xsd-schema/exchange-rate-bundle';
46
    }
47
48
    /**
49
     * {@inheritdoc}
50
     */
51 2
    public function getXsdValidationBasePath()
52
    {
53 2
        return __DIR__.'/../Resources/config/schema';
0 ignored issues
show
Bug Best Practice introduced by
The return type of return __DIR__ . '/../Resources/config/schema'; (string) is incompatible with the return type of the parent method Symfony\Component\Depend...etXsdValidationBasePath of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
54
    }
55
56
    /**
57
     * {@inheritdoc}
58
     */
59 10
    public function load(array $config, ContainerBuilder $container)
60
    {
61 10
        $configuration = new TreeConfiguration();
62 10
        $config = $this->processConfiguration($configuration, $config);
63
64 10
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config/services'));
65 10
        $loader->load('repository.xml');
66 10
        $loader->load('command.xml');
67 10
        $loader->load('form_type.xml');
68 10
        $loader->load('manager.xml');
69 10
        $loader->load('processor.xml');
70 10
        $loader->load('security.xml');
71 10
        $loader->load('source.xml');
72 10
        $loader->load('validator.xml');
73 10
        $loader->load('notifications.xml');
74
75
        $this
76 10
            ->configureBaseCurrency($config, $container)
77 10
            ->configureRepository($config, $container)
78 10
            ->configureFileRepository($config, $container)
79 10
            ->configureDoctrineDbalRepository($config, $container)
80 10
            ->configureAccessVoter($config, $container)
81 10
            ->configureRates($config, $container)
82 10
            ->configureSources($config, $container)
83 10
            ->configureSourceType($config, $container)
84 10
            ->configureRateTypeType($config, $container)
85 10
            ->configureCurrencyCodeType($config, $container)
86 10
            ->configureForeignCurrencyCodeType($config, $container)
87 10
            ->configureRateType($config, $container)
88 10
            ->configureNotifications($config, $container)
89
        ;
90 10
    }
91
92
    /**
93
     * Configure base currency.
94
     *
95
     * @param array $config Configuration parameters.
96
     * @param ContainerBuilder $container Service container.
97
     *
98
     * @return Extension $this Fluent interface.
99
     * @throws \RunOpenCode\ExchangeRate\Exception\UnknownCurrencyCodeException
100
     */
101 10
    protected function configureBaseCurrency(array $config, ContainerBuilder $container)
102
    {
103 10
        $baseCurrency = CurrencyCodeUtil::clean($config['base_currency']);
104 10
        $container->setParameter('runopencode.exchange_rate.base_currency', $baseCurrency);
105
106 10
        return $this;
107
    }
108
109
    /**
110
     * Configure rates.
111
     *
112
     * @param array $config Configuration parameters.
113
     * @param ContainerBuilder $container Service container.
114
     *
115
     * @return Extension $this Fluent interface.
116
     */
117 10
    protected function configureRates(array $config, ContainerBuilder $container)
118
    {
119 10
        foreach ($config['rates'] as $rate) {
120 10
            $definition = new Definition(Configuration::class);
121
122
            $arguments = [
123 10
                $rate['currency_code'],
124 10
                $rate['rate_type'],
125 10
                $rate['source'],
126 10
                (isset($rate['extra']) && $rate['extra']) ? $rate['extra'] : []
127
            ];
128
129
            $definition
130 10
                ->setArguments($arguments)
131 10
                ->setPublic(false)
132 10
                ->addTag('runopencode.exchange_rate.rate_configuration')
133
                ;
134
135 10
            $container->setDefinition(sprintf('runopencode.exchange_rate.rate_configuration.%s.%s.%s', $rate['currency_code'], $rate['rate_type'], $rate['source']), $definition);
136
        }
137
138 10
        return $this;
139
    }
140
141
142
    /**
143
     * Configure sources which does not have to be explicitly added to service container.
144
     *
145
     * @param array $config Configuration parameters.
146
     * @param ContainerBuilder $container Service container.
147
     *
148
     * @return Extension $this Fluent interface.
149
     */
150 10
    protected function configureSources(array $config, ContainerBuilder $container)
151
    {
152 10
        if (!empty($config['sources'])) {
153
154 1
            foreach ($config['sources'] as $name => $class) {
155
156 1
                $definition = new Definition($class);
157
                $definition
158 1
                    ->addTag('runopencode.exchange_rate.source', ['name' => $name]);
159
160 1
                $container->setDefinition(sprintf('runopencode.exchange_rate.source.%s', $name), $definition);
161
            }
162
        }
163
164 10
        return $this;
165
    }
166
167
    /**
168
     * Configure required processors.
169
     *
170
     * @param array $config Configuration parameters.
171
     * @param ContainerBuilder $container Service container.
172
     *
173
     * @return Extension $this Fluent interface.
174
     */
175 10
    protected function configureRepository(array $config, ContainerBuilder $container)
176
    {
177 10
        $container->setParameter('runopencode.exchange_rate.repository', $config['repository']);
178 10
        return $this;
179
    }
180
181
    /**
182
     * Configure file repository.
183
     *
184
     * @param array $config Configuration parameters.
185
     * @param ContainerBuilder $container Service container.
186
     *
187
     * @return Extension $this Fluent interface.
188
     */
189 10
    protected function configureFileRepository(array $config, ContainerBuilder $container)
190
    {
191 10
        $defintion = $container->getDefinition('runopencode.exchange_rate.repository.file_repository');
192
193
        $defintion
194 10
            ->setArguments([
195 10
                $config['file_repository']['path'],
196
            ]);
197
198 10
        return $this;
199
    }
200
201
    /**
202
     * Configure Doctrine Dbal repository.
203
     *
204
     * @param array $config Configuration parameters.
205
     * @param ContainerBuilder $container Service container.
206
     *
207
     * @return Extension $this Fluent interface.
208
     */
209 10
    protected function configureDoctrineDbalRepository(array $config, ContainerBuilder $container)
210
    {
211 10
        $defintion = $container->getDefinition('runopencode.exchange_rate.repository.doctrine_dbal_repository');
212
213
        $defintion
214 10
            ->setArguments([
215 10
                new Reference($config['doctrine_dbal_repository']['connection']),
216 10
                $config['doctrine_dbal_repository']['table_name'],
217
            ]);
218
219 10
        return $this;
220
    }
221
222
    /**
223
     * Configure access voter.
224
     *
225
     * @param array $config Configuration parameters.
226
     * @param ContainerBuilder $container Service container.
227
     *
228
     * @return Extension $this Fluent interface.
229
     */
230 10
    protected function configureAccessVoter(array $config, ContainerBuilder $container)
231
    {
232 10
        if ($config['security']['enabled']) {
233
234
            $container
235 9
                ->getDefinition('runopencode.exchange_rate.security.access_voter')
236 9
                ->setArguments([
237
                    [
238 9
                        AccessVoter::VIEW => $config['security'][AccessVoter::VIEW],
239 9
                        AccessVoter::CREATE => $config['security'][AccessVoter::CREATE],
240 9
                        AccessVoter::EDIT => $config['security'][AccessVoter::EDIT],
241 9
                        AccessVoter::DELETE => $config['security'][AccessVoter::DELETE],
242
                    ],
243
                    true
244
                ]);
245
246 9
            return $this;
247
        }
248
249
        $container
250 1
            ->getDefinition('runopencode.exchange_rate.security.access_voter')
251 1
            ->setArguments([ [], false ]);
252
253 1
        return $this;
254
    }
255
256
    /**
257
     * Configure "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\SourceType" default settings.
258
     *
259
     * @param array $config Configuration parameters.
260
     * @param ContainerBuilder $container Service container.
261
     *
262
     * @return Extension $this Fluent interface.
263
     */
264 10 View Code Duplication
    protected function configureSourceType(array $config, ContainerBuilder $container)
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...
265
    {
266 10
        $definition = $container->getDefinition('runopencode.exchange_rate.form_type.source_type');
267
268 10
        $arguments = $definition->getArguments();
269
270 10
        $arguments[1] = $config['form_types']['source_type'];
271
272 10
        $definition->setArguments($arguments);
273
274 10
        return $this;
275
    }
276
277
    /**
278
     * Configure "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\RateTypeType" default settings.
279
     *
280
     * @param array $config Configuration parameters.
281
     * @param ContainerBuilder $container Service container.
282
     *
283
     * @return Extension $this Fluent interface.
284
     */
285 10 View Code Duplication
    protected function configureRateTypeType(array $config, ContainerBuilder $container)
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...
286
    {
287 10
        $definition = $container->getDefinition('runopencode.exchange_rate.form_type.rate_type_type');
288
289 10
        $arguments = $definition->getArguments();
290
291 10
        $arguments[1] = $config['form_types']['rate_type_type'];
292
293 10
        $definition->setArguments($arguments);
294
295 10
        return $this;
296
    }
297
298
    /**
299
     * Configure "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\CurrencyCodeType" default settings.
300
     *
301
     * @param array $config Configuration parameters.
302
     * @param ContainerBuilder $container Service container.
303
     * @return Extension $this Fluent interface.
304
     */
305 10
    protected function configureCurrencyCodeType(array $config, ContainerBuilder $container)
306
    {
307 10
        $definition = $container->getDefinition('runopencode.exchange_rate.form_type.currency_code_type');
308
309 10
        $arguments = $definition->getArguments();
310
311 10
        $arguments[1] = CurrencyCodeUtil::clean($config['base_currency']);
312 10
        $arguments[2] = $config['form_types']['currency_code_type'];
313
314 10
        $definition->setArguments($arguments);
315
316 10
        return $this;
317
    }
318
319
    /**
320
     * Configure "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\ForeignCurrencyCodeType" default settings.
321
     *
322
     * @param array $config Configuration parameters.
323
     * @param ContainerBuilder $container Service container.
324
     *
325
     * @return Extension $this Fluent interface.
326
     */
327 10 View Code Duplication
    protected function configureForeignCurrencyCodeType(array $config, ContainerBuilder $container)
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...
328
    {
329
330 10
        $definition = $container->getDefinition('runopencode.exchange_rate.form_type.foreign_currency_code_type');
331
332 10
        $arguments = $definition->getArguments();
333
334 10
        $arguments[1] = $config['form_types']['foreign_currency_code_type'];
335
336 10
        $definition->setArguments($arguments);
337
338 10
        return $this;
339
    }
340
341
    /**
342
     * Configure "RunOpenCode\\Bundle\\ExchangeRate\\Form\\Type\\RateType" default settings.
343
     *
344
     * @param array $config Configuration parameters.
345
     * @param ContainerBuilder $container Service container.
346
     *
347
     * @return Extension $this Fluent interface.
348
     */
349 10 View Code Duplication
    protected function configureRateType(array $config, ContainerBuilder $container)
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...
350
    {
351 10
        $definition = $container->getDefinition('runopencode.exchange_rate.form_type.rate_type');
352
353 10
        $arguments = $definition->getArguments();
354
355 10
        $arguments[1] = $config['form_types']['rate_type'];
356
357 10
        $definition->setArguments($arguments);
358
359 10
        return $this;
360
    }
361
362
    /**
363
     * Configure notifications
364
     *
365
     * @param array $config Configuration parameters.
366
     * @param ContainerBuilder $container Service container.
367
     *
368
     * @return Extension $this Fluent interface.
369
     */
370 10
    protected function configureNotifications(array $config, ContainerBuilder $container)
371
    {
372 10
        if (isset($config['notifications']['e_mail']['enabled']) && $config['notifications']['e_mail']['enabled']) {
373 1
            $container->setParameter('runopencode.exchange_rate.notifications.email.recipients', $config['notifications']['e_mail']['recipients']);
374
        }
375
376 10
        return $this;
377
    }
378
}
379