Skip to content

Commit b0f7700

Browse files
committed
Doctrine3: Making actual progress
1 parent bf946f3 commit b0f7700

25 files changed

+664
-202
lines changed

CHANGES.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ CHANGES for crate-dbal
55
Unreleased
66
==========
77

8-
- Added support for Doctrine 3
8+
- Added support for Doctrine 3, dropped support for Doctrine 2.
99

1010
2025/11/13 4.0.3
1111
================

docs/appendices/data-types.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ Here's an example of how the ``MapType`` can be used:
8989
$objDefinition = array(
9090
'type' => MapType::STRICT,
9191
'fields' => array(
92-
new Column('id', Type::getType('integer'), array()),
93-
new Column('name', Type::getType('string'), array()),
92+
new Column('id', Type::getType('integer'), array()),
93+
new Column('name', Type::getType('string'), array()),
9494
),
9595
);
9696
$table->addColumn(

docs/appendices/table-options.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Example:
1818
1919
$options = [];
2020
$options['sharding_shards'] = 5;
21-
$myTable = new Table('my_table', [], [], [], 0, $options);
21+
$myTable = new Table('my_table', [], [], [], [], $options);
2222
2323
2424
Sharding Options
@@ -66,7 +66,7 @@ Example on how to adjust the replicas:
6666
$options = [];
6767
$options['table_options'] = [];
6868
$options['table_options']['number_of_replicas'] = '2';
69-
$myTable = new Table('my_table', [], [], [], 0, $options);
69+
$myTable = new Table('my_table', [], [], [], [], $options);
7070
7171
7272
.. _CrateDB CREATE TABLE Documentation: https://cratedb.com/docs/crate/reference/en/latest/sql/statements/create-table.html

examples/objects.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
/*
4+
* Basic example program about handling CrateDB OBJECTs with Doctrine DBAL.
5+
* https://github.com/crate/crate-dbal
6+
*/
7+
require __DIR__ . '/../vendor/autoload.php';
8+
9+
use Doctrine\DBAL\Exception\TableNotFoundException;
10+
use Doctrine\DBAL\Schema\Column;
11+
use Doctrine\DBAL\Schema\Table;
12+
use Doctrine\DBAL\Tools\DsnParser;
13+
use Doctrine\DBAL\Types\Type;
14+
use Doctrine\DBAL\DriverManager;
15+
16+
use Crate\DBAL\Platforms\CratePlatform4;
17+
use Crate\DBAL\Types\MapType;
18+
19+
// Initialize machinery.
20+
$platform = new CratePlatform4();
21+
22+
// Define table schema.
23+
$table = new Table('example');
24+
$objDefinition = array(
25+
'type' => MapType::STRICT,
26+
'fields' => array(
27+
new Column('id', Type::getType('integer'), array()),
28+
new Column('name', Type::getType('string'), array()),
29+
),
30+
);
31+
$table->addColumn(
32+
'data',
33+
MapType::NAME,
34+
array('platformOptions' => $objDefinition),
35+
);
36+
37+
// Register driver.
38+
$dsnParser = new DsnParser(array('crate' => 'Crate\DBAL\Driver\PDOCrate\Driver'));
39+
40+
// Connect to database.
41+
$connectionParams = $dsnParser->parse('crate://crate:crate@localhost:4200/');
42+
$connection = DriverManager::getConnection($connectionParams);
43+
$schemaManager = $connection->createSchemaManager();
44+
45+
// Provision database table.
46+
try {
47+
$schemaManager->dropTable($table);
48+
} catch (TableNotFoundException) {
49+
}
50+
$schemaManager->createTable($table);
51+
52+
// Insert data.
53+
$connection->insert('example', array('data' => array('id' => 42, 'name' => 'foo')), array('data' => 'map'));
54+
$connection->insert('example', array('data' => array('id' => 43, 'name' => 'bar')), array('data' => 'map'));
55+
$connection->executeStatement('REFRESH TABLE example');
56+
57+
// Query data.
58+
$result = $connection->executeQuery('SELECT * FROM example');
59+
print_r($result->fetchAllAssociative());
60+
61+
?>

src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php

Lines changed: 117 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,128 @@
2222

2323
namespace Crate\DBAL\Driver\PDOCrate;
2424

25+
use Crate\PDO\PDOStatement;
26+
use Crate\PDO\PDOInterface;
27+
use Doctrine\DBAL\Driver\PDO\Exception;
2528
use Doctrine\DBAL\Driver\PDOStatementImplementations;
2629
use Doctrine\DBAL\Driver\Statement as StatementInterface;
27-
use Crate\PDO\PDOStatement;
30+
use Doctrine\DBAL\Driver\Result as ResultInterface;
31+
use Doctrine\DBAL\ParameterType;
32+
use Doctrine\Deprecations\Deprecation;
33+
use PDO;
2834

2935
/**
3036
* @internal
3137
*/
32-
class CrateStatement extends PDOStatement implements StatementInterface
38+
final class CrateStatement implements StatementInterface
3339
{
34-
use PDOStatementImplementations;
40+
41+
/**
42+
* @var PDOInterface
43+
*/
44+
private $pdo;
45+
46+
private PDOStatement $stmt;
47+
48+
public function __construct(PDOInterface $pdo, $sql)
49+
{
50+
$this->pdo = $pdo;
51+
$this->stmt = $pdo->prepare($sql);
52+
}
53+
54+
/**
55+
* {@inheritDoc}
56+
*/
57+
public function execute($params = null): ResultInterface
58+
{
59+
60+
if ($params !== null) {
61+
Deprecation::trigger(
62+
'doctrine/dbal',
63+
'https://github.com/doctrine/dbal/pull/5556',
64+
'Passing $params to Statement::execute() is deprecated. Bind parameters using'
65+
. ' Statement::bindParam() or Statement::bindValue() instead.',
66+
);
67+
}
68+
$this->stmt->execute($params);
69+
return new Result($this);
70+
}
71+
72+
/**
73+
* {@inheritDoc}
74+
*/
75+
public function columnCount(): int
76+
{
77+
return $this->stmt->columnCount();
78+
}
79+
80+
/**
81+
* {@inheritDoc}
82+
*/
83+
public function rowCount(): int
84+
{
85+
return $this->stmt->rowCount();
86+
}
87+
88+
/**
89+
* {@inheritDoc}
90+
*/
91+
public function bindValue($param, $value, $type = ParameterType::STRING)
92+
{
93+
$this->stmt->bindValue($param, $value, $type);
94+
}
95+
96+
/**
97+
* {@inheritDoc}
98+
*/
99+
public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null)
100+
{
101+
return $this->stmt->bindParam($param, $variable, $type, $length);
102+
}
103+
104+
/**
105+
* {@inheritDoc}
106+
*/
107+
public function fetch(
108+
$fetch_style = PDO::FETCH_ASSOC,
109+
$cursor_orientation = PDO::FETCH_ORI_NEXT,
110+
$cursor_offset = 0,
111+
) {
112+
return $this->stmt->fetch($fetch_style, $cursor_orientation, $cursor_offset);
113+
}
114+
115+
/**
116+
* @phpstan-param PDO::FETCH_* $mode
117+
*
118+
* @return list<mixed>
119+
*
120+
* @throws Exception
121+
*/
122+
public function fetchAll(int $mode): array
123+
{
124+
return $this->stmt->fetchAll($mode);
125+
}
126+
127+
public function fetchColumn($column_number = 0)
128+
{
129+
return $this->stmt->fetchColumn($column_number);
130+
}
131+
132+
/**
133+
* {@inheritDoc}
134+
*/
135+
public function closeCursor(): int
136+
{
137+
return $this->stmt->closeCursor();
138+
}
139+
140+
/**
141+
* Gets the wrapped driver statement.
142+
*
143+
* @return Driver\Statement
144+
*/
145+
public function getWrappedStatement()
146+
{
147+
return $this->stmt;
148+
}
35149
}

src/Crate/DBAL/Driver/PDOCrate/Driver.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
use Crate\DBAL\Platforms\CratePlatform4;
2727
use Crate\DBAL\Schema\CrateSchemaManager;
2828
use Doctrine\DBAL\Connection;
29-
use Doctrine\DBAL\Driver\API\ExceptionConverter;
3029
use Doctrine\DBAL\Platforms\AbstractPlatform;
3130
use Doctrine\DBAL\VersionAwarePlatformDriver;
3231

@@ -70,16 +69,16 @@ private function constructPdoDsn(array $params)
7069
*/
7170
public function getDatabasePlatform()
7271
{
73-
return new CratePlatform();
72+
return new CratePlatform4();
7473
}
7574

7675
/**
7776
* {@inheritDoc}
7877
*/
7978
public function getSchemaManager(Connection $conn, AbstractPlatform $platform)
8079
{
81-
// TODO: `$platform` added when upgrading to Doctrine3 - what to do with it?
82-
return new CrateSchemaManager($conn);
80+
// Added by Doctrine 3.
81+
return new CrateSchemaManager($conn, $conn->getDatabasePlatform());
8382
}
8483

8584
/**
@@ -117,7 +116,7 @@ public function createDatabasePlatformForVersion($version)
117116
*/
118117
public function getExceptionConverter(): ExceptionConverter
119118
{
120-
// TODO: Implement getExceptionConverter() method.
121-
// Added when upgrading to Doctrine3.
119+
// Added by Doctrine 3.
120+
return new ExceptionConverter();
122121
}
123122
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Crate\DBAL\Driver\PDOCrate;
6+
7+
use Doctrine\DBAL\Driver\AbstractException;
8+
use PDOException;
9+
10+
/** @internal */
11+
final class Exception extends AbstractException
12+
{
13+
public static function new(PDOException $exception): self
14+
{
15+
if ($exception->errorInfo !== null) {
16+
[$sqlState, $code] = $exception->errorInfo;
17+
18+
$code ??= 0;
19+
} else {
20+
$code = $exception->getCode();
21+
$sqlState = null;
22+
}
23+
24+
return new self($exception->getMessage(), $sqlState, $code, $exception);
25+
}
26+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Crate\DBAL\Driver\PDOCrate;
6+
7+
use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface;
8+
use Doctrine\DBAL\Driver\Exception;
9+
use Doctrine\DBAL\Exception\ConnectionException;
10+
use Doctrine\DBAL\Exception\DriverException;
11+
use Doctrine\DBAL\Exception\InvalidFieldNameException;
12+
use Doctrine\DBAL\Exception\SchemaDoesNotExist;
13+
use Doctrine\DBAL\Exception\SyntaxErrorException;
14+
use Doctrine\DBAL\Exception\TableExistsException;
15+
use Doctrine\DBAL\Exception\TableNotFoundException;
16+
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
17+
use Doctrine\DBAL\Query;
18+
19+
use Doctrine\DBAL\Schema\Exception\ColumnDoesNotExist;
20+
use function strpos;
21+
22+
/** @internal */
23+
final class ExceptionConverter implements ExceptionConverterInterface
24+
{
25+
/** @link https://cratedb.com/docs/crate/reference/en/latest/interfaces/http.html#error-codes */
26+
public function convert(Exception $exception, ?Query $query): DriverException
27+
{
28+
switch ($exception->getCode()) {
29+
case '4000':
30+
return new SyntaxErrorException($exception, $query);
31+
32+
case '4008':
33+
case '4043':
34+
return new InvalidFieldNameException($exception, $query);
35+
36+
case '4041':
37+
return new TableNotFoundException($exception, $query);
38+
39+
case '4045':
40+
return new SchemaDoesNotExist($exception, $query);
41+
42+
case '4091':
43+
return new UniqueConstraintViolationException($exception, $query);
44+
45+
case '4093':
46+
return new TableExistsException($exception, $query);
47+
}
48+
49+
// Prior to fixing https://bugs.php.net/bug.php?id=64705 (PHP 7.4.10),
50+
// in some cases (mainly connection errors) the PDO exception wouldn't provide a SQLSTATE via its code.
51+
// We have to match against the SQLSTATE in the error message in these cases.
52+
if ($exception->getCode() === 7 && strpos($exception->getMessage(), 'SQLSTATE[08006]') !== false) {
53+
return new ConnectionException($exception, $query);
54+
}
55+
56+
return new DriverException($exception, $query);
57+
}
58+
}

0 commit comments

Comments
 (0)