JsonApiExtension::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
declare(strict_types = 1);
3
4
namespace Mikemirten\Bundle\JsonApiBundle\DependencyInjection;
5
6
use Symfony\Component\Config\FileLocator;
7
use Symfony\Component\Config\Loader\LoaderInterface;
8
use Symfony\Component\DependencyInjection\ChildDefinition;
9
use Symfony\Component\DependencyInjection\Definition;
10
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
11
use Symfony\Component\DependencyInjection\Reference;
12
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
13
use Symfony\Component\DependencyInjection\ContainerBuilder;
14
15
class JsonApiExtension extends Extension
16
{
17
    const ALIAS = 'mrtn_json_api';
18
19
    /**
20
     * Configuration loader
21
     *
22
     * @var LoaderInterface
23
     */
24
    protected $loader;
25
26
    /**
27
     * JsonApiExtension constructor.
28
     *
29
     * @param LoaderInterface $loader
30
     */
31 7
    public function __construct(LoaderInterface $loader = null)
32
    {
33 7
        $this->loader = $loader;
34 7
    }
35
36
    /**
37
     * {@inheritdoc}
38
     */
39 7
    public function load(array $configs, ContainerBuilder $container)
40
    {
41 7
        $configuration = new JsonApiConfiguration();
42 7
        $config = $this->processConfiguration($configuration, $configs);
43
44 7
        $loader = $this->loader ?? new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
45
46 7
        $loader->load('services.yml');
47 7
        $loader->load('hydrator.yml');
48 7
        $loader->load('mapper.yml');
49 7
        $loader->load('http_client.yml');
50
51 7
        $this->handleMappingDefinitionProvider($container);
52
53 7
        if (! empty($config['mappers'])) {
54 6
            $this->createMappers($config['mappers'], $container);
55
        }
56
57 7
        if (! empty($config['resource_clients'])) {
58 5
            $this->createResourceClients($config['resource_clients'], $container);
59
        }
60
61 7
        if (! empty($config['http_client'])) {
62 1
            $this->processHttpClient($config['http_client'], $container);
63
        }
64 7
    }
65
66
    /**
67
     * Process http client
68
     *
69
     * @param array            $config
70
     * @param ContainerBuilder $container
71
     */
72 1
    protected function processHttpClient(array $config, ContainerBuilder $container)
73
    {
74 1
        if (empty($config['guzzle_service'])) {
75
            return;
76
        }
77
78 1
        if ($container->hasDefinition($config['guzzle_service'])) {
79
            throw new \LogicException(sprintf('Service "%s" has not been defined.'));
80
        }
81
82 1
        $container->getDefinition('mrtn_json_api.http_client.adapter.guzzle')
83 1
            ->setArguments([
84 1
                new Reference($config['guzzle_service'])
85
            ]);
86 1
    }
87
88
    /**
89
     * Handle mapping definition provider depends on environment
90
     *
91
     * @param ContainerBuilder $container
92
     */
93 7
    protected function handleMappingDefinitionProvider(ContainerBuilder $container)
94
    {
95 7
        $env = $container->getParameter('kernel.environment');
96
97 7
        if ($env === 'prod') {
98 4
            $container->setAlias(
99 4
                'mrtn_json_api.object_mapper.definition_provider',
100 4
                'mrtn_json_api.object_mapper.definition_provider.cached'
101
            );
102
103 4
            return;
104
        }
105
106 3
        $container->setAlias(
107 3
            'mrtn_json_api.object_mapper.definition_provider',
108 3
            'mrtn_json_api.object_mapper.definition_provider.annotation'
109
        );
110 3
    }
111
112
    /**
113
     * Create mappers
114
     *
115
     * @param array            $config
116
     * @param ContainerBuilder $container
117
     */
118 6
    protected function createMappers(array $config, ContainerBuilder $container)
119
    {
120 6
        $handlers = $this->findMappingHandlers($container);
121
122 6
        foreach ($config as $name => $mapperDefinition)
123
        {
124 6
            $mapper = new ChildDefinition('mrtn_json_api.object_mapper.abstract');
125 6
            $mapper->addTag('mrtn_json_api.object_mapper', ['alias' => $name]);
126
127 6 View Code Duplication
            foreach ($mapperDefinition['handlers'] as $handlerName)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
128
            {
129 6
                if (! isset($handlers[$handlerName])) {
130
                    throw new \LogicException(sprintf('Mapping handler with name "%s" has not been registered as a service.', $handlerName));
131
                }
132
133 6
                $mapper->addMethodCall('addHandler', [
134 6
                    new Reference($handlers[$handlerName])
135
                ]);
136
            }
137
138 6
            $container->setDefinition('mrtn_json_api.object_mapper.' . $name, $mapper);
139
        }
140 6
    }
141
142
    /**
143
     * Find mapping handler registered in container
144
     *
145
     * @param  ContainerBuilder $container
146
     * @return array
147
     */
148 6
    protected function findMappingHandlers(ContainerBuilder $container): array
149
    {
150 6
        $handlers = $container->findTaggedServiceIds('mrtn_json_api.object_mapper.handler');
151
152 6
        $found = [];
153
154 6
        foreach ($handlers as $id => $tags)
155
        {
156 6
            foreach ($tags as $tag)
157
            {
158 6
                if (! isset($tag['alias'])) {
159
                    continue;
160
                }
161
162 6
                $found[$tag['alias']] = $id;
163
            }
164
        }
165
166 6
        return $found;
167
    }
168
169
    /**
170
     * Create resources-based clients
171
     *
172
     * @param array            $config
173
     * @param ContainerBuilder $container
174
     */
175 5
    protected function createResourceClients(array $config, ContainerBuilder $container)
176
    {
177 5
        $repositoryClass = $container->getParameter('mrtn_json_api.route_repository.class');
178 5
        $clientClass     = $container->getParameter('mrtn_json_api.resource_client.class');
179
180 5
        foreach ($config as $name => $definition)
181
        {
182 5
            $this->createEventDispatcherDecorator($container, $name);
183
184 5
            $routes = $this->createRoutesDefinition($definition['resources']);
185
186 5
            $repository = new Definition($repositoryClass, [$definition['base_url'], $routes]);
187 5
            $repository->setPublic(false);
188
189 5
            $client = new Definition($clientClass, [
190 5
                new Reference('mrtn_json_api.http_client.decorator.event_dispatcher.' . $name),
191 5
                new Reference('mrtn_json_api.route_repository.' . $name)
192
            ]);
193
194 5
            $container->setDefinition('mrtn_json_api.route_repository.' . $name, $repository);
195 5
            $container->setDefinition('mrtn_json_api.resource_client.' . $name, $client);
196
        }
197 5
    }
198
199
    /**
200
     * Create event dispatcher decorator for resource-based http-client
201
     *
202
     * @param ContainerBuilder $container
203
     * @param string           $name
204
     */
205 5
    protected function createEventDispatcherDecorator(ContainerBuilder $container, string $name)
206
    {
207 5
        $class = $container->getParameter('mrtn_json_api.http_client.decorator.event_dispatcher.class');
208
209 5
        $decorator = new Definition($class, [
210 5
            new Reference('mrtn_json_api.http_client'),
211 5
            new Reference('event_dispatcher'),
212 5
            sprintf('mrtn_json_api.resource_client.%s.request', $name),
213 5
            sprintf('mrtn_json_api.resource_client.%s.response', $name),
214 5
            sprintf('mrtn_json_api.resource_client.%s.exception', $name)
215
        ]);
216
217 5
        $decorator->setPublic(false);
218
219 5
        $container->setDefinition('mrtn_json_api.http_client.decorator.event_dispatcher.' . $name, $decorator);
220 5
    }
221
222
    /**
223
     * Create definition of routes for a route repository by a collection of endpoints
224
     *
225
     * @param  array $resources
226
     * @return array
227
     */
228 5
    protected function createRoutesDefinition(array $resources): array
229
    {
230 5
        $definition = [];
231
232 5
        foreach ($resources as $name => $resource)
233
        {
234 5
            $methods = array_keys($resource['methods']);
235 5
            $methods = array_map('strtoupper', $methods);
236
237 5
            $definition[$name] = [
238 5
                'path'    => trim($resource['path']),
239 5
                'methods' => array_map('trim', $methods)
240
            ];
241
        }
242
243 5
        return $definition;
244
    }
245
246
    /**
247
     * {@inheritdoc}
248
     */
249 5
    public function getAlias()
250
    {
251 5
        return self::ALIAS;
252
    }
253
}