Skip to content

Commit 573a689

Browse files
committed
corrected events
1 parent 0e570c8 commit 573a689

File tree

3 files changed

+84
-61
lines changed

3 files changed

+84
-61
lines changed

src/Bolt/BoltUnmanagedTransaction.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
use Bolt\error\ConnectionTimeoutException;
1717
use Bolt\error\MessageException;
18-
use Bolt\protocol\V3;
1918
use Laudis\Neo4j\Common\BoltConnection;
2019
use Laudis\Neo4j\Common\TransactionHelper;
2120
use Laudis\Neo4j\Contracts\FormatterInterface;

src/Common/BoltConnection.php

Lines changed: 82 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace Laudis\Neo4j\Common;
1515

16+
use BadMethodCallException;
1617
use Bolt\protocol\V3;
1718
use Bolt\protocol\V4;
1819
use Laudis\Neo4j\Bolt\ServerStateTransition;
@@ -23,6 +24,7 @@
2324
use Laudis\Neo4j\Databags\DriverConfiguration;
2425
use Laudis\Neo4j\Enum\AccessMode;
2526
use Laudis\Neo4j\Enum\ConnectionProtocol;
27+
use LogicException;
2628
use Psr\Http\Message\UriInterface;
2729
use RuntimeException;
2830
use Throwable;
@@ -41,7 +43,7 @@ final class BoltConnection implements ConnectionInterface
4143
private BoltFactory $factory;
4244

4345
private int $ownerCount = 0;
44-
private string $expectedState = 'READY';
46+
private ?string $expectedState = 'READY';
4547
/** @var list<callable(list<ServerStateTransition>): void> */
4648
private array $beforeTransitionEventListeners = [];
4749
/** @var list<callable(ServerStateTransition): void> */
@@ -132,6 +134,10 @@ public function isOpen(): bool
132134

133135
public function open(): void
134136
{
137+
if ($this->boltProtocol !== null) {
138+
throw new BadMethodCallException('Cannot open a connection that is already open');
139+
}
140+
135141
$this->boltProtocol = $this->factory->build()[0];
136142
}
137143

@@ -142,17 +148,24 @@ public function setTimeout(float $timeout): void
142148

143149
public function close(): void
144150
{
145-
if ($this->ownerCount === 0) {
146-
$this->boltProtocol = null;
147-
}
151+
$this->handleMessage('GOODBYE', function () {
152+
$this->boltProtocol->goodbye();
153+
});
154+
155+
$this->boltProtocol = null;
156+
$this->beforeTransitionEventListeners = [];
157+
$this->afterTransitionEventListeners = [];
148158
}
149159

150160
public function reset(): void
151161
{
152-
if ($this->boltProtocol) {
162+
$this->handleMessage('RESET', function () {
153163
$this->boltProtocol->reset();
154-
$this->boltProtocol = $this->factory->build()[0];
155-
}
164+
});
165+
166+
$this->boltProtocol = $this->factory->build()[0];
167+
$this->beforeTransitionEventListeners = [];
168+
$this->afterTransitionEventListeners = [];
156169
}
157170

158171
/**
@@ -161,95 +174,109 @@ public function reset(): void
161174
*/
162175
public function begin(?string $database, ?float $timeout): void
163176
{
164-
if ($this->boltProtocol === null) {
165-
throw new RuntimeException('Cannot begin on a closed connection');
177+
$this->handleMessage('BEGIN', function () use ($database, $timeout) {
178+
$this->boltProtocol->begin($this->buildExtra($database, $timeout));
179+
});
180+
}
181+
182+
/**
183+
* @template T
184+
*
185+
* @param string $message the bolt message we are trying to send
186+
* @param callable(): T $action the actual action to send the message
187+
*
188+
* @return T
189+
*/
190+
private function handleMessage(string $message, $action)
191+
{
192+
if ($this->boltProtocol === null || $this->expectedState === null) {
193+
throw new LogicException("Cannot send \"$message\" message on a closed connection");
166194
}
167195

168-
$transitions = $this->transitions->getAvailableTransitionsForStateAndMessage($this->expectedState, 'BEGIN');
196+
// First, we fetch the available transitions for the given state of the server
197+
// and the intended message to send.
198+
$transitions = $this->transitions->getAvailableTransitionsForStateAndMessage($this->expectedState, $message);
169199

200+
// We notify the event listeners before sending the message.
201+
// Since we don't know whether it will fail or not, we need to send all
202+
// possible transitions.
170203
$this->triggerBeforeEvents($transitions);
171204

172205
try {
173-
$this->boltProtocol->begin($this->buildExtra($database, $timeout));
174-
$transition = $this->getSuccessTransition($transitions);
206+
$tbr = $action();
175207

176-
$this->expectedState = $transition->getNewState() ?? 'READY';
208+
// If no exceptions are thrown, we know the underlying bolt library
209+
// received a success response, making sure we can use the success transition
210+
$transition = $this->getSuccessTransition($transitions);
211+
$this->expectedState = $transition->getNewState();
177212
} catch (Throwable $e) {
213+
// If an an exception is thrown, we know the underlying bolt library
214+
// received a failure response, making sure we can use the failure transition
215+
// and propagate the exception further
178216
$transition = $this->getFailureTransition($transitions);
179-
$this->expectedState = $transition->getNewState() ?? 'READY';
217+
$this->expectedState = $transition->getNewState();
180218

181219
throw $e;
182220
} finally {
183-
if (isset($transition)) {
184-
$this->triggerAfterEvents($transition);
185-
}
221+
// In the end, all listeners need to be able to handle the state transition,
222+
// regardless of the call stack.
223+
$this->triggerAfterEvents($transition);
186224
}
225+
226+
return $tbr;
187227
}
188228

189229
/**
190230
* @return BoltMeta
191231
*/
192232
public function run(string $text, array $parameters, ?string $database, ?float $timeout): array
193233
{
194-
if ($this->boltProtocol === null) {
195-
throw new RuntimeException('Cannot run on a closed connection');
196-
}
197-
198-
/** @var BoltMeta */
199-
return $this->boltProtocol->run($text, $parameters, $this->buildExtra($database, $timeout));
234+
return $this->handleMessage('RUN', function () use ($text, $parameters, $database, $timeout) {
235+
return $this->boltProtocol->run($text, $parameters, $this->buildExtra($database, $timeout));
236+
});
200237
}
201238

202239
public function commit(): void
203240
{
204-
if ($this->boltProtocol === null) {
205-
throw new RuntimeException('Cannot commit on a closed connection');
206-
}
207-
208-
$this->boltProtocol->commit();
241+
$this->handleMessage('COMMIT', fn () => $this->boltProtocol->commit());
209242
}
210243

211244
public function rollback(): void
212245
{
213-
if ($this->boltProtocol === null) {
214-
throw new RuntimeException('Cannot commit on a closed connection');
215-
}
216-
217-
$this->boltProtocol->rollback();
246+
$this->handleMessage('ROLLBACK', fn () => $this->boltProtocol->commit());
218247
}
219248

220249
/**
221250
* @return non-empty-list<list>
222251
*/
223252
public function pull(?int $qid, ?int $fetchSize): array
224253
{
225-
if ($this->boltProtocol === null) {
226-
throw new RuntimeException('Cannot pull on a closed connection');
227-
}
254+
return $this->handleMessage('PULL', function () use ($qid, $fetchSize) {
255+
$extra = [];
256+
if ($fetchSize) {
257+
$extra['n'] = $fetchSize;
258+
}
228259

229-
$extra = [];
230-
if ($fetchSize) {
231-
$extra['n'] = $fetchSize;
232-
}
260+
if ($qid) {
261+
$extra['qid'] = $qid;
262+
}
233263

234-
if ($qid) {
235-
$extra['qid'] = $qid;
236-
}
264+
if (!$this->boltProtocol instanceof V4) {
265+
/** @var non-empty-list<list> */
266+
return $this->boltProtocol->pullAll($extra);
267+
}
237268

238-
if (!$this->boltProtocol instanceof V4) {
239269
/** @var non-empty-list<list> */
240-
return $this->boltProtocol->pullAll($extra);
241-
}
242-
243-
/** @var non-empty-list<list> */
244-
return $this->boltProtocol->pull($extra);
270+
return $this->boltProtocol->pull($extra);
271+
});
245272
}
246273

247274
/**
248275
* @psalm-mutation-free
249276
*/
250277
public function getDriverConfiguration(): DriverConfiguration
251278
{
252-
return $this->driverConfiguration;
279+
return $this->config->getDriverConfiguration();
253280
}
254281

255282
public function __destruct()
@@ -297,10 +324,13 @@ private function bindAfterTransitionEventListener($listener): void
297324
$this->afterTransitionEventListeners[] = $listener;
298325
}
299326

327+
public function getExpectedState(): ?string
328+
{
329+
return $this->expectedState;
330+
}
331+
300332
/**
301333
* @param list<ServerStateTransition> $states
302-
*
303-
* @return ServerStateTransition
304334
*/
305335
private function getFailureTransition(array $states): ServerStateTransition
306336
{
@@ -309,8 +339,6 @@ private function getFailureTransition(array $states): ServerStateTransition
309339

310340
/**
311341
* @param list<ServerStateTransition> $states
312-
*
313-
* @return ServerStateTransition
314342
*/
315343
private function getSuccessTransition(array $states): ServerStateTransition
316344
{
@@ -319,8 +347,6 @@ private function getSuccessTransition(array $states): ServerStateTransition
319347

320348
/**
321349
* @param list<ServerStateTransition> $states
322-
*
323-
* @return ServerStateTransition
324350
*/
325351
private function getTransitionForResponse(array $states, string $response): ServerStateTransition
326352
{

src/Http/HttpConnection.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,8 @@ final class HttpConnection implements ConnectionInterface
3636
/**
3737
* @psalm-mutation-free
3838
*/
39-
public function __construct(
40-
ClientInterface $client,
41-
ConnectionConfiguration $config
42-
) {
39+
public function __construct(ClientInterface $client, ConnectionConfiguration $config)
40+
{
4341
$this->client = $client;
4442
$this->config = $config;
4543
}

0 commit comments

Comments
 (0)