Skip to content

Commit 43c9728

Browse files
author
Siddhesh
committed
fix: Add missing DriverInterface methods, fix transaction rollback bug, and update README.md
1 parent 948be2b commit 43c9728

File tree

9 files changed

+359
-103
lines changed

9 files changed

+359
-103
lines changed

Dockerfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ RUN apt-get update \
1010
&& docker-php-ext-enable xdebug \
1111
&& curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
1212

13+
# Configure git to allow the mounted project directory
14+
RUN git config --global --add safe.directory /opt/project
15+
1316
RUN echo "xdebug.client_host=host.docker.internal" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
1417
RUN echo "xdebug.mode=debug,develop" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
1518

composer.json

Lines changed: 65 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,69 @@
11
{
2-
"name": "neo4j/neo4j-bundle",
3-
"description": "Symfony integration for Neo4j",
4-
"type": "symfony-bundle",
5-
"keywords": ["neo4j", "symfony", "bundle", "graph", "database", "cypher"],
6-
"license": "MIT",
7-
"authors": [
8-
{
9-
"name": "Ghlen Nagels",
10-
"email": "ghlen@nagels.tech"
11-
},
12-
{
13-
"name": "Nabeel Parkar",
14-
"email": "nabeel@nagels.tech"
15-
}
16-
],
17-
"require": {
18-
"php": ">=8.1",
19-
"laudis/neo4j-php-client": "^3.3",
20-
"twig/twig": "^3.0",
21-
"ext-json": "*",
22-
"symfony/dependency-injection": "^6.4 || ^7.2",
23-
"symfony/config": "^6.4 || ^7.2"
2+
"name": "neo4j/neo4j-bundle",
3+
"description": "Symfony integration for Neo4j",
4+
"type": "symfony-bundle",
5+
"keywords": ["neo4j", "symfony", "bundle", "graph", "database", "cypher"],
6+
"license": "MIT",
7+
"authors": [
8+
{
9+
"name": "Ghlen Nagels",
10+
"email": "ghlen@nagels.tech"
2411
},
25-
"require-dev": {
26-
"friendsofphp/php-cs-fixer": "^3.75",
27-
"kubawerlos/php-cs-fixer-custom-fixers": "^3.0",
28-
"matthiasnoback/symfony-dependency-injection-test": "^4.3 || ^5.0",
29-
"phpunit/phpunit": "^9.5",
30-
"psalm/plugin-phpunit": "^0.19.5",
31-
"psalm/plugin-symfony": "^5.0",
32-
"symfony/console": "^6.4 || ^7.2",
33-
"symfony/framework-bundle": "^6.4 || ^7.2",
34-
"symfony/http-kernel": "^6.4 || ^7.2",
35-
"symfony/routing": "^6.4 || ^7.2",
36-
"symfony/stopwatch": "^6.4 || ^7.2",
37-
"symfony/test-pack": "^1.1",
38-
"symfony/twig-bundle": "^6.4 || ^7.2",
39-
"symfony/uid": "^6.4 || ^7.2",
40-
"symfony/web-profiler-bundle": "^6.4 || ^7.2",
41-
"symfony/yaml": "^6.4 || ^7.2",
42-
"vimeo/psalm": "^6.11"
43-
},
44-
"autoload": {
45-
"psr-4": {
46-
"Neo4j\\Neo4jBundle\\": "src/"
47-
}
48-
},
49-
"autoload-dev": {
50-
"psr-4": {
51-
"Neo4j\\Neo4jBundle\\Tests\\": "tests/"
52-
}
53-
},
54-
"config": {
55-
"sort-packages": true,
56-
"allow-plugins": {
57-
"php-http/discovery": false
58-
}
59-
},
60-
"scripts": {
61-
"psalm": "APP_ENV=dev php bin/console.php cache:warmup && vendor/bin/psalm --show-info=true",
62-
"fix-cs": "vendor/bin/php-cs-fixer fix",
63-
"check-cs": "vendor/bin/php-cs-fixer fix --dry-run",
64-
"ci-symfony-install-version": "./.github/scripts/setup-symfony-env.bash"
12+
{
13+
"name": "Nabeel Parkar",
14+
"email": "nabeel@nagels.tech"
15+
}
16+
],
17+
"require": {
18+
"php": ">=8.1",
19+
"laudis/neo4j-php-client": "^3.3",
20+
"twig/twig": "^3.0",
21+
"ext-json": "*",
22+
"symfony/dependency-injection": "^6.4 || ^7.2",
23+
"symfony/config": "^6.4 || ^7.2"
24+
},
25+
"require-dev": {
26+
"friendsofphp/php-cs-fixer": "^3.75",
27+
"kubawerlos/php-cs-fixer-custom-fixers": "^3.0",
28+
"matthiasnoback/symfony-dependency-injection-test": "^4.3 || ^5.0",
29+
"phpunit/phpunit": "^9.5",
30+
"psalm/plugin-phpunit": "^0.19.5",
31+
"psalm/plugin-symfony": "^5.0",
32+
"symfony/console": "^6.4 || ^7.2",
33+
"symfony/framework-bundle": "^6.4 || ^7.2",
34+
"symfony/http-kernel": "^6.4 || ^7.2",
35+
"symfony/routing": "^6.4 || ^7.2",
36+
"symfony/stopwatch": "^6.4 || ^7.2",
37+
"symfony/test-pack": "^1.1",
38+
"symfony/twig-bundle": "^6.4 || ^7.2",
39+
"symfony/uid": "^6.4 || ^7.2",
40+
"symfony/web-profiler-bundle": "^6.4 || ^7.2",
41+
"symfony/yaml": "^6.4 || ^7.2",
42+
"vimeo/psalm": "^6.11"
43+
},
44+
"autoload": {
45+
"psr-4": {
46+
"Neo4j\\Neo4jBundle\\": "src/"
47+
}
48+
},
49+
"autoload-dev": {
50+
"psr-4": {
51+
"Neo4j\\Neo4jBundle\\Tests\\": "tests/"
52+
}
53+
},
54+
"config": {
55+
"sort-packages": true,
56+
"allow-plugins": {
57+
"php-http/discovery": false
6558
}
59+
},
60+
"scripts": {
61+
"test": "vendor/bin/phpunit",
62+
"test:unit": "vendor/bin/phpunit --testsuite='Unit tests'",
63+
"test:functional": "vendor/bin/phpunit --testsuite='Functional tests'",
64+
"psalm": "APP_ENV=dev php bin/console.php cache:warmup && vendor/bin/psalm --show-info=true",
65+
"fix-cs": "vendor/bin/php-cs-fixer fix",
66+
"check-cs": "vendor/bin/php-cs-fixer fix --dry-run",
67+
"ci-symfony-install-version": "./.github/scripts/setup-symfony-env.bash"
68+
}
6669
}

docs/README.md

Lines changed: 69 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ Make sure Composer is installed globally, as explained in the
1414
[installation chapter](https://getcomposer.org/doc/00-intro.md)
1515
of the Composer documentation.
1616

17-
Applications that don't use Symfony Flex
18-
----------------------------------------
19-
2017
### Step 1: Download the Bundle
2118

2219
Open a command console, enter your project directory and execute the
@@ -43,23 +40,30 @@ return [
4340
## Documentation
4441

4542
The bundle is a convenient way of registering services. We register `Drivers` and one
46-
`Clients`. You will always have alias for the default services:
43+
`Client`. You will always have alias for the default services:
4744

48-
* neo4j.driver
49-
* neo4j.client
45+
* neo4j.driver
46+
* neo4j.client
5047

5148

5249
### Minimal configuration
5350

5451
```yaml
5552
neo4j:
5653
drivers:
57-
default: ~
54+
- alias: default
55+
```
56+
57+
Or even simpler, if you want to use all defaults:
58+
59+
```yaml
60+
neo4j:
61+
drivers: []
5862
```
5963
6064
With the minimal configuration we have services named:
61-
* neo4j.driver.default
62-
* neo4j.client
65+
* neo4j.driver.default
66+
* neo4j.client
6367
6468
### Full configuration example
6569
@@ -96,14 +100,68 @@ neo4j:
96100
97101
## Testing
98102
99-
``` bash
103+
### Prerequisites
104+
105+
Functional tests require a Neo4j instance to be running. The easiest way to set this up is using Docker Compose:
106+
107+
```bash
108+
$ docker-compose up -d
109+
```
110+
111+
This will start a Neo4j instance accessible at `bolt://neo4j:testtest@neo4j:7687`.
112+
113+
> **Note:** For single-instance Neo4j setups, use the `bolt://` scheme. The `neo4j://` scheme is intended for clustered setups with routing support.
114+
115+
### Running Tests
116+
117+
Run all tests:
118+
119+
```bash
100120
$ composer test
101121
```
102122

123+
Run only unit tests (no Neo4j instance required):
124+
125+
```bash
126+
$ composer test:unit
127+
```
128+
129+
Run only functional tests (requires Neo4j instance):
130+
131+
```bash
132+
$ composer test:functional
133+
```
134+
135+
You can also run PHPUnit directly:
136+
137+
```bash
138+
$ ./vendor/bin/phpunit
139+
```
140+
141+
### Code Quality
142+
143+
Check code style:
144+
145+
```bash
146+
$ composer check-cs
147+
```
148+
149+
Fix code style issues:
150+
151+
```bash
152+
$ composer fix-cs
153+
```
154+
155+
Run static analysis:
156+
157+
```bash
158+
$ composer psalm
159+
```
160+
103161
## Example application
104162

105163
See an example application at https://github.com/neo4j-examples/movies-symfony-php-bolt (legacy project)
106164

107165
## License
108166

109-
The MIT License (MIT). Please see [License File](../LICENSE) for more information.
167+
The MIT License (MIT). Please see [License File](LICENSE) for more information.

src/Collector/Neo4jDataCollector.php

Lines changed: 57 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -43,26 +43,62 @@ public function collect(Request $request, Response $response, ?\Throwable $excep
4343

4444
$statement[$key] = $t->recursiveToArray($value);
4545
}
46+
47+
if (isset($summary['result']) && method_exists($summary['result'], 'getStatement')) {
48+
/** @var object $result */
49+
$result = $summary['result'];
50+
if (method_exists($result, 'getStatement')) {
51+
$resultStatement = $result->getStatement();
52+
$statement['statement'] = $t->recursiveToArray($resultStatement);
53+
if (is_object($resultStatement) && method_exists($resultStatement, 'getParameters')) {
54+
$params = $resultStatement->getParameters();
55+
$statement['parameters'] = is_array($params)
56+
? $params
57+
: $t->recursiveToArray($params);
58+
}
59+
}
60+
}
4661
$successfulStatements[] = $statement;
4762
}
4863

4964
$failedStatements = array_map(
50-
static fn (array $x) => [
51-
'status' => 'failure',
52-
'time' => $x['time'],
53-
'timestamp' => $x['timestamp'],
54-
'result' => [
55-
'statement' => $x['statement']?->toArray(),
56-
],
57-
'exception' => [
58-
'code' => $x['exception']->getErrors()[0]->getCode(),
59-
'message' => $x['exception']->getErrors()[0]->getMessage(),
60-
'classification' => $x['exception']->getErrors()[0]->getClassification(),
61-
'category' => $x['exception']->getErrors()[0]->getCategory(),
62-
'title' => $x['exception']->getErrors()[0]->getTitle(),
63-
],
64-
'alias' => $x['alias'],
65-
],
65+
function (array $x) use ($t) {
66+
$statement = [
67+
'status' => 'failure',
68+
'time' => $x['time'],
69+
'timestamp' => $x['timestamp'],
70+
'result' => [
71+
'statement' => $x['statement']?->toArray(),
72+
],
73+
'exception' => [
74+
'code' => $x['exception']->getErrors()[0]->getCode(),
75+
'message' => $x['exception']->getErrors()[0]->getMessage(),
76+
'classification' => $x['exception']->getErrors()[0]->getClassification(),
77+
'category' => $x['exception']->getErrors()[0]->getCategory(),
78+
'title' => $x['exception']->getErrors()[0]->getTitle(),
79+
],
80+
'error' => [
81+
'code' => $x['exception']->getErrors()[0]->getCode(),
82+
'message' => $x['exception']->getErrors()[0]->getMessage(),
83+
'classification' => $x['exception']->getErrors()[0]->getClassification(),
84+
'category' => $x['exception']->getErrors()[0]->getCategory(),
85+
'title' => $x['exception']->getErrors()[0]->getTitle(),
86+
],
87+
'alias' => $x['alias'],
88+
];
89+
90+
if (null !== $x['statement']) {
91+
$statement['statement'] = $t->recursiveToArray($x['statement']);
92+
if (is_object($x['statement']) && method_exists($x['statement'], 'getParameters')) {
93+
$params = $x['statement']->getParameters();
94+
$statement['parameters'] = is_array($params)
95+
? $params
96+
: $t->recursiveToArray($params);
97+
}
98+
}
99+
100+
return $statement;
101+
},
66102
$this->subscriber->getProfiledFailures()
67103
);
68104

@@ -97,18 +133,18 @@ public function getStatements(): array
97133

98134
public function getSuccessfulStatements(): array
99135
{
100-
return array_filter(
136+
return array_values(array_filter(
101137
$this->data['statements'],
102138
static fn (array $x) => 'success' === $x['status']
103-
);
139+
));
104140
}
105141

106142
public function getFailedStatements(): array
107143
{
108-
return array_filter(
144+
return array_values(array_filter(
109145
$this->data['statements'],
110146
static fn (array $x) => 'failure' === $x['status']
111-
);
147+
));
112148
}
113149

114150
/** @api */
@@ -138,7 +174,7 @@ private function recursiveToArray(array|object $obj): mixed
138174
{
139175
if (is_array($obj)) {
140176
return array_map(
141-
fn (mixed $x): mixed => $this->recursiveToArray($x),
177+
fn (mixed $x): mixed => is_array($x) || is_object($x) ? $this->recursiveToArray($x) : $x,
142178
$obj
143179
);
144180
}

src/Decorators/SymfonyDriver.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Laudis\Neo4j\Basic\Driver;
66
use Laudis\Neo4j\Contracts\DriverInterface;
7+
use Laudis\Neo4j\Databags\ServerInfo;
78
use Laudis\Neo4j\Databags\SessionConfiguration;
89
use Neo4j\Neo4jBundle\Factories\SymfonyDriverFactory;
910

@@ -29,7 +30,13 @@ public function createSession(?SessionConfiguration $config = null): SymfonySess
2930
#[\Override]
3031
public function verifyConnectivity(?SessionConfiguration $config = null): bool
3132
{
32-
return $this->driver->verifyConnectivity();
33+
return $this->driver->verifyConnectivity($config);
34+
}
35+
36+
#[\Override]
37+
public function getServerInfo(?SessionConfiguration $config = null): ServerInfo
38+
{
39+
return $this->driver->getServerInfo($config);
3340
}
3441

3542
#[\Override]

0 commit comments

Comments
 (0)