Passed
Pull Request — master (#96)
by Mlax
10:34
created

Package::getYamlValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 0
cts 3
cp 0
rs 10
cc 1
nc 1
nop 2
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Composer\Config;
6
7
use Composer\Package\CompletePackageInterface;
8
use Composer\Package\PackageInterface;
9
use Composer\Package\RootPackageInterface;
10
use Composer\Util\Filesystem;
11
use Symfony\Component\Yaml\Yaml;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Yaml\Yaml was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
use Yiisoft\Composer\Config\Exception\UnsupportedFileTypeException;
13
14
/**
15
 * Class Package.
16
 */
17
class Package
18
{
19
    public const EXTRA_FILES_OPTION_NAME = 'config-plugin';
20
    public const EXTRA_DEV_FILES_OPTION_NAME = 'config-plugin-dev';
21
    public const EXTRA_OUTPUT_DIR_OPTION_NAME = 'config-plugin-output-dir';
22
    public const EXTRA_ALTERNATIVES_OPTION_NAME = 'config-plugin-alternatives';
23
24
    public const CONFIG_FILE_NAME_COMPOSER = 'composer.json';
25
    public const CONFIG_FILE_NAME_YAML = '.yii.yml';
26
27
    private PackageInterface $package;
28
29
    /**
30
     * @var array composer.json raw data array
31
     */
32
    private array $data;
33
34
    /**
35
     * @var array .yii.yml raw data array
36
     */
37
    private array $yamlData;
38
39
    /**
40
     * @var string absolute path to the root base directory
41
     */
42
    private string $baseDir;
43
44
    /**
45
     * @var string absolute path to vendor directory
46
     */
47
    private string $vendorDir;
48
49
    /**
50
     * @var Filesystem utility
51
     */
52
    private Filesystem $filesystem;
53
54
    public function __construct(PackageInterface $package, string $vendorDir)
55
    {
56
        $this->package = $package;
57
        $this->filesystem = new Filesystem();
58
59
        $this->vendorDir = $this->filesystem->normalizePath($vendorDir);
60
        $this->baseDir = dirname($this->vendorDir);
61
        $this->data = $this->readRawData();
62
        $this->yamlData = $this->readYamlData();
63
    }
64
65
    /**
66
     * @return string package pretty name, like: vendor/name
67
     */
68
    public function getPrettyName(): string
69
    {
70
        return $this->package->getPrettyName();
71
    }
72
73
    /**
74
     * @return string package version, like: 3.0.16.0, 9999999-dev
75
     */
76
    public function getVersion(): string
77
    {
78
        return $this->package->getVersion();
79
    }
80
81
    /**
82
     * @return string package CVS revision, like: 3a4654ac9655f32888efc82fb7edf0da517d8995
83
     */
84
    public function getSourceReference(): ?string
85
    {
86
        return $this->package->getSourceReference();
87
    }
88
89
    /**
90
     * @return string package dist revision, like: 3a4654ac9655f32888efc82fb7edf0da517d8995
91
     */
92
    public function getDistReference(): ?string
93
    {
94
        return $this->package->getDistReference();
95
    }
96
97
    /**
98
     * @return bool is package complete
99
     */
100
    public function isComplete(): bool
101
    {
102
        return $this->package instanceof CompletePackageInterface;
103
    }
104
105
    /**
106
     * @return bool is this a root package
107
     */
108
    public function isRoot(): bool
109
    {
110
        return $this->package instanceof RootPackageInterface;
111
    }
112
113
    /**
114
     * @return array autoload configuration array
115
     */
116
    public function getAutoload(): array
117
    {
118
        return $this->getRawValue('autoload') ?? $this->package->getAutoload();
119
    }
120
121
    /**
122
     * @return array autoload-dev configuration array
123
     */
124
    public function getDevAutoload(): array
125
    {
126
        return $this->getRawValue('autoload-dev') ?? $this->package->getDevAutoload();
127
    }
128
129
    /**
130
     * @return array require configuration array
131
     */
132
    public function getRequires(): array
133
    {
134
        return $this->getRawValue('require') ?? $this->package->getRequires();
135
    }
136
137
    /**
138
     * @return array require-dev configuration array
139
     */
140
    public function getDevRequires(): array
141
    {
142
        return $this->getRawValue('require-dev') ?? $this->package->getDevRequires();
143
    }
144
145
    /**
146
     * @return array files array
147
     */
148
    public function getFiles(): array
149
    {
150
        return $this->getConfigValue(self::EXTRA_FILES_OPTION_NAME, []);
151
    }
152
153
    /**
154
     * @return array dev-files array
155
     */
156
    public function getDevFiles(): array
157
    {
158
        return $this->getConfigValue(self::EXTRA_DEV_FILES_OPTION_NAME, []);
159
    }
160
161
    /**
162
     * @return mixed alternatives array or path to config
163
     */
164
    public function getAlternatives()
165
    {
166
        return $this->getConfigValue(self::EXTRA_ALTERNATIVES_OPTION_NAME);
167
    }
168
169
    /**
170
     * Get configuration value or default
171
     *
172
     * @param string $key key to look for in yaml or extra configuration
173
     * @param mixed $default default to return if there's no yaml and extra configuration value
174
     * @return mixed configuration value or default
175
     */
176
    private function getConfigValue(string $key, $default = null)
177
    {
178
        return $this->getYamlValue($key, $this->getExtraValue($key, $default));
179
    }
180
181
    /**
182
     * Get extra configuration value or default
183
     *
184
     * @param string $key key to look for in extra configuration
185
     * @param mixed $default default to return if there's no extra configuration value
186
     * @return mixed extra configuration value or default
187
     */
188
    private function getExtraValue(string $key, $default = null)
189
    {
190
        return $this->getExtra()[$key] ?? $default;
191
    }
192
193
    /**
194
     * @return array extra configuration array
195
     */
196
    private function getExtra(): array
197
    {
198
        return $this->getRawValue('extra') ?? $this->package->getExtra();
199
    }
200
201
    /**
202
     * @param string $name option name
203
     * @return mixed raw value from composer.json if available
204
     */
205
    private function getRawValue(string $name)
206
    {
207
        return $this->data[$name] ?? null;
208
    }
209
210
    /**
211
     * @param string $name option name
212
     * @return mixed yaml value from .yii.yml if available
213
     */
214
    private function getYamlValue(string $name, $default = null)
215
    {
216
        return $this->yamlData[$name] ?? $default;
217
    }
218
219
    /**
220
     * @return array composer.json contents as array
221
     * @throws \JsonException
222
     */
223
    private function readRawData(): array
224
    {
225
        $path = $this->preparePath(self::CONFIG_FILE_NAME_COMPOSER);
226
        if (file_exists($path)) {
227
            return json_decode(file_get_contents($path), true, 512, JSON_THROW_ON_ERROR);
228
        }
229
230
        return [];
231
    }
232
233
    /**
234
     * @return array .yii.yml contents as array
235
     * @throws UnsupportedFileTypeException
236
     */
237
    private function readYamlData(): array
238
    {
239
        $path = $this->preparePath(self::CONFIG_FILE_NAME_YAML);
240
        if (file_exists($path)) {
241
            if (!class_exists(Yaml::class)) {
242
                throw new UnsupportedFileTypeException("For YAML support require `symfony/yaml` in your composer.json (reading $path)");
243
            }
244
245
            return is_array($data = Yaml::parse(file_get_contents($path))) ? $data : [];
246
        }
247
248
        return [];
249
    }
250
251
    /**
252
     * Builds path inside of a package.
253
     *
254
     * @param string $file
255
     * @return string absolute paths will stay untouched
256
     */
257
    public function preparePath(string $file): string
258
    {
259
        if (0 === strncmp($file, '$', 1)) {
260
            return $file;
261
        }
262
263
        $skippable = 0 === strncmp($file, '?', 1) ? '?' : '';
264
        if ($skippable) {
265
            $file = substr($file, 1);
266
        }
267
268
        if (!$this->filesystem->isAbsolutePath($file)) {
269
            $prefix = $this->isRoot()
270
                ? $this->baseDir
271
                : $this->vendorDir . '/' . $this->getPrettyName();
272
            $file = $prefix . '/' . $file;
273
        }
274
275
        return $skippable . $this->filesystem->normalizePath($file);
276
    }
277
278
    public function getVendorDir(): string
279
    {
280
        return $this->vendorDir;
281
    }
282
283
    public function getBaseDir(): string
284
    {
285
        return $this->baseDir;
286
    }
287
}
288