Completed
Push — master ( 42ffad...778096 )
by Andrii
01:48
created

Builder::setFiles()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 2
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, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hiqdev\composer\config;
12
13
use Composer\IO\IOInterface;
14
15
/**
16
 * Builder assembles config files.
17
 *
18
 * @author Andrii Vasyliev <[email protected]>
19
 */
20
class Builder
21
{
22
    /**
23
     * @var string path to output assembled configs
24
     */
25
    protected $outputDir;
26
27
    /**
28
     * @var array files to build configs
29
     * @see buildConfigs()
30
     */
31
    protected $files = [];
32
33
    /**
34
     * @var array additional data to be merged into every config (e.g. aliases)
35
     */
36
    protected $addition = [];
37
38
    /**
39
     * @var IOInterface
40
     */
41
    protected $io;
42
43
    /**
44
     * @var array collected variables
45
     */
46
    protected $vars = [];
47
48
    const OUTPUT_DIR_SUFFIX = '-output';
49
    const BASE_DIR_MARKER = '<<<base-dir>>>';
50
51
    public function __construct(array $files = [], $outputDir = null)
52
    {
53
        $this->setFiles($files);
54
        $this->setOutputDir($outputDir);
55
    }
56
57
    public function setFiles(array $files)
58
    {
59
        $this->files = $files;
60
    }
61
62
    public function setOutputDir($outputDir)
63
    {
64
        $this->outputDir = isset($outputDir) ? $outputDir : static::defaultOutputDir();
65
    }
66
67
    public function setAddition(array $addition)
68
    {
69
        $this->addition = $addition;
70
    }
71
72
    public function loadFiles()
73
    {
74
        $this->files    = $this->readConfig('__files');
75
        $this->addition = $this->readConfig('__addition');
76
    }
77
78
    public function saveFiles()
79
    {
80
        $this->writeConfig('__files',    $this->files);
81
        $this->writeConfig('__addition', $this->addition);
82
    }
83
84
    public static function rebuild($outputDir)
85
    {
86
        $builder = new self([], $outputDir);
87
        $builder->loadFiles();
88
        $builder->buildConfigs();
89
    }
90
91
    /**
92
     * Returns default output dir.
93
     * @return string
94
     */
95
    public static function defaultOutputDir()
96
    {
97
        return dirname(__DIR__) . static::OUTPUT_DIR_SUFFIX;
98
    }
99
100
    /**
101
     * Returns full path to assembled config file.
102
     * @param string $filename name of config
103
     * @return string absolute path
104
     */
105
    public static function path($filename)
106
    {
107
        return static::defaultOutputDir() . DIRECTORY_SEPARATOR . $filename . '.php';
108
    }
109
110
    /**
111
     * Builds configs by given files list.
112
     * @param null|array $files files to process: config name => list of files
113
     */
114
    public function buildConfigs($files = null)
115
    {
116
        if (is_null($files)) {
117
            $files = $this->files;
118
        }
119
        foreach ($files as $name => $pathes) {
120
            $configs = [];
121
            foreach ($pathes as $path) {
122
                $configs[] = $this->readFile($path);
123
            }
124
            $this->buildConfig($name, $configs);
125
        }
126
        file_put_contents($this->getOutputPath('__rebuild'), file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . '__rebuild.php'));
127
    }
128
129
    /**
130
     * Merges given configs and writes at given name.
131
     * @param mixed $name
132
     * @param array $configs
133
     */
134
    public function buildConfig($name, array $configs)
135
    {
136
        if (!$this->isSpecialConfig($name)) {
137
            array_push($configs, $this->addition, [
138
                'params' => $this->vars['params'],
139
            ]);
140
        }
141
        $this->vars[$name] = call_user_func_array([Helper::className(), 'mergeConfig'], $configs);
142
        $this->writeConfig($name, (array) $this->vars[$name]);
143
    }
144
145
    protected function isSpecialConfig($name)
146
    {
147
        return in_array($name, ['defines', 'params'], true);
148
    }
149
150
    /**
151
     * Writes config file by name.
152
     * @param string $name
153
     * @param array $data
154
     */
155
    public function writeConfig($name, array $data)
156
    {
157
        $data = $this->substitutePathes($data, dirname(dirname(dirname($this->outputDir))), static::BASE_DIR_MARKER);
158
        static::writeFile($this->getOutputPath($name), $data);
159
    }
160
161
    public function getOutputPath($name)
162
    {
163
        return $this->outputDir . DIRECTORY_SEPARATOR . $name . '.php';
164
    }
165
166
    /**
167
     * Writes config file by full path.
168
     * @param string $path
169
     * @param array $data
170
     */
171
    public static function writeFile($path, array $data)
172
    {
173
        if (!file_exists(dirname($path))) {
174
            mkdir(dirname($path), 0777, true);
175
        }
176
        $content = str_replace("'" . static::BASE_DIR_MARKER, '$baseDir . \'', Helper::exportVar($data));
177
        static::putFile($path, "<?php\n\n\$baseDir = dirname(dirname(dirname(__DIR__)));\n\nreturn $content;\n");
178
    }
179
180
    /**
181
     * Writes file if content changed.
182
     * @param string $path 
183
     * @param string $content 
184
     */
185
    public static function putFile($path, $content)
186
    {
187
        if ($content !== file_get_contents($path)) {
188
            file_put_contents($path, $content);
189
        }
190
    }
191
192
    /**
193
     * Substitute all pathes in given array recursively with alias if applicable.
194
     * @param array $data
195
     * @param string $dir
196
     * @param string $alias
197
     * @return string
198
     */
199
    public static function substitutePathes($data, $dir, $alias)
200
    {
201
        foreach ($data as &$value) {
202
            if (is_string($value)) {
203
                $value = static::substitutePath($value, $dir, $alias);
204
            } elseif (is_array($value)) {
205
                $value = static::substitutePathes($value, $dir, $alias);
206
            }
207
        }
208
209
        return $data;
210
    }
211
212
    /**
213
     * Substitute path with alias if applicable.
214
     * @param string $path
215
     * @param string $dir
216
     * @param string $alias
217
     * @return string
218
     */
219
    protected static function substitutePath($path, $dir, $alias)
220
    {
221
        return (substr($path, 0, strlen($dir) + 1) === $dir . DIRECTORY_SEPARATOR) ? $alias . substr($path, strlen($dir)) : $path;
222
    }
223
224
    public function readConfig($name)
225
    {
226
        return $this->readFile($this->getOutputPath($name));
227
    }
228
229
    /**
230
     * Reads config file.
231
     * @param string $__path
232
     * @return array configuration read from file
233
     */
234
    public function readFile($__path)
235
    {
236
        if (strncmp($__path, '?', 1) === 0) {
237
            $__skippable = true;
238
            $__path = substr($__path, 1);
239
        }
240
241
        if (file_exists($__path)) {
242
            /// Expose variables to be used in configs
243
            extract($this->vars);
244
245
            return (array) require $__path;
246
        }
247
248
        if (empty($__skippable)) {
249
            $this->writeError("Failed read file $__path");
250
        }
251
252
        return [];
253
    }
254
255
    public function setIo(IOInterface $io)
256
    {
257
        $this->io = $io;
258
    }
259
260
    protected function writeError($text)
261
    {
262
        if (isset($this->io)) {
263
            $this->io->writeError("<error>$text</error>");
264
        } else {
265
            echo $text . "\n";
266
        }
267
    }
268
}
269