Completed
Push — develop ( 664159...ca40eb )
by Tom
04:40
created

Config::newCommand()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 14
rs 9.4285
cc 3
eloc 7
nc 2
nop 2
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\Input\ArgvInput;
15
use Symfony\Component\Console\Input\InputInterface;
16
use Symfony\Component\Console\Output\NullOutput;
17
use Symfony\Component\Console\Output\OutputInterface;
18
19
/**
20
 * Class Config
21
 *
22
 * Class representing the application configuration. Created to factor out configuration related application
23
 * functionality from @see N98\Magento\Application
24
 *
25
 * @package N98\Magento\Application
26
 */
27
class Config
28
{
29
    /**
30
     * @var array config data
31
     */
32
    private $config = array();
33
34
    /**
35
     * @var array
36
     */
37
    private $partialConfig = array();
38
39
    /**
40
     * @var ConfigurationLoader
41
     */
42
    private $loader;
43
44
    /**
45
     * @var array
46
     */
47
    private $initConfig;
48
49
    /**
50
     * @var boolean
51
     */
52
    private $isPharMode;
53
54
    /**
55
     * @var OutputInterface
56
     */
57
    private $output;
58
59
60
    /**
61
     * Config constructor.
62
     * @param array $initConfig
63
     * @param bool $isPharMode
64
     * @param OutputInterface $output [optional]
0 ignored issues
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...
65
     */
66
    public function __construct(array $initConfig = array(), $isPharMode = false, OutputInterface $output = null)
67
    {
68
        $this->initConfig = $initConfig;
69
        $this->isPharMode = (bool)$isPharMode;
70
        $this->output = $output ?: new NullOutput();
71
    }
72
73
    /**
74
     * alias magerun command in input from config
75
     *
76
     * @param InputInterface $input
77
     * @return ArgvInput|InputInterface
78
     */
79
    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...
80
    {
81
        foreach ($this->getArray(array('commands', 'aliases')) as $alias) {
82
            if (!is_array($alias)) {
83
                continue;
84
            }
85
            $aliasCommandName = key($alias);
86
            if ($input->getFirstArgument() !== $aliasCommandName) {
87
                continue;
88
            }
89
            $aliasCommandParams = array_slice(
90
                BinaryString::trimExplodeEmpty(' ', $alias[$aliasCommandName]),
91
                1
92
            );
93
            if (count($aliasCommandParams) > 0) {
94
                // replace with aliased data
95
                $mergedParams = array_merge(
96
                    array_slice($_SERVER['argv'], 0, 2),
97
                    $aliasCommandParams,
98
                    array_slice($_SERVER['argv'], 2)
99
                );
100
                $input = new ArgvInput($mergedParams);
101
            }
102
        }
103
104
        return $input;
105
    }
106
107
    /**
108
     * @param Command $command
109
     */
110
    public function registerConfigCommandAlias(Command $command)
111
    {
112
        foreach ($this->getArray(array('commands', 'aliases')) as $alias) {
113
            if (!is_array($alias)) {
114
                continue;
115
            }
116
117
            $aliasCommandName = key($alias);
118
            $commandString = $alias[$aliasCommandName];
119
            list($originalCommand) = explode(' ', $commandString, 2);
120
            if ($command->getName() !== $originalCommand) {
121
                continue;
122
            }
123
124
            $command->setAliases(array_merge($command->getAliases(), array($aliasCommandName)));
125
        }
126
    }
127
128
    /**
129
     * @param Application $application
130
     */
131
    public function registerCustomCommands(Application $application)
132
    {
133
        foreach ($this->getArray(array('commands', 'customCommands')) as $commandClass) {
134
            $command = null;
0 ignored issues
show
Unused Code introduced by
$command is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
135
136
            if (is_array($commandClass)) {
137
                // Support for key => value (name -> class)
138
                $command = $this->newCommand(current($commandClass), key($commandClass));
139
            } else {
140
                $command = $this->newCommand($commandClass, $commandClass);
141
            }
142
143
            $this->debugWriteln(sprintf('<debug>Add command </debug><comment>%s</comment>', get_class($command)));
144
            $application->add($command);
145
        }
146
    }
147
148
    /**
149
     * @param string $className
150
     *
151
     * @param string $commandName
152
     *
153
     * @return Command
154
     */
155
    private function newCommand($className, $commandName)
156
    {
157
        /** @var Command $command */
158
        if (!(is_string($className) || is_object($className))) {
159
            throw new InvalidArgumentException(
160
                sprintf('Command classname must be string, %s given', gettype($className))
161
            );
162
        }
163
164
        $command = new $className();
165
        $command->setName($commandName);
166
167
        return $command;
168
    }
169
170
    /**
171
     * Adds autoloader prefixes from user's config
172
     *
173
     * @param ClassLoader $autoloader
174
     */
175
    public function registerCustomAutoloaders(ClassLoader $autoloader)
176
    {
177
        $mask = '<debug>Registered %s autoloader </debug> <info>%s</info> -> <comment>%s</comment>';
178
179
        foreach ($this->getArray('autoloaders') as $prefix => $path) {
180
            $autoloader->add($prefix, $path);
181
            $this->debugWriteln(sprintf($mask, 'PSR-2', $prefix, $path));
182
        }
183
184
        foreach ($this->getArray('autoloaders_psr4') as $prefix => $path) {
185
            $autoloader->addPsr4($prefix, $path);
186
            $this->debugWriteln(sprintf($mask, 'PSR-4', $prefix, $path));
187
        }
188
    }
189
190
    /**
191
     * @param array $config
192
     */
193
    public function setConfig(array $config)
194
    {
195
        $this->config = $config;
196
    }
197
198
    /**
199
     * @return array
200
     */
201
    public function getConfig()
202
    {
203
        return $this->config;
204
    }
205
206
    /**
207
     * @param ConfigurationLoader $configurationLoader
208
     */
209
    public function setConfigurationLoader(ConfigurationLoader $configurationLoader)
210
    {
211
        $this->loader = $configurationLoader;
212
    }
213
214
    /**
215
     * @return ConfigurationLoader
216
     */
217
    public function getLoader()
218
    {
219
        if (!$this->loader) {
220
            $this->loader = $this->createLoader($this->initConfig, $this->isPharMode, $this->output);
221
            $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...
222
        }
223
224
        return $this->loader;
225
    }
226
227
    public function load()
228
    {
229
        $this->config = $this->getLoader()->toArray();
230
    }
231
232
    /**
233
     * @param bool $loadExternalConfig
234
     */
235
    public function loadPartialConfig($loadExternalConfig)
236
    {
237
        $loader = $this->getLoader();
238
        $this->partialConfig = $loader->getPartialConfig($loadExternalConfig);
239
    }
240
241
    /**
242
     * Get names of sub-folders to be scanned during Magento detection
243
     * @return array
244
     */
245
    public function getDetectSubFolders()
246
    {
247
        if (isset($this->partialConfig['detect']['subFolders'])) {
248
            return $this->partialConfig['detect']['subFolders'];
249
        }
250
251
        return array();
252
    }
253
254
    /**
255
     * @param array $initConfig
256
     * @param bool $isPharMode
257
     * @param OutputInterface $output
258
     *
259
     * @return ConfigurationLoader
260
     */
261
    public function createLoader(array $initConfig, $isPharMode, OutputInterface $output)
262
    {
263
        $config = ArrayFunctions::mergeArrays($this->config, $initConfig);
264
265
        $loader = new ConfigurationLoader($config, $isPharMode, $output);
266
267
        return $loader;
268
    }
269
270
    /**
271
     * @param string $message
272
     */
273
    private function debugWriteln($message)
274
    {
275
        $output = $this->output;
276
        if (OutputInterface::VERBOSITY_DEBUG <= $output->getVerbosity()) {
277
            $output->writeln($message);
278
        }
279
    }
280
281
    /**
282
     * Get array from config, default to an empty array if not set
283
     *
284
     * @param string|array $key
285
     * @param array $default [optional]
286
     * @return array
287
     */
288
    private function getArray($key, $default = array())
289
    {
290
        $result = $this->traverse((array)$key);
291
        if (null === $result) {
292
            return $default;
293
        }
294
        return $result;
295
    }
296
297
    private function traverse(array $keys)
298
    {
299
        $anchor = &$this->config;
300
        foreach ($keys as $key) {
301
            if (!isset($anchor[$key])) {
302
                return null;
303
            }
304
            $anchor = &$anchor[$key];
305
            if (!is_array($anchor)) {
306
                return null;
307
            }
308
        }
309
        return $anchor;
310
    }
311
}
312