Skip to content

Commit a4de370

Browse files
committed
Upgrade to Doctrine DBAL 3.0
1 parent cc61557 commit a4de370

21 files changed

+477
-348
lines changed

composer.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,12 @@
2222
"php": ">=7.4",
2323
"ext-pdo": "*",
2424
"squirrelphp/debug": "^0.5",
25-
"doctrine/dbal": "^2.5"
25+
"doctrine/dbal": "^3.0"
2626
},
2727
"require-dev": {
2828
"bamarni/composer-bin-plugin": "^1.3",
2929
"captainhook/plugin-composer": "^5.0",
30+
"phpunit/phpunit": "^9.0",
3031
"mockery/mockery": "^1.0"
3132
},
3233
"suggest": {
@@ -59,7 +60,7 @@
5960
"psalm_base": "vendor/bin/psalm --set-baseline=psalm-baseline.xml",
6061
"phpunit": "vendor/bin/phpunit --colors=always",
6162
"phpunit_clover": "vendor/bin/phpunit --coverage-text --coverage-clover build/logs/clover.xml",
62-
"codecoverage": "vendor/bin/phpunit --coverage-html tests/_reports",
63+
"coverage": "vendor/bin/phpunit --coverage-html tests/_reports",
6364
"phpcs": "vendor/bin/phpcs --standard=ruleset.xml --extensions=php --cache=.phpcs-cache --colors src tests",
6465
"phpcsfix": "vendor/bin/phpcbf --standard=ruleset.xml --extensions=php --cache=.phpcs-cache src tests",
6566
"binupdate": "@composer bin all update --ansi",

docker/compose-coverage.yml

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
version: "3.7"
2+
services:
3+
squirrel_queries_coverage:
4+
image: thecodingmachine/php:7.4-v3-cli
5+
container_name: squirrel_queries_coverage
6+
tty: true
7+
working_dir: /usr/src/app
8+
# --path-coverage could be added later, it is much too slow currently and only supported by xdebug
9+
command: [ "vendor/bin/phpunit", "--colors=always", "--stop-on-defect", "--coverage-html", "tests/_reports"]
10+
volumes:
11+
- ./src:/usr/src/app/src
12+
- ./tests:/usr/src/app/tests
13+
- ./composer.json:/usr/src/app/composer.json
14+
- ./phpunit.xml.dist:/usr/src/app/phpunit.xml.dist
15+
- ./vendor-bin:/usr/src/app/vendor-bin
16+
environment:
17+
# We currently use PCOV because it is at least 8x faster
18+
# - 3 seconds compared to 23 seconds (or 5 minutes with path coverage enabled)
19+
PHP_EXTENSION_XDEBUG: 1
20+
#PHP_EXTENSION_PCOV: 1
21+
PHP_EXTENSION_APCU: 0
22+
PHP_EXTENSION_REDIS: 0
23+
PHP_EXTENSION_SQLITE3: 1
24+
PHP_EXTENSION_PDO_MYSQL: 1
25+
PHP_EXTENSION_PDO_PGSQL: 1
26+
PHP_EXTENSION_PDO_SQLITE: 1
27+
PHP_INI_MEMORY_LIMIT: 1g
28+
PHP_INI_ERROR_REPORTING: E_ALL
29+
SQUIRREL_TEST_SQLITE: 'sqlite:///:memory:'
30+
SQUIRREL_TEST_POSTGRES: 'postgres://user:password@squirrel_queries_postgres/postgres?charset=UTF-8'
31+
SQUIRREL_TEST_MYSQL: 'mysql://user:password@squirrel_queries_mysql/shop'
32+
SQUIRREL_TEST_MARIADB: 'mysql://user:password@squirrel_queries_mariadb/shop'
33+
STARTUP_COMMAND_1: composer update --no-scripts --quiet
34+
STARTUP_COMMAND_2: rm -rf /usr/src/app/tests/_reports/*
35+
depends_on:
36+
- squirrel_queries_postgres
37+
- squirrel_queries_mysql
38+
- squirrel_queries_mariadb
39+
40+
squirrel_queries_postgres:
41+
image: postgres:latest
42+
container_name: squirrel_queries_postgres
43+
environment:
44+
POSTGRES_USER: 'user'
45+
POSTGRES_PASSWORD: 'password'
46+
47+
squirrel_queries_mysql:
48+
image: mysql/mysql-server:latest
49+
container_name: squirrel_queries_mysql
50+
command: --default-authentication-plugin=mysql_native_password
51+
environment:
52+
MYSQL_ROOT_PASSWORD: 'whatever'
53+
MYSQL_DATABASE: 'shop'
54+
MYSQL_USER: 'user'
55+
MYSQL_PASSWORD: 'password'
56+
57+
squirrel_queries_mariadb:
58+
image: mariadb:latest
59+
container_name: squirrel_queries_mariadb
60+
environment:
61+
MYSQL_ROOT_PASSWORD: 'whatever'
62+
MYSQL_DATABASE: 'shop'
63+
MYSQL_USER: 'user'
64+
MYSQL_PASSWORD: 'password'

docker/compose-test.yml

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
version: "3.7"
22
services:
3-
squirrel_queries_74:
3+
squirrel_queries_test:
44
image: thecodingmachine/php:7.4-v3-cli
5-
container_name: squirrel_queries_74
5+
container_name: squirrel_queries_test
66
tty: true
77
working_dir: /usr/src/app
88
command: ["vendor/bin/phpunit", "--colors=always", "--filter", "Integration"]
@@ -26,7 +26,6 @@ services:
2626
SQUIRREL_TEST_MYSQL: 'mysql://user:password@squirrel_queries_mysql/shop'
2727
SQUIRREL_TEST_MARIADB: 'mysql://user:password@squirrel_queries_mariadb/shop'
2828
STARTUP_COMMAND_1: composer update --no-scripts --quiet
29-
STARTUP_COMMAND_2: composer bin all update --quiet
3029
depends_on:
3130
- squirrel_queries_postgres
3231
- squirrel_queries_mysql

docker/coverage

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/usr/bin/env bash
2+
# Get directory of this script
3+
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
4+
5+
# Remove all running docker containers
6+
docker-compose -f "$DIR/compose-coverage.yml" --project-directory "$DIR/.." down -v --remove-orphans
7+
8+
# Test SQLite and real live tests with PostgreSQL and MySQL
9+
docker-compose -f "$DIR/compose-coverage.yml" --project-directory "$DIR/.." up --build --force-recreate --renew-anon-volumes squirrel_queries_coverage
10+
11+
# Remove all running docker containers
12+
docker-compose -f "$DIR/compose-coverage.yml" --project-directory "$DIR/.." down -v

docker/test-pull docker/pull

+2-4
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
# Get directory of this script
33
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
44

5-
# Remove all running docker containers
6-
docker-compose -f "$DIR/compose-test.yml" --project-directory "$DIR/.." down -v --remove-orphans
7-
85
# Pull new docker images in case there were updates
9-
docker-compose -f "$DIR/compose-test.yml" --project-directory "$DIR/.." pull
6+
docker-compose -f "$DIR/compose-test.yml" --project-directory "$DIR/.." pull
7+
docker-compose -f "$DIR/compose-coverage.yml" --project-directory "$DIR/.." pull

docker/test

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
66
docker-compose -f "$DIR/compose-test.yml" --project-directory "$DIR/.." down -v --remove-orphans
77

88
# Test SQLite and real live tests with PostgreSQL and MySQL
9-
docker-compose -f "$DIR/compose-test.yml" --project-directory "$DIR/.." up --build --force-recreate --renew-anon-volumes squirrel_queries_74
9+
docker-compose -f "$DIR/compose-test.yml" --project-directory "$DIR/.." up --build --force-recreate --renew-anon-volumes squirrel_queries_test
1010

1111
# Remove all running docker containers
1212
docker-compose -f "$DIR/compose-test.yml" --project-directory "$DIR/.." down -v

phpstan-baseline.neon

+5
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,8 @@ parameters:
2020
count: 1
2121
path: src/Builder/SelectEntries.php
2222

23+
-
24+
message: "#^Cannot access offset 'v' on array\\<string, mixed\\>\\|false\\.$#"
25+
count: 1
26+
path: src/Doctrine/DBSQLiteImplementation.php
27+

phpunit.xml.dist

+14-22
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,16 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
3-
<phpunit
4-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5-
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/9.1/phpunit.xsd"
6-
backupGlobals="false"
7-
colors="true"
8-
bootstrap="vendor/autoload.php"
9-
>
10-
<testsuites>
11-
<testsuite name="Unit Tests">
12-
<directory>tests</directory>
13-
</testsuite>
14-
</testsuites>
15-
16-
<filter>
17-
<whitelist>
18-
<directory suffix=".php">src</directory>
19-
<exclude>
20-
<directory>src/TestHelpers</directory>
21-
</exclude>
22-
</whitelist>
23-
</filter>
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" backupGlobals="false" colors="true" bootstrap="vendor/autoload.php">
3+
<coverage>
4+
<include>
5+
<directory suffix=".php">src</directory>
6+
</include>
7+
<exclude>
8+
<directory>src/TestHelpers</directory>
9+
</exclude>
10+
</coverage>
11+
<testsuites>
12+
<testsuite name="Unit Tests">
13+
<directory>tests</directory>
14+
</testsuite>
15+
</testsuites>
2416
</phpunit>

psalm-baseline.xml

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<files psalm-version="3.14.2@3538fe1955d47f6ee926c0769d71af6db08aa488">
2+
<files psalm-version="3.18.2@19aa905f7c3c7350569999a93c40ae91ae4e1626">
33
<file src="src/Builder/FlattenedFieldsWithTypeTrait.php">
44
<InvalidReturnType occurrences="4">
5-
<code>int[]</code>
5+
<code>bool[]</code>
66
<code>float[]</code>
7+
<code>int[]</code>
78
<code>string[]</code>
8-
<code>bool[]</code>
99
</InvalidReturnType>
1010
</file>
1111
<file src="src/Builder/SelectIteratorTrait.php">
@@ -18,4 +18,9 @@
1818
<code>$lowerLayer</code>
1919
</MissingConstructor>
2020
</file>
21+
<file src="src/Doctrine/DBAbstractImplementation.php">
22+
<PossiblyNullArgument occurrences="1">
23+
<code>$select['offset'] ?? null</code>
24+
</PossiblyNullArgument>
25+
</file>
2126
</files>

src/Doctrine/DBAbstractImplementation.php

+12-13
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
namespace Squirrel\Queries\Doctrine;
44

55
use Doctrine\DBAL\Connection;
6-
use Doctrine\DBAL\FetchMode;
76
use Squirrel\Debug\Debug;
87
use Squirrel\Queries\DBInterface;
98
use Squirrel\Queries\DBRawInterface;
@@ -76,10 +75,10 @@ public function select($query, array $vars = []): DBSelectQueryInterface
7675

7776
// Prepare and execute query
7877
$statement = $this->connection->prepare($query);
79-
$statement->execute($vars);
78+
$statementResult = $statement->execute($vars);
8079

8180
// Return select query object with PDO statement
82-
return new DBSelectQuery($statement);
81+
return new DBSelectQuery($statementResult);
8382
}
8483

8584
public function fetch(DBSelectQueryInterface $selectQuery): ?array
@@ -94,7 +93,7 @@ public function fetch(DBSelectQueryInterface $selectQuery): ?array
9493
}
9594

9695
// Get the result - can be an array of the entry, or false if it is empty
97-
$result = $selectQuery->getStatement()->fetch(FetchMode::ASSOCIATIVE);
96+
$result = $selectQuery->getStatement()->fetchAssociative();
9897

9998
// Return one result as an array
10099
return ($result === false ? null : $result);
@@ -112,7 +111,7 @@ public function clear(DBSelectQueryInterface $selectQuery): void
112111
}
113112

114113
// Close the result set
115-
$selectQuery->getStatement()->closeCursor();
114+
$selectQuery->getStatement()->free();
116115
}
117116

118117
public function fetchOne($query, array $vars = []): ?array
@@ -135,11 +134,11 @@ public function fetchAll($query, array $vars = []): array
135134

136135
// Prepare and execute query
137136
$statement = $this->connection->prepare($query);
138-
$statement->execute($vars);
137+
$statementResult = $statement->execute($vars);
139138

140139
// Get result and close result set
141-
$result = $statement->fetchAll(FetchMode::ASSOCIATIVE);
142-
$statement->closeCursor();
140+
$result = $statementResult->fetchAllAssociative();
141+
$statementResult->free();
143142

144143
// Return query result
145144
return $result;
@@ -188,8 +187,8 @@ public function insert(string $tableName, array $row = [], string $autoIncrement
188187
($columnValue instanceof LargeObject) ? \PDO::PARAM_LOB : \PDO::PARAM_STR,
189188
);
190189
}
191-
$statement->execute();
192-
$statement->closeCursor();
190+
$statementResult = $statement->execute();
191+
$statementResult->free();
193192

194193
// No autoincrement index - no insert ID return value needed
195194
if (\strlen($autoIncrementIndex) === 0) {
@@ -262,13 +261,13 @@ public function change(string $query, array $vars = []): int
262261
($columnValue instanceof LargeObject) ? \PDO::PARAM_LOB : \PDO::PARAM_STR,
263262
);
264263
}
265-
$statement->execute();
264+
$statementResult = $statement->execute();
266265

267266
// Get affected rows
268-
$result = $statement->rowCount();
267+
$result = $statementResult->rowCount();
269268

270269
// Close query
271-
$statement->closeCursor();
270+
$statementResult->free();
272271

273272
// Return affected rows
274273
return $result;

src/Doctrine/DBErrorHandler.php

-5
Original file line numberDiff line numberDiff line change
@@ -379,11 +379,6 @@ protected function attemptReconnect(array $connectionRetries): ?array
379379
// Close connection and establish a new connection
380380
$connection->close();
381381
$connection->connect();
382-
383-
// If we still do not have a connection we need to try again
384-
if ($connection->ping() === false) {
385-
return $this->attemptReconnect($connectionRetries);
386-
}
387382
} catch (ConnectionException $e) { // Connection could not be established - try again
388383
return $this->attemptReconnect($connectionRetries);
389384
}

src/Doctrine/DBMySQLImplementation.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public function insertOrUpdate(string $tableName, array $row = [], array $indexC
5252
);
5353
}
5454

55-
$statement->execute();
56-
$statement->closeCursor();
55+
$statementResult = $statement->execute();
56+
$statementResult->free();
5757
}
5858
}

src/Doctrine/DBPostgreSQLImplementation.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ public function insertOrUpdate(string $tableName, array $row = [], array $indexC
7474
);
7575
}
7676

77-
$statement->execute();
78-
$statement->closeCursor();
77+
$statementResult = $statement->execute();
78+
$statementResult->free();
7979
}
8080

8181
protected function generateUpsertSQLAndParameters(

src/Doctrine/DBSQLiteImplementation.php

+18-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
namespace Squirrel\Queries\Doctrine;
44

5+
use Squirrel\Debug\Debug;
6+
use Squirrel\Queries\DBInterface;
7+
use Squirrel\Queries\Exception\DBInvalidOptionException;
8+
59
/**
610
* DB SQLite implementation using Doctrine DBAL with custom upsert functionality
711
*
@@ -23,7 +27,20 @@ public function insertOrUpdate(
2327
if ($this->sqliteVersion === null) {
2428
$connection = $this->getConnection();
2529

26-
$this->sqliteVersion = \floatval($connection->query('select sqlite_version() AS "v"')->fetch()['v']);
30+
$statement = $connection->prepare('select sqlite_version() AS "v"');
31+
$statementResult = $statement->execute();
32+
$result = $statementResult->fetchAssociative();
33+
$statementResult->free();
34+
35+
if (!isset($result['v'])) {
36+
throw Debug::createException(
37+
DBInvalidOptionException::class,
38+
DBInterface::class,
39+
'SQLite version could not be retrieved',
40+
);
41+
}
42+
43+
$this->sqliteVersion = \floatval($result['v']);
2744
}
2845

2946
// SQLite below version 3.24 does not offer native upsert, so emulate it

src/Doctrine/DBSelectQuery.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@
22

33
namespace Squirrel\Queries\Doctrine;
44

5-
use Doctrine\DBAL\Driver\ResultStatement;
5+
use Doctrine\DBAL\Result;
66
use Squirrel\Queries\DBSelectQueryInterface;
77

88
class DBSelectQuery implements DBSelectQueryInterface
99
{
10-
private ResultStatement $statement;
10+
private Result $statement;
1111

12-
public function __construct(ResultStatement $statement)
12+
public function __construct(Result $statement)
1313
{
1414
$this->statement = $statement;
1515
}
1616

17-
public function getStatement(): ResultStatement
17+
public function getStatement(): Result
1818
{
1919
return $this->statement;
2020
}

0 commit comments

Comments
 (0)