Failed Conditions
Push — master ( dc9ff3...929e65 )
by Yo
03:56
created

DependencyInjection/JsonRpcHttpServerExtension.php (1 issue)

Labels
Severity
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
The type Symfony\Component\Depend...ection\ContainerBuilder was not found. Maybe you did not declare it correctly or list all dependencies?

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:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
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