LoadReplacementData::mu()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Sunnysideup\UpgradeToSilverstripe4\Api;
4
5
use SilverStripe\Upgrader\Util\ConfigFile;
6
/**
7
 * loads yml data if strings to replace in
8
 * code.
9
 *
10
 * The replacements should be in the same folder as this class.
11
 *
12
 * Alternatively, you can specify another folderContainingReplacementData in the
13
 * construct method.
14
 *
15
 * It will also search the root folders for any packages / projects being upgraded.
16
 * replacement data can be found in any path provided like this:
17
 *
18
 *     PATH / toFolder / '.upgrade.replacements.yml'
19
 *
20
 * toFolders have names like: SS37 or SS4.
21
 */
22
23
use Sunnysideup\UpgradeToSilverstripe4\ModuleUpgrader;
24
25
class LoadReplacementData
26
{
27
    /**
28
     * Standard file name
29
     */
30
    protected $ymlFileName = '.upgrade.replacements.yml';
31
32
    /**
33
     * Module Object
34
     * @var ModuleUpgrader
35
     */
36
    protected $myMu = null;
37
38
    /**
39
     * folder containing the replacement file
40
     *
41
     * @var string
42
     */
43
    protected $folderContainingReplacementData = '';
44
45
    /**
46
     * name of the sub-folder for the replacement data.
47
     * @var string
48
     */
49
    protected $toFolders = 'SS4';
50
51
    /**
52
     * array of replacements
53
     * @var array
54
     */
55
    protected $fullArray = [];
56
57
    /**
58
     * @var array
59
     */
60
    protected $languages = [];
61
62
    /**
63
     * @var array
64
     */
65
    protected $flatFindArray = [];
66
67
    /**
68
     * @var array
69
     */
70
    protected $flatReplacedArray = [];
71
72
    /**
73
     * path where to look for data.
74
     * @var array
75
     */
76
    protected $paths = [];
77
78
    protected $toFolder = '';
79
80
    /**
81
     * @param ModuleUpgrader $mu
82
     * @param string         $alternativeReplacementDataFolder
83
     * @param string         $toFolder - the subfolder used for the specific replace`
84
     */
85
    public function __construct($mu, $alternativeReplacementDataFolder = '', $toFolder = 'SS4')
86
    {
87
        $this->myMu = $mu;
88
        $this->folderContainingReplacementData = $alternativeReplacementDataFolder ?: $this->defaultLocation();
89
        $this->toFolder = $toFolder;
90
91
        $this->compileFlatArray();
92
    }
93
94
    public function setToFolder(string $s)
95
    {
96
        $this->toFolder = $s;
97
98
        return $this;
99
    }
100
101
    public function getReplacementArrays(): array
102
    {
103
        return $this->fullArray;
104
    }
105
106
    public function getLanguages()
107
    {
108
        return $this->languages;
109
    }
110
111
    public function getFlatFindArray(): array
112
    {
113
        return $this->flatFindArray;
114
    }
115
116
    public function getFlatReplacedArray(): array
117
    {
118
        return $this->flatReplacedArray;
119
    }
120
121
    protected function mu()
122
    {
123
        return $this->myMu;
124
    }
125
126
    protected function defaultLocation()
127
    {
128
        return $this->mu()->getLocationOfThisUpgrader() . DIRECTORY_SEPARATOR . 'ReplacementData';
129
    }
130
131
    protected function compileFlatArray()
132
    {
133
        $this->fullArray = $this->getData();
134
        $count = 0;
135
        foreach ($this->fullArray as $path => $pathArray) {
136
            foreach ($pathArray as $language => $languageArray) {
137
                $this->languages[$language] = $language;
138
                foreach ($languageArray as $findKey => $findKeyArray) {
139
                    if (! isset($findKeyArray['R'])) {
140
                        user_error('replacement key not set: ' . print_r($findKeyArray, true));
0 ignored issues
show
Bug introduced by
Are you sure print_r($findKeyArray, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

140
                        user_error('replacement key not set: ' . /** @scrutinizer ignore-type */ print_r($findKeyArray, true));
Loading history...
141
                    }
142
                    $replaceKey = $findKeyArray['R'];
143
                    $key = strtolower($language . '_' . $path . '_' . $count);
144
                    $this->flatFindArray[$key] = $findKey;
145
                    $this->flatReplacedArray[$key] = $replaceKey;
146
                    $count++;
147
                }
148
            }
149
        }
150
    }
151
152
    /**
153
     * retrieve all replacements
154
     */
155
    protected function getData(): array
156
    {
157
        $this->getPaths();
158
        // Merge with any other upgrade spec in the top level
159
        $config = [];
160
        foreach ($this->paths as $path) {
161
            $file = $path . DIRECTORY_SEPARATOR . $this->toFolder . DIRECTORY_SEPARATOR . $this->ymlFileName;
162
            if (file_exists($file)) {
163
                $nextConfig = ConfigFile::loadConfig($file);
164
                // Merge
165
                $config = $this->mergeConfig($config, $nextConfig);
166
                $this->mu()->colourPrint('loaded replacement file: ' . $file);
167
            } else {
168
                $this->mu()->colourPrint('could not find: ' . $file);
169
            }
170
        }
171
        ksort($config);
172
173
        return $config;
174
    }
175
176
    /**
177
     * returns a list of paths to be checked for replacement data.
178
     */
179
    protected function getPaths(): array
180
    {
181
        $array = [];
182
        foreach ($this->mu()->getExistingModuleDirLocations() as $moduleDir) {
183
            $array[$moduleDir] = $moduleDir;
184
        }
185
        $globalFixes = $this->mu()->checkIfPathExistsAndCleanItUp($this->folderContainingReplacementData);
186
        if ($globalFixes) {
187
            $array[$globalFixes] = $globalFixes;
188
        }
189
        $this->paths = $array;
190
191
        return $this->paths;
192
    }
193
194
    /**
195
     * merge config of two files ...
196
     */
197
    protected static function mergeConfig(array $left, array $right): array
198
    {
199
        //see ConfigFile for original
200
        $merged = $left;
201
        foreach ($right as $key => $value) {
202
            // if non-associative, just merge in unique items
203
            if (is_numeric($key)) {
204
                if (! in_array($value, $merged, true)) {
205
                    $merged[] = $value;
206
                }
207
                continue;
208
            }
209
210
            // If not merged into left hand side, then simply assign
211
            if (! isset($merged[$key])) {
212
                $merged[$key] = $value;
213
                continue;
214
            }
215
216
            // Make sure both sides are the same type
217
            if (is_array($merged[$key]) !== is_array($value)) {
218
                user_error(
219
                    "Config option ${key} cannot merge non-array with array value."
220
                );
221
            }
222
223
            // If array type, then merge
224
            if (is_array($value)) {
225
                $merged[$key] = self::mergeConfig($merged[$key], $value);
226
                continue;
227
            }
228
229
            // If non array types, don't merge, but instead assert both values are set
230
            if ($merged[$key] !== $value) {
231
                user_error(
232
                    "Config option ${key} is defined with different values in multiple files."
233
                );
234
            }
235
        }
236
237
        return $merged;
238
    }
239
}
240