Completed
Push — master ( 91d119...86b658 )
by Tobias
04:36
created

Neo4jExtension::handleEntityManagers()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 5.2742

Importance

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