Completed
Push — master ( 3faa6e...b6846d )
by Tobias
03:28
created

Neo4jExtension::handleClients()   C

Complexity

Conditions 7
Paths 20

Size

Total Lines 36
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 7.5754

Importance

Changes 0
Metric Value
dl 0
loc 36
ccs 17
cts 22
cp 0.7727
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 23
nc 20
nop 2
crap 7.5754
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Neo4j\Neo4jBundle\DependencyInjection;
6
7
use GraphAware\Bolt\Driver as BoltDriver;
8
use GraphAware\Neo4j\Client\Connection\Connection;
9
use GraphAware\Neo4j\OGM\EntityManager;
10
use GraphAware\Neo4j\Client\HttpDriver\Driver as HttpDriver;
11
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
12
use Symfony\Component\Config\FileLocator;
13
use Symfony\Component\DependencyInjection\ChildDefinition;
14
use Symfony\Component\DependencyInjection\ContainerBuilder;
15
use Symfony\Component\DependencyInjection\Definition;
16
use Symfony\Component\DependencyInjection\DefinitionDecorator;
17
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
18
use Symfony\Component\DependencyInjection\Reference;
19
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
20
21
/**
22
 * @author Tobias Nyholm <[email protected]>
23
 */
24
class Neo4jExtension extends Extension
25
{
26
    /**
27
     * {@inheritdoc}
28
     */
29 4
    public function load(array $configs, ContainerBuilder $container)
30
    {
31 4
        $configuration = $this->getConfiguration($configs, $container);
32 4
        $config = $this->processConfiguration($configuration, $configs);
33
34 4
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
35 4
        $loader->load('services.xml');
36
37 4
        $this->handleConnections($config, $container);
38 4
        $clientServiceIds = $this->handleClients($config, $container);
39
40 4
        if ($this->validateEntityManagers($config)) {
41 4
            $loader->load('entity_manager.xml');
42 4
            $this->handleEntityMangers($config, $container, $clientServiceIds);
43 4
            $container->setAlias('neo4j.entity_manager', 'neo4j.entity_manager.default');
44
        }
45
46
        // add aliases for the default services
47 4
        $container->setAlias('neo4j.connection', 'neo4j.connection.default');
48 4
        $container->setAlias('neo4j.client', 'neo4j.client.default');
49
50
        // Configure toolbar
51 4
        if ($this->isConfigEnabled($container, $config['profiling'])) {
52 2
            $loader->load('data-collector.xml');
53
        }
54 4
    }
55
56
    /**
57
     * {@inheritdoc}
58
     */
59 4
    public function getConfiguration(array $config, ContainerBuilder $container): Configuration
60
    {
61 4
        return new Configuration($container->getParameter('kernel.debug'));
62
    }
63
64
    /**
65
     * {@inheritdoc}
66
     */
67 4
    public function getAlias(): string
68
    {
69 4
        return 'neo4j';
70
    }
71
72
    /**
73
     * @param array            $config
74
     * @param ContainerBuilder $container
75
     *
76
     * @return array with service ids
77
     */
78 4
    private function handleClients(array &$config, ContainerBuilder $container): array
79
    {
80 4
        if (empty($config['clients'])) {
81
            // Add default entity manager if none set.
82 4
            $config['clients']['default'] = ['connections' => ['default']];
83
        }
84
85 4
        $serviceIds = [];
86 4
        foreach ($config['clients'] as $name => $data) {
87 4
            $connections = [];
88 4
            $serviceIds[$name] = $serviceId = sprintf('neo4j.client.%s', $name);
89 4
            foreach ($data['connections'] as $connectionName) {
90 4
                if (empty($config['connections'][$connectionName])) {
91
                    throw new InvalidConfigurationException(sprintf(
92
                        'Client "%s" is configured to use connection named "%s" but there is no such connection',
93
                        $name,
94
                        $connectionName
95
                    ));
96
                }
97 4
                $connections[] = $connectionName;
98
            }
99 4
            if (empty($connections)) {
100
                $connections[] = 'default';
101
            }
102
103 4
            $definition = class_exists(ChildDefinition::class)
104 4
                ? new ChildDefinition('neo4j.client.abstract')
105 4
                : new DefinitionDecorator('neo4j.client.abstract');
106
107
            $container
108 4
                ->setDefinition($serviceId, $definition)
109 4
                ->setArguments([$connections]);
110
        }
111
112 4
        return $serviceIds;
113
    }
114
115
    /**
116
     * @param array            $config
117
     * @param ContainerBuilder $container
118
     * @param array            $clientServiceIds
119
     *
120
     * @return array
121
     */
122 4
    private function handleEntityMangers(array &$config, ContainerBuilder $container, array $clientServiceIds): array
123
    {
124 4
        $serviceIds = [];
125 4
        foreach ($config['entity_managers'] as $name => $data) {
126 4
            $serviceIds[] = $serviceId = sprintf('neo4j.entity_manager.%s', $name);
127 4
            $clientName = $data['client'];
128 4
            if (empty($clientServiceIds[$clientName])) {
129
                throw new InvalidConfigurationException(sprintf(
130
                    'EntityManager "%s" is configured to use client named "%s" but there is no such client',
131
                    $name,
132
                    $clientName
133
                ));
134
            }
135
136 4
            $definition = class_exists(ChildDefinition::class)
137 4
                ? new ChildDefinition('neo4j.entity_manager.abstract')
138 4
                : new DefinitionDecorator('neo4j.entity_manager.abstract');
139
140
            $container
141 4
                ->setDefinition($serviceId, $definition)
142 4
                ->setArguments([
143 4
                    $container->getDefinition($clientServiceIds[$clientName]),
144 4
                    empty($data['cache_dir']) ? $container->getParameter('kernel.cache_dir').'/neo4j' : $data['cache_dir'],
145
                ]);
146
        }
147
148 4
        return $serviceIds;
149
    }
150
151
    /**
152
     * @param array            $config
153
     * @param ContainerBuilder $container
154
     *
155
     * @return array with service ids
156
     */
157 4
    private function handleConnections(array &$config, ContainerBuilder $container): array
158
    {
159 4
        $serviceIds = [];
160 4
        $firstName = null;
161 4
        foreach ($config['connections'] as $name => $data) {
162 4
            if (null === $firstName || 'default' === $name) {
163 4
                $firstName = $name;
164
            }
165 4
            $def = new Definition(Connection::class);
166 4
            $def->addArgument($name);
167 4
            $def->addArgument($this->getUrl($data));
168 4
            $serviceIds[$name] = $serviceId = 'neo4j.connection.'.$name;
169 4
            $container->setDefinition($serviceId, $def);
170
        }
171
172
        // Make sure we got a 'default'
173 4
        if ('default' !== $firstName) {
174
            $config['connections']['default'] = $config['connections'][$firstName];
175
        }
176
177
        // Add connections to connection manager
178 4
        $connectionManager = $container->getDefinition('neo4j.connection_manager');
179 4
        foreach ($serviceIds as $name => $serviceId) {
180 4
            $connectionManager->addMethodCall('registerExistingConnection', [$name, new Reference($serviceId)]);
181
        }
182 4
        $connectionManager->addMethodCall('setMaster', [$firstName]);
183
184 4
        return $serviceIds;
185
    }
186
187
    /**
188
     * Get URL form config.
189
     *
190
     * @param array $config
191
     *
192
     * @return string
193
     */
194 4
    private function getUrl(array $config): string
195
    {
196 4
        return sprintf(
197 4
            '%s://%s:%s@%s:%d',
198 4
            $config['scheme'],
199 4
            $config['username'],
200 4
            $config['password'],
201 4
            $config['host'],
202 4
            $this->getPort($config)
203
        );
204
    }
205
206
    /**
207
     * Return the correct default port if not manually set.
208
     *
209
     * @param array $config
210
     *
211
     * @return int
212
     */
213 4
    private function getPort(array $config)
214
    {
215 4
        if (isset($config['port'])) {
216 3
            return $config['port'];
217
        }
218
219 1
        return 'http' == $config['scheme'] ? HttpDriver::DEFAULT_HTTP_PORT : BoltDriver::DEFAULT_TCP_PORT;
220
    }
221
222
    /**
223
     * Make sure the EntityManager is installed if we have configured it.
224
     *
225
     * @param array &$config
226
     *
227
     * @return bool true if "graphaware/neo4j-php-ogm" is installed
228
     *
229
     * @thorws \LogicException if EntityManagers os not installed but they are configured.
230
     */
231 4
    private function validateEntityManagers(array &$config): bool
232
    {
233 4
        $dependenciesInstalled = class_exists(EntityManager::class);
234 4
        $entityManagersConfigured = !empty($config['entity_managers']);
235
236 4
        if ($dependenciesInstalled && !$entityManagersConfigured) {
237
            // Add default entity manager if none set.
238 4
            $config['entity_managers']['default'] = ['client' => 'default'];
239
        } elseif (!$dependenciesInstalled && $entityManagersConfigured) {
240
            throw new \LogicException(
241
                'You need to install "graphaware/neo4j-php-ogm" to be able to use the EntityManager'
242
            );
243
        }
244
245 4
        return $dependenciesInstalled;
246
    }
247
}
248