Neo4jExtension::load()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 3

Importance

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