Skip to content

Commit 265155b

Browse files
exaby73transistivep123-stackpratikshazalte69
authored
refactor: Add bolt message objects (#248)
* refactor: Add BoltMessages and BoltMessageFactory * refactor: Create factory for messages * Fixed cluster tests --------- Co-authored-by: pratikshazalte69 <[email protected]> * fix: Neo4j 4 Cluster tests * test: Skip logger tests for clusters --------- Co-authored-by: Ghlen Nagels <[email protected]> Co-authored-by: p123-stack <[email protected]> Co-authored-by: pratikshazalte69 <[email protected]>
1 parent 6d9238d commit 265155b

29 files changed

+1326
-164
lines changed

.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
CONNECTIONS=bolt://neo4j:testtest@neo4j,http://neo4j:testtest@neo4j,bolt://neo4j:testtest@core1
1+
PHP_VERSION=8.1

.github/workflows/integration-test-cluster-neo4j-4.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,14 @@ jobs:
1414
strategy:
1515
matrix:
1616
php: ['8.1.31', '8.3.17']
17-
env:
18-
PHP_VERSION: ${{ matrix.php }}
19-
CONNECTION: neo4j://neo4j:testtest@localhost:7688
2017
name: "Running on PHP ${{ matrix.php }} in a Neo4j 4.4 cluster"
2118

2219
steps:
2320
- uses: actions/checkout@v4
2421
- name: Populate .env
2522
run: |
2623
echo "PHP_VERSION=${{ matrix.php }}" > .env
27-
echo "CONNECTION=neo4j://neo4j:testtest@neo4j" >> .env
24+
echo "CONNECTION=neo4j://neo4j:testtest@core1" >> .env
2825
- uses: hoverkraft-tech/[email protected]
2926
name: Start services
3027
with:

.github/workflows/integration-test-cluster-neo4j-5.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,14 @@ jobs:
1414
strategy:
1515
matrix:
1616
php: ['8.1.31', '8.3.17']
17-
env:
18-
PHP_VERSION: ${{ matrix.php }}
19-
CONNECTION: neo4j://neo4j:testtest@localhost:7687
2017
name: "Running on PHP ${{ matrix.php }} with a Neo4j 5.20-enterprise cluster"
2118

2219
steps:
2320
- uses: actions/checkout@v4
2421
- name: Populate .env
2522
run: |
2623
echo "PHP_VERSION=${{ matrix.php }}" > .env
27-
echo "CONNECTION=neo4j://neo4j:testtest@neo4j" >> .env
24+
echo "CONNECTION=neo4j://neo4j:testtest@server1" >> .env
2825
- uses: hoverkraft-tech/[email protected]
2926
name: Start services
3027
with:

src/Authentication/Authenticate.php

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ final class Authenticate
3535
*/
3636
public static function basic(string $username, string $password, ?Neo4jLogger $logger = null): BasicAuth
3737
{
38+
/** @psalm-suppress ImpureMethodCall Uri is a pure object */
39+
3840
return new BasicAuth($username, $password, $logger);
3941
}
4042

4143
/**
4244
* Authenticate using a kerberos token.
43-
*
44-
* @pure
4545
*/
4646
public static function kerberos(string $token, ?Neo4jLogger $logger = null): KerberosAuth
4747
{
@@ -50,8 +50,6 @@ public static function kerberos(string $token, ?Neo4jLogger $logger = null): Ker
5050

5151
/**
5252
* Authenticate using a OpenID Connect token.
53-
*
54-
* @pure
5553
*/
5654
public static function oidc(string $token, ?Neo4jLogger $logger = null): OpenIDConnectAuth
5755
{
@@ -60,8 +58,6 @@ public static function oidc(string $token, ?Neo4jLogger $logger = null): OpenIDC
6058

6159
/**
6260
* Don't authenticate at all.
63-
*
64-
* @pure
6561
*/
6662
public static function disabled(?Neo4jLogger $logger = null): NoAuth
6763
{
@@ -70,8 +66,6 @@ public static function disabled(?Neo4jLogger $logger = null): NoAuth
7066

7167
/**
7268
* Authenticate from information found in the url.
73-
*
74-
* @pure
7569
*/
7670
public static function fromUrl(UriInterface $uri, ?Neo4jLogger $logger = null): AuthenticateInterface
7771
{

src/Authentication/BasicAuth.php

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,17 @@
2020
use Bolt\protocol\V5_3;
2121
use Bolt\protocol\V5_4;
2222
use Exception;
23+
use Laudis\Neo4j\Bolt\BoltMessageFactory;
2324
use Laudis\Neo4j\Common\Neo4jLogger;
2425
use Laudis\Neo4j\Common\ResponseHelper;
2526
use Laudis\Neo4j\Contracts\AuthenticateInterface;
2627
use Psr\Http\Message\UriInterface;
27-
use Psr\Log\LogLevel;
2828

2929
/**
3030
* Authenticates connections using a basic username and password.
3131
*/
3232
final class BasicAuth implements AuthenticateInterface
3333
{
34-
/**
35-
* @psalm-external-mutation-free
36-
*/
3734
public function __construct(
3835
private readonly string $username,
3936
private readonly string $password,
@@ -48,36 +45,60 @@ public function __construct(
4845
*/
4946
public function authenticateBolt(V4_4|V5|V5_1|V5_2|V5_3|V5_4 $protocol, string $userAgent): array
5047
{
48+
$factory = $this->createMessageFactory($protocol);
49+
5150
if (method_exists($protocol, 'logon')) {
52-
$this->logger?->log(LogLevel::DEBUG, 'HELLO', ['user_agent' => $userAgent]);
53-
$protocol->hello(['user_agent' => $userAgent]);
51+
$helloMetadata = ['user_agent' => $userAgent];
52+
53+
$factory->createHelloMessage($helloMetadata)->send();
5454
$response = ResponseHelper::getResponse($protocol);
55-
$this->logger?->log(LogLevel::DEBUG, 'LOGON', ['scheme' => 'basic', 'principal' => $this->username]);
56-
$protocol->logon([
55+
56+
$credentials = [
5757
'scheme' => 'basic',
5858
'principal' => $this->username,
5959
'credentials' => $this->password,
60-
]);
60+
];
61+
62+
$factory->createLogonMessage($credentials)->send();
6163
ResponseHelper::getResponse($protocol);
6264

6365
/** @var array{server: string, connection_id: string, hints: list} */
6466
return $response->content;
65-
} else {
66-
$this->logger?->log(LogLevel::DEBUG, 'HELLO', ['user_agent' => $userAgent, 'scheme' => 'basic', 'principal' => $this->username]);
67-
$protocol->hello([
68-
'user_agent' => $userAgent,
69-
'scheme' => 'basic',
70-
'principal' => $this->username,
71-
'credentials' => $this->password,
72-
]);
73-
74-
/** @var array{server: string, connection_id: string, hints: list} */
75-
return ResponseHelper::getResponse($protocol)->content;
7667
}
68+
69+
$helloMetadata = [
70+
'user_agent' => $userAgent,
71+
'scheme' => 'basic',
72+
'principal' => $this->username,
73+
'credentials' => $this->password,
74+
];
75+
76+
$factory->createHelloMessage($helloMetadata)->send();
77+
78+
/** @var array{server: string, connection_id: string, hints: list} */
79+
return ResponseHelper::getResponse($protocol)->content;
80+
}
81+
82+
/**
83+
* @throws Exception
84+
*/
85+
public function logoff(V4_4|V5|V5_1|V5_2|V5_3|V5_4 $protocol): void
86+
{
87+
$factory = $this->createMessageFactory($protocol);
88+
$factory->createLogoffMessage()->send();
89+
ResponseHelper::getResponse($protocol);
7790
}
7891

7992
public function toString(UriInterface $uri): string
8093
{
8194
return sprintf('Basic %s:%s@%s:%s', $this->username, '######', $uri->getHost(), $uri->getPort() ?? '');
8295
}
96+
97+
/**
98+
* Helper to create message factory.
99+
*/
100+
private function createMessageFactory(V4_4|V5|V5_1|V5_2|V5_3|V5_4 $protocol): BoltMessageFactory
101+
{
102+
return new BoltMessageFactory($protocol, $this->logger);
103+
}
83104
}

src/Authentication/KerberosAuth.php

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Bolt\protocol\V5_3;
2121
use Bolt\protocol\V5_4;
2222
use Exception;
23+
use Laudis\Neo4j\Bolt\BoltMessageFactory;
2324
use Laudis\Neo4j\Common\Neo4jLogger;
2425
use Laudis\Neo4j\Common\ResponseHelper;
2526
use Laudis\Neo4j\Contracts\AuthenticateInterface;
@@ -34,9 +35,6 @@
3435
*/
3536
final class KerberosAuth implements AuthenticateInterface
3637
{
37-
/**
38-
* @psalm-external-mutation-free
39-
*/
4038
public function __construct(
4139
private readonly string $token,
4240
private readonly ?Neo4jLogger $logger,
@@ -47,11 +45,6 @@ public function authenticateHttp(RequestInterface $request, UriInterface $uri, s
4745
{
4846
$this->logger?->log(LogLevel::DEBUG, 'Authenticating using KerberosAuth');
4947

50-
/**
51-
* @psalm-suppress ImpureMethodCall Request is a pure object:
52-
*
53-
* @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-7-http-message-meta.md#why-value-objects
54-
*/
5548
return $request->withHeader('Authorization', 'Kerberos '.$this->token)
5649
->withHeader('User-Agent', $userAgent);
5750
}
@@ -63,36 +56,40 @@ public function authenticateHttp(RequestInterface $request, UriInterface $uri, s
6356
*/
6457
public function authenticateBolt(V4_4|V5|V5_1|V5_2|V5_3|V5_4 $protocol, string $userAgent): array
6558
{
66-
if (method_exists($protocol, 'logon')) {
67-
$this->logger?->log(LogLevel::DEBUG, 'HELLO', ['user_agent' => $userAgent]);
68-
$protocol->hello(['user_agent' => $userAgent]);
69-
$response = ResponseHelper::getResponse($protocol);
70-
$this->logger?->log(LogLevel::DEBUG, 'LOGON', ['scheme' => 'kerberos', 'principal' => '']);
71-
$protocol->logon([
72-
'scheme' => 'kerberos',
73-
'principal' => '',
74-
'credentials' => $this->token,
75-
]);
76-
ResponseHelper::getResponse($protocol);
77-
78-
/** @var array{server: string, connection_id: string, hints: list} */
79-
return $response->content;
80-
} else {
81-
$this->logger?->log(LogLevel::DEBUG, 'HELLO', ['user_agent' => $userAgent, 'scheme' => 'kerberos', 'principal' => '']);
82-
$protocol->hello([
83-
'user_agent' => $userAgent,
84-
'scheme' => 'kerberos',
85-
'principal' => '',
86-
'credentials' => $this->token,
87-
]);
88-
89-
/** @var array{server: string, connection_id: string, hints: list} */
90-
return ResponseHelper::getResponse($protocol)->content;
91-
}
59+
$factory = $this->createMessageFactory($protocol);
60+
61+
$this->logger?->log(LogLevel::DEBUG, 'HELLO', ['user_agent' => $userAgent]);
62+
63+
$factory->createHelloMessage(['user_agent' => $userAgent])->send();
64+
65+
$response = ResponseHelper::getResponse($protocol);
66+
67+
$this->logger?->log(LogLevel::DEBUG, 'LOGON', ['scheme' => 'kerberos', 'principal' => '']);
68+
69+
$factory->createLogonMessage([
70+
'scheme' => 'kerberos',
71+
'principal' => '',
72+
'credentials' => $this->token,
73+
])->send();
74+
75+
ResponseHelper::getResponse($protocol);
76+
77+
/**
78+
* @var array{server: string, connection_id: string, hints: list}
79+
*/
80+
return $response->content;
9281
}
9382

9483
public function toString(UriInterface $uri): string
9584
{
9685
return sprintf('Kerberos %s@%s:%s', $this->token, $uri->getHost(), $uri->getPort() ?? '');
9786
}
87+
88+
/**
89+
* Helper to create the message factory.
90+
*/
91+
private function createMessageFactory(V4_4|V5|V5_1|V5_2|V5_3|V5_4 $protocol): BoltMessageFactory
92+
{
93+
return new BoltMessageFactory($protocol, $this->logger);
94+
}
9895
}

src/Authentication/NoAuth.php

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Bolt\protocol\V5_3;
2121
use Bolt\protocol\V5_4;
2222
use Exception;
23+
use Laudis\Neo4j\Bolt\BoltMessageFactory;
2324
use Laudis\Neo4j\Common\Neo4jLogger;
2425
use Laudis\Neo4j\Common\ResponseHelper;
2526
use Laudis\Neo4j\Contracts\AuthenticateInterface;
@@ -29,14 +30,8 @@
2930

3031
use function sprintf;
3132

32-
/**
33-
* Doesn't authenticate connections.
34-
*/
3533
final class NoAuth implements AuthenticateInterface
3634
{
37-
/**
38-
* @pure
39-
*/
4035
public function __construct(
4136
private readonly ?Neo4jLogger $logger,
4237
) {
@@ -46,11 +41,6 @@ public function authenticateHttp(RequestInterface $request, UriInterface $uri, s
4641
{
4742
$this->logger?->log(LogLevel::DEBUG, 'Authentication disabled');
4843

49-
/**
50-
* @psalm-suppress ImpureMethodCall Request is a pure object:
51-
*
52-
* @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-7-http-message-meta.md#why-value-objects
53-
*/
5444
return $request->withHeader('User-Agent', $userAgent);
5545
}
5646

@@ -61,32 +51,46 @@ public function authenticateHttp(RequestInterface $request, UriInterface $uri, s
6151
*/
6252
public function authenticateBolt(V4_4|V5|V5_1|V5_2|V5_3|V5_4 $protocol, string $userAgent): array
6353
{
54+
$factory = $this->createMessageFactory($protocol);
55+
6456
if (method_exists($protocol, 'logon')) {
65-
$this->logger?->log(LogLevel::DEBUG, 'HELLO', ['user_agent' => $userAgent]);
66-
$protocol->hello(['user_agent' => $userAgent]);
57+
$helloMetadata = ['user_agent' => $userAgent];
58+
59+
$factory->createHelloMessage($helloMetadata)->send();
6760
$response = ResponseHelper::getResponse($protocol);
68-
$this->logger?->log(LogLevel::DEBUG, 'LOGON', ['scheme' => 'none']);
69-
$protocol->logon([
70-
'scheme' => 'none',
71-
]);
61+
62+
$factory->createLogonMessage(['scheme' => 'none'])->send();
7263
ResponseHelper::getResponse($protocol);
7364

7465
/** @var array{server: string, connection_id: string, hints: list} */
7566
return $response->content;
76-
} else {
77-
$this->logger?->log(LogLevel::DEBUG, 'HELLO', ['user_agent' => $userAgent, 'scheme' => 'none']);
78-
$protocol->hello([
79-
'user_agent' => $userAgent,
80-
'scheme' => 'none',
81-
]);
82-
83-
/** @var array{server: string, connection_id: string, hints: list} */
84-
return ResponseHelper::getResponse($protocol)->content;
8567
}
68+
69+
$helloMetadata = [
70+
'user_agent' => $userAgent,
71+
'scheme' => 'none',
72+
];
73+
74+
$factory->createHelloMessage($helloMetadata)->send();
75+
76+
/** @var array{server: string, connection_id: string, hints: list} */
77+
return ResponseHelper::getResponse($protocol)->content;
78+
}
79+
80+
public function logoff(V4_4|V5|V5_1|V5_2|V5_3|V5_4 $protocol): void
81+
{
82+
$factory = $this->createMessageFactory($protocol);
83+
$factory->createLogoffMessage()->send();
84+
ResponseHelper::getResponse($protocol);
8685
}
8786

8887
public function toString(UriInterface $uri): string
8988
{
9089
return sprintf('No Auth %s:%s', $uri->getHost(), $uri->getPort() ?? '');
9190
}
91+
92+
private function createMessageFactory(V4_4|V5|V5_1|V5_2|V5_3|V5_4 $protocol): BoltMessageFactory
93+
{
94+
return new BoltMessageFactory($protocol, $this->logger);
95+
}
9296
}

0 commit comments

Comments
 (0)