Skip to content

Commit 5bc2ad5

Browse files
committed
wip
1 parent f356080 commit 5bc2ad5

17 files changed

+217
-269
lines changed

src/Authentication/AuthenticateInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
*/
1010
interface AuthenticateInterface
1111
{
12+
public function getHeader(): string;
13+
public function getType(): string;
1214
/**
1315
* Authenticates the request by returning a new instance of the request with the authentication information attached.
1416
*/

src/Authentication/BasicAuthentication.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ class BasicAuthentication implements AuthenticateInterface
1414

1515
public function __construct(?string $username = null, ?string $password = null)
1616
{
17-
$this->username = $username ?? getenv("NEO4J_USERNAME") ?: '';
18-
$this->password = $password ?? getenv("NEO4J_PASSWORD") ?: '';
17+
$this->username = $username ?? (getenv("NEO4J_USERNAME") !== false ? getenv("NEO4J_USERNAME") : '');
18+
$this->password = $password ?? (getenv("NEO4J_PASSWORD") !== false ? getenv("NEO4J_PASSWORD") : '');
1919
}
2020

2121
public function authenticate(RequestInterface $request): RequestInterface

src/Authentication/BearerAuthentication.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class BearerAuthentication implements AuthenticateInterface
1111
{
1212
public function __construct(private string $token)
1313
{
14+
$this->token = $token;
1415
}
1516

1617
public function authenticate(RequestInterface $request): RequestInterface

src/Authentication/NoAuth.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@
99
*/
1010
class NoAuth implements AuthenticateInterface
1111
{
12+
public function getHeader(): string
13+
{
14+
return '';
15+
}
16+
17+
public function getType(): string
18+
{
19+
return 'NoAuth';
20+
}
1221
public function authenticate(RequestInterface $request): RequestInterface
1322
{
1423
return $request;

src/Neo4jQueryAPI.php

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,20 @@
1111
use Psr\Http\Client\ClientInterface;
1212
use Psr\Http\Client\RequestExceptionInterface;
1313
use Psr\Http\Message\ResponseInterface;
14+
use RuntimeException;
1415

1516
class Neo4jQueryAPI
1617
{
1718
public function __construct(
18-
private ClientInterface $client,
19-
private ResponseParser $responseParser,
20-
private Neo4jRequestFactory $requestFactory
21-
) {
19+
20+
private ClientInterface $client,
21+
private ResponseParser $responseParser,
22+
private Neo4jRequestFactory $requestFactory,
23+
24+
25+
)
26+
{
27+
2228
}
2329

2430
/**
@@ -45,38 +51,51 @@ public static function login(string $address, AuthenticateInterface $auth = null
4551
}
4652

4753

48-
4954
/**
5055
* Executes a Cypher query.
5156
*/
5257
public function run(string $cypher, array $parameters = []): ResultSet
5358
{
5459
$request = $this->requestFactory->buildRunQueryRequest($cypher, $parameters);
5560

61+
$response = null;
62+
5663
try {
5764
$response = $this->client->sendRequest($request);
5865
} catch (RequestExceptionInterface $e) {
5966
$this->handleRequestException($e);
6067
}
68+
if ($response === null) {
69+
throw new \RuntimeException('Failed to get a response');
70+
}
6171

6272
return $this->responseParser->parseRunQueryResponse($response);
6373
}
6474

75+
6576
/**
6677
* Starts a transaction.
6778
*/
6879
public function beginTransaction(): Transaction
6980
{
7081
$request = $this->requestFactory->buildBeginTransactionRequest();
7182

83+
$response = null;
84+
7285
try {
7386
$response = $this->client->sendRequest($request);
7487
} catch (RequestExceptionInterface $e) {
7588
$this->handleRequestException($e);
7689
}
7790

91+
if ($response === null) {
92+
throw new \RuntimeException('No response received for transaction request');
93+
}
94+
7895
$clusterAffinity = $response->getHeaderLine('neo4j-cluster-affinity');
79-
$responseData = json_decode($response->getBody(), true);
96+
$body = $response->getBody()->getContents();
97+
98+
$responseData = json_decode($body, true);
8099
$transactionId = $responseData['transaction']['id'];
81100

82101
return new Transaction(
@@ -88,19 +107,15 @@ public function beginTransaction(): Transaction
88107
);
89108
}
90109

110+
91111
/**
92112
* Handles request exceptions by parsing error details and throwing a Neo4jException.
93113
*
94114
* @throws Neo4jException
95115
*/
96-
private function handleRequestException(RequestExceptionInterface $e): void
116+
public function handleRequestException(RequestExceptionInterface $e): void
97117
{
98-
$response = $e->getResponse();
99-
if ($response instanceof ResponseInterface) {
100-
$errorResponse = json_decode((string)$response->getBody(), true);
101-
throw Neo4jException::fromNeo4jResponse($errorResponse, $e);
102-
}
103-
104-
throw new Neo4jException(['message' => $e->getMessage()], 500, $e);
118+
throw new \RuntimeException('Request failed: ' . $e->getMessage(), 0, $e);
105119
}
106120
}
121+

src/Neo4jRequestFactory.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,30 +57,31 @@ private function createRequest(string $uri, ?string $cypher, ?array $parameters)
5757
$request = $this->psr17Factory->createRequest('POST', $this->configuration->baseUri . $uri);
5858

5959
$payload = [
60-
'parameters' => empty($parameters) ? new \stdClass() : $parameters,
60+
'parameters' => $parameters ?? new \stdClass(),
6161
'includeCounters' => $this->configuration->includeCounters
6262
];
6363

6464
if ($this->configuration->accessMode === AccessMode::READ) {
6565
$payload['accessMode'] = AccessMode::READ;
6666
}
6767

68-
if ($cypher) {
68+
if ($cypher !== null && $cypher !== '') {
6969
$payload['statement'] = $cypher;
7070
}
7171

72-
if ($parameters) {
72+
if ($parameters !== null && $parameters !== []) {
7373
$payload['parameters'] = $parameters;
7474
}
7575

76+
/** @psalm-suppress RedundantCondition */
7677
if ($this->configuration->bookmarks !== null) {
7778
$payload['bookmarks'] = $this->configuration->bookmarks;
7879
}
7980

8081
$request = $request->withHeader('Content-Type', 'application/json');
8182
$request = $request->withHeader('Accept', 'application/vnd.neo4j.query');
8283

83-
$body = json_encode($payload);
84+
$body = json_encode($payload, JSON_THROW_ON_ERROR);
8485

8586
$stream = $this->streamFactory->createStream($body);
8687

src/OGM.php

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ class OGM
1818
*/
1919
public function map(array $object): mixed
2020
{
21+
2122
if (!isset($object['$type'])) {
22-
if (isset($object['elementId'], $object['labels'], $object['properties'])) {
23-
return $this->mapNode($object); // Handle as a Node
23+
if (array_key_exists('elementId', $object) && array_key_exists('labels', $object) && array_key_exists('properties', $object)) {
24+
return $this->mapNode($object);
2425
}
25-
throw new \InvalidArgumentException('Unknown object type: ' . json_encode($object));
26+
throw new \InvalidArgumentException('Unknown object type: ' . json_encode($object, JSON_THROW_ON_ERROR));
2627
}
2728

2829
// if (!isset($object['_value'])) {
@@ -39,21 +40,30 @@ public function map(array $object): mixed
3940
'Point' => $this->parseWKT($object['_value']),
4041
'Relationship' => $this->mapRelationship($object['_value']),
4142
'Path' => $this->mapPath($object['_value']),
42-
default => throw new \InvalidArgumentException('Unknown type: ' . $object['$type'] . ' in object: ' . json_encode($object)),
43+
default => throw new \InvalidArgumentException('Unknown type: ' . $object['$type'] . ' in object: ' . json_encode($object, JSON_THROW_ON_ERROR)),
4344
};
4445
}
4546

4647
public static function parseWKT(string $wkt): Point
4748
{
48-
$sridPart = substr($wkt, 0, strpos($wkt, ';'));
49+
$sridPos = strpos($wkt, ';');
50+
if ($sridPos === false) {
51+
throw new \InvalidArgumentException("Invalid WKT format: missing ';'");
52+
}
53+
$sridPart = substr($wkt, 0, $sridPos);
4954
$srid = (int)str_replace('SRID=', '', $sridPart);
5055

51-
$pointPart = substr($wkt, strpos($wkt, 'POINT') + 6);
56+
$pointPos = strpos($wkt, 'POINT');
57+
if ($pointPos === false) {
58+
throw new \InvalidArgumentException("Invalid WKT format: missing 'POINT'");
59+
}
60+
$pointPart = substr($wkt, $pointPos + 6);
61+
5262
$pointPart = str_replace('Z', '', $pointPart);
5363
$pointPart = trim($pointPart, ' ()');
5464
$coordinates = explode(' ', $pointPart);
5565

56-
[$x, $y, $z] = array_pad(array_map('floatval', $coordinates), 3, null);
66+
[$x, $y, $z] = array_pad(array_map('floatval', $coordinates), 3, 0.0);
5767

5868
return new Point($x, $y, $z, $srid);
5969
}

src/Objects/Authentication.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@
1212
*/
1313
class Authentication
1414
{
15+
1516
public static function basic(string $username, string $password): AuthenticateInterface
1617
{
18+
$username = $username ?: 'defaultUsername';
19+
$password = $password ?: 'defaultPassword';
20+
1721
return new BasicAuthentication($username, $password);
1822
}
1923

0 commit comments

Comments
 (0)