Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge 3.1.x into 3.2.x #4668

Merged
merged 17 commits into from
Jun 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,9 @@ jobs:
with:
composer_require_dev: true
args: --shepherd

- name: Psalm type inference tests
uses: docker://vimeo/psalm-github-actions:4.6.4
with:
composer_require_dev: true
args: --config=psalm-strict.xml
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"psr/cache": "^1|^2|^3"
},
"require-dev": {
"doctrine/coding-standard": "8.2.0",
"doctrine/coding-standard": "9.0.0",
"jetbrains/phpstorm-stubs": "2020.2",
"phpstan/phpstan": "0.12.81",
"phpstan/phpstan-strict-rules": "^0.12.2",
Expand Down
51 changes: 38 additions & 13 deletions docs/en/reference/caching.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
Caching
=======

A ``Doctrine\DBAL\Statement`` can automatically cache result sets.
A ``Doctrine\DBAL\Statement`` can automatically cache result sets. The
feature is optional though, and by default, no result set is cached.

For this to work an instance of ``Doctrine\Common\Cache\Cache`` must be provided.
This can be set on the configuration object (optionally it can also be passed at query time):
To use the result cache, there are three mandatory steps:

1. Configure a global result cache, or provide one at query time.
2. Provide a cache profile for the result set you want to cache when
making a query.
3. Read the entire result set from the database.

Configuring the result cache
----------------------------

Any instance of ``Doctrine\Common\Cache\Cache`` can be used as a result
cache and can be set on the configuration object (optionally it can also
be passed at query time):

::

Expand All @@ -13,29 +25,40 @@ This can be set on the configuration object (optionally it can also be passed at
$config = $conn->getConfiguration();
$config->setResultCacheImpl($cache);

To get the result set of a query cached it is necessary to pass a
``Doctrine\DBAL\Cache\QueryCacheProfile`` instance to the ``executeQuery`` or ``executeCacheQuery``
instance. The difference between these two methods is that the former does not
require this instance, while the later has this instance as a required parameter:
Providing a cache profile
-------------------------

To get the result set of a query cached, it is necessary to pass a
``Doctrine\DBAL\Cache\QueryCacheProfile`` instance to the
``executeQuery()`` or ``executeCacheQuery()`` methods. The difference
between these two methods is that the former has the cache profile as an
optional argument, whereas it is required when calling the latter:

::

<?php
$stmt = $conn->executeQuery($query, $params, $types, new QueryCacheProfile(0, "some key"));
$stmt = $conn->executeCacheQuery($query, $params, $types, new QueryCacheProfile(0, "some key"));

It is also possible to pass in a ``Doctrine\Common\Cache\Cache`` instance into the
constructor of ``Doctrine\DBAL\Cache\QueryCacheProfile`` in which case it overrides
the default cache instance:
As stated before, it is also possible to pass in a
``Doctrine\Common\Cache\Cache`` instance into the constructor of
``Doctrine\DBAL\Cache\QueryCacheProfile`` in which case it overrides the
default cache instance:

::

<?php
$cache = new \Doctrine\Common\Cache\FilesystemCache(__DIR__);
new QueryCacheProfile(0, "some key", $cache);

In order for the data to actually be cached its necessary to ensure that the entire
result set is read (the easiest way to ensure this is to use one of the ``fetchAll*()`` methods):
Reading the entire result set
-----------------------------

Caching half a result set would cause bugs if a subsequent caller needed
more rows from that same result sets. To be able to cache the entire
result set, it must be fetched entirely from the database, and not all
APIs do that. The easiest way to ensure that is to use one of the
``fetchAll*()`` methods:

::

Expand All @@ -45,4 +68,6 @@ result set is read (the easiest way to ensure this is to use one of the ``fetchA

.. warning::

When using the cache layer not all fetch modes are supported. See the code of the ``Doctrine\DBAL\Cache\CachingResult`` for details.
When using the cache layer not all fetch modes are supported. See
the code of the ``Doctrine\DBAL\Cache\CachingResult`` for
details.
9 changes: 0 additions & 9 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,6 @@
<exclude-pattern>src/Events.php</exclude-pattern>
</rule>

<rule ref="SlevomatCodingStandard.Classes.UnusedPrivateElements.UnusedProperty">
<exclude-pattern>tests/Tools/TestAsset/*</exclude-pattern>
</rule>

<!-- see https://github.com/squizlabs/PHP_CodeSniffer/issues/2099 -->
<rule ref="Squiz.Commenting.FunctionComment.InvalidNoReturn">
<exclude-pattern>src/Platforms/AbstractPlatform.php</exclude-pattern>
Expand Down Expand Up @@ -122,11 +118,6 @@
<exclude-pattern>tests/Functional/ResultCacheTest.php</exclude-pattern>
</rule>

<rule ref="SlevomatCodingStandard.Classes.UnusedPrivateElements.UnusedMethod">
<exclude-pattern>*/lib/Doctrine/DBAL/Driver/PDOConnection.php</exclude-pattern>
<exclude-pattern>*/lib/Doctrine/DBAL/Driver/PDOStatement.php</exclude-pattern>
</rule>

<!-- See https://github.com/slevomat/coding-standard/issues/770 -->
<rule ref="SlevomatCodingStandard.Namespaces.UnusedUses">
<exclude-pattern>src/Driver/ExceptionConverterDriver.php</exclude-pattern>
Expand Down
15 changes: 15 additions & 0 deletions psalm-strict.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0"?>
<psalm
totallyTyped="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="static-analysis" />
<ignoreFiles>
<directory name="src" />
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
</psalm>
1 change: 1 addition & 0 deletions psalm.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
>
<projectFiles>
<directory name="src" />
<directory name="static-analysis" />
<directory name="tests" />
<ignoreFiles>
<directory name="vendor" />
Expand Down
8 changes: 3 additions & 5 deletions src/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,10 @@ class Connection
* @param Driver $driver The driver to use.
* @param Configuration|null $config The configuration, optional.
* @param EventManager|null $eventManager The event manager, optional.
* @psalm-param Params $params
* @phpstan-param array<string,mixed> $params
*
* @throws Exception
*
* @phpstan-param array<string,mixed> $params
* @psalm-param Params $params
*/
public function __construct(
array $params,
Expand Down Expand Up @@ -207,9 +206,8 @@ public function __construct(
* @internal
*
* @return array<string,mixed>
*
* @phpstan-return array<string,mixed>
* @psalm-return Params
* @phpstan-return array<string,mixed>
*/
public function getParams()
{
Expand Down
8 changes: 4 additions & 4 deletions src/Connections/PrimaryReadReplicaConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Driver\Connection as DriverConnection;
use Doctrine\DBAL\Driver\Exception as DriverException;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Event\ConnectionEventArgs;
use Doctrine\DBAL\Events;
use Doctrine\DBAL\Exception;
Expand Down Expand Up @@ -56,7 +57,7 @@
*
* Instantiation through the DriverManager looks like:
*
* @psalm-import-type Params from \Doctrine\DBAL\DriverManager
* @psalm-import-type Params from DriverManager
* @example
*
* $conn = DriverManager::getConnection(array(
Expand Down Expand Up @@ -95,12 +96,11 @@ class PrimaryReadReplicaConnection extends Connection
* @internal The connection can be only instantiated by the driver manager.
*
* @param array<string,mixed> $params
* @psalm-param Params $params
* @phpstan-param array<string,mixed> $params
*
* @throws Exception
* @throws InvalidArgumentException
*
* @phpstan-param array<string,mixed> $params
* @psalm-param Params $params
*/
public function __construct(
array $params,
Expand Down
44 changes: 33 additions & 11 deletions src/DriverManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,36 @@ private function __construct()
* @param array<string,mixed> $params
* @param Configuration|null $config The configuration to use.
* @param EventManager|null $eventManager The event manager to use.
* @psalm-param array{
* charset?: string,
* dbname?: string,
* default_dbname?: string,
* driver?: key-of<self::DRIVER_MAP>,
* driverClass?: class-string<Driver>,
* driverOptions?: array<mixed>,
* host?: string,
* keepSlave?: bool,
* keepReplica?: bool,
* master?: OverrideParams,
* memory?: bool,
* password?: string,
* path?: string,
* pdo?: \PDO,
* platform?: Platforms\AbstractPlatform,
* port?: int,
* primary?: OverrideParams,
* replica?: array<OverrideParams>,
* sharding?: array<string,mixed>,
* slaves?: array<OverrideParams>,
* user?: string,
* wrapperClass?: class-string<T>,
* } $params
* @phpstan-param array<string,mixed> $params
*
* @psalm-return ($params is array{wrapperClass:mixed} ? T : Connection)
*
* @throws Exception
*
* @phpstan-param array<string,mixed> $params
* @psalm-param Params $params
* @psalm-return ($params is array{wrapperClass:mixed} ? T : Connection)
* @template T of Connection
*/
public static function getConnection(
Expand Down Expand Up @@ -211,11 +235,10 @@ public static function getAvailableDrivers(): array

/**
* @param array<string,mixed> $params
* @psalm-param Params $params
* @phpstan-param array<string,mixed> $params
*
* @throws Exception
*
* @phpstan-param array<string,mixed> $params
* @psalm-param Params $params
*/
private static function createDriver(array $params): Driver
{
Expand Down Expand Up @@ -258,16 +281,15 @@ private static function normalizeDatabaseUrlPath(string $urlPath): string
* updated list of parameters.
*
* @param mixed[] $params The list of parameters.
* @psalm-param Params $params
* @phpstan-param array<string,mixed> $params
*
* @return mixed[] A modified list of parameters with info from a database
* URL extracted into indidivual parameter parts.
* @psalm-return Params
* @phpstan-return array<string,mixed>
*
* @throws Exception
*
* @phpstan-param array<string,mixed> $params
* @phpstan-return array<string,mixed>
* @psalm-param Params $params
* @psalm-return Params
*/
private static function parseDatabaseUrl(array $params): array
{
Expand Down
3 changes: 1 addition & 2 deletions src/Platforms/AbstractPlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -3529,10 +3529,9 @@ protected function createReservedKeywordsList(): KeywordList
* @deprecated Implement {@link createReservedKeywordsList()} instead.
*
* @return string
* @psalm-return class-string<KeywordList>
*
* @throws Exception If not supported on this platform.
*
* @psalm-return class-string<KeywordList>
*/
protected function getReservedKeywordsClass()
{
Expand Down
2 changes: 1 addition & 1 deletion src/Platforms/SQLServer2012Platform.php
Original file line number Diff line number Diff line change
Expand Up @@ -1584,7 +1584,7 @@ protected function getReservedKeywordsClass()
*/
public function quoteSingleIdentifier($str)
{
return '[' . str_replace(']', '][', $str) . ']';
return '[' . str_replace(']', ']]', $str) . ']';
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Schema/Table.php
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ public function removeUniqueConstraint(string $name): void
{
$name = $this->normalizeIdentifier($name);

if (! $this->hasForeignKey($name)) {
if (! $this->hasUniqueConstraint($name)) {
throw SchemaException::uniqueConstraintDoesNotExist($name, $this->_name);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Doctrine\StaticAnalysis\DBAL;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DriverManager;

final class MyConnection extends Connection
{
}

function makeMeACustomConnection(): MyConnection
{
return DriverManager::getConnection([
'wrapperClass' => MyConnection::class,
]);
}
30 changes: 20 additions & 10 deletions tests/DriverManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
use PHPUnit\Framework\TestCase;
use stdClass;

use function array_intersect_key;
use function array_merge;
use function get_class;
use function in_array;
use function is_array;
Expand Down Expand Up @@ -125,18 +127,26 @@ public function testDatabaseUrlPrimaryReplica(): void
'password' => 'bar',
'host' => 'localhost',
'port' => 11211,
'dbname' => 'baz',
'driver' => 'pdo_mysql',
'url' => 'mysql://foo:bar@localhost:11211/baz',
];

foreach ($expected as $key => $value) {
self::assertArrayHasKey($key, $params['primary']);
self::assertEquals($value, $params['primary'][$key]);

self::assertArrayHasKey($key, $params['replica']['replica1']);
self::assertEquals($value, $params['replica']['replica1'][$key]);
}

self::assertEquals('baz', $params['primary']['dbname']);
self::assertEquals('baz_replica', $params['replica']['replica1']['dbname']);
self::assertEquals(
[
'primary' => $expected,
'replica' => [
'replica1' => array_merge(
$expected,
[
'dbname' => 'baz_replica',
'url' => 'mysql://foo:bar@localhost:11211/baz_replica',
]
),
],
],
array_intersect_key($params, ['primary' => null, 'replica' => null])
);
}

/**
Expand Down
3 changes: 1 addition & 2 deletions tests/Functional/ExceptionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -353,10 +353,9 @@ public function testConnectionExceptionSqLite(): void

/**
* @param array<string, mixed> $params
* @psalm-param Params $params
*
* @dataProvider getConnectionParams
*
* @psalm-param Params $params
*/
public function testConnectionException(array $params): void
{
Expand Down
Loading