diff --git a/analysis-baseline.toml b/analysis-baseline.toml index f333111..6c710f0 100644 --- a/analysis-baseline.toml +++ b/analysis-baseline.toml @@ -6,12 +6,6 @@ code = "falsable-return-statement" message = '''Function `PhpDb\Mysql\AdapterPlatform::quoteViaDriver` is declared to return `null|string` but possibly returns 'false' (inferred as `false|string`).''' count = 1 -[[issues]] -file = "src/AdapterPlatform.php" -code = "impossible-condition" -message = "This condition (type `false`) will always evaluate to false." -count = 1 - [[issues]] file = "src/AdapterPlatform.php" code = "invalid-return-statement" @@ -30,12 +24,6 @@ code = "possibly-invalid-argument" message = 'Possible argument type mismatch for argument #1 of `PhpDb\Mysql\AdapterPlatform::quoteViaDriver`: expected `string`, but possibly received `bool|float|int|string`.' count = 1 -[[issues]] -file = "src/Connection.php" -code = "incompatible-property-type" -message = 'Property `PhpDb\Mysql\Connection::$resource` has an incompatible type declaration from docblock.' -count = 1 - [[issues]] file = "src/Connection.php" code = "invalid-iterator" @@ -135,7 +123,7 @@ count = 1 [[issues]] file = "src/Connection.php" code = "mixed-return-statement" -message = "Could not infer a precise return type for function `{closure:src/Connection.php:118:31}`. Saw type `nonnull`." +message = "Could not infer a precise return type for function `{closure:src/Connection.php:119:31}`. Saw type `nonnull`." count = 1 [[issues]] @@ -258,12 +246,6 @@ code = "mixed-argument" message = 'Invalid argument type for argument #1 of `PhpDb\Mysql\Statement::__construct`: expected `bool`, but found `nonnull`.' count = 1 -[[issues]] -file = "src/Driver.php" -code = "docblock-type-mismatch" -message = "Docblock type mismatch for variable `$resource`." -count = 1 - [[issues]] file = "src/Driver.php" code = "incompatible-parameter-type" @@ -456,42 +438,6 @@ code = "unused-property" message = "Property `$numberOfRows` is never used." count = 1 -[[issues]] -file = "src/Sql/SelectDecorator.php" -code = "invalid-property-assignment-value" -message = "Invalid type for property `$specifications`: expected `array>|array`, but got `array{'limit': string('LIMIT 18446744073709551615'), ...>}|array{'limit': string('LIMIT 18446744073709551615'), ...}`." -count = 1 - -[[issues]] -file = "src/Sql/SelectDecorator.php" -code = "invalid-return-statement" -message = 'Invalid return type for function `PhpDb\Mysql\Sql\SelectDecorator::processLimit`: expected `array|null`, but found `list{int|string}`.' -count = 1 - -[[issues]] -file = "src/Sql/SelectDecorator.php" -code = "invalid-return-statement" -message = 'Invalid return type for function `PhpDb\Mysql\Sql\SelectDecorator::processOffset`: expected `array|null`, but found `list{int|string}`.' -count = 1 - -[[issues]] -file = "src/Sql/SelectDecorator.php" -code = "less-specific-nested-return-statement" -message = '''Returned type `list{mixed}` is less specific than the declared return type `array|null` for function `PhpDb\Mysql\Sql\SelectDecorator::processLimit` due to nested 'mixed'.''' -count = 1 - -[[issues]] -file = "src/Sql/SelectDecorator.php" -code = "less-specific-nested-return-statement" -message = '''Returned type `list{mixed}` is less specific than the declared return type `array|null` for function `PhpDb\Mysql\Sql\SelectDecorator::processOffset` due to nested 'mixed'.''' -count = 1 - -[[issues]] -file = "src/Sql/SelectDecorator.php" -code = "possible-method-access-on-null" -message = "Attempting to call a method on `null`." -count = 2 - [[issues]] file = "src/Sql/SelectDecorator.php" code = "write-only-property" diff --git a/composer.lock b/composer.lock index 0453b9d..44f23c6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "66c86539851d7b014c3a1346f3152db0", + "content-hash": "c0726ac42b2f776c7c819829fcfd6ca9", "packages": [ { "name": "brick/varexporter", @@ -262,12 +262,12 @@ "source": { "type": "git", "url": "https://github.com/php-db/phpdb.git", - "reference": "b57f549b411d0b4fe46de8a469983816395be850" + "reference": "0c4ed091d5895168d80faa34f851b4dbc295dc4f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-db/phpdb/zipball/b57f549b411d0b4fe46de8a469983816395be850", - "reference": "b57f549b411d0b4fe46de8a469983816395be850", + "url": "https://api.github.com/repos/php-db/phpdb/zipball/0c4ed091d5895168d80faa34f851b4dbc295dc4f", + "reference": "0c4ed091d5895168d80faa34f851b4dbc295dc4f", "shasum": "" }, "require": { @@ -276,7 +276,6 @@ "php": "~8.3.0 || ~8.4.0 || ~8.5.0" }, "conflict": { - "laminas/laminas-db": "*", "zendframework/zend-db": "*" }, "require-dev": { @@ -322,7 +321,7 @@ "issues": "https://github.com/php-db/phpdb/issues", "source": "https://github.com/php-db/phpdb" }, - "time": "2026-08-24T01:49:39+00:00" + "time": "2026-10-08T01:29:57+00:00" }, { "name": "psr/container", @@ -4485,6 +4484,7 @@ "aliases": [], "minimum-stability": "dev", "stability-flags": { + "php-db/phpdb": 20, "php-db/phpdb-qa-tools": 20 }, "prefer-stable": true, @@ -4499,5 +4499,5 @@ "platform-overrides": { "php": "8.3.99" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/src/Connection.php b/src/Connection.php index 1069a9e..5ccba0c 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -15,6 +15,7 @@ use PhpDb\Adapter\Driver\ResultInterface; use PhpDb\Adapter\Exception; use PhpDb\Adapter\Exception\InvalidArgumentException; +use PhpDb\Exception\ExceptionInterface as PhpDbExceptionInterface; use function constant; use function defined; @@ -64,7 +65,7 @@ public function __construct( /** * @inheritDoc * - * @throws Exception\ExceptionInterface + * @throws PhpDbExceptionInterface */ #[Override] public function beginTransaction(): ConnectionInterface @@ -82,7 +83,7 @@ public function beginTransaction(): ConnectionInterface /** * @inheritDoc * - * @throws Exception\ExceptionInterface + * @throws PhpDbExceptionInterface */ #[Override] public function commit(): ConnectionInterface @@ -101,7 +102,7 @@ public function commit(): ConnectionInterface /** * @inheritDoc * - * @throws Exception\ExceptionInterface + * @throws PhpDbExceptionInterface */ // @mago-expect lint:halstead #[Override] @@ -207,7 +208,7 @@ public function disconnect(): ConnectionInterface /** * {@inheritDoc} * - * @throws Exception\ExceptionInterface + * @throws PhpDbExceptionInterface */ #[Override] public function execute(string $sql): ?ResultInterface @@ -241,7 +242,7 @@ public function execute(string $sql): ?ResultInterface /** * @inheritDoc * - * @throws Exception\ExceptionInterface + * @throws PhpDbExceptionInterface */ #[Override] public function getCurrentSchema(): string|false @@ -287,7 +288,7 @@ public function isConnected(): bool /** * @inheritDoc * - * @throws Exception\ExceptionInterface + * @throws PhpDbExceptionInterface */ #[Override] public function rollback(): ConnectionInterface diff --git a/src/Container/ConnectionInterfaceFactory.php b/src/Container/ConnectionInterfaceFactory.php index 9d18ed9..a05064d 100644 --- a/src/Container/ConnectionInterfaceFactory.php +++ b/src/Container/ConnectionInterfaceFactory.php @@ -6,6 +6,7 @@ use PhpDb\Adapter\Driver\ConnectionInterface; use PhpDb\Adapter\Exception\InvalidConnectionParametersException; +use PhpDb\Exception\ExceptionInterface as PhpDbExceptionInterface; use PhpDb\Mysql\Connection; use Psr\Container\ContainerInterface; @@ -16,7 +17,7 @@ final class ConnectionInterfaceFactory /** * @param array|null $options * - * @throws \PhpDb\Adapter\Exception\ExceptionInterface + * @throws PhpDbExceptionInterface * * @mago-expect analysis:unused-parameter */ diff --git a/src/Container/DriverInterfaceFactory.php b/src/Container/DriverInterfaceFactory.php index 9cfb5b7..fc0d31d 100644 --- a/src/Container/DriverInterfaceFactory.php +++ b/src/Container/DriverInterfaceFactory.php @@ -8,6 +8,7 @@ use PhpDb\Adapter\Driver\DriverInterface; use PhpDb\Adapter\Driver\ResultInterface; use PhpDb\Exception\ContainerException; +use PhpDb\Exception\ExceptionInterface as PhpDbExceptionInterface; use PhpDb\Mysql\Connection; use PhpDb\Mysql\Driver; use PhpDb\Mysql\Result; @@ -24,7 +25,7 @@ final class DriverInterfaceFactory * @throws \Laminas\ServiceManager\Exception\ExceptionInterface * @throws \Psr\Container\ContainerExceptionInterface * @throws \Psr\Container\NotFoundExceptionInterface - * @throws \PhpDb\Exception\ExceptionInterface + * @throws PhpDbExceptionInterface * * @mago-expect analysis:unused-parameter */ diff --git a/src/Container/PdoConnectionInterfaceFactory.php b/src/Container/PdoConnectionInterfaceFactory.php index 8b3abd7..b002507 100644 --- a/src/Container/PdoConnectionInterfaceFactory.php +++ b/src/Container/PdoConnectionInterfaceFactory.php @@ -6,6 +6,7 @@ use PhpDb\Adapter\Driver\PdoConnectionInterface; use PhpDb\Adapter\Exception\InvalidConnectionParametersException; +use PhpDb\Exception\ExceptionInterface as PhpDbExceptionInterface; use PhpDb\Mysql\Pdo\Connection; use Psr\Container\ContainerInterface; @@ -16,7 +17,7 @@ final class PdoConnectionInterfaceFactory /** * @param array|null $options * - * @throws \PhpDb\Adapter\Exception\ExceptionInterface + * @throws PhpDbExceptionInterface * * @mago-expect analysis:unused-parameter */ diff --git a/src/Driver.php b/src/Driver.php index 4f1d8c9..1dae818 100644 --- a/src/Driver.php +++ b/src/Driver.php @@ -15,6 +15,7 @@ use PhpDb\Adapter\Exception; use PhpDb\Adapter\Profiler\ProfilerAwareInterface; use PhpDb\Adapter\Profiler\ProfilerInterface; +use PhpDb\Exception\ExceptionInterface as PhpDbExceptionInterface; use function array_intersect_key; use function extension_loaded; @@ -32,7 +33,7 @@ final class Driver implements DriverInterface, ProfilerAwareInterface /** * @param array $options * - * @throws \PhpDb\Exception\ExceptionInterface + * @throws PhpDbExceptionInterface */ public function __construct( protected readonly ConnectionInterface&Connection $connection, @@ -79,7 +80,7 @@ public function createResult($resource, ?bool $isBuffered = null): ResultInterfa * * @param mysqli|mysqli_stmt|string $sqlOrResource * - * @throws Exception\ExceptionInterface + * @throws PhpDbExceptionInterface */ #[Override] public function createStatement($sqlOrResource = null): StatementInterface&Statement diff --git a/src/Pdo/Connection.php b/src/Pdo/Connection.php index 6bef316..a0da2a4 100644 --- a/src/Pdo/Connection.php +++ b/src/Pdo/Connection.php @@ -11,6 +11,7 @@ use PhpDb\Adapter\Driver\ConnectionInterface; use PhpDb\Adapter\Driver\Pdo\AbstractPdoConnection; use PhpDb\Adapter\Exception; +use PhpDb\Exception\ExceptionInterface as PhpDbExceptionInterface; use function array_diff_key; use function implode; @@ -143,7 +144,7 @@ public function connect(): ConnectionInterface /** * {@inheritDoc} * - * @throws Exception\ExceptionInterface + * @throws PhpDbExceptionInterface * @throws PDOException */ #[Override] @@ -187,7 +188,7 @@ public function getLastGeneratedValue(?string $name = null): string|int|false|nu * Return a value that is safe to interpolate into a generated DSN. * * @todo Promote to AbstractPdoConnection in php-db/phpdb as a protected method once a second - * PDO driver package needs it — the validation is generic to all semicolon-delimited + * PDO driver package needs it; the validation is generic to all semicolon-delimited * PDO DSN formats and has no MySQL-specific dependencies. * * @throws Exception\InvalidConnectionParametersException If the value contains DSN control characters. diff --git a/src/Result.php b/src/Result.php index 4b40b06..674ce08 100644 --- a/src/Result.php +++ b/src/Result.php @@ -11,6 +11,7 @@ use Override; use PhpDb\Adapter\Driver\ResultInterface; use PhpDb\Adapter\Exception; +use PhpDb\Exception\ExceptionInterface as PhpDbExceptionInterface; use PhpDb\ResultSet\ResultSet; use PhpDb\ResultSet\ResultSetInterface; // phpcs:ignore SlevomatCodingStandard.Namespaces.UnusedUses.UnusedUse @@ -91,7 +92,7 @@ public function count() /** * Current * - * @throws Exception\ExceptionInterface + * @throws PhpDbExceptionInterface * * @return array|null */ @@ -277,7 +278,7 @@ public function rewind() /** * Valid * - * @throws Exception\ExceptionInterface + * @throws PhpDbExceptionInterface * * @return bool */ diff --git a/src/Sql/Ddl/AlterTableDecorator.php b/src/Sql/Ddl/AlterTableDecorator.php index 9602678..adf2ddc 100644 --- a/src/Sql/Ddl/AlterTableDecorator.php +++ b/src/Sql/Ddl/AlterTableDecorator.php @@ -30,7 +30,7 @@ public function setSubject( } /** - * @return array> + * @return array{0: list} */ #[Override] protected function processAddColumns(?PlatformInterface $adapterPlatform = null): array @@ -43,11 +43,10 @@ protected function processAddColumns(?PlatformInterface $adapterPlatform = null) /** @var array $addColumns */ $addColumns = $this->addColumns; - foreach ($addColumns as $i => $column) { - /** @var array $options */ + foreach ($addColumns as $column) { $options = $column->getOptions(); - $sqls[$i] = $this->processColumnOptions( + $sqls[] = $this->processColumnOptions( $this->processExpression($column, $platform), $options, $platform, @@ -69,11 +68,9 @@ protected function processChangeColumns(?PlatformInterface $adapterPlatform = nu $sqls = []; - /** @var array $changeColumns */ $changeColumns = $this->changeColumns; foreach ($changeColumns as $name => $column) { - /** @var array $options */ $options = $column->getOptions(); $sqls[] = [ diff --git a/src/Sql/Ddl/CreateTableDecorator.php b/src/Sql/Ddl/CreateTableDecorator.php index 8668233..8eba2c8 100644 --- a/src/Sql/Ddl/CreateTableDecorator.php +++ b/src/Sql/Ddl/CreateTableDecorator.php @@ -48,7 +48,6 @@ protected function processColumns(?PlatformInterface $adapterPlatform = null): ? $columns = $this->columns; foreach ($columns as $i => $column) { - /** @var array $options */ $options = $column->getOptions(); $sqls[$i] = $this->processColumnOptions( diff --git a/src/Sql/SelectDecorator.php b/src/Sql/SelectDecorator.php index 4f05437..2baeaab 100644 --- a/src/Sql/SelectDecorator.php +++ b/src/Sql/SelectDecorator.php @@ -34,7 +34,7 @@ protected function localizeVariables(): void } } - /** @return string[]|null */ + /** @return array{0: string}|null */ #[Override] protected function processLimit( PlatformInterface $platform, @@ -47,16 +47,16 @@ protected function processLimit( if (null === $this->limit) { return null; } - if ($parameterContainer) { + if ($parameterContainer && null !== $driver) { $paramPrefix = $this->processInfo['paramPrefix']; $parameterContainer->offsetSet("{$paramPrefix}limit", $this->limit, ParameterContainer::TYPE_INTEGER); return [$driver->formatParameterName("{$paramPrefix}limit")]; } - return [$this->limit]; + return [(string) $this->limit]; } - /** @return string[]|null */ + /** @return array{0: string}|null */ #[Override] protected function processOffset( PlatformInterface $platform, @@ -66,12 +66,12 @@ protected function processOffset( if (null === $this->offset) { return null; } - if ($parameterContainer) { + if ($parameterContainer && null !== $driver) { $paramPrefix = $this->processInfo['paramPrefix']; $parameterContainer->offsetSet("{$paramPrefix}offset", $this->offset, ParameterContainer::TYPE_INTEGER); return [$driver->formatParameterName("{$paramPrefix}offset")]; } - return [$this->offset]; + return [(string) $this->offset]; } } diff --git a/src/Statement.php b/src/Statement.php index aac76ee..8ba502c 100644 --- a/src/Statement.php +++ b/src/Statement.php @@ -16,6 +16,7 @@ use PhpDb\Adapter\Profiler\ProfilerAwareInterface; use PhpDb\Adapter\Profiler\ProfilerInterface; use PhpDb\Adapter\StatementContainerInterface; +use PhpDb\Exception\ExceptionInterface as PhpDbExceptionInterface; use function array_unshift; use function call_user_func_array; @@ -46,7 +47,7 @@ public function __construct( * * @param array|ParameterContainer|null $parameters * - * @throws Exception\ExceptionInterface + * @throws PhpDbExceptionInterface */ #[Override] public function execute(ParameterContainer|array|null $parameters = null): ?ResultInterface @@ -134,7 +135,7 @@ public function isPrepared(): bool } /** - * @throws Exception\ExceptionInterface + * @throws PhpDbExceptionInterface */ #[Override] public function prepare(?string $sql = null): StatementInterface diff --git a/test/unit/Sql/SelectDecoratorTest.php b/test/unit/Sql/SelectDecoratorTest.php index 65cd091..85db47d 100644 --- a/test/unit/Sql/SelectDecoratorTest.php +++ b/test/unit/Sql/SelectDecoratorTest.php @@ -79,11 +79,18 @@ public function prepareStatementBindsLimitAndOffsetParameters(): void $parameterContainer = new ParameterContainer(); + $sql = ''; $statementContainer = $this->createMock(StatementContainerInterface::class); $statementContainer->method('getParameterContainer')->willReturn($parameterContainer); $statementContainer->expects($this->once()) ->method('setSql') - ->with($this->isString()); + ->willReturnCallback( + static function (?string $sqlString) use (&$sql, $statementContainer): StatementContainerInterface { + $sql = (string) $sqlString; + + return $statementContainer; + }, + ); $driver = $this->createStub(DriverInterface::class); $driver->method('formatParameterName') @@ -98,6 +105,8 @@ public function prepareStatementBindsLimitAndOffsetParameters(): void static::assertSame($statementContainer, $result); static::assertSame(10, $parameterContainer->offsetGet('limit')); static::assertSame(5, $parameterContainer->offsetGet('offset')); + static::assertStringContainsString('LIMIT :limit', $sql); + static::assertStringContainsString('OFFSET :offset', $sql); } #[Test]