ConfigProcessor::add()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Consolidation\Config\Loader;
4
5
use Grasmash\Expander\Expander;
6
use Consolidation\Config\Util\ArrayUtil;
7
8
/**
9
 * The config processor combines multiple configuration
10
 * files together, and processes them as necessary.
11
 */
12
class ConfigProcessor
13
{
14
    protected $processedConfig = [];
15
    protected $unprocessedConfig = [];
16
    protected $nameOfItemsToMerge = [];
17
    protected $expander;
18
19
    public function __construct($expander = null)
20
    {
21
        $this->expander = $expander ?: new Expander();
22
    }
23
24
    /**
25
     * By default, string config items always REPLACE, not MERGE when added
26
     * from different sources. This method will allow applications to alter
27
     * this behavior for specific items so that strings from multiple sources
28
     * will be merged together into an array instead.
29
     */
30
    public function useMergeStrategyForKeys($itemName)
31
    {
32
        if (is_array($itemName)) {
33
            $this->nameOfItemsToMerge = array_merge($this->nameOfItemsToMerge, $itemName);
34
            return $this;
35
        }
36
        $this->nameOfItemsToMerge[] = $itemName;
37
        return $this;
38
    }
39
40
    /**
41
     * Extend the configuration to be processed with the
42
     * configuration provided by the specified loader.
43
     *
44
     * @param ConfigLoaderInterface $loader
45
     */
46
    public function extend(ConfigLoaderInterface $loader)
47
    {
48
        return $this->addFromSource($loader->export(), $loader->getSourceName());
49
    }
50
51
    /**
52
     * Extend the configuration to be processed with
53
     * the provided nested array.
54
     *
55
     * @param array $data
56
     */
57
    public function add($data)
58
    {
59
        $this->unprocessedConfig[] = $data;
60
        return $this;
61
    }
62
63
    /**
64
     * Extend the configuration to be processed with
65
     * the provided nested array. Also record the name
66
     * of the data source, if applicable.
67
     *
68
     * @param array $data
69
     * @param string $source
70
     */
71
    protected function addFromSource($data, $source = '')
72
    {
73
        if (empty($source)) {
74
            return $this->add($data);
75
        }
76
        $this->unprocessedConfig[$source] = $data;
77
        return $this;
78
    }
79
80
    /**
81
     * Process all of the configuration that has been collected,
82
     * and return a nested array.
83
     *
84
     * @return array
85
     */
86
    public function export($referenceArray = [])
87
    {
88
        if (!empty($this->unprocessedConfig)) {
89
            $this->processedConfig = $this->process(
90
                $this->processedConfig,
91
                $this->fetchUnprocessed(),
92
                $referenceArray
93
            );
94
        }
95
        return $this->processedConfig;
96
    }
97
98
    /**
99
     * To aid in debugging: return the source of each configuration item.
100
     * n.b. Must call this function *before* export and save the result
101
     * if persistence is desired.
102
     */
103
    public function sources()
104
    {
105
        $sources = [];
106
        foreach ($this->unprocessedConfig as $sourceName => $config) {
107
            if (!empty($sourceName)) {
108
                $configSources = ArrayUtil::fillRecursive($config, $sourceName);
109
                $sources = ArrayUtil::mergeRecursiveDistinct($sources, $configSources);
110
            }
111
        }
112
        return $sources;
113
    }
114
115
    /**
116
     * Get the configuration to be processed, and clear out the
117
     * 'unprocessed' list.
118
     *
119
     * @return array
120
     */
121
    protected function fetchUnprocessed()
122
    {
123
        $toBeProcessed = $this->unprocessedConfig;
124
        $this->unprocessedConfig = [];
125
        return $toBeProcessed;
126
    }
127
128
    /**
129
     * Use a map-reduce to evaluate the items to be processed,
130
     * and merge them into the processed array.
131
     *
132
     * @param array $processed
133
     * @param array $toBeProcessed
134
     * @return array
135
     */
136
    protected function process(array $processed, array $toBeProcessed, $referenceArray = [])
137
    {
138
        $toBeReduced = array_map([$this, 'preprocess'], $toBeProcessed);
139
        $reduced = array_reduce($toBeReduced, [$this, 'reduceOne'], $processed);
140
        return $this->evaluate($reduced, $referenceArray);
141
    }
142
143
    /**
144
     * Process a single configuration file from the 'to be processed'
145
     * list. By default this is a no-op. Override this method to
146
     * provide any desired configuration preprocessing, e.g. dot-notation
147
     * expansion of the configuration keys, etc.
148
     *
149
     * @param array $config
150
     * @return array
151
     */
152
    protected function preprocess(array $config)
153
    {
154
        return $config;
155
    }
156
157
    /**
158
     * Evaluate one item in the 'to be evaluated' list, and then
159
     * merge it into the processed configuration (the 'carry').
160
     *
161
     * @param array $processed
162
     * @param array $config
163
     * @return array
164
     */
165
    protected function reduceOne(array $processed, array $config)
166
    {
167
        return ArrayUtil::mergeRecursiveSelect($processed, $config, $this->nameOfItemsToMerge);
168
    }
169
170
    /**
171
     * Evaluate one configuration item.
172
     *
173
     * @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...
174
     * @param array $config
175
     * @return array
176
     */
177
    protected function evaluate(array $config, $referenceArray = [])
178
    {
179
        return $this->expander->expandArrayProperties(
180
            $config,
181
            $referenceArray
182
        );
183
    }
184
}
185