Completed
Push — master ( 83bc09...9f61a7 )
by Andrii
11:02
created

Helper::mergeConfig()   C

Complexity

Conditions 13
Paths 3

Size

Total Lines 32
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 182

Importance

Changes 0
Metric Value
eloc 22
dl 0
loc 32
ccs 0
cts 24
cp 0
rs 6.6166
c 0
b 0
f 0
cc 13
nc 3
nop 0
crap 182

How to fix   Complexity   

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
 * Composer plugin for config assembling
4
 *
5
 * @link      https://github.com/hiqdev/composer-config-plugin
6
 * @package   composer-config-plugin
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2016-2018, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hiqdev\composer\config;
12
13
use Closure;
14
use ReflectionFunction;
15
use yii\helpers\UnsetArrayValue;
0 ignored issues
show
Bug introduced by
The type yii\helpers\UnsetArrayValue was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use yii\helpers\ReplaceArrayValue;
0 ignored issues
show
Bug introduced by
The type yii\helpers\ReplaceArrayValue was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
18
/**
19
 * Helper class.
20
 *
21
 * @author Andrii Vasyliev <[email protected]>
22
 */
23
class Helper
24
{
25
    /**
26
     * Merges two or more arrays into one recursively.
27
     * Based on Yii2 yii\helpers\BaseArrayHelper::merge.
28
     * @return array the merged array
29
     */
30
    public static function mergeConfig(): array
31
    {
32
        $args = \func_get_args();
33
        $res = array_shift($args) ?: [];
34
        foreach ($args as $items) {
35
            if (!\is_array($items)) {
36
                continue;
37
            }
38
            foreach ($items as $k => $v) {
39
                if ($v instanceof UnsetArrayValue) {
40
                    unset($res[$k]);
41
                } elseif ($v instanceof ReplaceArrayValue) {
42
                    $res[$k] = $v->value;
43
                } elseif (\is_int($k)) {
44
                    /// XXX skip repeated values
45
                    if (\in_array($v, $res, true))  {
46
                        continue;
47
                    }
48
                    if (isset($res[$k])) {
49
                        $res[] = $v;
50
                    } else {
51
                        $res[$k] = $v;
52
                    }
53
                } elseif (\is_array($v) && isset($res[$k]) && \is_array($res[$k])) {
54
                    $res[$k] = self::mergeConfig($res[$k], $v);
55
                } else {
56
                    $res[$k] = $v;
57
                }
58
            }
59
        }
60
61
        return $res;
62
    }
63
64
    public static function exportDefines(array $defines): string
65
    {
66
        $res = '';
67
        foreach ($defines as $key => $value) {
68
            $var = static::exportVar($value);
69
            $res .= "defined('$key') or define('$key', $var);\n";
70
        }
71
72
        return $res;
73
    }
74
75
    /**
76
     * Returns a parsable string representation of given value.
77
     * In contrast to var_dump outputs Closures as PHP code.
78
     * @param mixed $value
79
     * @return string
80
     * @throws \ReflectionException
81
     */
82
    public static function exportVar($value): string
83
    {
84
        $closures = self::collectClosures($value);
85
        $res = var_export($value, true);
86
        if (!empty($closures)) {
87
            $subs = [];
88
            foreach ($closures as $key => $closure) {
89
                $subs["'" . $key . "'"] = self::dumpClosure($closure);
90
            }
91
            $res = strtr($res, $subs);
92
        }
93
94
        return $res;
95
    }
96
97
    /**
98
     * Collects closures from given input.
99
     * Substitutes closures with a tag.
100
     * @param mixed $input will be changed
101
     * @return array array of found closures
102
     */
103
    private static function collectClosures(&$input): array
104
    {
105
        static $closureNo = 1;
106
        $closures = [];
107
        if (\is_array($input)) {
108
            foreach ($input as &$value) {
109
                if (\is_array($value) || $value instanceof Closure) {
110
                    $closures = array_merge($closures, self::collectClosures($value));
111
                }
112
            }
113
        } elseif ($input instanceof Closure) {
114
            ++$closureNo;
115
            $key = "--==<<[[((Closure#$closureNo))]]>>==--";
116
            $closures[$key] = $input;
117
            $input = $key;
118
        }
119
120
        return $closures;
121
    }
122
123
    /**
124
     * Dumps closure object to string.
125
     * Based on http://www.metashock.de/2013/05/dump-source-code-of-closure-in-php/.
126
     * @param Closure $closure
127
     * @return string
128
     * @throws \ReflectionException
129
     */
130
    public static function dumpClosure(Closure $closure): string
131
    {
132
        $res = 'function (';
133
        $fun = new ReflectionFunction($closure);
134
        $args = [];
135
        foreach ($fun->getParameters() as $arg) {
136
            $str = '';
137
            if ($arg->isArray()) {
138
                $str .= 'array ';
139
            } elseif ($arg->getClass()) {
140
                $str .= $arg->getClass()->name . ' ';
141
            }
142
            if ($arg->isPassedByReference()) {
143
                $str .= '&';
144
            }
145
            $str .= '$' . $arg->name;
146
            if ($arg->isOptional()) {
147
                $str .= ' = ' . var_export($arg->getDefaultValue(), true);
148
            }
149
            $args[] = $str;
150
        }
151
        $res .= implode(', ', $args);
152
        $res .= ') {' . PHP_EOL;
153
        $lines = file($fun->getFileName());
154
        for ($i = $fun->getStartLine(); $i < $fun->getEndLine(); ++$i) {
155
            $res .= $lines[$i];
156
        }
157
158
        return rtrim($res, "\r\n ,");
159
    }
160
}
161