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\Module; |
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\Discovery\BindingDescriptor; |
19
|
|
|
use Puli\Manager\Api\Discovery\BindingTypeDescriptor; |
20
|
|
|
use Puli\Manager\Api\Module\ModuleFile; |
21
|
|
|
use Puli\Manager\Api\Repository\PathMapping; |
22
|
|
|
use Puli\Manager\Assert\Assert; |
23
|
|
|
use Rhumsaa\Uuid\Uuid; |
24
|
|
|
use stdClass; |
25
|
|
|
use Webmozart\Json\Conversion\JsonConverter; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Converts module files to JSON and back. |
29
|
|
|
* |
30
|
|
|
* @since 1.0 |
31
|
|
|
* |
32
|
|
|
* @author Bernhard Schussek <[email protected]> |
33
|
|
|
*/ |
34
|
|
|
class ModuleFileConverter implements JsonConverter |
35
|
|
|
{ |
36
|
|
|
/** |
37
|
|
|
* The JSON version this converter supports. |
38
|
|
|
*/ |
39
|
|
|
const VERSION = '1.0'; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* The default order of the keys in the written module file. |
43
|
|
|
* |
44
|
|
|
* @var string[] |
45
|
|
|
*/ |
46
|
|
|
private static $keyOrder = array( |
47
|
|
|
'version', |
48
|
|
|
'name', |
49
|
|
|
'path-mappings', |
50
|
|
|
'bindings', |
51
|
|
|
'binding-types', |
52
|
|
|
'override', |
53
|
|
|
'extra', |
54
|
|
|
); |
55
|
|
|
|
56
|
3 |
|
public static function compareBindingDescriptors(BindingDescriptor $a, BindingDescriptor $b) |
57
|
|
|
{ |
58
|
|
|
// Make sure that bindings are always printed in the same order |
59
|
3 |
|
return strcmp($a->getUuid()->toString(), $b->getUuid()->toString()); |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* {@inheritdoc} |
64
|
|
|
*/ |
65
|
14 |
View Code Duplication |
public function toJson($moduleFile, array $options = array()) |
|
|
|
|
66
|
|
|
{ |
67
|
14 |
|
Assert::isInstanceOf($moduleFile, 'Puli\Manager\Api\Module\ModuleFile'); |
68
|
|
|
|
69
|
14 |
|
$jsonData = new stdClass(); |
70
|
|
|
|
71
|
14 |
|
$this->addModuleFileToJson($moduleFile, $jsonData); |
72
|
|
|
|
73
|
|
|
// Sort according to key order |
74
|
14 |
|
$jsonArray = (array) $jsonData; |
75
|
14 |
|
$orderedKeys = array_intersect_key(array_flip(self::$keyOrder), $jsonArray); |
76
|
14 |
|
$jsonData = (object) array_replace($orderedKeys, $jsonArray); |
77
|
|
|
|
78
|
14 |
|
return $jsonData; |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* {@inheritdoc} |
83
|
|
|
*/ |
84
|
22 |
|
public function fromJson($jsonData, array $options = array()) |
85
|
|
|
{ |
86
|
22 |
|
Assert::isInstanceOf($jsonData, 'stdClass'); |
87
|
|
|
|
88
|
22 |
|
$moduleFile = new ModuleFile(null, isset($options['path']) ? $options['path'] : null); |
89
|
|
|
|
90
|
22 |
|
$this->addJsonToModuleFile($jsonData, $moduleFile); |
91
|
|
|
|
92
|
22 |
|
return $moduleFile; |
93
|
|
|
} |
94
|
|
|
|
95
|
20 |
|
protected function addModuleFileToJson(ModuleFile $moduleFile, stdClass $jsonData) |
96
|
|
|
{ |
97
|
20 |
|
$mappings = $moduleFile->getPathMappings(); |
98
|
20 |
|
$bindingDescriptors = $moduleFile->getBindingDescriptors(); |
99
|
20 |
|
$typeDescriptors = $moduleFile->getTypeDescriptors(); |
100
|
20 |
|
$overrides = $moduleFile->getOverriddenModules(); |
101
|
20 |
|
$extra = $moduleFile->getExtraKeys(); |
102
|
|
|
|
103
|
20 |
|
if (null !== $moduleFile->getModuleName()) { |
104
|
2 |
|
$jsonData->name = $moduleFile->getModuleName(); |
105
|
|
|
} |
106
|
|
|
|
107
|
20 |
|
if (count($mappings) > 0) { |
108
|
4 |
|
$jsonData->{'path-mappings'} = new stdClass(); |
109
|
|
|
|
110
|
4 |
|
foreach ($mappings as $mapping) { |
111
|
4 |
|
$puliPath = $mapping->getRepositoryPath(); |
112
|
4 |
|
$localPaths = $mapping->getPathReferences(); |
113
|
|
|
|
114
|
4 |
|
$jsonData->{'path-mappings'}->$puliPath = count($localPaths) > 1 ? $localPaths : reset($localPaths); |
115
|
|
|
} |
116
|
|
|
} |
117
|
|
|
|
118
|
20 |
|
if (count($bindingDescriptors) > 0) { |
119
|
6 |
|
uasort($bindingDescriptors, array(__CLASS__, 'compareBindingDescriptors')); |
120
|
|
|
|
121
|
6 |
|
$jsonData->bindings = new stdClass(); |
122
|
|
|
|
123
|
6 |
|
foreach ($bindingDescriptors as $bindingDescriptor) { |
124
|
6 |
|
$binding = $bindingDescriptor->getBinding(); |
125
|
6 |
|
$bindingData = new stdClass(); |
126
|
6 |
|
$bindingData->_class = get_class($binding); |
127
|
|
|
|
128
|
|
|
// This needs to be moved to external classes to allow adding |
129
|
|
|
// custom binding classes at some point |
130
|
6 |
|
if ($binding instanceof ResourceBinding) { |
131
|
6 |
|
$bindingData->query = $binding->getQuery(); |
132
|
|
|
|
133
|
6 |
|
if ('glob' !== $binding->getLanguage()) { |
134
|
6 |
|
$bindingData->language = $binding->getLanguage(); |
135
|
|
|
} |
136
|
|
|
} elseif ($binding instanceof ClassBinding) { |
137
|
3 |
|
$bindingData->class = $binding->getClassName(); |
138
|
|
|
} |
139
|
|
|
|
140
|
6 |
|
$bindingData->type = $bindingDescriptor->getTypeName(); |
141
|
|
|
|
142
|
|
|
// Don't include the default values of the binding type |
143
|
6 |
|
if ($binding->hasParameterValues(false)) { |
144
|
1 |
|
$parameterData = $binding->getParameterValues(false); |
145
|
1 |
|
ksort($parameterData); |
146
|
1 |
|
$bindingData->parameters = (object) $parameterData; |
147
|
|
|
} |
148
|
|
|
|
149
|
6 |
|
$jsonData->bindings->{$bindingDescriptor->getUuid()->toString()} = $bindingData; |
150
|
|
|
} |
151
|
|
|
} |
152
|
|
|
|
153
|
20 |
|
if (count($typeDescriptors) > 0) { |
154
|
8 |
|
$bindingTypesData = array(); |
155
|
|
|
|
156
|
8 |
|
foreach ($typeDescriptors as $typeDescriptor) { |
157
|
8 |
|
$type = $typeDescriptor->getType(); |
158
|
8 |
|
$typeData = new stdClass(); |
159
|
|
|
|
160
|
8 |
|
if ($typeDescriptor->getDescription()) { |
161
|
2 |
|
$typeData->description = $typeDescriptor->getDescription(); |
162
|
|
|
} |
163
|
|
|
|
164
|
8 |
|
if ($type->hasParameters()) { |
165
|
6 |
|
$parametersData = array(); |
166
|
|
|
|
167
|
6 |
|
foreach ($type->getParameters() as $parameter) { |
168
|
6 |
|
$parameterData = new stdClass(); |
169
|
|
|
|
170
|
6 |
|
if ($typeDescriptor->hasParameterDescription($parameter->getName())) { |
171
|
3 |
|
$parameterData->description = $typeDescriptor->getParameterDescription($parameter->getName()); |
172
|
|
|
} |
173
|
|
|
|
174
|
6 |
|
if ($parameter->isRequired()) { |
175
|
1 |
|
$parameterData->required = true; |
176
|
|
|
} |
177
|
|
|
|
178
|
6 |
|
if (null !== $parameter->getDefaultValue()) { |
179
|
3 |
|
$parameterData->default = $parameter->getDefaultValue(); |
180
|
|
|
} |
181
|
|
|
|
182
|
6 |
|
$parametersData[$parameter->getName()] = $parameterData; |
183
|
|
|
} |
184
|
|
|
|
185
|
6 |
|
ksort($parametersData); |
186
|
|
|
|
187
|
6 |
|
$typeData->parameters = (object) $parametersData; |
188
|
|
|
} |
189
|
|
|
|
190
|
8 |
|
$bindingTypesData[$type->getName()] = $typeData; |
191
|
|
|
} |
192
|
|
|
|
193
|
8 |
|
ksort($bindingTypesData); |
194
|
|
|
|
195
|
8 |
|
$jsonData->{'binding-types'} = (object) $bindingTypesData; |
196
|
|
|
} |
197
|
|
|
|
198
|
20 |
|
if (count($overrides) > 0) { |
199
|
3 |
|
$jsonData->override = count($overrides) > 1 ? $overrides : reset($overrides); |
200
|
|
|
} |
201
|
|
|
|
202
|
20 |
|
if (count($extra) > 0) { |
203
|
2 |
|
$jsonData->extra = (object) $extra; |
204
|
|
|
} |
205
|
20 |
|
} |
206
|
|
|
|
207
|
38 |
|
protected function addJsonToModuleFile(stdClass $jsonData, ModuleFile $moduleFile) |
208
|
|
|
{ |
209
|
38 |
|
if (isset($jsonData->name)) { |
210
|
28 |
|
$moduleFile->setModuleName($jsonData->name); |
211
|
|
|
} |
212
|
|
|
|
213
|
38 |
|
if (isset($jsonData->{'path-mappings'})) { |
214
|
2 |
|
foreach ($jsonData->{'path-mappings'} as $path => $relativePaths) { |
215
|
2 |
|
$moduleFile->addPathMapping(new PathMapping($path, (array) $relativePaths)); |
216
|
|
|
} |
217
|
|
|
} |
218
|
|
|
|
219
|
38 |
|
if (isset($jsonData->bindings)) { |
220
|
6 |
|
foreach ($jsonData->bindings as $uuid => $bindingData) { |
221
|
6 |
|
$binding = null; |
|
|
|
|
222
|
6 |
|
$class = isset($bindingData->_class) |
223
|
4 |
|
? $bindingData->_class |
224
|
6 |
|
: 'Puli\Discovery\Binding\ResourceBinding'; |
225
|
|
|
|
226
|
|
|
// Move this code to external classes to allow use of custom |
227
|
|
|
// bindings |
228
|
|
|
switch ($class) { |
229
|
6 |
|
case 'Puli\Discovery\Binding\ClassBinding': |
230
|
3 |
|
$binding = new ClassBinding( |
231
|
3 |
|
$bindingData->class, |
232
|
3 |
|
$bindingData->type, |
233
|
3 |
|
isset($bindingData->parameters) ? (array) $bindingData->parameters : array(), |
234
|
3 |
|
Uuid::fromString($uuid) |
235
|
|
|
); |
236
|
3 |
|
break; |
237
|
|
|
case 'Puli\Discovery\Binding\ResourceBinding': |
238
|
5 |
|
$binding = new ResourceBinding( |
239
|
5 |
|
$bindingData->query, |
240
|
5 |
|
$bindingData->type, |
241
|
5 |
|
isset($bindingData->parameters) ? (array) $bindingData->parameters : array(), |
242
|
5 |
|
isset($bindingData->language) ? $bindingData->language : 'glob', |
243
|
5 |
|
Uuid::fromString($uuid) |
244
|
|
|
); |
245
|
5 |
|
break; |
246
|
|
|
default: |
247
|
|
|
continue 2; |
248
|
|
|
} |
249
|
|
|
|
250
|
6 |
|
$moduleFile->addBindingDescriptor(new BindingDescriptor($binding)); |
251
|
|
|
} |
252
|
|
|
} |
253
|
|
|
|
254
|
38 |
|
if (isset($jsonData->{'binding-types'})) { |
255
|
3 |
|
foreach ((array) $jsonData->{'binding-types'} as $typeName => $data) { |
256
|
3 |
|
$parameters = array(); |
257
|
3 |
|
$parameterDescriptions = array(); |
258
|
|
|
|
259
|
3 |
|
if (isset($data->parameters)) { |
260
|
3 |
|
foreach ((array) $data->parameters as $parameterName => $parameterData) { |
261
|
3 |
|
$required = isset($parameterData->required) ? $parameterData->required : false; |
262
|
|
|
|
263
|
3 |
|
$parameters[] = new BindingParameter( |
264
|
|
|
$parameterName, |
265
|
3 |
|
$required ? BindingParameter::REQUIRED : BindingParameter::OPTIONAL, |
266
|
3 |
|
isset($parameterData->default) ? $parameterData->default : null |
267
|
|
|
); |
268
|
|
|
|
269
|
3 |
|
if (isset($parameterData->description)) { |
270
|
3 |
|
$parameterDescriptions[$parameterName] = $parameterData->description; |
271
|
|
|
}; |
272
|
|
|
} |
273
|
|
|
} |
274
|
|
|
|
275
|
3 |
|
$moduleFile->addTypeDescriptor(new BindingTypeDescriptor( |
276
|
3 |
|
new BindingType($typeName, $parameters), |
277
|
3 |
|
isset($data->description) ? $data->description : null, |
278
|
|
|
$parameterDescriptions |
279
|
|
|
)); |
280
|
|
|
} |
281
|
|
|
} |
282
|
|
|
|
283
|
38 |
|
if (isset($jsonData->override)) { |
284
|
2 |
|
$moduleFile->setOverriddenModules((array) $jsonData->override); |
285
|
|
|
} |
286
|
|
|
|
287
|
38 |
|
if (isset($jsonData->extra)) { |
288
|
2 |
|
$moduleFile->setExtraKeys((array) $jsonData->extra); |
289
|
|
|
} |
290
|
38 |
|
} |
291
|
|
|
} |
292
|
|
|
|
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.