Test Failed
Push — master ( b71f19...57db9a )
by Michael
02:20
created

JsonApiExtension::createRoutesDefinition()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 0
cts 0
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 9
nc 2
nop 1
crap 6
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\Definition;
9
use Symfony\Component\DependencyInjection\DefinitionDecorator;
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 2
     *
29
     * @param LoaderInterface $loader
30 2
     */
31 2
    public function __construct(LoaderInterface $loader = null)
32
    {
33
        $this->loader = $loader;
34
    }
35
36 2
    /**
37
     * {@inheritdoc}
38 2
     */
39 2
    public function load(array $configs, ContainerBuilder $container)
40
    {
41 2
        $configuration = new JsonApiConfiguration();
42
        $config = $this->processConfiguration($configuration, $configs);
43 2
44 2
        $loader = $this->loader ?? new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
45 2
46 2
        $loader->load('services.yml');
47
        $loader->load('hydrator.yml');
48 2
        $loader->load('mapper.yml');
49 2
        $loader->load('http_client.yml');
50
51 2
        if (! empty($config['mappers'])) {
52
            $this->createMappers($config['mappers'], $container);
53
        }
54
55
        if (! empty($config['http_clients'])) {
56
            $this->createResourceClients($config['http_clients'], $container);
57
        }
58
    }
59 2
60
    /**
61 2
     * Create mappers
62
     *
63 2
     * @param array            $config
64
     * @param ContainerBuilder $container
65 2
     */
66 2
    protected function createMappers(array $config, ContainerBuilder $container)
67
    {
68 2
        $handlers = $this->findMappingHandlers($container);
69
70 2
        foreach ($config as $name => $mapperDefinition)
71
        {
72
            $mapper = new DefinitionDecorator('mrtn_json_api.object_mapper.abstract');
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
73
            $mapper->addTag('mrtn_json_api.object_mapper', ['alias' => $name]);
74 2
75 2 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...
76
            {
77
                if (! isset($handlers[$handlerName])) {
78
                    throw new \LogicException(sprintf('Mapping handler with name "%s" has not been registered as a service.', $handlerName));
79 2
                }
80
81 2
                $mapper->addMethodCall('addHandler', [
82
                    new Reference($handlers[$handlerName])
83
                ]);
84
            }
85
86
            $container->setDefinition('mrtn_json_api.object_mapper.' . $name, $mapper);
87
        }
88
    }
89 2
90
    /**
91 2
     * Find mapping handler registered in container
92
     *
93 2
     * @param  ContainerBuilder $container
94
     * @return array
95 2
     */
96
    protected function findMappingHandlers(ContainerBuilder $container): array
97 2
    {
98
        $handlers = $container->findTaggedServiceIds('mrtn_json_api.object_mapper.handler');
99 2
100
        $found = [];
101
102
        foreach ($handlers as $id => $tags)
103 2
        {
104
            foreach ($tags as $tag)
105
            {
106
                if (! isset($tag['alias'])) {
107 2
                    continue;
108
                }
109
110
                $found[$tag['alias']] = $id;
111
            }
112
        }
113 1
114
        return $found;
115 1
    }
116
117
    /**
118
     * Create resources-based clients
119
     *
120
     * @param array            $config
121
     * @param ContainerBuilder $container
122
     */
123
    protected function createResourceClients(array $config, ContainerBuilder $container): void
124
    {
125
        $repositoryClass = $container->getParameter('mrtn_json_api.route_repository.class');
126
        $clientClass     = $container->getParameter('mrtn_json_api.resource_http_client.class');
127
128
        foreach ($config as $name => $definition)
129
        {
130
            $routes = $this->createRoutesDefinition($definition['resources']);
131
132
            $repository = new Definition($repositoryClass, [$definition['base_url'], $routes]);
133
            $repository->setPublic(false);
134
135
            $client = new Definition($clientClass, [
136
                new Reference('mrtn_json_api.http_client'),
137
                new Reference('mrtn_json_api.route_repository.' . $name)
138
            ]);
139
140
            $container->setDefinition('mrtn_json_api.route_repository.' . $name, $repository);
141
            $container->setDefinition('mrtn_json_api.http_client.' . $name, $client);
142
        }
143
    }
144
145
    /**
146
     * Create definition of routes for a route repository by a collection of endpoints
147
     *
148
     * @param  array $resources
149
     * @return array
150
     */
151
    protected function createRoutesDefinition(array $resources): array
152
    {
153
        $definition = [];
154
155
        foreach ($resources as $name => $resource)
156
        {
157
            $methods = array_keys($resource['methods']);
158
            $methods = array_map('strtoupper', $methods);
159
160
            $definition[$name] = [
161
                'path'    => trim($resource['path']),
162
                'methods' => array_map('trim', $methods)
163
            ];
164
        }
165
166
        return $definition;
167
    }
168
169
    /**
170
     * {@inheritdoc}
171
     */
172
    public function getAlias()
173
    {
174
        return self::ALIAS;
175
    }
176
}