Skip to content

Commit 0e570c8

Browse files
committed
added common connection config
1 parent 006f198 commit 0e570c8

File tree

5 files changed

+212
-71
lines changed

5 files changed

+212
-71
lines changed

src/Bolt/ServerStateTransition.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
/**
1717
* @psalm-immutable
1818
*/
19-
final class StateTransition
19+
final class ServerStateTransition
2020
{
2121
public function __construct(
2222
private string $originalState,

src/Bolt/ServerStateTransitionRepository.php

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,16 @@
2222
*
2323
* @psalm-immutable
2424
*/
25-
final class StateTransitionRepository
25+
final class ServerStateTransitionRepository
2626
{
27+
/**
28+
* The order of the 2nd dimension arrays are:
29+
* - original state
30+
* - message
31+
* - triggers signal
32+
* - server response
33+
* - new state.
34+
*/
2735
private const TRANSITIONS = [
2836
['CONNECTED', 'HELLO', null, 'SUCCESS', 'READY'],
2937
['CONNECTED', 'HELLO', null, 'FAILURE', 'DEFUNCT'],
@@ -82,12 +90,12 @@ final class StateTransitionRepository
8290
['INTERRUPTED', 'GOODBYE', 'DISCONNECT', null, 'DEFUNCT'],
8391
];
8492

85-
/** @var list<StateTransition> */
93+
/** @var list<ServerStateTransition> */
8694
private array $transitions;
8795

8896
private function __construct()
8997
{
90-
$this->transitions = array_map(static fn ($x) => StateTransition::fromArray($x), self::TRANSITIONS);
98+
$this->transitions = array_map(static fn ($x) => ServerStateTransition::fromArray($x), self::TRANSITIONS);
9199
}
92100

93101
private static ?self $instance = null;
@@ -137,7 +145,7 @@ public function expectedSignalForResponse(string $state, string $message, string
137145
}
138146

139147
/**
140-
* @return list<StateTransition>
148+
* @return list<ServerStateTransition>
141149
*/
142150
public function getAvailableTransitionsForStateAndMessage(string $state, string $message): array
143151
{
@@ -150,7 +158,7 @@ public function getAvailableTransitionsForStateAndMessage(string $state, string
150158
/**
151159
* Returns the available transitions for the state.
152160
*
153-
* @return list<StateTransition>
161+
* @return list<ServerStateTransition>
154162
*/
155163
private function getAvailableTransitionsForState(string $state): array
156164
{

src/Common/BoltConnection.php

Lines changed: 107 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
use Bolt\protocol\V3;
1717
use Bolt\protocol\V4;
18+
use Laudis\Neo4j\Bolt\ServerStateTransition;
19+
use Laudis\Neo4j\Bolt\ServerStateTransitionRepository;
1820
use Laudis\Neo4j\BoltFactory;
1921
use Laudis\Neo4j\Contracts\ConnectionInterface;
2022
use Laudis\Neo4j\Databags\DatabaseInfo;
@@ -23,6 +25,7 @@
2325
use Laudis\Neo4j\Enum\ConnectionProtocol;
2426
use Psr\Http\Message\UriInterface;
2527
use RuntimeException;
28+
use Throwable;
2629

2730
/**
2831
* @implements ConnectionInterface<V3>
@@ -33,47 +36,30 @@ final class BoltConnection implements ConnectionInterface
3336
{
3437
private ?V3 $boltProtocol;
3538
/** @psalm-readonly */
36-
private string $serverAgent;
37-
/** @psalm-readonly */
38-
private UriInterface $serverAddress;
39-
/** @psalm-readonly */
40-
private string $serverVersion;
41-
/** @psalm-readonly */
42-
private ConnectionProtocol $protocol;
43-
/** @psalm-readonly */
44-
private AccessMode $accessMode;
45-
/** @psalm-readonly */
46-
private DatabaseInfo $databaseInfo;
39+
private ConnectionConfiguration $config;
4740
/** @psalm-readonly */
4841
private BoltFactory $factory;
49-
/** @psalm-readonly */
50-
private DriverConfiguration $driverConfiguration;
42+
5143
private int $ownerCount = 0;
5244
private string $expectedState = 'READY';
45+
/** @var list<callable(list<ServerStateTransition>): void> */
46+
private array $beforeTransitionEventListeners = [];
47+
/** @var list<callable(ServerStateTransition): void> */
48+
private array $afterTransitionEventListeners = [];
49+
private ServerStateTransitionRepository $transitions;
5350

5451
/**
5552
* @psalm-mutation-free
5653
*/
5754
public function __construct(
58-
string $serverAgent,
59-
UriInterface $serverAddress,
60-
string $serverVersion,
61-
ConnectionProtocol $protocol,
62-
AccessMode $accessMode,
63-
DatabaseInfo $databaseInfo,
6455
BoltFactory $factory,
6556
?V3 $boltProtocol,
66-
DriverConfiguration $config
57+
ConnectionConfiguration $config
6758
) {
68-
$this->serverAgent = $serverAgent;
69-
$this->serverAddress = $serverAddress;
70-
$this->serverVersion = $serverVersion;
71-
$this->protocol = $protocol;
72-
$this->accessMode = $accessMode;
73-
$this->databaseInfo = $databaseInfo;
7459
$this->factory = $factory;
7560
$this->boltProtocol = $boltProtocol;
76-
$this->driverConfiguration = $config;
61+
$this->transitions = ServerStateTransitionRepository::getInstance();
62+
$this->config = $config;
7763
}
7864

7965
/**
@@ -93,47 +79,47 @@ public function getImplementation(): V3
9379
*/
9480
public function getServerAgent(): string
9581
{
96-
return $this->serverAgent;
82+
return $this->config->getServerAgent();
9783
}
9884

9985
/**
10086
* @psalm-mutation-free
10187
*/
10288
public function getServerAddress(): UriInterface
10389
{
104-
return $this->serverAddress;
90+
return $this->config->getServerAddress();
10591
}
10692

10793
/**
10894
* @psalm-mutation-free
10995
*/
11096
public function getServerVersion(): string
11197
{
112-
return $this->serverVersion;
98+
return $this->config->getServerVersion();
11399
}
114100

115101
/**
116102
* @psalm-mutation-free
117103
*/
118104
public function getProtocol(): ConnectionProtocol
119105
{
120-
return $this->protocol;
106+
return $this->config->getProtocol();
121107
}
122108

123109
/**
124110
* @psalm-mutation-free
125111
*/
126112
public function getAccessMode(): AccessMode
127113
{
128-
return $this->accessMode;
114+
return $this->config->getAccessMode();
129115
}
130116

131117
/**
132118
* @psalm-mutation-free
133119
*/
134120
public function getDatabaseInfo(): DatabaseInfo
135121
{
136-
return $this->databaseInfo;
122+
return $this->config->getDatabaseInfo();
137123
}
138124

139125
/**
@@ -179,7 +165,25 @@ public function begin(?string $database, ?float $timeout): void
179165
throw new RuntimeException('Cannot begin on a closed connection');
180166
}
181167

182-
$this->boltProtocol->begin($this->buildExtra($database, $timeout));
168+
$transitions = $this->transitions->getAvailableTransitionsForStateAndMessage($this->expectedState, 'BEGIN');
169+
170+
$this->triggerBeforeEvents($transitions);
171+
172+
try {
173+
$this->boltProtocol->begin($this->buildExtra($database, $timeout));
174+
$transition = $this->getSuccessTransition($transitions);
175+
176+
$this->expectedState = $transition->getNewState() ?? 'READY';
177+
} catch (Throwable $e) {
178+
$transition = $this->getFailureTransition($transitions);
179+
$this->expectedState = $transition->getNewState() ?? 'READY';
180+
181+
throw $e;
182+
} finally {
183+
if (isset($transition)) {
184+
$this->triggerAfterEvents($transition);
185+
}
186+
}
183187
}
184188

185189
/**
@@ -276,4 +280,73 @@ private function buildExtra(?string $database, ?float $timeout): array
276280

277281
return $extra;
278282
}
283+
284+
/**
285+
* @param callable(list<ServerStateTransition>): void $listener
286+
*/
287+
public function bindBeforeTransitionEventListener($listener): void
288+
{
289+
$this->beforeTransitionEventListeners[] = $listener;
290+
}
291+
292+
/**
293+
* @param callable(ServerStateTransition): void $listener
294+
*/
295+
private function bindAfterTransitionEventListener($listener): void
296+
{
297+
$this->afterTransitionEventListeners[] = $listener;
298+
}
299+
300+
/**
301+
* @param list<ServerStateTransition> $states
302+
*
303+
* @return ServerStateTransition
304+
*/
305+
private function getFailureTransition(array $states): ServerStateTransition
306+
{
307+
return $this->getTransitionForResponse($states, 'FAILURE');
308+
}
309+
310+
/**
311+
* @param list<ServerStateTransition> $states
312+
*
313+
* @return ServerStateTransition
314+
*/
315+
private function getSuccessTransition(array $states): ServerStateTransition
316+
{
317+
return $this->getTransitionForResponse($states, 'SUCCESS');
318+
}
319+
320+
/**
321+
* @param list<ServerStateTransition> $states
322+
*
323+
* @return ServerStateTransition
324+
*/
325+
private function getTransitionForResponse(array $states, string $response): ServerStateTransition
326+
{
327+
foreach ($states as $state) {
328+
if ($state->getServerResponse() === $response) {
329+
return $state;
330+
}
331+
}
332+
333+
throw new RuntimeException("Cannot find $response transition");
334+
}
335+
336+
public function triggerAfterEvents(ServerStateTransition $transition): void
337+
{
338+
foreach ($this->afterTransitionEventListeners as $listener) {
339+
$listener($transition);
340+
}
341+
}
342+
343+
/**
344+
* @param list<ServerStateTransition> $transitions
345+
*/
346+
public function triggerBeforeEvents(array $transitions): void
347+
{
348+
foreach ($this->beforeTransitionEventListeners as $listener) {
349+
$listener($transitions);
350+
}
351+
}
279352
}
Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,87 @@
11
<?php
22

3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Laudis Neo4j package.
7+
*
8+
* (c) Laudis technologies <http://laudis.tech>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
314
namespace Laudis\Neo4j\Common;
415

5-
class ConnectionConfiguration
16+
use Laudis\Neo4j\Databags\DatabaseInfo;
17+
use Laudis\Neo4j\Databags\DriverConfiguration;
18+
use Laudis\Neo4j\Enum\AccessMode;
19+
use Laudis\Neo4j\Enum\ConnectionProtocol;
20+
use Psr\Http\Message\UriInterface;
21+
22+
/**
23+
* @psalm-immutable
24+
*/
25+
final class ConnectionConfiguration
626
{
27+
private string $serverAgent;
28+
private UriInterface $serverAddress;
29+
private string $serverVersion;
30+
private ConnectionProtocol $protocol;
31+
private AccessMode $accessMode;
32+
private DatabaseInfo $databaseInfo;
33+
private DriverConfiguration $driverConfiguration;
34+
35+
public function __construct(
36+
string $serverAgent,
37+
UriInterface $serverAddress,
38+
string $serverVersion,
39+
ConnectionProtocol $protocol,
40+
AccessMode $accessMode,
41+
DatabaseInfo $databaseInfo,
42+
DriverConfiguration $driverConfiguration
43+
) {
44+
$this->serverAgent = $serverAgent;
45+
$this->serverAddress = $serverAddress;
46+
$this->serverVersion = $serverVersion;
47+
$this->protocol = $protocol;
48+
$this->accessMode = $accessMode;
49+
$this->databaseInfo = $databaseInfo;
50+
$this->driverConfiguration = $driverConfiguration;
51+
}
52+
53+
public function getServerAgent(): string
54+
{
55+
return $this->serverAgent;
56+
}
57+
58+
public function getServerAddress(): UriInterface
59+
{
60+
return $this->serverAddress;
61+
}
62+
63+
public function getServerVersion(): string
64+
{
65+
return $this->serverVersion;
66+
}
67+
68+
public function getProtocol(): ConnectionProtocol
69+
{
70+
return $this->protocol;
71+
}
72+
73+
public function getAccessMode(): AccessMode
74+
{
75+
return $this->accessMode;
76+
}
77+
78+
public function getDatabaseInfo(): DatabaseInfo
79+
{
80+
return $this->databaseInfo;
81+
}
782

83+
public function getDriverConfiguration(): DriverConfiguration
84+
{
85+
return $this->driverConfiguration;
86+
}
887
}

0 commit comments

Comments
 (0)