Config   B
last analyzed

Complexity

Total Complexity 39

Size/Duplication

Total Lines 294
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 7
Bugs 1 Features 2
Metric Value
wmc 39
c 7
b 1
f 2
lcom 1
cbo 6
dl 0
loc 294
rs 8.2857

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 2
B checkConfigCommandAlias() 0 27 5
A registerConfigCommandAlias() 0 17 4
A registerCustomCommands() 0 20 3
A newCommand() 0 16 4
A registerCustomAutoloaders() 0 14 3
A setConfig() 0 4 1
A getConfig() 0 4 1
A setConfigurationLoader() 0 4 1
A getLoader() 0 9 2
A load() 0 4 1
A loadPartialConfig() 0 5 1
A getDetectSubFolders() 0 8 2
A createLoader() 0 8 1
A debugWriteln() 0 7 2
A getArray() 0 9 2
A traverse() 0 15 4
1
<?php
2
/*
3
 * @author Tom Klingenberg <[email protected]>
4
 */
5
6
namespace N98\Magento\Application;
7
8
use Composer\Autoload\ClassLoader;
9
use InvalidArgumentException;
10
use N98\Magento\Application;
11
use N98\Util\ArrayFunctions;
12
use N98\Util\BinaryString;
13
use Symfony\Component\Console\Command\Command;
14
use Symfony\Component\Console\Formatter\OutputFormatter;
15
use Symfony\Component\Console\Input\ArgvInput;
16
use Symfony\Component\Console\Input\InputInterface;
17
use Symfony\Component\Console\Output\NullOutput;
18
use Symfony\Component\Console\Output\OutputInterface;
19
20
/**
21
 * Class Config
22
 *
23
 * Class representing the application configuration. Created to factor out configuration related application
24
 * functionality from @see N98\Magento\Application
25
 *
26
 * @package N98\Magento\Application
27
 */
28
class Config
29
{
30
    /**
31
     * @var array config data
32
     */
33
    private $config = array();
34
35
    /**
36
     * @var array
37
     */
38
    private $partialConfig = array();
39
40
    /**
41
     * @var ConfigurationLoader
42
     */
43
    private $loader;
44
45
    /**
46
     * @var array
47
     */
48
    private $initConfig;
49
50
    /**
51
     * @var boolean
52
     */
53
    private $isPharMode;
54
55
    /**
56
     * @var OutputInterface
57
     */
58
    private $output;
59
60
61
    /**
62
     * Config constructor.
63
     *
64
     * @param array $initConfig
65
     * @param bool $isPharMode
66
     * @param OutputInterface $output [optional]
1 ignored issue
show
Documentation introduced by
Should the type for parameter $output not be null|OutputInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
67
     */
68
    public function __construct(array $initConfig = array(), $isPharMode = false, OutputInterface $output = null)
69
    {
70
        $this->initConfig = $initConfig;
71
        $this->isPharMode = (bool) $isPharMode;
72
        $this->output = $output ?: new NullOutput();
73
    }
74
75
    /**
76
     * alias magerun command in input from config
77
     *
78
     * @param InputInterface $input
79
     * @return ArgvInput|InputInterface
80
     */
81
    public function checkConfigCommandAlias(InputInterface $input)
0 ignored issues
show
Coding Style introduced by
checkConfigCommandAlias uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
82
    {
83
        foreach ($this->getArray(array('commands', 'aliases')) as $alias) {
84
            if (!is_array($alias)) {
85
                continue;
86
            }
87
            $aliasCommandName = key($alias);
88
            if ($input->getFirstArgument() !== $aliasCommandName) {
89
                continue;
90
            }
91
            $aliasCommandParams = array_slice(
92
                BinaryString::trimExplodeEmpty(' ', $alias[$aliasCommandName]),
93
                1
94
            );
95
            if (count($aliasCommandParams) > 0) {
96
                // replace with aliased data
97
                $mergedParams = array_merge(
98
                    array_slice($_SERVER['argv'], 0, 2),
99
                    $aliasCommandParams,
100
                    array_slice($_SERVER['argv'], 2)
101
                );
102
                $input = new ArgvInput($mergedParams);
103
            }
104
        }
105
106
        return $input;
107
    }
108
109
    /**
110
     * @param Command $command
111
     */
112
    public function registerConfigCommandAlias(Command $command)
113
    {
114
        foreach ($this->getArray(array('commands', 'aliases')) as $alias) {
115
            if (!is_array($alias)) {
116
                continue;
117
            }
118
119
            $aliasCommandName = key($alias);
120
            $commandString = $alias[$aliasCommandName];
121
            list($originalCommand) = explode(' ', $commandString, 2);
122
            if ($command->getName() !== $originalCommand) {
123
                continue;
124
            }
125
126
            $command->setAliases(array_merge($command->getAliases(), array($aliasCommandName)));
127
        }
128
    }
129
130
    /**
131
     * @param Application $application
132
     */
133
    public function registerCustomCommands(Application $application)
134
    {
135
        foreach ($this->getArray(array('commands', 'customCommands')) as $commandClass) {
136
            $commandName = null;
137
            if (is_array($commandClass)) {
138
                // Support for key => value (name -> class)
139
                $commandName = key($commandClass);
140
                $commandClass = current($commandClass);
141
            }
142
            $command = $this->newCommand($commandClass, $commandName);
143
            $this->debugWriteln(
144
                sprintf(
145
                    '<debug>Add command </debug> <info>%s</info> -> <comment>%s</comment>',
146
                    $command->getName(),
147
                    get_class($command)
148
                )
149
            );
150
            $application->add($command);
151
        }
152
    }
153
154
    /**
155
     * @param string $className
156
     * @param string|null $commandName
157
     * @return Command
158
     * @throws InvalidArgumentException
159
     */
160
    private function newCommand($className, $commandName)
161
    {
162
        /** @var Command $command */
163
        if (!(is_string($className) || is_object($className))) {
164
            throw new InvalidArgumentException(
165
                sprintf('Command classname must be string, %s given', gettype($className))
166
            );
167
        }
168
169
        $command = new $className();
170
        if (null !== $commandName) {
171
            $command->setName($commandName);
172
        }
173
174
        return $command;
175
    }
176
177
    /**
178
     * Adds autoloader prefixes from user's config
179
     *
180
     * @param ClassLoader $autoloader
181
     */
182
    public function registerCustomAutoloaders(ClassLoader $autoloader)
183
    {
184
        $mask = '<debug>Registered %s autoloader </debug> <info>%s</info> -> <comment>%s</comment>';
185
186
        foreach ($this->getArray('autoloaders') as $prefix => $path) {
187
            $autoloader->add($prefix, $path);
188
            $this->debugWriteln(sprintf($mask, 'PSR-2', $prefix, $path));
189
        }
190
191
        foreach ($this->getArray('autoloaders_psr4') as $prefix => $path) {
192
            $autoloader->addPsr4($prefix, $path);
193
            $this->debugWriteln(sprintf($mask, 'PSR-4', OutputFormatter::escape($prefix), $path));
194
        }
195
    }
196
197
    /**
198
     * @param array $config
199
     */
200
    public function setConfig(array $config)
201
    {
202
        $this->config = $config;
203
    }
204
205
    /**
206
     * @return array
207
     */
208
    public function getConfig()
209
    {
210
        return $this->config;
211
    }
212
213
    /**
214
     * @param ConfigurationLoader $configurationLoader
215
     */
216
    public function setConfigurationLoader(ConfigurationLoader $configurationLoader)
217
    {
218
        $this->loader = $configurationLoader;
219
    }
220
221
    /**
222
     * @return ConfigurationLoader
223
     */
224
    public function getLoader()
225
    {
226
        if (!$this->loader) {
227
            $this->loader = $this->createLoader($this->initConfig, $this->isPharMode, $this->output);
228
            $this->initConfig = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $initConfig.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
229
        }
230
231
        return $this->loader;
232
    }
233
234
    public function load()
235
    {
236
        $this->config = $this->getLoader()->toArray();
237
    }
238
239
    /**
240
     * @param bool $loadExternalConfig
241
     */
242
    public function loadPartialConfig($loadExternalConfig)
243
    {
244
        $loader = $this->getLoader();
245
        $this->partialConfig = $loader->getPartialConfig($loadExternalConfig);
246
    }
247
248
    /**
249
     * Get names of sub-folders to be scanned during Magento detection
250
     *
251
     * @return array
252
     */
253
    public function getDetectSubFolders()
254
    {
255
        if (isset($this->partialConfig['detect']['subFolders'])) {
256
            return $this->partialConfig['detect']['subFolders'];
257
        }
258
259
        return array();
260
    }
261
262
    /**
263
     * @param array $initConfig
264
     * @param bool $isPharMode
265
     * @param OutputInterface $output
266
     *
267
     * @return ConfigurationLoader
268
     */
269
    public function createLoader(array $initConfig, $isPharMode, OutputInterface $output)
270
    {
271
        $config = ArrayFunctions::mergeArrays($this->config, $initConfig);
272
273
        $loader = new ConfigurationLoader($config, $isPharMode, $output);
274
275
        return $loader;
276
    }
277
278
    /**
279
     * @param string $message
280
     */
281
    private function debugWriteln($message)
282
    {
283
        $output = $this->output;
284
        if (OutputInterface::VERBOSITY_DEBUG <= $output->getVerbosity()) {
285
            $output->writeln($message);
286
        }
287
    }
288
289
    /**
290
     * Get array from config, default to an empty array if not set
291
     *
292
     * @param string|array $key
293
     * @param array $default [optional]
294
     * @return array
295
     */
296
    private function getArray($key, $default = array())
297
    {
298
        $result = $this->traverse((array) $key);
299
        if (null === $result) {
300
            return $default;
301
        }
302
303
        return $result;
304
    }
305
306
    private function traverse(array $keys)
307
    {
308
        $anchor = &$this->config;
309
        foreach ($keys as $key) {
310
            if (!isset($anchor[$key])) {
311
                return null;
312
            }
313
            $anchor = &$anchor[$key];
314
            if (!is_array($anchor)) {
315
                return null;
316
            }
317
        }
318
319
        return $anchor;
320
    }
321
}
322