Completed
Push — master ( b85299...2a4a53 )
by Andrii
01:53
created

Builder::getOutputPath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
/*
4
 * Composer plugin for config assembling
5
 *
6
 * @link      https://github.com/hiqdev/composer-config-plugin
7
 * @package   composer-config-plugin
8
 * @license   BSD-3-Clause
9
 * @copyright Copyright (c) 2016, HiQDev (http://hiqdev.com/)
10
 */
11
12
namespace hiqdev\composer\config;
13
14
use Composer\IO\IOInterface;
15
16
/**
17
 * Builder assembles config files.
18
 *
19
 * @author Andrii Vasyliev <[email protected]>
20
 */
21
class Builder
22
{
23
    /**
24
     * @var string path to output assembled configs
25
     */
26
    protected $outputDir;
27
28
    /**
29
     * @var array files to build configs
30
     * @see buildConfigs()
31
     */
32
    protected $files = [];
33
34
    /**
35
     * @var array additional data to be merged into every config (e.g. aliases)
36
     */
37
    protected $addition = [];
38
39
    /**
40
     * @var IOInterface
41
     */
42
    protected $io;
43
44
    /**
45
     * @var array collected variables
46
     */
47
    protected $vars = [];
48
49
    const OUTPUT_DIR_SUFFIX = '-output';
50
    const BASE_DIR_MARKER = '<<<base-dir>>>';
51
52
    public function __construct(array $files = [], $outputDir = null)
53
    {
54
        $this->setFiles($files);
55
        $this->setOutputDir($outputDir);
56
    }
57
58
    public function setFiles(array $files)
59
    {
60
        $this->files = $files;
61
    }
62
63
    public function setOutputDir($outputDir)
64
    {
65
        $this->outputDir = isset($outputDir) ? $outputDir : static::defaultOutputDir();
66
    }
67
68
    public function setAddition(array $addition)
69
    {
70
        $this->addition = $addition;
71
    }
72
73
    public function loadFiles()
74
    {
75
        $this->files    = $this->readConfig('__files');
76
        $this->addition = $this->readConfig('__addition');
77
    }
78
79
    public function saveFiles()
80
    {
81
        $this->writeConfig('__files',    $this->files);
82
        $this->writeConfig('__addition', $this->addition);
83
    }
84
85
    public static function rebuild($outputDir)
86
    {
87
        $builder = new Builder([], $outputDir);
88
        $builder->loadFiles();
89
        $builder->buildConfigs();
90
    }
91
92
    /**
93
     * Returns default output dir.
94
     * @return string
95
     */
96
    public static function defaultOutputDir()
97
    {
98
        return dirname(__DIR__) . static::OUTPUT_DIR_SUFFIX;
99
    }
100
101
    /**
102
     * Returns full path to assembled config file.
103
     * @param string $filename name of config
104
     * @return string absolute path
105
     */
106
    public static function path($filename)
107
    {
108
        return static::defaultOutputDir() . DIRECTORY_SEPARATOR . $filename . '.php';
109
    }
110
111
    /**
112
     * Builds configs by given files list
113
     * @param null|array $files files to process: config name => list of files
114
     */
115
    public function buildConfigs($files = null)
116
    {
117
        if (is_null($files)) {
118
            $files = $this->files;
119
        }
120
        foreach ($files as $name => $pathes) {
121
            $configs = [];
122
            foreach ($pathes as $path) {
123
                $configs[] = $this->readFile($path);
124
            }
125
            $this->buildConfig($name, $configs);
126
        }
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
        file_put_contents($path, "<?php\n\n\$baseDir = dirname(dirname(dirname(__DIR__)));\n\nreturn $content;\n");
178
    }
179
180
    /**
181
     * Substitute all pathes in given array recursively with alias if applicable.
182
     * @param array $data
183
     * @param string $dir
184
     * @param string $alias
185
     * @return string
186
     */
187
    public static function substitutePathes($data, $dir, $alias)
188
    {
189
        foreach ($data as &$value) {
190
            if (is_string($value)) {
191
                $value = static::substitutePath($value, $dir, $alias);
192
            } elseif (is_array($value)) {
193
                $value = static::substitutePathes($value, $dir, $alias);
194
            }
195
        }
196
197
        return $data;
198
    }
199
200
    /**
201
     * Substitute path with alias if applicable.
202
     * @param string $path
203
     * @param string $dir
204
     * @param string $alias
205
     * @return string
206
     */
207
    protected static function substitutePath($path, $dir, $alias)
208
    {
209
        return (substr($path, 0, strlen($dir) + 1) === $dir . '/') ? $alias . substr($path, strlen($dir)) : $path;
210
    }
211
212
    public function readConfig($name)
213
    {
214
        return $this->readFile($this->getOutputPath($name));
215
    }
216
217
    /**
218
     * Reads config file.
219
     * @param string $__path
220
     * @return array configuration read from file
221
     */
222
    public function readFile($__path)
223
    {
224
        if (strncmp($__path, '?', 1) === 0) {
225
            $__skippable = true;
226
            $__path = substr($__path, 1);
227
        }
228
229
        if (file_exists($__path)) {
230
            /// Expose variables to be used in configs
231
            extract($this->vars);
232
233
            return (array) require $__path;
234
        }
235
236
        if (empty($__skippable)) {
237
            $this->writeError('<error>Non existent config file</error> ' . $__path);
238
        }
239
240
        return [];
241
    }
242
243
    public function setIo(IOInterface $io)
244
    {
245
        $this->io = $io;
246
    }
247
248
    protected function writeError($text)
249
    {
250
        if (isset($this->io)) {
251
            $this->io->writeError($text);
252
        } else {
253
            echo $text . "\n";
254
        }
255
    }
256
}
257