Skip to content

Commit 4690cf5

Browse files
committed
initial implementation of driver manager
1 parent 439a592 commit 4690cf5

File tree

5 files changed

+145
-66
lines changed

5 files changed

+145
-66
lines changed

src/Client.php

Lines changed: 12 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,11 @@
1313

1414
namespace Laudis\Neo4j;
1515

16-
use function array_key_exists;
17-
use InvalidArgumentException;
16+
use Laudis\Neo4j\Common\DriverSetupManager;
1817
use Laudis\Neo4j\Contracts\ClientInterface;
1918
use Laudis\Neo4j\Contracts\DriverInterface;
20-
use Laudis\Neo4j\Contracts\FormatterInterface;
2119
use Laudis\Neo4j\Contracts\SessionInterface;
2220
use Laudis\Neo4j\Contracts\UnmanagedTransactionInterface;
23-
use Laudis\Neo4j\Databags\DriverConfiguration;
24-
use Laudis\Neo4j\Databags\DriverSetup;
2521
use Laudis\Neo4j\Databags\SessionConfiguration;
2622
use Laudis\Neo4j\Databags\Statement;
2723
use Laudis\Neo4j\Databags\TransactionConfiguration;
@@ -37,26 +33,24 @@
3733
*/
3834
final class Client implements ClientInterface
3935
{
40-
private const DEFAULT_DRIVER_CONFIG = 'bolt://localhost:7687';
41-
/** @var non-empty-array<string, DriverInterface<ResultFormat>> */
42-
private array $drivers;
43-
/** @psalm-readonly */
44-
private ?string $default;
4536
private SessionConfiguration $defaultSessionConfiguration;
4637
private TransactionConfiguration $defaultTransactionConfiguration;
38+
/** @var DriverSetupManager<ResultFormat> */
39+
private DriverSetupManager $driverSetups;
4740

4841
/**
4942
* @psalm-mutation-free
5043
*
51-
* @param array<string, DriverSetup> $driverSetups
52-
* @param FormatterInterface<ResultFormat> $formatter
44+
* @param DriverSetupManager<ResultFormat> $driverSetups
5345
*/
54-
public function __construct(array $driverSetups, DriverConfiguration $defaultDriverConfiguration, SessionConfiguration $defaultSessionConfiguration, TransactionConfiguration $defaultTransactionConfiguration, FormatterInterface $formatter, ?string $default)
55-
{
56-
$this->default = $default;
57-
$this->drivers = $this->createDrivers($driverSetups, $formatter, $defaultDriverConfiguration);
46+
public function __construct(
47+
DriverSetupManager $driverSetups,
48+
SessionConfiguration $defaultSessionConfiguration,
49+
TransactionConfiguration $defaultTransactionConfiguration
50+
) {
5851
$this->defaultSessionConfiguration = $defaultSessionConfiguration;
5952
$this->defaultTransactionConfiguration = $defaultTransactionConfiguration;
53+
$this->driverSetups = $driverSetups;
6054
}
6155

6256
public function run(string $statement, iterable $parameters = [], ?string $alias = null)
@@ -84,23 +78,12 @@ public function beginTransaction(?iterable $statements = null, ?string $alias =
8478
return $session->beginTransaction($statements, $config);
8579
}
8680

87-
/**
88-
* @psalm-mutation-free
89-
*/
9081
public function getDriver(?string $alias): DriverInterface
9182
{
92-
$alias = $this->decideAlias($alias);
93-
94-
if (!array_key_exists($alias, $this->drivers)) {
95-
throw new InvalidArgumentException(sprintf('The provided alias: "%s" was not found in the client', $alias));
96-
}
97-
98-
return $this->drivers[$alias];
83+
return $this->driverSetups->getDriver($alias);
9984
}
10085

10186
/**
102-
* @psalm-mutation-free
103-
*
10487
* @return SessionInterface<ResultFormat>
10588
*/
10689
private function startSession(?string $alias, SessionConfiguration $configuration): SessionInterface
@@ -131,41 +114,7 @@ public function transaction(callable $tsxHandler, ?string $alias = null, ?Transa
131114

132115
public function verifyConnectivity(?string $driver = null): bool
133116
{
134-
return $this->getDriver($driver)->verifyConnectivity();
135-
}
136-
137-
/**
138-
* @psalm-mutation-free
139-
*/
140-
private function decideAlias(?string $alias): string
141-
{
142-
return $alias ?? $this->default ?? array_key_first($this->drivers);
143-
}
144-
145-
/**
146-
* @psalm-mutation-free
147-
*
148-
* @param array<string, DriverSetup> $driverSetups
149-
* @param FormatterInterface<ResultFormat> $formatter
150-
*
151-
* @return non-empty-array<string, DriverInterface<ResultFormat>>
152-
*/
153-
private function createDrivers(array $driverSetups, FormatterInterface $formatter, DriverConfiguration $configuration): array
154-
{
155-
if (count($driverSetups) === 0) {
156-
$drivers = ['default' => DriverFactory::create(self::DEFAULT_DRIVER_CONFIG, null, null, $formatter)];
157-
} else {
158-
$drivers = [];
159-
foreach ($driverSetups as $alias => $setup) {
160-
$uri = $setup->getUri();
161-
$auth = $setup->getAuth();
162-
163-
$drivers[$alias] = DriverFactory::create($uri, $configuration, $auth, $formatter);
164-
}
165-
}
166-
167-
/** @var non-empty-array<string, DriverInterface<ResultFormat>> */
168-
return $drivers;
117+
return $this->driverSetups->verifyConnectivity($driver);
169118
}
170119

171120
private function getTsxConfig(?TransactionConfiguration $config): TransactionConfiguration

src/ClientBuilder.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
use Laudis\Neo4j\Databags\SummarizedResult;
2929
use Laudis\Neo4j\Databags\TransactionConfiguration;
3030
use Laudis\Neo4j\Exception\UnsupportedScheme;
31-
use Laudis\Neo4j\Formatter\OGMFormatter;
3231
use Laudis\Neo4j\Formatter\SummarizedResultFormatter;
3332
use Laudis\Neo4j\Http\HttpConfig;
3433
use Laudis\Neo4j\Types\CypherMap;

src/Common/DriverSetupManager.php

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Neo4j PHP Client and Driver package.
5+
*
6+
* (c) Nagels <https://nagels.tech>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Laudis\Neo4j\Common;
13+
14+
use function array_key_exists;
15+
use function array_key_first;
16+
use function array_reduce;
17+
use Countable;
18+
use InvalidArgumentException;
19+
use Laudis\Neo4j\Authentication\Authenticate;
20+
use Laudis\Neo4j\Contracts\DriverInterface;
21+
use Laudis\Neo4j\Contracts\FormatterInterface;
22+
use Laudis\Neo4j\Databags\DriverConfiguration;
23+
use Laudis\Neo4j\Databags\DriverSetup;
24+
use Laudis\Neo4j\DriverFactory;
25+
use const PHP_INT_MIN;
26+
use RuntimeException;
27+
use SplPriorityQueue;
28+
use function sprintf;
29+
30+
/**
31+
* @template ResultFormat
32+
*/
33+
class DriverSetupManager implements Countable
34+
{
35+
private const DEFAULT_DRIVER_CONFIG = 'bolt://localhost:7687';
36+
37+
/** @var array<string, SplPriorityQueue<int, DriverSetup>> */
38+
private array $driverSetups = [];
39+
private array $drivers = [];
40+
private ?string $default = null;
41+
private FormatterInterface $formatter;
42+
private DriverConfiguration $configuration;
43+
44+
/**
45+
* @param FormatterInterface<ResultFormat> $formatter
46+
* @param DriverConfiguration $configuration
47+
*/
48+
public function __construct(FormatterInterface $formatter, DriverConfiguration $configuration)
49+
{
50+
$this->formatter = $formatter;
51+
$this->configuration = $configuration;
52+
}
53+
54+
public function addSetup(DriverSetup $setup, ?string $alias = null, ?int $priority = 0): void
55+
{
56+
$alias ??= $this->decideAlias($alias);
57+
58+
$this->driverSetups[$alias] ??= new SplPriorityQueue();
59+
$this->driverSetups[$alias]->insert($setup, $priority ?? 0);
60+
}
61+
62+
/**
63+
* @return DriverInterface<ResultFormat>
64+
*/
65+
public function getDriver(?string $alias = null): DriverInterface
66+
{
67+
$alias ??= $this->decideAlias($alias);
68+
69+
if (!array_key_exists($alias, $this->driverSetups)) {
70+
if ($alias !== 'default') {
71+
throw new InvalidArgumentException(sprintf('Cannot find a driver setup with alias: "%s"', $alias));
72+
}
73+
74+
$this->driverSetups['default'] = new SplPriorityQueue();
75+
$setup = new DriverSetup(Uri::create(self::DEFAULT_DRIVER_CONFIG), Authenticate::disabled());
76+
$this->driverSetups['default']->insert($setup, PHP_INT_MIN);
77+
78+
return $this->getDriver();
79+
}
80+
81+
if (array_key_exists($alias, $this->drivers)) {
82+
return $this->drivers[$alias];
83+
}
84+
85+
$urisTried = [];
86+
foreach ($this->driverSetups[$alias] as $setup) {
87+
$uri = $setup->getUri();
88+
$auth = $setup->getAuth();
89+
90+
$driver = DriverFactory::create($uri, $this->configuration, $auth, $this->formatter);
91+
$urisTried[] = $uri->__toString();
92+
if ($driver->verifyConnectivity()) {
93+
$this->drivers[$alias] = $driver;
94+
95+
return $driver;
96+
}
97+
}
98+
99+
throw new RuntimeException(sprintf('Cannot connect to any server on alias: %s with Uris: (\'%s\')', $alias, implode('\', ', array_unique($urisTried))));
100+
}
101+
102+
public function verifyConnectivity(?string $alias = null): bool
103+
{
104+
try {
105+
$this->getDriver($alias);
106+
} catch (RuntimeException $e) {
107+
return false;
108+
}
109+
110+
return true;
111+
}
112+
113+
/**
114+
* @psalm-mutation-free
115+
*/
116+
private function decideAlias(?string $alias): string
117+
{
118+
return $alias ?? $this->default ?? array_key_first($this->driverSetups) ?? 'default';
119+
}
120+
121+
public function setDefault(string $default): void
122+
{
123+
$this->default = $default;
124+
}
125+
126+
public function count(): int
127+
{
128+
return array_reduce($this->driverSetups, static fn (int $acc, SplPriorityQueue $x) => $acc + $x->count(), 0);
129+
}
130+
}

src/Contracts/ClientInterface.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ public function beginTransaction(?iterable $statements = null, ?string $alias =
7070
/**
7171
* Gets the driver with the provided alias. Gets the default driver if no alias is provided.
7272
*
73-
* @return DriverInterface<ResultFormat>
73+
* The driver is guaranteed to have its connectivity verified at least once during its lifetime.
7474
*
75-
* @psalm-mutation-free
75+
* @return DriverInterface<ResultFormat>
7676
*/
7777
public function getDriver(?string $alias): DriverInterface;
7878

src/Databags/DriverSetup.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace Laudis\Neo4j\Databags;
1515

1616
use Laudis\Neo4j\Contracts\AuthenticateInterface;
17+
use Laudis\Neo4j\Contracts\FormatterInterface;
1718
use Psr\Http\Message\UriInterface;
1819

1920
/**

0 commit comments

Comments
 (0)