Completed
Push — master ( 74fc93...195e55 )
by Sandro
06:11
created

ConfigDumper::createConfig()   C

Complexity

Conditions 9
Paths 72

Size

Total Lines 52
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 9

Importance

Changes 0
Metric Value
dl 0
loc 52
ccs 30
cts 30
cp 1
rs 6.5703
c 0
b 0
f 0
cc 9
eloc 30
nc 72
nop 2
crap 9

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Sandro Keil (https://sandro-keil.de)
4
 *
5
 * @link      http://github.com/sandrokeil/interop-config for the canonical source repository
6
 * @copyright Copyright (c) 2017-2017 Sandro Keil
7
 * @license   http://github.com/sandrokeil/interop-config/blob/master/LICENSE.md New BSD License
8
 */
9
10
declare(strict_types=1);
11
12
namespace Interop\Config\Tool;
13
14
use Interop\Config\ProvidesDefaultOptions;
15
use Interop\Config\RequiresConfig;
16
use Interop\Config\RequiresConfigId;
17
use Interop\Config\RequiresMandatoryOptions;
18
19
/**
20
 * Dumps configuration based on factory definition
21
 *
22
 * @copyright Copyright (c) 2016 Zend Technologies USA Inc. (http://www.zend.com)
23
 */
24
class ConfigDumper extends AbstractConfig
25
{
26
    const CONFIG_TEMPLATE = <<<EOC
27
<?php
28
/**
29
 * This file is generated by \Interop\Config\Tool\ConfigDumper.
30
 *
31
 * @see https://sandrokeil.github.io/interop-config/reference/console-tools.html interop-config documentation
32
 */ 
33
34
EOC;
35
36
    /**
37
     * @var ConsoleHelper
38
     */
39
    private $helper;
40
41 13
    public function __construct(ConsoleHelper $helper = null)
42
    {
43 13
        $this->helper = $helper ?: new ConsoleHelper();
44 13
    }
45
46
    /**
47
     * @param array $config
48
     * @param string $className
49
     * @return array
50
     */
51 12
    public function createConfig(array $config, string $className): array
52
    {
53 12
        $reflectionClass = new \ReflectionClass($className);
54
55 12
        $interfaces = $reflectionClass->getInterfaceNames();
56
57 12
        $factory = $reflectionClass->newInstanceWithoutConstructor();
58 12
        $dimensions = [];
59 12
        $mandatoryOptions = [];
60 12
        $defaultOptions = [];
61
62 12
        if (in_array(RequiresConfig::class, $interfaces, true)) {
63 12
            $dimensions = $factory->dimensions();
64
        }
65
66 12
        if (in_array(RequiresConfigId::class, $interfaces, true)) {
67 8
            $configId = $this->helper->readLine(
68 8
                'config id (default)',
69 8
                'Multiple instances are supported, please enter a'
70
            );
71 8
            if ('' === $configId) {
72 1
                $configId = 'default';
73
            }
74 8
            $dimensions[] = $configId;
75
        }
76
77 12
        $parent = &$config;
78
79 12
        foreach ($dimensions as $dimension) {
80 12
            if (empty($parent[$dimension])) {
81 6
                $parent[$dimension] = [];
82
            }
83 12
            $parent = &$parent[$dimension];
84
        }
85
86 12
        if (in_array(RequiresMandatoryOptions::class, $interfaces, true)) {
87 5
            $mandatoryOptions = $this->readMandatoryOption($factory->mandatoryOptions(), $parent);
88
        }
89
90 12
        if (in_array(ProvidesDefaultOptions::class, $interfaces)) {
91 7
            $defaultOptions = $this->readDefaultOption($factory->defaultOptions(), $parent);
92
        }
93
94 12
        $options = array_replace_recursive(
95 12
            $defaultOptions instanceof \Iterator ? iterator_to_array($defaultOptions) : (array)$defaultOptions,
96 12
            (array)$mandatoryOptions
97
        );
98
99 12
        $parent = array_replace_recursive($parent, $options);
100
101 12
        return $config;
102
    }
103
104 5
    private function readMandatoryOption(iterable $mandatoryOptions, array $config, string $path = ''): array
105
    {
106 5
        $options = [];
107
108 5
        foreach ($mandatoryOptions as $key => $mandatoryOption) {
109 5
            if (!is_scalar($mandatoryOption)) {
110 2
                $options[$key] = $this->readMandatoryOption(
111 2
                    $mandatoryOptions[$key],
112 2
                    $config[$key] ?? [],
113 2
                    trim($path . '.' . $key, '.')
114
                );
115 2
                continue;
116
            }
117 5
            $previousValue = isset($config[$mandatoryOption]) ? ' (' . $config[$mandatoryOption] . ')' : '';
118
119 5
            $options[$mandatoryOption] = $this->helper->readLine(
120 5
                trim($path . '.' . $mandatoryOption, '.') . $previousValue
121
            );
122
123 5
            if ('' === $options[$mandatoryOption] && isset($config[$mandatoryOption])) {
124 5
                $options[$mandatoryOption] = $config[$mandatoryOption];
125
            }
126
        }
127 5
        return $options;
128
    }
129
130 7
    private function readDefaultOption(iterable $defaultOptions, array $config, string $path = ''): array
131
    {
132 7
        $options = [];
133
134 7
        foreach ($defaultOptions as $key => $defaultOption) {
135 7
            if (!is_scalar($defaultOption)) {
136 7
                $options[$key] = $this->readDefaultOption(
137 7
                    $defaultOptions[$key],
138 7
                    $config[$key] ?? [],
139 7
                    trim($path . '.' . $key, '.')
140
                );
141 7
                continue;
142
            }
143 7
            $previousValue = isset($config[$key])
144 3
                ? ' (' . $config[$key] . '), current value <value>' . $defaultOption . '</value>'
145 7
                : ' (' . $defaultOption . ')';
146
147 7
            $options[$key] = $this->helper->readLine(trim($path . '.' . $key, '.') . $previousValue);
148
149 7
            if ('' === $options[$key]) {
150 6
                $options[$key] = $config[$key] ?? $defaultOption;
151
            } else {
152 7
                $options[$key] = $this->convertToType($options[$key], $defaultOption);
153
            }
154
        }
155 7
        return $options;
156
    }
157
158 1
    private function convertToType($value, $originValue)
159
    {
160 1
        switch (gettype($originValue)) {
161 1
            case 'boolean':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
162
                return (bool)$value;
163 1
            case 'integer':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
164 1
                return (int)$value;
165 1
            case 'double':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
166
                return (float)$value;
167 1
            case 'string':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
168
            default:
0 ignored issues
show
Coding Style introduced by
DEFAULT statements must be defined using a colon

As per the PSR-2 coding standard, default statements should not be wrapped in curly braces.

switch ($expr) {
    default: { //wrong
        doSomething();
        break;
    }
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
169 1
                return $value;
170
        }
171
    }
172
173 1
    public function dumpConfigFile(iterable $config): string
174
    {
175 1
        return 'return ' . $this->prepareConfig($config) . ';';
176
    }
177
}
178