Failed Conditions
Push — feature/extension ( 4da90f...371818 )
by Yo
02:21
created

Behat3SymfonyExtension::loadInitializer()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 33
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 33
ccs 26
cts 26
cp 1
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 22
nc 1
nop 1
crap 1
1
<?php
2
namespace Yoanm\Behat3SymfonyExtension\ServiceContainer;
3
4
use Behat\Testwork\ServiceContainer\Exception\ProcessingException;
5
use Behat\Testwork\ServiceContainer\Extension;
6
use Behat\Testwork\ServiceContainer\ExtensionManager;
7
use Monolog\Handler\StreamHandler;
8
use Monolog\Logger;
9
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
10
use Symfony\Component\DependencyInjection\ContainerBuilder;
11
use Symfony\Component\DependencyInjection\Definition;
12
use Symfony\Component\DependencyInjection\Reference;
13
use Yoanm\Behat3SymfonyExtension\Context\Initializer\BehatContextSubscriberInitializer;
14
use Yoanm\Behat3SymfonyExtension\Context\Initializer\KernelHandlerAwareInitializer;
15
use Yoanm\Behat3SymfonyExtension\Context\Initializer\LoggerAwareInitializer;
16
use Yoanm\Behat3SymfonyExtension\Handler\KernelHandler;
17
use Yoanm\Behat3SymfonyExtension\Logger\SfKernelEventLogger;
18
use Yoanm\Behat3SymfonyExtension\ServiceContainer\Driver\Behat3SymfonyDriverFactory;
19
use Yoanm\Behat3SymfonyExtension\Subscriber\RebootKernelSubscriber;
20
use Yoanm\Behat3SymfonyExtension\Subscriber\SfKernelLoggerSubscriber;
21
22
class Behat3SymfonyExtension implements Extension
23
{
24
    const BASE_CONTAINER_ID = 'behat3_symfony_extension';
25
    const KERNEL_SERVICE_ID = 'behat3_symfony_extension.kernel';
26
27
    /**
28
     * {@inheritdoc}
29
     */
30 1
    public function getConfigKey()
31
    {
32 1
        return 'behat3_symfony';
33
    }
34
35
    /**
36
     * {@inheritdoc}
37
     */
38
    public function initialize(ExtensionManager $extensionManager)
39
    {
40
        $extensionManager->getExtension('mink')
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Behat\Testwork\ServiceContainer\Extension as the method registerDriverFactory() does only exist in the following implementations of said interface: Behat\MinkExtension\ServiceContainer\MinkExtension.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
41
            ->registerDriverFactory(new Behat3SymfonyDriverFactory());
42
    }
43
44
    /**
45
     * {@inheritdoc}
46
     */
47
    public function configure(ArrayNodeDefinition $builder)
48
    {
49
        $castToBool = function ($value) {
50
            $filtered = filter_var(
51
                $value,
52
                FILTER_VALIDATE_BOOLEAN,
53
                FILTER_NULL_ON_FAILURE
54
            );
55
56
            return (null === $filtered) ? (bool) $value : $filtered;
57
        };
58
59
        $builder
60
            ->addDefaultsIfNotSet()
61
                ->children()
62
                    ->arrayNode('logger')
63
                        ->addDefaultsIfNotSet()
64
                        ->children()
65
                            ->scalarNode('path')
66
                                ->defaultValue('var/log/behat.log')
67
                            ->end()
68
                            ->scalarNode('level')
69
                                ->beforeNormalization()
70
                                ->always()
71
                                ->then(function ($value) {
72
                                    return Logger::toMonologLevel($value);
73
                                })
74
                                ->end()
75
                                ->defaultValue(Logger::DEBUG)
76
                            ->end()
77
                        ->end()
78
                    ->end()
79
                    ->arrayNode('kernel')
80
                        ->addDefaultsIfNotSet()
81
                        ->children()
82
                            ->scalarNode('bootstrap')
83
                                ->defaultValue('app/autoload.php')
84
                            ->end()
85
                            ->scalarNode('path')
86
                                ->defaultValue('app/AppKernel.php')
87
                            ->end()
88
                            ->scalarNode('class')
89
                                ->defaultValue('AppKernel')
90
                            ->end()
91
                            ->scalarNode('env')
92
                                ->defaultValue('test')
93
                            ->end()
94
                            ->booleanNode('debug')
95
                                ->beforeNormalization()
96
                                ->always()
97
                                    ->then($castToBool)
98
                                ->end()
99
                                ->defaultTrue()
100
                            ->end()
101
                            ->booleanNode('reboot')
102
                                ->info('If true symfony kernel will be rebooted after each scenario/example')
103
                                ->beforeNormalization()
104
                                    ->always()
105
                                    ->then($castToBool)
106
                                ->end()
107
                                ->defaultTrue()
108
                            ->end()
109
                        ->end()
110
                    ->end()
111
                ->end()
112
            ->end();
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     */
118 2
    public function load(ContainerBuilder $container, array $config)
119
    {
120 2
        $this->loadKernel($container, $config['kernel']);
121 2
        $this->loadLogger($container, $config['logger']);
122 2
        $this->loadHandler($container);
123 2
        $this->loadInitializer($container);
124 2
        $this->loadSubscriber($container, $config['kernel']);
125 2
    }
126
127
    /**
128
     * {@inheritdoc}
129
     */
130 3
    public function process(ContainerBuilder $container)
131
    {
132 3
        $bootstrapPath = $container->getParameter($this->getContainerParamOrServiceId('kernel.bootstrap'));
133 3
        if ($bootstrapPath) {
134 2
            $bootstrap = sprintf(
135 2
                '%s/%s',
136 2
                $container->getParameter('paths.base'),
137
                $bootstrapPath
138 2
            );
139 2
            if (file_exists($bootstrap)) {
140 1
                require_once($bootstrap);
141 1
            } else {
142 1
                throw new ProcessingException('Could not find bootstrap file !');
143
            }
144 1
        }
145 2
    }
146
147
    /**
148
     * @param ContainerBuilder $container
149
     * @param array            $kernelConfig
150
     */
151 2
    protected function loadKernel(ContainerBuilder $container, array $kernelConfig)
152
    {
153 2
        $container->setParameter(
154 2
            $this->getContainerParamOrServiceId('kernel.reboot'),
155 2
            $kernelConfig['reboot']
156 2
        );
157 2
        $this->createService(
158 2
            $container,
159 2
            'kernel',
160 2
            $kernelConfig['class'],
161
            array(
162 2
                $kernelConfig['env'],
163 2
                $kernelConfig['debug'],
164
            )
165 2
        );
166 2
    }
167
168
    /**
169
     * @param ContainerBuilder $container
170
     * @param array            $loggerConfig
171
     */
172 2
    protected function loadLogger(ContainerBuilder $container, array $loggerConfig)
173
    {
174 2
        $baseHandlerServiceId = 'logger.handler';
175
        // Handler
176 2
        $this->createService(
177 2
            $container,
178 2
            $baseHandlerServiceId,
179 2
            StreamHandler::class,
180
            array(
181 2
                sprintf(
182 2
                    '%s/%s',
183 2
                    '%behat.paths.base%',
184 2
                    sprintf(
185 2
                        '%%%s%%',
186 2
                        $loggerConfig['path']
187 2
                    )
188 2
                ),
189 2
                $loggerConfig['level'],
190
            )
191 2
        );
192
        // Logger
193 2
        $this->createService(
194 2
            $container,
195 2
            'logger',
196 2
            Logger::class,
197
            array(
198 2
                'behat3Symfony',
199 2
                $loggerConfig['level'],
200 2
            ),
201 2
            array('event_dispatcher.subscriber'),
202
            array(
203
                array(
204 2
                    'pushHandler',
205 2
                    array(new Reference($this->getContainerParamOrServiceId($baseHandlerServiceId)))
206 2
                )
207 2
            )
208 2
        );
209
        // SfKernelEventLogger
210 2
        $this->createService(
211 2
            $container,
212 2
            'logger.sf_kernel_logger',
213 2
            SfKernelEventLogger::class,
214
            array(
215 2
                new Reference($this->getContainerParamOrServiceId('kernel'))
216 2
            ),
217 2
            array('event_dispatcher.subscriber')
218 2
        );
219 2
    }
220
221
    /**
222
     * @param ContainerBuilder $container
223
     */
224 2
    protected function loadHandler(ContainerBuilder $container)
225
    {
226 2
        $this->createService(
227 2
            $container,
228 2
            'handler.kernel',
229 2
            KernelHandler::class,
230
            array(
231 2
                new Reference('event_dispatcher'),
232 2
                new Reference(self::KERNEL_SERVICE_ID),
233
            )
234 2
        );
235 2
    }
236
237
    /**
238
     * @param ContainerBuilder $container
239
     */
240 2
    protected function loadInitializer(ContainerBuilder $container)
241
    {
242
        // KernelAware
243 2
        $this->createService(
244 2
            $container,
245 2
            'initializer.kernel_aware',
246 2
            KernelHandlerAwareInitializer::class,
247
            array(
248 2
                new Reference($this->getContainerParamOrServiceId('handler.kernel')),
249 2
            ),
250 2
            array('context.initializer')
251 2
        );
252
        // LoggerAware
253 2
        $this->createService(
254 2
            $container,
255 2
            'initializer.logger_aware',
256 2
            LoggerAwareInitializer::class,
257
            array(
258 2
                new Reference($this->getContainerParamOrServiceId('logger')),
259 2
            ),
260 2
            array('context.initializer')
261 2
        );
262
        // BehatSubscriber
263 2
        $this->createService(
264 2
            $container,
265 2
            'initializer.behat_subscriber',
266 2
            BehatContextSubscriberInitializer::class,
267
            array(
268 2
                new Reference('event_dispatcher'),
269 2
            ),
270 2
            array('context.initializer')
271 2
        );
272 2
    }
273
274
    /**
275
     * @param ContainerBuilder $container
276
     * @param array            $kernelConfig
277
     */
278 2
    protected function loadSubscriber(ContainerBuilder $container, array $kernelConfig)
279
    {
280 2
        $this->createService(
281 2
            $container,
282 2
            'subscriber.sf_kernel_logger',
283 2
            SfKernelLoggerSubscriber::class,
284
            array(
285 2
                new Reference($this->getContainerParamOrServiceId('logger.sf_kernel_logger')),
286 2
            ),
287 2
            array('event_dispatcher.subscriber')
288 2
        );
289
290 2
        if (true === $kernelConfig['reboot']) {
291 1
            $this->loadAutoRebootKernel($container);
292 1
        }
293 2
    }
294
295
    /**
296
     * @param ContainerBuilder $container
297
     */
298 1
    protected function loadAutoRebootKernel(ContainerBuilder $container)
299
    {
300 1
        $this->createService(
301 1
            $container,
302 1
            'subscriber.reboot_kernel',
303 1
            RebootKernelSubscriber::class,
304
            array(
305 1
                new Reference($this->getContainerParamOrServiceId('handler.kernel')),
306 1
            ),
307
            array(
308
                'event_dispatcher.subscriber'
309 1
            )
310 1
        );
311 1
    }
312
313
    /**
314
     * @param string $key
315
     *
316
     * @return string
317
     */
318 5
    private function getContainerParamOrServiceId($key)
319
    {
320 5
        return sprintf(
321 5
            '%s.%s',
322 5
            self::BASE_CONTAINER_ID,
323
            $key
324 5
        );
325
    }
326
327
    /**
328
     * @param ContainerBuilder $container
329
     * @param string           $id
330
     * @param string           $class
331
     * @param array            $argumentList
332
     * @param array            $tagList
333
     * @param array            $addMethodCallList
334
     */
335 2
    private function createService(
336
        ContainerBuilder $container,
337
        $id,
338
        $class,
339
        $argumentList = array(),
340
        $tagList = array(),
341
        $addMethodCallList = array()
342
    ) {
343 2
        $definition = new Definition($class, $argumentList);
344
345 2
        foreach ($tagList as $tag) {
346 2
            $definition->addTag($tag);
347 2
        }
348
349 2
        foreach ($addMethodCallList as $methodCall) {
350 2
            $definition->addMethodCall($methodCall[0], $methodCall[1]);
351 2
        }
352
353 2
        $container->setDefinition($this->getContainerParamOrServiceId($id), $definition);
354 2
    }
355
}
356