Skip to content

Commit 1a8e80f

Browse files
authored
Introduce serialization of InjectorDefinition to JSON (#11)
* Introduce serialization of InjectorDefinition to JSON * Work on InjectorDefinition deserialization * Account for filesystem sorting differences * Fix more array comparisons to canonicalize
1 parent 248efd9 commit 1a8e80f

11 files changed

+897
-80
lines changed

phpunit.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
bootstrap="vendor/autoload.php"
55
cacheResultFile=".phpunit.cache/test-results"
66
executionOrder="depends,defects"
7-
forceCoversAnnotation="true"
7+
forceCoversAnnotation="false"
88
beStrictAboutCoversAnnotation="true"
99
beStrictAboutOutputDuringTests="true"
1010
beStrictAboutTodoAnnotatedTests="true"

src/InjectorDefinition.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Interface InjectorDefinition
99
* @package Cspray\AnnotatedInjector
1010
*/
11-
interface InjectorDefinition extends JsonSerializable {
11+
interface InjectorDefinition {
1212

1313
/**
1414
* Returns a set of ServiceDefinition that are shared with the Injector.

src/InjectorDefinitionSerializer.php

+222
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
<?php
2+
3+
namespace Cspray\AnnotatedInjector;
4+
5+
use JsonSerializable;
6+
7+
class InjectorDefinitionSerializer {
8+
9+
public function serialize(InjectorDefinition $injectorDefinition) : JsonSerializable {
10+
return new class($injectorDefinition) implements JsonSerializable {
11+
12+
private InjectorDefinition $injectorDefinition;
13+
14+
public function __construct(InjectorDefinition $injectorDefinition) {
15+
$this->injectorDefinition = $injectorDefinition;
16+
}
17+
18+
public function jsonSerialize() {
19+
$compiledServiceDefinitions = [];
20+
$addCompiledServiceDefinition = function(string $key, ServiceDefinition $serviceDefinition) use(&$compiledServiceDefinitions, &$addCompiledServiceDefinition) : void {
21+
if (!isset($compiledServiceDefinitions[$key])) {
22+
$implementedServices = [];
23+
foreach ($serviceDefinition->getImplementedServices() as $implementedService) {
24+
$implementedKey = md5($implementedService->getType());
25+
$addCompiledServiceDefinition($implementedKey, $implementedService);
26+
$implementedServices[] = $implementedKey;
27+
}
28+
29+
$extendedServices = [];
30+
foreach ($serviceDefinition->getExtendedServices() as $extendedService) {
31+
$extendedKey = md5($extendedService->getType());
32+
$addCompiledServiceDefinition($extendedKey, $extendedService);
33+
$extendedServices[] = $extendedKey;
34+
}
35+
36+
$compiledServiceDefinitions[$key] = [
37+
'type' => $serviceDefinition->getType(),
38+
'implementedServices' => $implementedServices,
39+
'extendedServices' => $extendedServices,
40+
'environments' => $serviceDefinition->getEnvironments(),
41+
'isInterface' => $serviceDefinition->isInterface(),
42+
'isClass' => $serviceDefinition->isClass(),
43+
'isAbstract' => $serviceDefinition->isAbstract()
44+
];
45+
}
46+
};
47+
$serviceDefinitions = [];
48+
foreach ($this->injectorDefinition->getSharedServiceDefinitions() as $serviceDefinition) {
49+
$key = md5($serviceDefinition->getType());
50+
$addCompiledServiceDefinition($key, $serviceDefinition);
51+
$serviceDefinitions[] = $key;
52+
}
53+
54+
$aliasDefinitions = [];
55+
foreach ($this->injectorDefinition->getAliasDefinitions() as $aliasDefinition) {
56+
$originalKey = md5($aliasDefinition->getOriginalServiceDefinition()->getType());
57+
$addCompiledServiceDefinition($originalKey, $aliasDefinition->getOriginalServiceDefinition());
58+
$aliasKey = md5($aliasDefinition->getAliasServiceDefinition()->getType());
59+
$addCompiledServiceDefinition($aliasKey, $aliasDefinition->getAliasServiceDefinition());
60+
$aliasDefinitions[] = [
61+
'original' => $originalKey,
62+
'alias' => $aliasKey
63+
];
64+
}
65+
66+
$servicePrepareDefinitions = [];
67+
foreach ($this->injectorDefinition->getServicePrepareDefinitions() as $servicePrepareDefinition) {
68+
$servicePrepareDefinitions[] = [
69+
'type' => $servicePrepareDefinition->getType(),
70+
'method' => $servicePrepareDefinition->getMethod()
71+
];
72+
}
73+
74+
$useScalarDefinitions = [];
75+
foreach ($this->injectorDefinition->getUseScalarDefinitions() as $useScalarDefinition) {
76+
$useScalarDefinitions[] = [
77+
'type' => $useScalarDefinition->getType(),
78+
'method' => $useScalarDefinition->getMethod(),
79+
'paramName' => $useScalarDefinition->getParamName(),
80+
'paramType' => $useScalarDefinition->getParamType(),
81+
'value' => $useScalarDefinition->getValue()
82+
];
83+
}
84+
85+
$useServiceDefinitions = [];
86+
foreach ($this->injectorDefinition->getUseServiceDefinitions() as $useServiceDefinition) {
87+
$useServiceDefinitions[] = [
88+
'type' => $useServiceDefinition->getType(),
89+
'method' => $useServiceDefinition->getMethod(),
90+
'paramName' => $useServiceDefinition->getParamName(),
91+
'paramType' => $useServiceDefinition->getParamType(),
92+
'value' => $useServiceDefinition->getValue()
93+
];
94+
}
95+
96+
$serviceDelegateDefinitions = [];
97+
foreach ($this->injectorDefinition->getServiceDelegateDefinitions() as $serviceDelegateDefinition) {
98+
$serviceDelegateDefinitions[] = [
99+
'delegateType' => $serviceDelegateDefinition->getDelegateType(),
100+
'delegateMethod' => $serviceDelegateDefinition->getDelegateMethod(),
101+
'serviceType' => $serviceDelegateDefinition->getServiceType()
102+
];
103+
}
104+
105+
return [
106+
'compiledServiceDefinitions' => $compiledServiceDefinitions,
107+
'sharedServiceDefinitions' => $serviceDefinitions,
108+
'aliasDefinitions' => $aliasDefinitions,
109+
'servicePrepareDefinitions' => $servicePrepareDefinitions,
110+
'useScalarDefinitions' => $useScalarDefinitions,
111+
'useServiceDefinitions' => $useServiceDefinitions,
112+
'serviceDelegateDefinitions' => $serviceDelegateDefinitions
113+
];
114+
}
115+
};
116+
}
117+
118+
public function deserialize(string $json) : InjectorDefinition {
119+
$data = json_decode($json, true);
120+
121+
$serviceDefinitions = [];
122+
foreach ($data['compiledServiceDefinitions'] as $serviceHash => $compiledServiceDefinition) {
123+
$serviceDefinitions[$serviceHash] = new ServiceDefinition(
124+
$compiledServiceDefinition['type'],
125+
[],
126+
$compiledServiceDefinition['implementedServices'],
127+
$compiledServiceDefinition['extendedServices'],
128+
$compiledServiceDefinition['isInterface'],
129+
$compiledServiceDefinition['isAbstract']
130+
);
131+
}
132+
133+
$sharedServiceDefinitions = [];
134+
foreach ($data['sharedServiceDefinitions'] as $serviceHash) {
135+
$sharedServiceDefinitions[] = $serviceDefinitions[$serviceHash];
136+
}
137+
138+
$aliasDefinitions = [];
139+
foreach ($data['aliasDefinitions'] as $aliasDefinition) {
140+
$aliasDefinitions[] = new AliasDefinition(
141+
$serviceDefinitions[$aliasDefinition['original']],
142+
$serviceDefinitions[$aliasDefinition['alias']]
143+
);
144+
}
145+
146+
$servicePrepareDefinitions = [];
147+
foreach ($data['servicePrepareDefinitions'] as $servicePrepareDefinition) {
148+
$servicePrepareDefinitions[] = new ServicePrepareDefinition(
149+
$servicePrepareDefinition['type'],
150+
$servicePrepareDefinition['method']
151+
);
152+
}
153+
154+
$useScalarDefinitions = [];
155+
foreach ($data['useScalarDefinitions'] as $useScalarDefinition) {
156+
$useScalarDefinitions[] = new UseScalarDefinition(
157+
$useScalarDefinition['type'],
158+
$useScalarDefinition['method'],
159+
$useScalarDefinition['paramName'],
160+
$useScalarDefinition['paramType'],
161+
$useScalarDefinition['value']
162+
);
163+
}
164+
165+
$useServiceDefinitions = [];
166+
foreach ($data['useServiceDefinitions'] as $useServiceDefinition) {
167+
$useServiceDefinitions[] = new UseServiceDefinition(
168+
$useServiceDefinition['type'],
169+
$useServiceDefinition['method'],
170+
$useServiceDefinition['paramName'],
171+
$useServiceDefinition['paramType'],
172+
$useServiceDefinition['value']
173+
);
174+
}
175+
176+
$serviceDelegateDefinitions = [];
177+
foreach ($data['serviceDelegateDefinitions'] as $serviceDelegateDefinition) {
178+
$serviceDelegateDefinitions[] = new ServiceDelegateDefinition(
179+
$serviceDelegateDefinition['delegateType'],
180+
$serviceDelegateDefinition['delegateMethod'],
181+
$serviceDelegateDefinition['serviceType']
182+
);
183+
}
184+
185+
return new class($sharedServiceDefinitions, $aliasDefinitions, $servicePrepareDefinitions, $useScalarDefinitions, $useServiceDefinitions, $serviceDelegateDefinitions) implements InjectorDefinition {
186+
187+
public function __construct(
188+
private array $sharedServiceDefinitions,
189+
private array $aliasDefinitions,
190+
private array $servicePrepareDefinitions,
191+
private array $useScalarDefinitions,
192+
private array $useServiceDefinitions,
193+
private array $serviceDelegateDefinitions
194+
) {}
195+
196+
public function getSharedServiceDefinitions(): array {
197+
return $this->sharedServiceDefinitions;
198+
}
199+
200+
public function getAliasDefinitions(): array {
201+
return $this->aliasDefinitions;
202+
}
203+
204+
public function getServicePrepareDefinitions(): array {
205+
return $this->servicePrepareDefinitions;
206+
}
207+
208+
public function getUseScalarDefinitions(): array {
209+
return $this->useScalarDefinitions;
210+
}
211+
212+
public function getUseServiceDefinitions(): array {
213+
return $this->useServiceDefinitions;
214+
}
215+
216+
public function getServiceDelegateDefinitions(): array {
217+
return $this->serviceDelegateDefinitions;
218+
}
219+
};
220+
}
221+
222+
}

src/Internal/Interrogator/ServiceDefinitionInterrogator.php

+1-3
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@ public function findServiceDefinitionForType(string $type) : ?ServiceDefinition
3030

3131
public function gatherSharedServices() : Generator {
3232
foreach ($this->serviceDefinitions as $serviceDefinition) {
33-
if ($serviceDefinition->isInterface() || $serviceDefinition->isAbstract()) {
34-
yield $serviceDefinition;
35-
} else if (empty($serviceDefinition->getImplementedServices()) && empty($serviceDefinition->getExtendedServices())) {
33+
if (empty($serviceDefinition->getEnvironments()) || in_array($this->environment, $serviceDefinition->getEnvironments())) {
3634
yield $serviceDefinition;
3735
}
3836
}

src/Internal/Visitor/UseScalarDefinitionVisitor.php

+8-10
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,21 @@ final class UseScalarDefinitionVisitor extends AbstractNodeVisitor implements No
1515

1616
public function enterNode(Node $node) {
1717
if ($node instanceof Param) {
18-
$UseScalarAttribute = $this->findAttribute(UseScalar::class, ...$node->attrGroups);
19-
$UseScalarEnvAttribute = $this->findAttribute(UseScalarFromEnv::class, ...$node->attrGroups);
20-
if (isset($UseScalarAttribute) || $UseScalarEnvAttribute) {
18+
$useScalarAttribute = $this->findAttribute(UseScalar::class, ...$node->attrGroups);
19+
$useScalarEnvAttribute = $this->findAttribute(UseScalarFromEnv::class, ...$node->attrGroups);
20+
if (isset($useScalarAttribute) || $useScalarEnvAttribute) {
2121
// These calls are intentionally not chained together for future work that will do more checks on the
2222
// method and class that this attribute is defined on
2323
$methodNode = $node->getAttribute('parent');
2424
$classNode = $methodNode->getAttribute('parent');
25-
if (isset($UseScalarAttribute)) {
26-
$valueArg = $UseScalarAttribute->args[0];
25+
if (isset($useScalarAttribute)) {
26+
$valueArg = $useScalarAttribute->args[0];
2727
} else {
28-
$valueArg = $UseScalarEnvAttribute->args[0];
28+
$valueArg = $useScalarEnvAttribute->args[0];
2929
}
3030

3131
$value = $this->getAttributeArgumentValue($valueArg);
32-
if (isset($UseScalarEnvAttribute)) {
32+
if (isset($useScalarEnvAttribute)) {
3333
$value = "!env($value)";
3434
}
3535

@@ -39,9 +39,7 @@ public function enterNode(Node $node) {
3939
'method' => $methodNode->name->toString(),
4040
'param' => $node->var->name,
4141
'paramType' => $node->type->name,
42-
'value' => $value,
43-
'isPlainValue' => isset($UseScalarAttribute),
44-
'isEnvironmentVar' => isset($UseScalarEnvAttribute)
42+
'value' => $value
4543
];
4644
}
4745
}

src/PhpParserInjectorDefinitionCompiler.php

+1-7
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,7 @@ private function marshalRawUseScalarDefinitions(array $rawUseScalarDefinitions)
157157
$rawUseScalarDefinition['method'],
158158
$rawUseScalarDefinition['param'],
159159
$rawUseScalarDefinition['paramType'],
160-
$rawUseScalarDefinition['value'],
161-
$rawUseScalarDefinition['isPlainValue'],
162-
$rawUseScalarDefinition['isEnvironmentVar']
160+
$rawUseScalarDefinition['value']
163161
);
164162
}
165163
return $marshaledDefinitions;
@@ -295,10 +293,6 @@ public function getUseServiceDefinitions() : array {
295293
public function getServiceDelegateDefinitions(): array {
296294
return $this->serviceDelegateDefinitions;
297295
}
298-
299-
public function jsonSerialize() {
300-
return [];
301-
}
302296
};
303297
}
304298

src/ServiceDefinition.php

+3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ public function getImplementedServices() : array {
3434
return $this->implementedServices;
3535
}
3636

37+
/**
38+
* @return ServiceDefinition[]
39+
*/
3740
public function getExtendedServices() : array {
3841
return $this->extendedServices;
3942
}

src/UseScalarDefinition.php

+1-11
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ public function __construct(
99
private string $method,
1010
private string $param,
1111
private string $paramType,
12-
private string|int|float|bool|array $value,
13-
private bool $isPlainValue,
14-
private bool $isEnvironmentVar
12+
private string|int|float|bool|array $value
1513
) {}
1614

1715
public function getType() : string {
@@ -34,12 +32,4 @@ public function getValue() : string|int|float|bool|array {
3432
return $this->value;
3533
}
3634

37-
public function isPlainValue() : bool {
38-
return $this->isPlainValue;
39-
}
40-
41-
public function isEnvironmentVar() : bool {
42-
return $this->isEnvironmentVar;
43-
}
44-
4535
}

test/DummyApps/SimpleUseScalar/FooImplementation.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ public function __construct(
2020
#[UseScalar([
2121
['a', 'b', 'c'],
2222
[1, 2, 3],
23-
[1.0, 2.0, 3.0],
23+
[1.1, 2.1, 3.1],
2424
[true, false, true],
25-
[['a', 'b', 'c'], [1, 2, 3], [1.0, 2.0, 3.0], [true, false, true]]
25+
[['a', 'b', 'c'], [1, 2, 3], [1.1, 2.1, 3.1], [true, false, true]]
2626
])]
2727
public array $arrayParam
2828
) {}

0 commit comments

Comments
 (0)