Completed
Pull Request — master (#552)
by Greg
03:27
created

ConfigProcessor::export()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 0
1
<?php
2
3
namespace Robo\Config;
4
5
use Grasmash\YamlExpander\Expander;
6
7
/**
8
 * The config processor combines multiple configuration
9
 * files together, and processes them as necessary.
10
 */
11
class ConfigProcessor
12
{
13
    protected $processedConfig = [];
14
    protected $unprocessedConfig = [];
15
16
    /**
17
     * Extend the configuration to be processed with the
18
     * configuration provided by the specified loader.
19
     *
20
     * @param ConfigLoaderInterface $loader
21
     */
22
    public function extend(ConfigLoaderInterface $loader)
23
    {
24
        return $this->addFromSource($loader->export(), $loader->getSourceName());
25
    }
26
27
    /**
28
     * Extend the configuration to be processed with
29
     * the provided nested array.
30
     *
31
     * @param array $data
32
     */
33
    public function add($data)
34
    {
35
        $this->unprocessedConfig[] = $data;
36
        return $this;
37
    }
38
39
    /**
40
     * Extend the configuration to be processed with
41
     * the provided nested array. Also record the name
42
     * of the data source, if applicable.
43
     *
44
     * @param array $data
45
     * @param string $source
46
     */
47
    protected function addFromSource($data, $source = '')
48
    {
49
        if (empty($source)) {
50
            return $this->add($data);
51
        }
52
        $this->unprocessedConfig[$source] = $data;
53
        return $this;
54
    }
55
56
    /**
57
     * Process all of the configuration that has been collected,
58
     * and return a nested array.
59
     *
60
     * @return array
61
     */
62
    public function export()
63
    {
64
        if (!empty($this->unprocessedConfig)) {
65
            $this->processedConfig = $this->process(
66
                $this->processedConfig,
67
                $this->fetchUnprocessed()
68
            );
69
        }
70
        return $this->processedConfig;
71
    }
72
73
    /**
74
     * Get the configuration to be processed, and clear out the
75
     * 'unprocessed' list.
76
     *
77
     * @return array
78
     */
79
    protected function fetchUnprocessed()
80
    {
81
        $toBeProcessed = $this->unprocessedConfig;
82
        $this->unprocessedConfig = [];
83
        return $toBeProcessed;
84
    }
85
86
    /**
87
     * Use a map-reduce to evaluate the items to be processed,
88
     * and merge them into the processed array.
89
     *
90
     * @param array $processed
91
     * @param array $toBeProcessed
92
     * @return array
93
     */
94
    protected function process($processed, $toBeProcessed)
95
    {
96
        $toBeReduced = array_map([$this, 'preprocess'], $toBeProcessed);
97
        $reduced = array_reduce($toBeReduced, [$this, 'reduceOne'], $processed);
98
        return $this->evaluate($reduced);
99
    }
100
101
    /**
102
     * Process a single configuration file from the 'to be processed'
103
     * list. By default this is a no-op. Override this method to
104
     * provide any desired configuration preprocessing, e.g. dot-notation
105
     * expansion of the configuration keys, etc.
106
     *
107
     * @param array $config
108
     * @return array
109
     */
110
    protected function preprocess($config)
111
    {
112
        return $config;
113
    }
114
115
    /**
116
     * Evaluate one item in the 'to be evaluated' list, and then
117
     * merge it into the processed configuration (the 'carry').
118
     *
119
     * @param array $processed
120
     * @param array $config
121
     * @return array
122
     */
123
    protected function reduceOne($processed, $config)
124
    {
125
        return static::arrayMergeRecursiveDistinct($processed, $config);
126
    }
127
128
    /**
129
     * Evaluate one configuration item.
130
     *
131
     * @param array $processed
0 ignored issues
show
Bug introduced by
There is no parameter named $processed. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
132
     * @param array $config
133
     * @return array
134
     */
135
    protected function evaluate($config)
136
    {
137
        return Expander::expandArrayProperties(
138
            $config,
139
            []
140
        );
141
    }
142
143
    /**
144
     * Merges arrays recursively while preserving.
145
     *
146
     * @param array $array1
147
     * @param array $array2
148
     *
149
     * @return array
150
     *
151
     * @see http://php.net/manual/en/function.array-merge-recursive.php#92195
152
     * @see https://github.com/grasmash/bolt/blob/robo-rebase/src/Robo/Common/ArrayManipulator.php#L22
153
     */
154
    public static function arrayMergeRecursiveDistinct(
155
        array &$array1,
156
        array &$array2
157
    ) {
158
        $merged = $array1;
159
        foreach ($array2 as $key => &$value) {
160
            if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
161
                $merged[$key] = self::arrayMergeRecursiveDistinct($merged[$key], $value);
162
            } else {
163
                $merged[$key] = $value;
164
            }
165
        }
166
        return $merged;
167
    }
168
}
169