15
15
16
16
use Bolt \protocol \V3 ;
17
17
use Bolt \protocol \V4 ;
18
+ use Laudis \Neo4j \Bolt \ServerStateTransition ;
19
+ use Laudis \Neo4j \Bolt \ServerStateTransitionRepository ;
18
20
use Laudis \Neo4j \BoltFactory ;
19
21
use Laudis \Neo4j \Contracts \ConnectionInterface ;
20
22
use Laudis \Neo4j \Databags \DatabaseInfo ;
23
25
use Laudis \Neo4j \Enum \ConnectionProtocol ;
24
26
use Psr \Http \Message \UriInterface ;
25
27
use RuntimeException ;
28
+ use Throwable ;
26
29
27
30
/**
28
31
* @implements ConnectionInterface<V3>
@@ -33,47 +36,30 @@ final class BoltConnection implements ConnectionInterface
33
36
{
34
37
private ?V3 $ boltProtocol ;
35
38
/** @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 ;
47
40
/** @psalm-readonly */
48
41
private BoltFactory $ factory ;
49
- /** @psalm-readonly */
50
- private DriverConfiguration $ driverConfiguration ;
42
+
51
43
private int $ ownerCount = 0 ;
52
44
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 ;
53
50
54
51
/**
55
52
* @psalm-mutation-free
56
53
*/
57
54
public function __construct (
58
- string $ serverAgent ,
59
- UriInterface $ serverAddress ,
60
- string $ serverVersion ,
61
- ConnectionProtocol $ protocol ,
62
- AccessMode $ accessMode ,
63
- DatabaseInfo $ databaseInfo ,
64
55
BoltFactory $ factory ,
65
56
?V3 $ boltProtocol ,
66
- DriverConfiguration $ config
57
+ ConnectionConfiguration $ config
67
58
) {
68
- $ this ->serverAgent = $ serverAgent ;
69
- $ this ->serverAddress = $ serverAddress ;
70
- $ this ->serverVersion = $ serverVersion ;
71
- $ this ->protocol = $ protocol ;
72
- $ this ->accessMode = $ accessMode ;
73
- $ this ->databaseInfo = $ databaseInfo ;
74
59
$ this ->factory = $ factory ;
75
60
$ this ->boltProtocol = $ boltProtocol ;
76
- $ this ->driverConfiguration = $ config ;
61
+ $ this ->transitions = ServerStateTransitionRepository::getInstance ();
62
+ $ this ->config = $ config ;
77
63
}
78
64
79
65
/**
@@ -93,47 +79,47 @@ public function getImplementation(): V3
93
79
*/
94
80
public function getServerAgent (): string
95
81
{
96
- return $ this ->serverAgent ;
82
+ return $ this ->config -> getServerAgent () ;
97
83
}
98
84
99
85
/**
100
86
* @psalm-mutation-free
101
87
*/
102
88
public function getServerAddress (): UriInterface
103
89
{
104
- return $ this ->serverAddress ;
90
+ return $ this ->config -> getServerAddress () ;
105
91
}
106
92
107
93
/**
108
94
* @psalm-mutation-free
109
95
*/
110
96
public function getServerVersion (): string
111
97
{
112
- return $ this ->serverVersion ;
98
+ return $ this ->config -> getServerVersion () ;
113
99
}
114
100
115
101
/**
116
102
* @psalm-mutation-free
117
103
*/
118
104
public function getProtocol (): ConnectionProtocol
119
105
{
120
- return $ this ->protocol ;
106
+ return $ this ->config -> getProtocol () ;
121
107
}
122
108
123
109
/**
124
110
* @psalm-mutation-free
125
111
*/
126
112
public function getAccessMode (): AccessMode
127
113
{
128
- return $ this ->accessMode ;
114
+ return $ this ->config -> getAccessMode () ;
129
115
}
130
116
131
117
/**
132
118
* @psalm-mutation-free
133
119
*/
134
120
public function getDatabaseInfo (): DatabaseInfo
135
121
{
136
- return $ this ->databaseInfo ;
122
+ return $ this ->config -> getDatabaseInfo () ;
137
123
}
138
124
139
125
/**
@@ -179,7 +165,25 @@ public function begin(?string $database, ?float $timeout): void
179
165
throw new RuntimeException ('Cannot begin on a closed connection ' );
180
166
}
181
167
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
+ }
183
187
}
184
188
185
189
/**
@@ -276,4 +280,73 @@ private function buildExtra(?string $database, ?float $timeout): array
276
280
277
281
return $ extra ;
278
282
}
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
+ }
279
352
}
0 commit comments