Passed
Pull Request — master (#53)
by Alexander
13:52
created

Builder::defaultOutputDir()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 9
c 0
b 0
f 0
rs 10
ccs 0
cts 5
cp 0
cc 2
nc 2
nop 1
crap 6
1
<?php
2
3
namespace Yiisoft\Composer\Config;
4
5
use JsonException;
6
use Yiisoft\Composer\Config\Config\Config;
7
use Yiisoft\Composer\Config\Config\ConfigFactory;
8
use Yiisoft\Composer\Config\Util\Resolver;
9
10
use function dirname;
11
12
/**
13
 * Builder assembles config files.
14
 */
15
class Builder
16
{
17
    private const OUTPUT_DIR_SUFFIX = '-output';
18
19
    /**
20
     * @var string path to the Composer project root
21
     */
22
    private string $baseDir;
23
24
    /**
25
     * @var string path to output assembled configs
26
     */
27
    private string $outputDir;
28
29
    /**
30
     * @var Config[] configurations
31
     */
32
    private array $configs = [];
33
34
    private ConfigFactory $configFactory;
35
36
    /**
37
     * Builder constructor.
38
     *
39 2
     * @param ConfigFactory $configFactory
40
     * @param string $baseDir path to the Composer project root
41 2
     */
42 2
    public function __construct(ConfigFactory $configFactory, string $baseDir)
43
    {
44 2
        $this->configFactory = $configFactory;
45
        $this->baseDir = $baseDir;
46 2
        $this->outputDir = self::findOutputDir($baseDir);
47 2
    }
48
49
    public function createAlternative($name): Builder
50
    {
51
        $alt = new static($this->configFactory, $this->baseDir);
52
        $alt->setOutputDir($this->outputDir . DIRECTORY_SEPARATOR . $name);
53
        foreach (['aliases', 'packages'] as $key) {
54
            $alt->configs[$key] = $this->getConfig($key)->clone($alt);
55
        }
56
57
        return $alt;
58
    }
59
60
    public function setOutputDir(?string $outputDir): void
61
    {
62
        $this->outputDir = $outputDir
63
            ? static::buildAbsPath($this->getBaseDir(), $outputDir)
64
            : static::findOutputDir($this->getBaseDir());
65 2
    }
66
67 2
    public static function rebuild(string $outputDir = null): void
68
    {
69
        $builder = new self(new ConfigFactory(), static::findOutputDir($outputDir));
70 2
        $files = $builder->getConfig('__files')->load();
71
        $builder->buildUserConfigs($files->getValues());
72
    }
73 2
74
    /**
75
     * Returns default output dir.
76
     *
77
     * @param string|null $baseDir path to the root Composer package. When `null`,
78
     * {@see findBaseDir()} will be called to find a base dir.
79
     *
80
     * @return string
81
     * @throws JsonException
82
     */
83
    private static function findOutputDir(string $baseDir = null): string
84
    {
85
        $baseDir = $baseDir ?: static::findBaseDir();
86
        $path = $baseDir . DIRECTORY_SEPARATOR . 'composer.json';
87
        $data = @json_decode(file_get_contents($path), true);
88
        $dir = $data['extra'][Package::EXTRA_OUTPUT_DIR_OPTION_NAME] ?? null;
89
90
        return $dir ? static::buildAbsPath($baseDir, $dir) : static::defaultOutputDir($baseDir);
91
    }
92
93
    private static function findBaseDir(): string
94
    {
95
        return dirname(__DIR__, 4);
96
    }
97
98
    /**
99
     * Returns default output dir.
100
     *
101
     * @param string $baseDir path to base directory
102
     * @return string
103
     */
104
    private static function defaultOutputDir(string $baseDir = null): string
105
    {
106
        if ($baseDir) {
107
            $dir = $baseDir . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'yiisoft' . DIRECTORY_SEPARATOR . basename(dirname(__DIR__));
108
        } else {
109
            $dir = dirname(__DIR__);
110
        }
111
112
        return $dir . static::OUTPUT_DIR_SUFFIX;
113
    }
114
115
    /**
116
     * Returns full path to assembled config file.
117
     *
118
     * @param string $filename name of config
119
     * @param string $baseDir path to base dir
120
     * @return string absolute path
121
     * @throws JsonException
122
     */
123
    public static function path(string $filename, string $baseDir = null): string
124
    {
125
        return static::buildAbsPath(static::findOutputDir($baseDir), $filename . '.php');
126
    }
127
128
    private static function buildAbsPath(string $dir, string $file): string
129
    {
130
        return strncmp($file, DIRECTORY_SEPARATOR, 1) === 0 ? $file : $dir . DIRECTORY_SEPARATOR . $file;
131
    }
132
133
    /**
134
     * Builds all (user and system) configs by given files list.
135
     *
136
     * @param null|array $files files to process: config name => list of files
137
     */
138
    public function buildAllConfigs(array $files): void
139
    {
140
        $this->buildUserConfigs($files);
141
        $this->buildSystemConfigs($files);
142
    }
143
144
    /**
145
     * Builds configs by given files list.
146
     *
147
     * @param null|array $files files to process: config name => list of files
148
     * @return array
149
     */
150
    private function buildUserConfigs(array $files): array
151
    {
152
        $resolver = new Resolver($files);
153
        $files = $resolver->get();
154
        foreach ($files as $name => $paths) {
155
            $this->getConfig($name)->load($paths)->build()->write();
156
        }
157
158
        return $files;
159
    }
160
161
    private function buildSystemConfigs(array $files): void
162
    {
163
        $this->getConfig('__files')->setValues($files);
164
        foreach (['__files', 'aliases', 'packages'] as $name) {
165
            $this->getConfig($name)->build()->write();
166
        }
167
    }
168
169
    public function getOutputPath($name): string
170
    {
171
        return $this->outputDir . DIRECTORY_SEPARATOR . $name . '.php';
172
    }
173
174
    private function createConfig($name): Config
175
    {
176
        $config = $this->configFactory->create($this, $name);
177
        $this->configs[$name] = $config;
178
179
        return $config;
180
    }
181
182
    public function getConfig(string $name)
183
    {
184
        if (!isset($this->configs[$name])) {
185
            $this->configs[$name] = $this->createConfig($name);
186
        }
187
188
        return $this->configs[$name];
189
    }
190
191
    public function getVars(): array
192
    {
193
        $vars = [];
194
        foreach ($this->configs as $name => $config) {
195
            $vars[$name] = $config->getValues();
196
        }
197
198
        return $vars;
199
    }
200
201
    public function mergeAliases(array $aliases): void
202
    {
203
        $this->getConfig('aliases')->mergeValues($aliases);
204
    }
205
206
    public function setPackage(string $name, array $data): void
207
    {
208
        $this->getConfig('packages')->setValue($name, $data);
209
    }
210
211
    /**
212
     * @return string a full path to the project root
213
     */
214
    public function getBaseDir(): string
215
    {
216
        return $this->baseDir;
217
    }
218
}
219