Passed
Pull Request — develop (#4)
by ANTHONIUS
04:07
created

Application::getContainer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
/*
4
 * This file is part of PhpSpec, A php toolset to drive emergent
5
 * design by specification.
6
 *
7
 * (c) Marcello Duarte <[email protected]>
8
 * (c) Konstantin Kudryashov <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Doyo\PhpSpec\CodeCoverage\Context;
15
16
use PhpSpec\Console\ConsoleIO;
17
use PhpSpec\Console\ContainerAssembler;
18
use PhpSpec\Exception\Configuration\InvalidConfigurationException;
19
use PhpSpec\Matcher\Matcher;
20
use PhpSpec\ServiceContainer;
21
use Symfony\Component\Console\Application as BaseApplication;
22
use PhpSpec\ServiceContainer\IndexedServiceContainer;
23
use PhpSpec\Extension;
24
use Symfony\Component\Console\Command\Command;
25
use Symfony\Component\Console\Helper\DebugFormatterHelper;
26
use Symfony\Component\Console\Helper\FormatterHelper;
27
use Symfony\Component\Console\Helper\HelperSet;
28
use Symfony\Component\Console\Helper\ProcessHelper;
29
use Symfony\Component\Console\Helper\QuestionHelper;
30
use Symfony\Component\Console\Input\StringInput;
31
use Symfony\Component\Console\Output\StreamOutput;
32
33
/**
34
 * The command line application entry point
35
 *
36
 * @internal
37
 */
38
final class Application extends BaseApplication
39
{
40
    /**
41
     * @var IndexedServiceContainer
42
     */
43
    private $container;
44
45
    public function __construct($config)
46
    {
47
        $container = new IndexedServiceContainer();
48
        $container->set('console.commands.run', new Command());
49
        $container->set('console.input', new StringInput('run --coverage'));
50
        $container->set('console.output', new StreamOutput(fopen('php://memory','+w')));
0 ignored issues
show
Bug introduced by
It seems like fopen('php://memory', '+w') can also be of type false; however, parameter $stream of Symfony\Component\Consol...amOutput::__construct() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

50
        $container->set('console.output', new StreamOutput(/** @scrutinizer ignore-type */ fopen('php://memory','+w')));
Loading history...
51
        $container->set('console.helper_set', $this->getDefaultHelperSet());
52
        $this->loadConfig($container, $config);
53
54
        $assembler = new ContainerAssembler();
55
        $assembler->build($container);
56
        $this->container = $container;
57
    }
58
59
    /**
60
     * Gets the default helper set with the helpers that should always be available.
61
     *
62
     * @return HelperSet A HelperSet instance
63
     */
64
    protected function getDefaultHelperSet()
65
    {
66
        return new HelperSet([
67
            new FormatterHelper(),
68
            new DebugFormatterHelper(),
69
            new ProcessHelper(),
70
            new QuestionHelper(),
71
        ]);
72
    }
73
74
    /**
75
     * @throws \RuntimeException
76
     */
77
    protected function loadConfig(IndexedServiceContainer $container, array $config)
78
    {
79
        $this->populateContainerParameters($container, $config);
80
81
        foreach ($config as $key => $val) {
82
            if ('extensions' === $key && \is_array($val)) {
83
                foreach ($val as $class => $extensionConfig) {
84
                    $this->loadExtension($container, $class, $extensionConfig ?: []);
85
                }
86
            }
87
            elseif ('matchers' === $key && \is_array($val)) {
88
                $this->registerCustomMatchers($container, $val);
89
            }
90
        }
91
    }
92
93
    /**
94
     * @return IndexedServiceContainer
95
     */
96
    public function getContainer(): IndexedServiceContainer
97
    {
98
        return $this->container;
99
    }
100
101
    private function registerCustomMatchers(IndexedServiceContainer $container, array $matchersClassnames)
102
    {
103
        foreach ($matchersClassnames as $class) {
104
            $this->ensureIsValidMatcherClass($class);
105
106
            $container->define(sprintf('matchers.%s', $class), function () use ($class) {
107
                return new $class();
108
            }, ['matchers']);
109
        }
110
    }
111
112
    private function ensureIsValidMatcherClass(string $class)
113
    {
114
        if (!class_exists($class)) {
115
            throw new InvalidConfigurationException(sprintf('Custom matcher %s does not exist.', $class));
116
        }
117
118
        if (!is_subclass_of($class, Matcher::class)) {
119
            throw new InvalidConfigurationException(sprintf(
120
                'Custom matcher %s must implement %s interface, but it does not.',
121
                $class,
122
                Matcher::class
123
            ));
124
        }
125
    }
126
127
    private function loadExtension(ServiceContainer $container, string $extensionClass, $config)
128
    {
129
        if (!class_exists($extensionClass)) {
130
            throw new InvalidConfigurationException(sprintf('Extension class `%s` does not exist.', $extensionClass));
131
        }
132
133
        if (!\is_array($config)) {
134
            throw new InvalidConfigurationException('Extension configuration must be an array or null.');
135
        }
136
137
        if (!is_a($extensionClass, Extension::class, true)) {
138
            throw new InvalidConfigurationException(sprintf('Extension class `%s` must implement Extension interface', $extensionClass));
139
        }
140
141
        (new $extensionClass)->load($container, $config);
142
    }
143
144
    private function populateContainerParameters(IndexedServiceContainer $container, array $config)
145
    {
146
        foreach ($config as $key => $val) {
147
            if ('extensions' !== $key && 'matchers' !== $key) {
148
                $container->setParam($key, $val);
149
            }
150
        }
151
    }
152
}
153