1 | <?php |
||
2 | namespace Yoanm\SymfonyJsonRpcHttpServer\DependencyInjection; |
||
3 | |||
4 | use Symfony\Component\Config\Definition\Processor; |
||
5 | use Symfony\Component\Config\FileLocator; |
||
6 | use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; |
||
7 | use Symfony\Component\DependencyInjection\ContainerBuilder; |
||
1 ignored issue
–
show
|
|||
8 | use Symfony\Component\DependencyInjection\Definition; |
||
9 | use Symfony\Component\DependencyInjection\Exception\LogicException; |
||
10 | use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; |
||
11 | use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; |
||
12 | use Symfony\Component\DependencyInjection\Reference; |
||
13 | use Yoanm\JsonRpcServer\App\Dispatcher\JsonRpcServerDispatcherAwareTrait; |
||
14 | use Yoanm\JsonRpcServer\Domain\JsonRpcMethodAwareInterface; |
||
15 | |||
16 | /** |
||
17 | * Class JsonRpcHttpServerExtension |
||
18 | */ |
||
19 | class JsonRpcHttpServerExtension implements ExtensionInterface, CompilerPassInterface |
||
20 | { |
||
21 | // Extension identifier (used in configuration for instance) |
||
22 | public const EXTENSION_IDENTIFIER = 'json_rpc_http_server'; |
||
23 | |||
24 | public const ENDPOINT_PATH_CONTAINER_PARAM_ID = self::EXTENSION_IDENTIFIER.'.http_endpoint_path'; |
||
25 | |||
26 | /** Tags */ |
||
27 | /**** Methods tags **/ |
||
28 | // Use this tag to inject your JSON-RPC methods into the default method resolver |
||
29 | public const JSONRPC_METHOD_TAG = 'json_rpc_http_server.jsonrpc_method'; |
||
30 | // And add an attribute with following key |
||
31 | public const JSONRPC_METHOD_TAG_METHOD_NAME_KEY = 'method'; |
||
32 | /**** END - Methods tags **/ |
||
33 | |||
34 | // Server dispatcher - Use this tag and server dispatcher will be injected |
||
35 | public const JSONRPC_SERVER_DISPATCHER_AWARE_TAG = 'json_rpc_http_server.server_dispatcher_aware'; |
||
36 | |||
37 | // JSON-RPC Methods mapping - Use this tag and all JSON-RPC method instance will be injected |
||
38 | // Useful for documentation for instance |
||
39 | public const JSONRPC_METHOD_AWARE_TAG = 'json_rpc_http_server.method_aware'; |
||
40 | |||
41 | |||
42 | private const PARAMS_VALIDATOR_ALIAS = 'json_rpc_http_server.alias.params_validator'; |
||
43 | private const REQUEST_HANDLER_SERVICE_ID = 'json_rpc_server_sdk.app.handler.jsonrpc_request'; |
||
44 | |||
45 | /** |
||
46 | * {@inheritdoc} |
||
47 | */ |
||
48 | 10 | public function load(array $configs, ContainerBuilder $container) |
|
49 | { |
||
50 | 10 | $this->compileAndProcessConfigurations($configs, $container); |
|
51 | |||
52 | 10 | $loader = new YamlFileLoader( |
|
53 | 10 | $container, |
|
54 | 10 | new FileLocator(__DIR__.'/../Resources/config') |
|
55 | 10 | ); |
|
56 | 10 | $loader->load('sdk.services.app.yaml'); |
|
57 | 10 | $loader->load('sdk.services.infra.yaml'); |
|
58 | 10 | $loader->load('services.private.yaml'); |
|
59 | 10 | $loader->load('services.public.yaml'); |
|
60 | } |
||
61 | |||
62 | /** |
||
63 | * {@inheritdoc} |
||
64 | */ |
||
65 | 10 | public function process(ContainerBuilder $container) |
|
66 | { |
||
67 | 10 | $this->bindJsonRpcServerDispatcher($container); |
|
68 | 9 | $this->bindValidatorIfDefined($container); |
|
69 | 9 | $this->binJsonRpcMethods($container); |
|
70 | } |
||
71 | |||
72 | /** |
||
73 | * {@inheritdoc} |
||
74 | */ |
||
75 | 11 | public function getNamespace() |
|
76 | { |
||
77 | 11 | return 'http://example.org/schema/dic/'.$this->getAlias(); |
|
78 | } |
||
79 | |||
80 | /** |
||
81 | * {@inheritdoc} |
||
82 | */ |
||
83 | 1 | public function getXsdValidationBasePath() |
|
84 | { |
||
85 | 1 | return ''; |
|
86 | } |
||
87 | |||
88 | /** |
||
89 | * {@inheritdoc} |
||
90 | */ |
||
91 | 11 | public function getAlias() |
|
92 | { |
||
93 | 11 | return self::EXTENSION_IDENTIFIER; |
|
94 | } |
||
95 | |||
96 | /** |
||
97 | * @param array $configs |
||
98 | * @param ContainerBuilder $container |
||
99 | */ |
||
100 | 10 | private function compileAndProcessConfigurations(array $configs, ContainerBuilder $container) : void |
|
101 | { |
||
102 | 10 | $configuration = new Configuration(); |
|
103 | 10 | $config = (new Processor())->processConfiguration($configuration, $configs); |
|
104 | |||
105 | 10 | $httpEndpointPath = $config['endpoint']; |
|
106 | |||
107 | 10 | $container->setParameter(self::ENDPOINT_PATH_CONTAINER_PARAM_ID, $httpEndpointPath); |
|
108 | } |
||
109 | |||
110 | /** |
||
111 | * @param ContainerBuilder $container |
||
112 | */ |
||
113 | 10 | private function bindJsonRpcServerDispatcher(ContainerBuilder $container) : void |
|
114 | { |
||
115 | 10 | $dispatcherRef = new Reference('json_rpc_http_server.dispatcher.server'); |
|
116 | 10 | $dispatcherAwareServiceList = $container->findTaggedServiceIds(self::JSONRPC_SERVER_DISPATCHER_AWARE_TAG); |
|
117 | 10 | foreach ($dispatcherAwareServiceList as $serviceId => $tagAttributeList) { |
|
118 | 10 | $definition = $container->getDefinition($serviceId); |
|
119 | |||
120 | 10 | if (!in_array(JsonRpcServerDispatcherAwareTrait::class, class_uses($definition->getClass()))) { |
|
121 | 1 | throw new LogicException( |
|
122 | 1 | sprintf( |
|
123 | 1 | 'Service "%s" is taggued with "%s" but does not use "%s"', |
|
124 | 1 | $serviceId, |
|
125 | 1 | self::JSONRPC_SERVER_DISPATCHER_AWARE_TAG, |
|
126 | 1 | JsonRpcServerDispatcherAwareTrait::class |
|
127 | 1 | ) |
|
128 | 1 | ); |
|
129 | } |
||
130 | |||
131 | 9 | $definition->addMethodCall('setJsonRpcServerDispatcher', [$dispatcherRef]); |
|
132 | } |
||
133 | } |
||
134 | |||
135 | 9 | private function bindValidatorIfDefined(ContainerBuilder $container) : void |
|
136 | { |
||
137 | 9 | if ($container->hasAlias(self::PARAMS_VALIDATOR_ALIAS)) { |
|
138 | 1 | $container->getDefinition(self::REQUEST_HANDLER_SERVICE_ID) |
|
139 | 1 | ->addMethodCall( |
|
140 | 1 | 'setMethodParamsValidator', |
|
141 | 1 | [ |
|
142 | 1 | new Reference(self::PARAMS_VALIDATOR_ALIAS) |
|
143 | 1 | ] |
|
144 | 1 | ) |
|
145 | 1 | ; |
|
146 | } |
||
147 | } |
||
148 | |||
149 | /** |
||
150 | * @param ContainerBuilder $container |
||
151 | */ |
||
152 | 9 | private function binJsonRpcMethods(ContainerBuilder $container) : void |
|
153 | { |
||
154 | 9 | $mappingAwareServiceDefinitionList = $this->findAndValidateMappingAwareDefinitionList($container); |
|
155 | |||
156 | 8 | $jsonRpcMethodDefinitionList = (new JsonRpcMethodDefinitionHelper()) |
|
157 | 8 | ->findAndValidateJsonRpcMethodDefinition($container); |
|
158 | |||
159 | 8 | $methodMappingList = []; |
|
160 | 8 | foreach ($jsonRpcMethodDefinitionList as $jsonRpcMethodServiceId => $methodNameList) { |
|
161 | 3 | foreach ($methodNameList as $methodName) { |
|
162 | 3 | $methodMappingList[$methodName] = new Reference($jsonRpcMethodServiceId); |
|
163 | 3 | $this->bindJsonRpcMethod($methodName, $jsonRpcMethodServiceId, $mappingAwareServiceDefinitionList); |
|
164 | } |
||
165 | } |
||
166 | |||
167 | // Service locator for method resolver |
||
168 | // => first argument is an array of wanted service with keys as alias for internal use |
||
169 | 8 | $container->getDefinition('json_rpc_http_server.service_locator.method_resolver') |
|
170 | 8 | ->setArgument(0, $methodMappingList); |
|
171 | } |
||
172 | |||
173 | /** |
||
174 | * @param string $methodName |
||
175 | * @param string $jsonRpcMethodServiceId |
||
176 | * @param Definition[] $mappingAwareServiceDefinitionList |
||
177 | */ |
||
178 | 3 | private function bindJsonRpcMethod( |
|
179 | string $methodName, |
||
180 | string $jsonRpcMethodServiceId, |
||
181 | array $mappingAwareServiceDefinitionList |
||
182 | ) : void { |
||
183 | 3 | foreach ($mappingAwareServiceDefinitionList as $methodAwareServiceDefinition) { |
|
184 | 2 | $methodAwareServiceDefinition->addMethodCall( |
|
185 | 2 | 'addJsonRpcMethod', |
|
186 | 2 | [$methodName, new Reference($jsonRpcMethodServiceId)] |
|
187 | 2 | ); |
|
188 | } |
||
189 | } |
||
190 | |||
191 | /** |
||
192 | * @param ContainerBuilder $container |
||
193 | * |
||
194 | * @return array |
||
195 | */ |
||
196 | 9 | private function findAndValidateMappingAwareDefinitionList(ContainerBuilder $container): array |
|
197 | { |
||
198 | 9 | $mappingAwareServiceDefinitionList = []; |
|
199 | 9 | $methodAwareServiceIdList = array_keys($container->findTaggedServiceIds(self::JSONRPC_METHOD_AWARE_TAG)); |
|
200 | 9 | foreach ($methodAwareServiceIdList as $serviceId) { |
|
201 | 3 | $definition = $container->getDefinition($serviceId); |
|
202 | |||
203 | 3 | $this->checkMethodAwareServiceIdList($definition, $serviceId, $container); |
|
204 | |||
205 | 2 | $mappingAwareServiceDefinitionList[$serviceId] = $definition; |
|
206 | } |
||
207 | |||
208 | 8 | return $mappingAwareServiceDefinitionList; |
|
209 | } |
||
210 | |||
211 | 3 | private function checkMethodAwareServiceIdList( |
|
212 | Definition $definition, |
||
213 | string $serviceId, |
||
214 | ContainerBuilder $container |
||
215 | ) : void { |
||
216 | 3 | $class = $container->getReflectionClass($definition->getClass()); |
|
217 | |||
218 | 3 | if (null !== $class && !$class->implementsInterface(JsonRpcMethodAwareInterface::class)) { |
|
219 | 1 | throw new LogicException(sprintf( |
|
220 | 1 | 'Service "%s" is tagged as JSON-RPC method aware but does not implement %s', |
|
221 | 1 | $serviceId, |
|
222 | 1 | JsonRpcMethodAwareInterface::class |
|
223 | 1 | )); |
|
224 | } |
||
225 | } |
||
226 | } |
||
227 |
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:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths