Failed Conditions
Push — feature/extension ( 371818...753603 )
by Yo
02:13
created

Behat3SymfonyExtension   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 344
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 71.22%

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 8
dl 0
loc 344
ccs 146
cts 205
cp 0.7122
rs 10
c 0
b 0
f 0

13 Methods

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