55use Symfony \Component \Config \FileLocator ;
66use Symfony \Component \DependencyInjection \Compiler \CompilerPassInterface ;
77use Symfony \Component \DependencyInjection \ContainerBuilder ;
8+ use Symfony \Component \DependencyInjection \Definition ;
89use Symfony \Component \DependencyInjection \Exception \LogicException ;
910use Symfony \Component \DependencyInjection \Extension \ExtensionInterface ;
1011use Symfony \Component \DependencyInjection \Loader \YamlFileLoader ;
1112use Symfony \Component \DependencyInjection \Reference ;
1213use Yoanm \JsonRpcServer \App \Dispatcher \JsonRpcServerDispatcherAwareTrait ;
14+ use Yoanm \JsonRpcServer \Domain \JsonRpcMethodAwareInterface ;
1315
1416/**
1517 * Class JsonRpcHttpServerExtension
1618 */
1719class JsonRpcHttpServerExtension implements ExtensionInterface, CompilerPassInterface
1820{
1921 // Extension identifier (used in configuration for instance)
20- const EXTENSION_IDENTIFIER = 'json_rpc_http_server ' ;
22+ public const EXTENSION_IDENTIFIER = 'json_rpc_http_server ' ;
2123
2224 /** Tags */
25+ /**** Methods tags **/
26+ // Use this tag to inject your JSON-RPC methods into the default method resolver
27+ public const JSONRPC_METHOD_TAG = 'json_rpc_http_server.jsonrpc_method ' ;
28+ // And add an attribute with following key
29+ public const JSONRPC_METHOD_TAG_METHOD_NAME_KEY = 'method ' ;
30+ /**** END - Methods tags **/
31+
2332 // Server dispatcher - Use this tag and server dispatcher will be injected
24- const JSONRPC_SERVER_DISPATCHER_AWARE_TAG = 'json_rpc_http_server.server_dispatcher_aware ' ;
33+ public const JSONRPC_SERVER_DISPATCHER_AWARE_TAG = 'json_rpc_http_server.server_dispatcher_aware ' ;
2534
35+ // JSON-RPC Methods mapping - Use this tag and all JSON-RPC method instance will be injected
36+ // Useful for documentation for instance
37+ public const JSONRPC_METHOD_AWARE_TAG = 'json_rpc_http_server.method_aware ' ;
2638
27- /** Method resolver */
28- const METHOD_RESOLVER_ALIAS = 'json_rpc_http_server.alias.method_resolver ' ;
29- /** Params validator */
30- const PARAMS_VALIDATOR_ALIAS = 'json_rpc_http_server.alias.params_validator ' ;
3139
32- const REQUEST_HANDLER_SERVICE_ID = 'json_rpc_server_sdk.app.handler.jsonrpc_request ' ;
40+ private const PARAMS_VALIDATOR_ALIAS = 'json_rpc_http_server.alias.params_validator ' ;
41+ private const REQUEST_HANDLER_SERVICE_ID = 'json_rpc_server_sdk.app.handler.jsonrpc_request ' ;
3342
3443 /**
3544 * {@inheritdoc}
@@ -54,6 +63,7 @@ public function process(ContainerBuilder $container)
5463 {
5564 $ this ->bindJsonRpcServerDispatcher ($ container );
5665 $ this ->bindValidatorIfDefined ($ container );
66+ $ this ->binJsonRpcMethods ($ container );
5767 }
5868
5969 /**
@@ -80,12 +90,26 @@ public function getAlias()
8090 return self ::EXTENSION_IDENTIFIER ;
8191 }
8292
93+ /**
94+ * @param array $configs
95+ * @param ContainerBuilder $container
96+ */
97+ private function compileAndProcessConfigurations (array $ configs , ContainerBuilder $ container ) : void
98+ {
99+ $ configuration = new Configuration ();
100+ $ config = (new Processor ())->processConfiguration ($ configuration , $ configs );
101+
102+ $ httpEndpointPath = $ config ['endpoint ' ];
103+
104+ $ container ->setParameter (self ::EXTENSION_IDENTIFIER .'.http_endpoint_path ' , $ httpEndpointPath );
105+ }
106+
83107 /**
84108 * @param ContainerBuilder $container
85109 *
86110 * @return Reference|null Null in case no dispatcher found
87111 */
88- private function bindJsonRpcServerDispatcher (ContainerBuilder $ container )
112+ private function bindJsonRpcServerDispatcher (ContainerBuilder $ container ) : void
89113 {
90114 $ dispatcherRef = new Reference ('json_rpc_http_server.dispatcher.server ' );
91115 $ dispatcherAwareServiceList = $ container ->findTaggedServiceIds (self ::JSONRPC_SERVER_DISPATCHER_AWARE_TAG );
@@ -107,21 +131,7 @@ private function bindJsonRpcServerDispatcher(ContainerBuilder $container)
107131 }
108132 }
109133
110- /**
111- * @param array $configs
112- * @param ContainerBuilder $container
113- */
114- private function compileAndProcessConfigurations (array $ configs , ContainerBuilder $ container )
115- {
116- $ configuration = new Configuration ();
117- $ config = (new Processor ())->processConfiguration ($ configuration , $ configs );
118-
119- $ httpEndpointPath = $ config ['endpoint ' ];
120-
121- $ container ->setParameter (self ::EXTENSION_IDENTIFIER .'.http_endpoint_path ' , $ httpEndpointPath );
122- }
123-
124- private function bindValidatorIfDefined (ContainerBuilder $ container )
134+ private function bindValidatorIfDefined (ContainerBuilder $ container ) : void
125135 {
126136 if ($ container ->hasAlias (self ::PARAMS_VALIDATOR_ALIAS )) {
127137 $ container ->getDefinition (self ::REQUEST_HANDLER_SERVICE_ID )
@@ -134,4 +144,80 @@ private function bindValidatorIfDefined(ContainerBuilder $container)
134144 ;
135145 }
136146 }
147+
148+ /**
149+ * @param ContainerBuilder $container
150+ */
151+ private function binJsonRpcMethods (ContainerBuilder $ container ) : void
152+ {
153+ $ mappingAwareServiceDefinitionList = $ this ->findAndValidateMappingAwareDefinitionList ($ container );
154+
155+ if (0 === count ($ mappingAwareServiceDefinitionList )) {
156+ return ;
157+ }
158+
159+ $ jsonRpcMethodDefinitionList = (new JsonRpcMethodDefinitionHelper ())
160+ ->findAndValidateJsonRpcMethodDefinition ($ container );
161+
162+ foreach ($ jsonRpcMethodDefinitionList as $ jsonRpcMethodServiceId => $ methodNameList ) {
163+ foreach ($ methodNameList as $ methodName ) {
164+ $ this ->bindJsonRpcMethod ($ methodName , $ jsonRpcMethodServiceId , $ mappingAwareServiceDefinitionList );
165+ }
166+ }
167+ }
168+
169+ /**
170+ * @param string $methodName
171+ * @param Definition $jsonRpcMethodDefinition
172+ * @param Definition[] $mappingAwareServiceDefinitionList
173+ */
174+ private function bindJsonRpcMethod (
175+ string $ methodName ,
176+ string $ jsonRpcMethodServiceId ,
177+ array $ mappingAwareServiceDefinitionList
178+ ) : void {
179+ foreach ($ mappingAwareServiceDefinitionList as $ methodAwareServiceDefinition ) {
180+ $ methodAwareServiceDefinition ->addMethodCall (
181+ 'addJsonRpcMethod ' ,
182+ [$ methodName , new Reference ($ jsonRpcMethodServiceId )]
183+ );
184+ }
185+ }
186+
187+ /**
188+ * @param ContainerBuilder $container
189+ *
190+ * @return array
191+ * @throws \ReflectionException
192+ */
193+ private function findAndValidateMappingAwareDefinitionList (ContainerBuilder $ container ): array
194+ {
195+ $ mappingAwareServiceDefinitionList = [];
196+ $ methodAwareServiceIdList = array_keys ($ container ->findTaggedServiceIds (self ::JSONRPC_METHOD_AWARE_TAG ));
197+ foreach ($ methodAwareServiceIdList as $ serviceId ) {
198+ $ definition = $ container ->getDefinition ($ serviceId );
199+
200+ $ this ->checkMethodAwareServiceIdList ($ definition , $ serviceId , $ container );
201+
202+ $ mappingAwareServiceDefinitionList [$ serviceId ] = $ definition ;
203+ }
204+
205+ return $ mappingAwareServiceDefinitionList ;
206+ }
207+
208+ private function checkMethodAwareServiceIdList (
209+ Definition $ definition ,
210+ string $ serviceId ,
211+ ContainerBuilder $ container
212+ ) : void {
213+ $ class = $ container ->getReflectionClass ($ definition ->getClass ());
214+
215+ if (null !== $ class && !$ class ->implementsInterface (JsonRpcMethodAwareInterface::class)) {
216+ throw new LogicException (sprintf (
217+ 'Service "%s" is taggued as JSON-RPC method aware but does not implement %s ' ,
218+ $ serviceId ,
219+ JsonRpcMethodAwareInterface::class
220+ ));
221+ }
222+ }
137223}
0 commit comments