Skip to content

Commit 7b86e21

Browse files
authored
Merge pull request #75 from neo4j-php/protocol_versions
added version method to AProtocol classes
2 parents 62570ca + c5060e5 commit 7b86e21

File tree

10 files changed

+67
-71
lines changed

10 files changed

+67
-71
lines changed

src/Bolt.php

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,6 @@ final class Bolt
3939
*/
4040
private $versions = [4.4, 4.3, 4.2, 3];
4141

42-
/**
43-
* @var float
44-
*/
45-
private $version;
46-
4742
/**
4843
* Print debug info
4944
* @var bool
@@ -71,11 +66,11 @@ public function build(): AProtocol
7166
if (!$this->connection->connect())
7267
throw new ConnectException('Connection failed');
7368

74-
$this->handshake();
69+
$version = $this->handshake();
7570

76-
$protocolClass = "\\Bolt\\protocol\\V" . str_replace('.', '_', $this->version);
71+
$protocolClass = "\\Bolt\\protocol\\V" . str_replace('.', '_', $version);
7772
if (!class_exists($protocolClass))
78-
throw new ConnectException('Requested Protocol version (' . $this->version . ') not yet implemented');
73+
throw new ConnectException('Requested Protocol version (' . $version . ') not yet implemented');
7974

8075
return new $protocolClass($this->packer, $this->unpacker, $this->connection);
8176
}
@@ -112,45 +107,43 @@ public function setPackStreamVersion(int $version = 1): Bolt
112107
return $this;
113108
}
114109

115-
/**
116-
* Version is available after successful connection with init/hello message
117-
* @return float
118-
*/
119-
public function getProtocolVersion(): float
120-
{
121-
return $this->version;
122-
}
123-
124110
/**
125111
* @link https://7687.org/bolt/bolt-protocol-handshake-specification.html
112+
* @return string
126113
* @throws Exception
127114
*/
128-
private function handshake()
115+
private function handshake(): string
129116
{
130117
if (self::$debug)
131118
echo 'HANDSHAKE';
132119

133120
$this->connection->write(chr(0x60) . chr(0x60) . chr(0xb0) . chr(0x17));
134121
$this->connection->write($this->packProtocolVersions());
135122

136-
$this->unpackProtocolVersion();
137-
if (empty($this->version))
123+
$version = $this->unpackProtocolVersion();
124+
if (empty($version))
138125
throw new ConnectException('Wrong version');
126+
127+
return $version;
139128
}
140129

141130
/**
142131
* Read and compose selected protocol version
132+
* @return string
143133
*/
144-
private function unpackProtocolVersion()
134+
private function unpackProtocolVersion(): string
145135
{
146136
$result = [];
147137

148-
foreach (str_split($this->connection->read(4)) as $ch)
138+
foreach (str_split($this->connection->read(4)) as $ch) {
149139
$result[] = unpack('C', $ch)[1] ?? 0;
140+
}
141+
142+
while (count($result) > 0 && reset($result) == 0) {
143+
array_shift($result);
144+
}
150145

151-
$result = array_filter($result);
152-
$result = array_reverse($result);
153-
$this->version = implode('.', $result);
146+
return implode('.', array_reverse($result));
154147
}
155148

156149
/**

src/protocol/AProtocol.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
*/
1717
abstract class AProtocol
1818
{
19-
2019
protected const SUCCESS = 0x70;
2120
protected const FAILURE = 0x7F;
2221
protected const IGNORED = 0x7E;
@@ -87,4 +86,17 @@ protected function read(?int &$signature)
8786
return $output;
8887
}
8988

89+
/**
90+
* Returns the bolt protocol version as a string.
91+
*
92+
* @return string
93+
*/
94+
public function getVersion(): string
95+
{
96+
if (preg_match("/V([\d_]+)$/", static::class, $match)) {
97+
return str_replace('_', '.', $match[1]);
98+
}
99+
100+
throw new Exception('Protocol version class name is not valid');
101+
}
90102
}

src/protocol/V1.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,5 +175,4 @@ public function reset(): array
175175

176176
return $message;
177177
}
178-
179178
}

src/protocol/V2.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,4 @@
1212
*/
1313
class V2 extends V1
1414
{
15-
1615
}

src/protocol/V3.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,5 +176,4 @@ public function goodbye()
176176
$this->write($this->packer->pack(0x02));
177177
$this->connection->disconnect();
178178
}
179-
180179
}

src/protocol/V4.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,5 +100,4 @@ public function discard(...$args): array
100100

101101
return $message;
102102
}
103-
104103
}

src/protocol/V4_1.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
*/
1313
class V4_1 extends V4
1414
{
15-
1615
/**
1716
* @link https://7687.org/bolt/bolt-protocol-message-specification-4.html#request-message---41---hello
1817
* @link https://7687.org/bolt/bolt-protocol-message-specification-4.html#request-message---43---hello
@@ -25,5 +24,4 @@ public function hello(...$args): array
2524

2625
return parent::hello(...$args);
2726
}
28-
2927
}

src/protocol/V4_2.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,4 @@
1212
*/
1313
class V4_2 extends V4_1
1414
{
15-
1615
}

src/protocol/V4_4.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,4 @@ public function route(...$args): array
2121
$args[2] = (object)$args[2];
2222
return parent::route(...$args);
2323
}
24-
2524
}

tests/BoltTest.php

Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@
3636
class BoltTest extends ATest
3737
{
3838

39-
private static $version;
40-
4139
public function testSockets()
4240
{
4341
if (!extension_loaded('sockets'))
@@ -85,7 +83,6 @@ public function testHello(): AProtocol
8583

8684
$this->assertNotEmpty($protocol->init(\Bolt\helpers\Auth::basic($GLOBALS['NEO_USER'], $GLOBALS['NEO_PASS'])));
8785

88-
self::$version = $bolt->getProtocolVersion();
8986
return $protocol;
9087
} catch (Exception $e) {
9188
$this->markTestIncomplete($e->getMessage());
@@ -94,16 +91,16 @@ public function testHello(): AProtocol
9491

9592
/**
9693
* @depends testHello
97-
* @param AProtocol $bolt
94+
* @param AProtocol $protocol
9895
*/
99-
public function testPull(AProtocol $bolt)
96+
public function testPull(AProtocol $protocol)
10097
{
10198
try {
102-
$res = $bolt->run('RETURN 1 AS num, 2 AS cnt');
99+
$res = $protocol->run('RETURN 1 AS num, 2 AS cnt');
103100
$this->assertIsArray($res);
104101
$this->assertArrayHasKey('fields', $res);
105102

106-
$res = $bolt->pullAll();
103+
$res = $protocol->pullAll();
107104
$this->assertEquals(1, $res[0][0] ?? 0);
108105
$this->assertEquals(2, $res[0][1] ?? 0);
109106
} catch (Exception $e) {
@@ -113,61 +110,62 @@ public function testPull(AProtocol $bolt)
113110

114111
/**
115112
* @depends testHello
116-
* @param AProtocol $bolt
113+
* @param AProtocol $protocol
117114
*/
118-
public function testDiscard(AProtocol $bolt)
115+
public function testDiscard(AProtocol $protocol)
119116
{
120117
try {
121-
$this->assertNotFalse($bolt->run('MATCH (a:Test) RETURN *'));
122-
$this->assertIsArray($bolt->discardAll());
118+
$this->assertNotFalse($protocol->run('MATCH (a:Test) RETURN *'));
119+
$this->assertIsArray($protocol->discardAll());
123120
} catch (Exception $e) {
124121
$this->markTestIncomplete($e->getMessage());
125122
}
126123
}
127124

128125
/**
129126
* @depends testHello
130-
* @param AProtocol $bolt
127+
* @param AProtocol $protocol
131128
*/
132-
public function testNode(AProtocol $bolt)
129+
public function testNode(AProtocol $protocol)
133130
{
134131
try {
135-
$this->assertNotFalse($bolt->run('CREATE (a:Test) RETURN a, ID(a)'));
132+
$this->assertNotFalse($protocol->run('CREATE (a:Test) RETURN a, ID(a)'));
136133

137-
$created = $bolt->pullAll();
134+
$created = $protocol->pullAll();
138135
$this->assertIsArray($created);
139136
$this->assertInstanceOf(\Bolt\structures\Node::class, $created[0][0]);
140137

141-
$this->assertNotFalse($bolt->run('MATCH (a:Test) WHERE ID(a) = ' . $this->formatParameter($bolt, 'a') . ' DELETE a', [
138+
$this->assertNotFalse($protocol->run('MATCH (a:Test) WHERE ID(a) = ' . $this->formatParameter($protocol, 'a') . ' DELETE a', [
142139
'a' => $created[0][1]
143140
]));
144-
$this->assertEquals(1, $bolt->pullAll()[0]['stats']['nodes-deleted'] ?? 0);
141+
$this->assertEquals(1, $protocol->pullAll()[0]['stats']['nodes-deleted'] ?? 0);
145142
} catch (Exception $e) {
146143
$this->markTestIncomplete($e->getMessage());
147144
}
148145
}
149146

150147
/**
151148
* @depends testHello
152-
* @param AProtocol $bolt
149+
* @param AProtocol $protocol
150+
* @throws Exception
153151
*/
154-
public function testTransaction(AProtocol $bolt)
152+
public function testTransaction(AProtocol $protocol)
155153
{
156-
if (self::$version < 3) {
154+
if (version_compare($protocol->getVersion(), 3, '<')) {
157155
$this->markTestSkipped('Old Neo4j version does not support transactions');
158156
}
159157

160158
try {
161-
$this->assertIsArray($bolt->begin());
162-
$this->assertIsArray($bolt->run('CREATE (a:Test) RETURN a, ID(a)'));
163-
$created = $bolt->pullAll();
159+
$this->assertIsArray($protocol->begin());
160+
$this->assertIsArray($protocol->run('CREATE (a:Test) RETURN a, ID(a)'));
161+
$created = $protocol->pullAll();
164162
$this->assertIsArray($created);
165-
$this->assertIsArray($bolt->rollback());
163+
$this->assertIsArray($protocol->rollback());
166164

167-
$this->assertIsArray($bolt->run('MATCH (a:Test) WHERE ID(a) = ' . $this->formatParameter($bolt, 'a') . ' RETURN COUNT(a)', [
165+
$this->assertIsArray($protocol->run('MATCH (a:Test) WHERE ID(a) = ' . $this->formatParameter($protocol, 'a') . ' RETURN COUNT(a)', [
168166
'a' => $created[0][1]
169167
]));
170-
$res = $bolt->pullAll();
168+
$res = $protocol->pullAll();
171169
$this->assertIsArray($res);
172170
$this->assertEquals(0, $res[0][0]);
173171
} catch (Exception $e) {
@@ -182,16 +180,16 @@ public function testTransaction(AProtocol $bolt)
182180

183181
/**
184182
* Because from Neo4j >= 4.0 is different placeholder for parameters
185-
* @param AProtocol $bolt
183+
* @param AProtocol $protocol
186184
* @param string $name
187185
* @return string
188186
* @throws Exception
189187
*/
190-
private function formatParameter(AProtocol $bolt, string $name): string
188+
private function formatParameter(AProtocol $protocol, string $name): string
191189
{
192190
if (self::$parameterType == null) {
193-
$this->assertNotFalse($bolt->run('call dbms.components() yield versions unwind versions as version return version'));
194-
$neo4jVersion = $bolt->pullAll()[0][0] ?? '';
191+
$this->assertNotFalse($protocol->run('call dbms.components() yield versions unwind versions as version return version'));
192+
$neo4jVersion = $protocol->pullAll()[0][0] ?? '';
195193
$this->assertNotEmpty($neo4jVersion);
196194
self::$parameterType = version_compare($neo4jVersion, '4') == -1;
197195
}
@@ -201,12 +199,13 @@ private function formatParameter(AProtocol $bolt, string $name): string
201199

202200
/**
203201
* @depends testHello
204-
* @param AProtocol $bolt
202+
* @param AProtocol $protocol
203+
* @throws Exception
205204
*/
206-
public function testRoute(AProtocol $bolt): void
205+
public function testRoute(AProtocol $protocol): void
207206
{
208-
if (self::$version >= 4.3) {
209-
self::assertIsArray($bolt->route([
207+
if (version_compare($protocol->getVersion(), 4.3, '>=')) {
208+
self::assertIsArray($protocol->route([
210209
'address' => ($GLOBALS['NEO_HOST'] ?? '127.0.0.1') . ':' . ($GLOBALS['NEO_PORT'] ?? 7687)
211210
], [], []));
212211
} else {
@@ -216,12 +215,12 @@ public function testRoute(AProtocol $bolt): void
216215

217216
/**
218217
* @depends testHello
219-
* @param AProtocol $bolt
218+
* @param AProtocol $protocol
220219
*/
221-
public function testReset(AProtocol $bolt): void
220+
public function testReset(AProtocol $protocol): void
222221
{
223222
try {
224-
$this->assertIsArray($bolt->reset());
223+
$this->assertIsArray($protocol->reset());
225224
} catch (Exception $e) {
226225
$this->markTestIncomplete($e->getMessage());
227226
}

0 commit comments

Comments
 (0)