1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the puli/manager package. |
5
|
|
|
* |
6
|
|
|
* (c) Bernhard Schussek <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace Puli\Manager\Package; |
13
|
|
|
|
14
|
|
|
use Puli\Discovery\Api\Type\BindingParameter; |
15
|
|
|
use Puli\Discovery\Api\Type\BindingType; |
16
|
|
|
use Puli\Discovery\Binding\ClassBinding; |
17
|
|
|
use Puli\Discovery\Binding\ResourceBinding; |
18
|
|
|
use Puli\Manager\Api\Config\Config; |
19
|
|
|
use Puli\Manager\Api\Discovery\BindingDescriptor; |
20
|
|
|
use Puli\Manager\Api\Discovery\BindingTypeDescriptor; |
21
|
|
|
use Puli\Manager\Api\Environment; |
22
|
|
|
use Puli\Manager\Api\InvalidConfigException; |
23
|
|
|
use Puli\Manager\Api\Package\InstallInfo; |
24
|
|
|
use Puli\Manager\Api\Package\PackageFile; |
25
|
|
|
use Puli\Manager\Api\Package\PackageFileSerializer; |
26
|
|
|
use Puli\Manager\Api\Package\RootPackageFile; |
27
|
|
|
use Puli\Manager\Api\Package\UnsupportedVersionException; |
28
|
|
|
use Puli\Manager\Api\Repository\PathMapping; |
29
|
|
|
use Puli\Manager\Migration\MigrationManager; |
30
|
|
|
use Rhumsaa\Uuid\Uuid; |
31
|
|
|
use stdClass; |
32
|
|
|
use Webmozart\Json\DecodingFailedException; |
33
|
|
|
use Webmozart\Json\JsonDecoder; |
34
|
|
|
use Webmozart\Json\JsonEncoder; |
35
|
|
|
use Webmozart\Json\JsonValidator; |
36
|
|
|
use Webmozart\PathUtil\Path; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Serializes and unserializes package files to/from JSON. |
40
|
|
|
* |
41
|
|
|
* The JSON is validated against the schema `res/schema/package-schema.json`. |
42
|
|
|
* |
43
|
|
|
* @since 1.0 |
44
|
|
|
* |
45
|
|
|
* @author Bernhard Schussek <[email protected]> |
46
|
|
|
*/ |
47
|
|
|
class PackageJsonSerializer implements PackageFileSerializer |
48
|
|
|
{ |
49
|
|
|
/** |
50
|
|
|
* The default order of the keys in the written package file. |
51
|
|
|
* |
52
|
|
|
* @var string[] |
53
|
|
|
*/ |
54
|
|
|
private static $keyOrder = array( |
55
|
|
|
'version', |
56
|
|
|
'name', |
57
|
|
|
'path-mappings', |
58
|
|
|
'bindings', |
59
|
|
|
'binding-types', |
60
|
|
|
'override', |
61
|
|
|
'override-order', |
62
|
|
|
'config', |
63
|
|
|
'plugins', |
64
|
|
|
'extra', |
65
|
|
|
'packages', |
66
|
|
|
); |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* @var MigrationManager |
70
|
|
|
*/ |
71
|
|
|
private $migrationManager; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* @var string |
75
|
|
|
*/ |
76
|
|
|
private $schemaDir; |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* @var string |
80
|
|
|
*/ |
81
|
|
|
private $targetVersion; |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* @var string[] |
85
|
|
|
*/ |
86
|
|
|
private $knownVersions; |
87
|
|
|
|
88
|
3 |
|
public static function compareBindingDescriptors(BindingDescriptor $a, BindingDescriptor $b) |
89
|
|
|
{ |
90
|
|
|
// Make sure that bindings are always printed in the same order |
91
|
3 |
|
return strcmp($a->getUuid()->toString(), $b->getUuid()->toString()); |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Creates a new serializer. |
96
|
|
|
* |
97
|
|
|
* @param MigrationManager $migrationManager The manager for migrating |
98
|
|
|
* puli.json files between |
99
|
|
|
* versions. |
100
|
|
|
* @param string $schemaDir The directory that contains the |
101
|
|
|
* schema files. |
102
|
|
|
* @param string $targetVersion The file version that this |
103
|
|
|
* serializer reads and produces. |
104
|
|
|
*/ |
105
|
77 |
|
public function __construct(MigrationManager $migrationManager, $schemaDir, $targetVersion = PackageFile::DEFAULT_VERSION) |
106
|
|
|
{ |
107
|
77 |
|
$this->migrationManager = $migrationManager; |
108
|
77 |
|
$this->targetVersion = $targetVersion; |
109
|
77 |
|
$this->knownVersions = $this->migrationManager->getKnownVersions(); |
110
|
|
|
|
111
|
77 |
|
if (!in_array($targetVersion, $this->knownVersions, true)) { |
112
|
26 |
|
$this->knownVersions[] = $targetVersion; |
113
|
26 |
|
usort($this->knownVersions, 'version_compare'); |
114
|
26 |
|
} |
115
|
|
|
|
116
|
|
|
// We can't use realpath(), which doesn't work inside PHARs. |
117
|
|
|
// However, we want to display nice paths if the file is not found. |
118
|
77 |
|
$this->schemaDir = Path::canonicalize($schemaDir); |
119
|
77 |
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* {@inheritdoc} |
123
|
|
|
*/ |
124
|
15 |
View Code Duplication |
public function serializePackageFile(PackageFile $packageFile) |
|
|
|
|
125
|
|
|
{ |
126
|
15 |
|
$this->assertVersionSupported($packageFile->getVersion()); |
127
|
|
|
|
128
|
15 |
|
$jsonData = (object) array('version' => $this->targetVersion); |
129
|
|
|
|
130
|
15 |
|
$this->packageFileToJson($packageFile, $jsonData); |
131
|
|
|
|
132
|
|
|
// Sort according to key order |
133
|
15 |
|
$jsonArray = (array) $jsonData; |
134
|
15 |
|
$orderedKeys = array_intersect_key(array_flip(self::$keyOrder), $jsonArray); |
135
|
15 |
|
$jsonData = (object) array_replace($orderedKeys, $jsonArray); |
136
|
|
|
|
137
|
15 |
|
$this->migrationManager->migrate($jsonData, $packageFile->getVersion()); |
138
|
|
|
|
139
|
15 |
|
return $this->encode($jsonData, $packageFile->getPath()); |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* {@inheritdoc} |
144
|
|
|
*/ |
145
|
7 |
View Code Duplication |
public function serializeRootPackageFile(RootPackageFile $packageFile) |
|
|
|
|
146
|
|
|
{ |
147
|
7 |
|
$this->assertVersionSupported($packageFile->getVersion()); |
148
|
|
|
|
149
|
7 |
|
$jsonData = (object) array('version' => $this->targetVersion); |
150
|
|
|
|
151
|
7 |
|
$this->packageFileToJson($packageFile, $jsonData); |
152
|
7 |
|
$this->rootPackageFileToJson($packageFile, $jsonData); |
153
|
|
|
|
154
|
|
|
// Sort according to key order |
155
|
7 |
|
$jsonArray = (array) $jsonData; |
156
|
7 |
|
$orderedKeys = array_intersect_key(array_flip(self::$keyOrder), $jsonArray); |
157
|
7 |
|
$jsonData = (object) array_replace($orderedKeys, $jsonArray); |
158
|
|
|
|
159
|
7 |
|
$this->migrationManager->migrate($jsonData, $packageFile->getVersion()); |
160
|
|
|
|
161
|
7 |
|
return $this->encode($jsonData, $packageFile->getPath()); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* {@inheritdoc} |
166
|
|
|
*/ |
167
|
35 |
|
public function unserializePackageFile($serialized, $path = null) |
168
|
|
|
{ |
169
|
35 |
|
$packageFile = new PackageFile(null, $path); |
170
|
|
|
|
171
|
35 |
|
$jsonData = $this->decode($serialized, $path); |
172
|
|
|
|
173
|
|
|
// Remember original version of the package file |
174
|
24 |
|
$packageFile->setVersion($jsonData->version); |
175
|
|
|
|
176
|
|
|
// Migrate to the expected version |
177
|
24 |
|
$this->migrationManager->migrate($jsonData, $this->targetVersion); |
178
|
|
|
|
179
|
24 |
|
$this->jsonToPackageFile($jsonData, $packageFile); |
180
|
|
|
|
181
|
24 |
|
return $packageFile; |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* {@inheritdoc} |
186
|
|
|
*/ |
187
|
34 |
|
public function unserializeRootPackageFile($serialized, $path = null, Config $baseConfig = null) |
188
|
|
|
{ |
189
|
34 |
|
$packageFile = new RootPackageFile(null, $path, $baseConfig); |
190
|
|
|
|
191
|
34 |
|
$jsonData = $this->decode($serialized, $path); |
192
|
|
|
|
193
|
|
|
// Remember original version of the package file |
194
|
31 |
|
$packageFile->setVersion($jsonData->version); |
195
|
|
|
|
196
|
|
|
// Migrate to the expected version |
197
|
31 |
|
$this->migrationManager->migrate($jsonData, $this->targetVersion); |
198
|
|
|
|
199
|
31 |
|
$this->jsonToPackageFile($jsonData, $packageFile); |
200
|
31 |
|
$this->jsonToRootPackageFile($jsonData, $packageFile); |
201
|
|
|
|
202
|
31 |
|
return $packageFile; |
203
|
|
|
} |
204
|
|
|
|
205
|
22 |
|
private function packageFileToJson(PackageFile $packageFile, stdClass $jsonData) |
206
|
|
|
{ |
207
|
22 |
|
$mappings = $packageFile->getPathMappings(); |
208
|
22 |
|
$bindingDescriptors = $packageFile->getBindingDescriptors(); |
209
|
22 |
|
$typeDescriptors = $packageFile->getTypeDescriptors(); |
210
|
22 |
|
$overrides = $packageFile->getOverriddenPackages(); |
211
|
22 |
|
$extra = $packageFile->getExtraKeys(); |
212
|
|
|
|
213
|
22 |
|
if (null !== $packageFile->getPackageName()) { |
214
|
6 |
|
$jsonData->name = $packageFile->getPackageName(); |
215
|
6 |
|
} |
216
|
|
|
|
217
|
22 |
|
if (count($mappings) > 0) { |
218
|
4 |
|
$jsonData->{'path-mappings'} = new stdClass(); |
219
|
|
|
|
220
|
4 |
|
foreach ($mappings as $mapping) { |
221
|
4 |
|
$puliPath = $mapping->getRepositoryPath(); |
222
|
4 |
|
$localPaths = $mapping->getPathReferences(); |
223
|
|
|
|
224
|
4 |
|
$jsonData->{'path-mappings'}->$puliPath = count($localPaths) > 1 ? $localPaths : reset($localPaths); |
225
|
4 |
|
} |
226
|
4 |
|
} |
227
|
|
|
|
228
|
22 |
|
if (count($bindingDescriptors) > 0) { |
229
|
6 |
|
uasort($bindingDescriptors, array(__CLASS__, 'compareBindingDescriptors')); |
230
|
|
|
|
231
|
6 |
|
$jsonData->bindings = new stdClass(); |
232
|
|
|
|
233
|
6 |
|
foreach ($bindingDescriptors as $bindingDescriptor) { |
234
|
6 |
|
$binding = $bindingDescriptor->getBinding(); |
235
|
6 |
|
$bindingData = new stdClass(); |
236
|
6 |
|
$bindingData->_class = get_class($binding); |
237
|
|
|
|
238
|
|
|
// This needs to be moved to external classes to allow adding |
239
|
|
|
// custom binding classes at some point |
240
|
6 |
|
if ($binding instanceof ResourceBinding) { |
241
|
6 |
|
$bindingData->query = $binding->getQuery(); |
242
|
|
|
|
243
|
6 |
|
if ('glob' !== $binding->getLanguage()) { |
244
|
1 |
|
$bindingData->language = $binding->getLanguage(); |
245
|
1 |
|
} |
246
|
6 |
|
} elseif ($binding instanceof ClassBinding) { |
247
|
3 |
|
$bindingData->class = $binding->getClassName(); |
248
|
3 |
|
} |
249
|
|
|
|
250
|
6 |
|
$bindingData->type = $bindingDescriptor->getTypeName(); |
251
|
|
|
|
252
|
|
|
// Don't include the default values of the binding type |
253
|
6 |
|
if ($binding->hasParameterValues(false)) { |
254
|
1 |
|
$parameterData = $binding->getParameterValues(false); |
255
|
1 |
|
ksort($parameterData); |
256
|
1 |
|
$bindingData->parameters = (object) $parameterData; |
257
|
1 |
|
} |
258
|
|
|
|
259
|
6 |
|
$jsonData->bindings->{$bindingDescriptor->getUuid()->toString()} = $bindingData; |
260
|
6 |
|
} |
261
|
6 |
|
} |
262
|
|
|
|
263
|
22 |
|
if (count($typeDescriptors) > 0) { |
264
|
8 |
|
$bindingTypesData = array(); |
265
|
|
|
|
266
|
8 |
|
foreach ($typeDescriptors as $typeDescriptor) { |
267
|
8 |
|
$type = $typeDescriptor->getType(); |
268
|
8 |
|
$typeData = new stdClass(); |
269
|
|
|
|
270
|
8 |
|
if ($typeDescriptor->getDescription()) { |
271
|
2 |
|
$typeData->description = $typeDescriptor->getDescription(); |
272
|
2 |
|
} |
273
|
|
|
|
274
|
8 |
|
if ($type->hasParameters()) { |
275
|
6 |
|
$parametersData = array(); |
276
|
|
|
|
277
|
6 |
|
foreach ($type->getParameters() as $parameter) { |
278
|
6 |
|
$parameterData = new stdClass(); |
279
|
|
|
|
280
|
6 |
|
if ($typeDescriptor->hasParameterDescription($parameter->getName())) { |
281
|
3 |
|
$parameterData->description = $typeDescriptor->getParameterDescription($parameter->getName()); |
282
|
3 |
|
} |
283
|
|
|
|
284
|
6 |
|
if ($parameter->isRequired()) { |
285
|
1 |
|
$parameterData->required = true; |
286
|
1 |
|
} |
287
|
|
|
|
288
|
6 |
|
if (null !== $parameter->getDefaultValue()) { |
289
|
3 |
|
$parameterData->default = $parameter->getDefaultValue(); |
290
|
3 |
|
} |
291
|
|
|
|
292
|
6 |
|
$parametersData[$parameter->getName()] = $parameterData; |
293
|
6 |
|
} |
294
|
|
|
|
295
|
6 |
|
ksort($parametersData); |
296
|
|
|
|
297
|
6 |
|
$typeData->parameters = (object) $parametersData; |
298
|
6 |
|
} |
299
|
|
|
|
300
|
8 |
|
$bindingTypesData[$type->getName()] = $typeData; |
301
|
8 |
|
} |
302
|
|
|
|
303
|
8 |
|
ksort($bindingTypesData); |
304
|
|
|
|
305
|
8 |
|
$jsonData->{'binding-types'} = (object) $bindingTypesData; |
306
|
8 |
|
} |
307
|
|
|
|
308
|
22 |
|
if (count($overrides) > 0) { |
309
|
3 |
|
$jsonData->override = count($overrides) > 1 ? $overrides : reset($overrides); |
310
|
3 |
|
} |
311
|
|
|
|
312
|
22 |
|
if (count($extra) > 0) { |
313
|
2 |
|
$jsonData->extra = (object) $extra; |
314
|
2 |
|
} |
315
|
22 |
|
} |
316
|
|
|
|
317
|
7 |
|
private function rootPackageFileToJson(RootPackageFile $packageFile, stdClass $jsonData) |
318
|
|
|
{ |
319
|
7 |
|
$overrideOrder = $packageFile->getOverrideOrder(); |
320
|
7 |
|
$installInfos = $packageFile->getInstallInfos(); |
321
|
|
|
|
322
|
|
|
// Pass false to exclude base configuration values |
323
|
7 |
|
$configValues = $packageFile->getConfig()->toRawArray(false); |
324
|
|
|
|
325
|
7 |
|
if (count($overrideOrder) > 0) { |
326
|
1 |
|
$jsonData->{'override-order'} = $overrideOrder; |
327
|
1 |
|
} |
328
|
|
|
|
329
|
7 |
|
if (count($configValues) > 0) { |
330
|
1 |
|
$jsonData->config = (object) $configValues; |
331
|
1 |
|
} |
332
|
|
|
|
333
|
7 |
|
if (array() !== $packageFile->getPluginClasses()) { |
334
|
2 |
|
$jsonData->plugins = $packageFile->getPluginClasses(); |
335
|
|
|
|
336
|
2 |
|
sort($jsonData->plugins); |
337
|
2 |
|
} |
338
|
|
|
|
339
|
7 |
|
if (count($installInfos) > 0) { |
340
|
3 |
|
$packagesData = array(); |
341
|
|
|
|
342
|
3 |
|
foreach ($installInfos as $installInfo) { |
343
|
3 |
|
$installData = new stdClass(); |
344
|
3 |
|
$installData->{'install-path'} = $installInfo->getInstallPath(); |
345
|
|
|
|
346
|
3 |
|
if (InstallInfo::DEFAULT_INSTALLER_NAME !== $installInfo->getInstallerName()) { |
347
|
1 |
|
$installData->installer = $installInfo->getInstallerName(); |
348
|
1 |
|
} |
349
|
|
|
|
350
|
3 |
|
if ($installInfo->hasDisabledBindingUuids()) { |
351
|
2 |
|
$installData->{'disabled-bindings'} = array(); |
352
|
|
|
|
353
|
2 |
|
foreach ($installInfo->getDisabledBindingUuids() as $uuid) { |
354
|
2 |
|
$installData->{'disabled-bindings'}[] = $uuid->toString(); |
355
|
2 |
|
} |
356
|
|
|
|
357
|
2 |
|
sort($installData->{'disabled-bindings'}); |
358
|
2 |
|
} |
359
|
|
|
|
360
|
3 |
|
if (Environment::PROD !== $installInfo->getEnvironment()) { |
361
|
1 |
|
$installData->env = $installInfo->getEnvironment(); |
362
|
1 |
|
} |
363
|
|
|
|
364
|
3 |
|
$packagesData[$installInfo->getPackageName()] = $installData; |
365
|
3 |
|
} |
366
|
|
|
|
367
|
3 |
|
ksort($packagesData); |
368
|
|
|
|
369
|
3 |
|
$jsonData->packages = (object) $packagesData; |
370
|
3 |
|
} |
371
|
7 |
|
} |
372
|
|
|
|
373
|
41 |
|
private function jsonToPackageFile(stdClass $jsonData, PackageFile $packageFile) |
374
|
|
|
{ |
375
|
41 |
|
if (isset($jsonData->name)) { |
376
|
31 |
|
$packageFile->setPackageName($jsonData->name); |
377
|
31 |
|
} |
378
|
|
|
|
379
|
41 |
|
if (isset($jsonData->{'path-mappings'})) { |
380
|
4 |
|
foreach ($jsonData->{'path-mappings'} as $path => $relativePaths) { |
381
|
4 |
|
$packageFile->addPathMapping(new PathMapping($path, (array) $relativePaths)); |
382
|
4 |
|
} |
383
|
4 |
|
} |
384
|
|
|
|
385
|
41 |
|
if (isset($jsonData->bindings)) { |
386
|
8 |
|
foreach ($jsonData->bindings as $uuid => $bindingData) { |
387
|
8 |
|
$binding = null; |
388
|
8 |
|
$class = isset($bindingData->_class) |
389
|
8 |
|
? $bindingData->_class |
390
|
8 |
|
: 'Puli\Discovery\Binding\ResourceBinding'; |
391
|
|
|
|
392
|
|
|
// Move this code to external classes to allow use of custom |
393
|
|
|
// bindings |
394
|
|
|
switch ($class) { |
395
|
8 |
|
case 'Puli\Discovery\Binding\ClassBinding': |
396
|
5 |
|
$binding = new ClassBinding( |
397
|
5 |
|
$bindingData->class, |
398
|
5 |
|
$bindingData->type, |
399
|
5 |
|
isset($bindingData->parameters) ? (array) $bindingData->parameters : array(), |
400
|
5 |
|
Uuid::fromString($uuid) |
401
|
5 |
|
); |
402
|
5 |
|
break; |
403
|
7 |
|
case 'Puli\Discovery\Binding\ResourceBinding': |
404
|
7 |
|
$binding = new ResourceBinding( |
405
|
7 |
|
$bindingData->query, |
406
|
7 |
|
$bindingData->type, |
407
|
7 |
|
isset($bindingData->parameters) ? (array) $bindingData->parameters : array(), |
408
|
7 |
|
isset($bindingData->language) ? $bindingData->language : 'glob', |
409
|
7 |
|
Uuid::fromString($uuid) |
410
|
7 |
|
); |
411
|
7 |
|
break; |
412
|
|
|
default: |
413
|
|
|
continue; |
414
|
|
|
} |
415
|
|
|
|
416
|
8 |
|
$packageFile->addBindingDescriptor(new BindingDescriptor($binding)); |
|
|
|
|
417
|
8 |
|
} |
418
|
8 |
|
} |
419
|
|
|
|
420
|
41 |
|
if (isset($jsonData->{'binding-types'})) { |
421
|
5 |
|
foreach ((array) $jsonData->{'binding-types'} as $typeName => $data) { |
422
|
5 |
|
$parameters = array(); |
423
|
5 |
|
$parameterDescriptions = array(); |
424
|
|
|
|
425
|
5 |
|
if (isset($data->parameters)) { |
426
|
5 |
|
foreach ((array) $data->parameters as $parameterName => $parameterData) { |
427
|
5 |
|
$required = isset($parameterData->required) ? $parameterData->required : false; |
428
|
|
|
|
429
|
5 |
|
$parameters[] = new BindingParameter( |
430
|
5 |
|
$parameterName, |
431
|
5 |
|
$required ? BindingParameter::REQUIRED : BindingParameter::OPTIONAL, |
432
|
5 |
|
isset($parameterData->default) ? $parameterData->default : null |
433
|
5 |
|
); |
434
|
|
|
|
435
|
5 |
|
if (isset($parameterData->description)) { |
436
|
4 |
|
$parameterDescriptions[$parameterName] = $parameterData->description; |
437
|
4 |
|
}; |
438
|
5 |
|
} |
439
|
5 |
|
} |
440
|
|
|
|
441
|
5 |
|
$packageFile->addTypeDescriptor(new BindingTypeDescriptor( |
442
|
5 |
|
new BindingType($typeName, $parameters), |
443
|
5 |
|
isset($data->description) ? $data->description : null, |
444
|
|
|
$parameterDescriptions |
445
|
5 |
|
)); |
446
|
5 |
|
} |
447
|
5 |
|
} |
448
|
|
|
|
449
|
41 |
|
if (isset($jsonData->override)) { |
450
|
5 |
|
$packageFile->setOverriddenPackages((array) $jsonData->override); |
451
|
5 |
|
} |
452
|
|
|
|
453
|
41 |
|
if (isset($jsonData->extra)) { |
454
|
4 |
|
$packageFile->setExtraKeys((array) $jsonData->extra); |
455
|
4 |
|
} |
456
|
41 |
|
} |
457
|
|
|
|
458
|
31 |
|
private function jsonToRootPackageFile(stdClass $jsonData, RootPackageFile $packageFile) |
459
|
|
|
{ |
460
|
31 |
|
if (isset($jsonData->{'override-order'})) { |
461
|
2 |
|
$packageFile->setOverrideOrder((array) $jsonData->{'override-order'}); |
462
|
2 |
|
} |
463
|
|
|
|
464
|
31 |
|
if (isset($jsonData->plugins)) { |
465
|
28 |
|
$packageFile->setPluginClasses($jsonData->plugins); |
466
|
28 |
|
} |
467
|
|
|
|
468
|
31 |
|
if (isset($jsonData->config)) { |
469
|
3 |
|
$config = $packageFile->getConfig(); |
470
|
|
|
|
471
|
3 |
|
foreach ($this->objectsToArrays($jsonData->config) as $key => $value) { |
472
|
3 |
|
$config->set($key, $value); |
473
|
3 |
|
} |
474
|
3 |
|
} |
475
|
|
|
|
476
|
31 |
|
if (isset($jsonData->packages)) { |
477
|
28 |
|
foreach ($jsonData->packages as $packageName => $packageData) { |
478
|
28 |
|
$installInfo = new InstallInfo($packageName, $packageData->{'install-path'}); |
479
|
|
|
|
480
|
28 |
|
if (isset($packageData->env)) { |
481
|
2 |
|
$installInfo->setEnvironment($packageData->env); |
482
|
2 |
|
} |
483
|
|
|
|
484
|
28 |
|
if (isset($packageData->installer)) { |
485
|
2 |
|
$installInfo->setInstallerName($packageData->installer); |
486
|
2 |
|
} |
487
|
|
|
|
488
|
28 |
|
if (isset($packageData->{'disabled-bindings'})) { |
489
|
2 |
|
foreach ($packageData->{'disabled-bindings'} as $uuid) { |
490
|
2 |
|
$installInfo->addDisabledBindingUuid(Uuid::fromString($uuid)); |
491
|
2 |
|
} |
492
|
2 |
|
} |
493
|
|
|
|
494
|
28 |
|
$packageFile->addInstallInfo($installInfo); |
495
|
28 |
|
} |
496
|
28 |
|
} |
497
|
31 |
|
} |
498
|
|
|
|
499
|
22 |
|
private function encode(stdClass $jsonData, $path = null) |
500
|
|
|
{ |
501
|
22 |
|
$encoder = new JsonEncoder(); |
502
|
22 |
|
$encoder->setPrettyPrinting(true); |
503
|
22 |
|
$encoder->setEscapeSlash(false); |
504
|
22 |
|
$encoder->setTerminateWithLineFeed(true); |
505
|
|
|
|
506
|
22 |
|
$this->validate($jsonData, $path); |
507
|
|
|
|
508
|
22 |
|
return $encoder->encode($jsonData); |
509
|
|
|
} |
510
|
|
|
|
511
|
55 |
|
private function decode($json, $path = null) |
512
|
|
|
{ |
513
|
55 |
|
$decoder = new JsonDecoder(); |
514
|
|
|
|
515
|
|
|
try { |
516
|
55 |
|
$jsonData = $decoder->decode($json); |
517
|
55 |
|
} catch (DecodingFailedException $e) { |
518
|
2 |
|
throw new InvalidConfigException(sprintf( |
519
|
2 |
|
"The configuration%s could not be decoded:\n%s", |
520
|
2 |
|
$path ? ' in '.$path : '', |
521
|
2 |
|
$e->getMessage() |
522
|
2 |
|
), $e->getCode(), $e); |
523
|
|
|
} |
524
|
|
|
|
525
|
53 |
|
$this->assertVersionSupported($jsonData->version, $path); |
526
|
|
|
|
527
|
51 |
|
$this->validate($jsonData, $path); |
528
|
|
|
|
529
|
41 |
|
return $jsonData; |
530
|
|
|
} |
531
|
|
|
|
532
|
3 |
View Code Duplication |
private function objectsToArrays($data) |
|
|
|
|
533
|
|
|
{ |
534
|
3 |
|
$data = (array) $data; |
535
|
|
|
|
536
|
3 |
|
foreach ($data as $key => $value) { |
537
|
3 |
|
$data[$key] = is_object($value) ? $this->objectsToArrays($value) : $value; |
538
|
3 |
|
} |
539
|
|
|
|
540
|
3 |
|
return $data; |
541
|
|
|
} |
542
|
|
|
|
543
|
75 |
|
private function assertVersionSupported($version, $path = null) |
544
|
|
|
{ |
545
|
75 |
|
if (!in_array($version, $this->knownVersions, true)) { |
546
|
2 |
|
throw UnsupportedVersionException::forVersion( |
547
|
2 |
|
$version, |
548
|
2 |
|
$this->knownVersions, |
549
|
|
|
$path |
550
|
2 |
|
); |
551
|
|
|
} |
552
|
73 |
|
} |
553
|
|
|
|
554
|
73 |
|
private function validate($jsonData, $path = null) |
555
|
|
|
{ |
556
|
73 |
|
$validator = new JsonValidator(); |
557
|
73 |
|
$schema = $this->schemaDir.'/package-schema-'.$jsonData->version.'.json'; |
558
|
|
|
|
559
|
73 |
|
if (!file_exists($schema)) { |
560
|
|
|
throw new InvalidConfigException(sprintf( |
561
|
|
|
'The JSON schema file for version %s was not found%s.', |
562
|
|
|
$jsonData->version, |
563
|
|
|
$path ? ' in '.$path : '' |
564
|
|
|
)); |
565
|
|
|
} |
566
|
|
|
|
567
|
73 |
|
$errors = $validator->validate($jsonData, $schema); |
568
|
|
|
|
569
|
73 |
|
if (count($errors) > 0) { |
570
|
10 |
|
throw new InvalidConfigException(sprintf( |
571
|
10 |
|
"The configuration%s is invalid:\n%s", |
572
|
10 |
|
$path ? ' in '.$path : '', |
573
|
10 |
|
implode("\n", $errors) |
574
|
10 |
|
)); |
575
|
|
|
} |
576
|
63 |
|
} |
577
|
|
|
} |
578
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.