From 2d915d977a70f264c21703bcb458084e800c8811 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Sat, 25 Jul 2026 19:56:45 +0200 Subject: [PATCH 01/34] Upgrade to PHP 8.2 minimum, PHPUnit 10, and fix deprecations --- composer.json | 27 +++++++++++++---- examples/logging/SlowRequestHandler.php | 2 ++ .../tarantool16_call/LegacyCallMiddleware.php | 1 + .../tarantool16_call/LegacyCallRequest.php | 2 ++ examples/user_defined_type/EmailExtension.php | 3 ++ src/Connection/StreamConnection.php | 4 +++ src/Handler/DefaultHandler.php | 3 ++ src/Handler/MiddlewareHandler.php | 3 ++ src/Middleware/AuthenticationMiddleware.php | 1 + src/Middleware/CustomErrorMiddleware.php | 1 + src/Middleware/FirewallMiddleware.php | 1 + src/Middleware/LoggingMiddleware.php | 1 + src/Middleware/RetryMiddleware.php | 1 + src/Packer/Extension/DecimalExtension.php | 3 ++ src/Packer/Extension/ErrorExtension.php | 3 ++ src/Packer/Extension/UuidExtension.php | 3 ++ src/Packer/PurePacker.php | 2 ++ src/Request/AuthenticateRequest.php | 2 ++ src/Request/CallRequest.php | 2 ++ src/Request/DeleteRequest.php | 2 ++ src/Request/EvaluateRequest.php | 2 ++ src/Request/ExecuteRequest.php | 2 ++ src/Request/InsertRequest.php | 2 ++ src/Request/PingRequest.php | 2 ++ src/Request/PrepareRequest.php | 2 ++ src/Request/ReplaceRequest.php | 2 ++ src/Request/SelectRequest.php | 2 ++ src/Request/UpdateRequest.php | 2 ++ src/Request/UpsertRequest.php | 2 ++ src/SqlQueryResult.php | 6 ++++ src/SqlUpdateResult.php | 1 + tests/PhpUnitCompat.php | 29 ------------------- 32 files changed, 86 insertions(+), 35 deletions(-) diff --git a/composer.json b/composer.json index 1e1f7b15..1b07b29a 100644 --- a/composer.json +++ b/composer.json @@ -11,18 +11,19 @@ } ], "require": { - "php": "^7.2.5|^8", + "php": ">=8.2", "rybakit/msgpack": "^0.9", "symfony/uid": "^5.1|^6|^7" }, "require-dev": { "ext-json": "*", "ext-sockets": "*", - "friendsofphp/php-cs-fixer": "^2.19", - "monolog/monolog": "^1.24|^2.0", - "psr/log": "^1.1", - "tarantool/phpunit-extras": "^0.2.0", - "vimeo/psalm": "^3.9|^4" + "friendsofphp/php-cs-fixer": "^3.0", + "monolog/monolog": "^3.0", + "phpunit/phpunit": "^10.5", + "psr/log": "^3.0", + "tarantool/phpunit-extras": "dev-feature/php82-phpunit10-attributes-migration", + "vimeo/psalm": "^5.23|^6" }, "suggest": { "ext-decimal": "For using decimals with Tarantool 2.3+", @@ -45,6 +46,20 @@ }, "sort-packages": true }, + "minimum-stability": "dev", + "prefer-stable": true, + "repositories": [ + { + "type": "path", + "url": "/Users/gen/dev/php/phpunit-extras", + "options": { "symlink": true } + }, + { + "type": "path", + "url": "/Users/gen/dev/php/tarantool-php/phpunit-extras", + "options": { "symlink": true } + } + ], "extra": { "branch-alias": { "dev-master": "0.10.x-dev" diff --git a/examples/logging/SlowRequestHandler.php b/examples/logging/SlowRequestHandler.php index fc46596e..7b22ef16 100644 --- a/examples/logging/SlowRequestHandler.php +++ b/examples/logging/SlowRequestHandler.php @@ -42,12 +42,14 @@ public function __construct(HandlerInterface $handler, int $thresholdMs, int $le $this->levelName = Logger::getLevelName($this->level); } + #[\Override] public function isHandling(array $record) : bool { // Handle all levels return true; } + #[\Override] public function handle(array $record) : bool { if (!isset($record['context']['duration_ms'], $record['context']['request'])) { diff --git a/examples/tarantool16_call/LegacyCallMiddleware.php b/examples/tarantool16_call/LegacyCallMiddleware.php index 51bbe225..2a9f42c0 100644 --- a/examples/tarantool16_call/LegacyCallMiddleware.php +++ b/examples/tarantool16_call/LegacyCallMiddleware.php @@ -21,6 +21,7 @@ final class LegacyCallMiddleware implements Middleware { + #[\Override] public function process(Request $request, Handler $handler) : Response { if (!$request instanceof CallRequest) { diff --git a/examples/tarantool16_call/LegacyCallRequest.php b/examples/tarantool16_call/LegacyCallRequest.php index 6b3470b2..308dcc6a 100644 --- a/examples/tarantool16_call/LegacyCallRequest.php +++ b/examples/tarantool16_call/LegacyCallRequest.php @@ -36,11 +36,13 @@ public static function fromCallRequest(CallRequest $request) : self return new self($request->getBody()); } + #[\Override] public function getType() : int { return self::TYPE; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/examples/user_defined_type/EmailExtension.php b/examples/user_defined_type/EmailExtension.php index 085c6f8a..8ab9df90 100644 --- a/examples/user_defined_type/EmailExtension.php +++ b/examples/user_defined_type/EmailExtension.php @@ -26,6 +26,7 @@ public function __construct(int $type) $this->type = $type; } + #[\Override] public function getType() : int { return $this->type; @@ -34,6 +35,7 @@ public function getType() : int /** * @param mixed $value */ + #[\Override] public function pack(Packer $packer, $value) : ?string { if (!$value instanceof Email) { @@ -45,6 +47,7 @@ public function pack(Packer $packer, $value) : ?string ); } + #[\Override] public function unpackExt(BufferUnpacker $unpacker, int $extLength) : Email { return new Email($unpacker->unpackStr()); diff --git a/src/Connection/StreamConnection.php b/src/Connection/StreamConnection.php index f15927c2..6f9c35a6 100644 --- a/src/Connection/StreamConnection.php +++ b/src/Connection/StreamConnection.php @@ -84,6 +84,7 @@ public static function create(string $uri, array $options = []) : self : self::createTcp($uri, $options); } + #[\Override] public function open() : Greeting { if ($this->greeting) { @@ -128,6 +129,7 @@ public function open() : Greeting return $this->greeting = Greeting::parse($greeting); } + #[\Override] public function close() : void { if ($this->stream) { @@ -139,11 +141,13 @@ public function close() : void $this->greeting = null; } + #[\Override] public function isClosed() : bool { return !$this->stream; } + #[\Override] public function send(string $data) : string { if (!$this->stream) { diff --git a/src/Handler/DefaultHandler.php b/src/Handler/DefaultHandler.php index 26984b93..0c3c56e7 100644 --- a/src/Handler/DefaultHandler.php +++ b/src/Handler/DefaultHandler.php @@ -31,6 +31,7 @@ public function __construct(Connection $connection, Packer $packer) $this->packer = $packer; } + #[\Override] public function handle(Request $request) : Response { $packet = $this->packer->pack($request, $sync = \mt_rand()); @@ -51,11 +52,13 @@ public function handle(Request $request) : Response return $response; } + #[\Override] public function getConnection() : Connection { return $this->connection; } + #[\Override] public function getPacker() : Packer { return $this->packer; diff --git a/src/Handler/MiddlewareHandler.php b/src/Handler/MiddlewareHandler.php index 5b0f882b..3a690e81 100644 --- a/src/Handler/MiddlewareHandler.php +++ b/src/Handler/MiddlewareHandler.php @@ -70,6 +70,7 @@ public static function prepend(Handler $handler, array $middleware) : Handler return $handler; } + #[\Override] public function handle(Request $request) : Response { if (!isset($this->middleware[$this->index])) { @@ -82,11 +83,13 @@ public function handle(Request $request) : Response return $this->middleware[$this->index]->process($request, $new); } + #[\Override] public function getConnection() : Connection { return $this->handler->getConnection(); } + #[\Override] public function getPacker() : Packer { return $this->handler->getPacker(); diff --git a/src/Middleware/AuthenticationMiddleware.php b/src/Middleware/AuthenticationMiddleware.php index 3c6788f2..9e581b4f 100644 --- a/src/Middleware/AuthenticationMiddleware.php +++ b/src/Middleware/AuthenticationMiddleware.php @@ -33,6 +33,7 @@ public function __construct(string $username, string $password = '') $this->password = $password; } + #[\Override] public function process(Request $request, Handler $handler) : Response { $greeting = $handler->getConnection()->open(); diff --git a/src/Middleware/CustomErrorMiddleware.php b/src/Middleware/CustomErrorMiddleware.php index d351ca43..75a15304 100644 --- a/src/Middleware/CustomErrorMiddleware.php +++ b/src/Middleware/CustomErrorMiddleware.php @@ -123,6 +123,7 @@ static function (Error $err, RequestFailed $ex) use ($namespace) : \Exception { ); } + #[\Override] public function process(Request $request, Handler $handler) : Response { try { diff --git a/src/Middleware/FirewallMiddleware.php b/src/Middleware/FirewallMiddleware.php index b45c5ddc..c8a26f0b 100644 --- a/src/Middleware/FirewallMiddleware.php +++ b/src/Middleware/FirewallMiddleware.php @@ -99,6 +99,7 @@ public function andDenyOnly(int $requestType, int ...$requestTypes) : self return $new; } + #[\Override] public function process(Request $request, Handler $handler) : Response { $requestType = $request->getType(); diff --git a/src/Middleware/LoggingMiddleware.php b/src/Middleware/LoggingMiddleware.php index 527264bf..c5e07020 100644 --- a/src/Middleware/LoggingMiddleware.php +++ b/src/Middleware/LoggingMiddleware.php @@ -28,6 +28,7 @@ public function __construct(LoggerInterface $logger) $this->logger = $logger; } + #[\Override] public function process(Request $request, Handler $handler) : Response { $requestName = RequestTypes::getName($request->getType()); diff --git a/src/Middleware/RetryMiddleware.php b/src/Middleware/RetryMiddleware.php index 86b7de89..cd9fa3b2 100644 --- a/src/Middleware/RetryMiddleware.php +++ b/src/Middleware/RetryMiddleware.php @@ -66,6 +66,7 @@ public static function custom(\Closure $getDelayMs) : self }); } + #[\Override] public function process(Request $request, Handler $handler) : Response { $retries = 0; diff --git a/src/Packer/Extension/DecimalExtension.php b/src/Packer/Extension/DecimalExtension.php index 6f939ef1..7b18d8c1 100644 --- a/src/Packer/Extension/DecimalExtension.php +++ b/src/Packer/Extension/DecimalExtension.php @@ -23,11 +23,13 @@ final class DecimalExtension implements Extension private const TYPE = 1; private const PRECISION = 38; + #[\Override] public function getType() : int { return self::TYPE; } + #[\Override] public function pack(Packer $packer, $value) : ?string { if (!$value instanceof Decimal) { @@ -60,6 +62,7 @@ public function pack(Packer $packer, $value) : ?string /** * @return Decimal */ + #[\Override] public function unpackExt(BufferUnpacker $unpacker, int $extLength) { /** diff --git a/src/Packer/Extension/ErrorExtension.php b/src/Packer/Extension/ErrorExtension.php index 74b733cd..19224790 100644 --- a/src/Packer/Extension/ErrorExtension.php +++ b/src/Packer/Extension/ErrorExtension.php @@ -23,11 +23,13 @@ final class ErrorExtension implements Extension { private const TYPE = 3; + #[\Override] public function getType() : int { return self::TYPE; } + #[\Override] public function pack(Packer $packer, $value) : ?string { if (!$value instanceof Error) { @@ -49,6 +51,7 @@ public function pack(Packer $packer, $value) : ?string /** * @return Error */ + #[\Override] public function unpackExt(BufferUnpacker $unpacker, int $extLength) { return Error::fromMap($unpacker->unpackMap()); diff --git a/src/Packer/Extension/UuidExtension.php b/src/Packer/Extension/UuidExtension.php index 153265ea..ac9b8540 100644 --- a/src/Packer/Extension/UuidExtension.php +++ b/src/Packer/Extension/UuidExtension.php @@ -22,11 +22,13 @@ final class UuidExtension implements Extension { private const TYPE = 2; + #[\Override] public function getType() : int { return self::TYPE; } + #[\Override] public function pack(Packer $packer, $value) : ?string { if (!$value instanceof Uuid) { @@ -39,6 +41,7 @@ public function pack(Packer $packer, $value) : ?string /** * @return Uuid */ + #[\Override] public function unpackExt(BufferUnpacker $unpacker, int $extLength) { return Uuid::fromString($unpacker->read($extLength)); diff --git a/src/Packer/PurePacker.php b/src/Packer/PurePacker.php index 844b9a45..d6d9326d 100644 --- a/src/Packer/PurePacker.php +++ b/src/Packer/PurePacker.php @@ -68,6 +68,7 @@ public static function fromAvailableExtensions() : self ); } + #[\Override] public function pack(Request $request, int $sync) : string { // Hot path optimization @@ -78,6 +79,7 @@ public function pack(Request $request, int $sync) : string return PacketLength::pack(\strlen($packet)).$packet; } + #[\Override] public function unpack(string $packet) : Response { $this->unpacker->reset($packet); diff --git a/src/Request/AuthenticateRequest.php b/src/Request/AuthenticateRequest.php index 5d28a99c..4afc7120 100644 --- a/src/Request/AuthenticateRequest.php +++ b/src/Request/AuthenticateRequest.php @@ -32,11 +32,13 @@ public function __construct(string $salt, string $username, string $password = ' ]; } + #[\Override] public function getType() : int { return RequestTypes::AUTHENTICATE; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/CallRequest.php b/src/Request/CallRequest.php index ec1a9d6b..f45878fb 100644 --- a/src/Request/CallRequest.php +++ b/src/Request/CallRequest.php @@ -29,11 +29,13 @@ public function __construct(string $funcName, array $args = []) ]; } + #[\Override] public function getType() : int { return RequestTypes::CALL; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/DeleteRequest.php b/src/Request/DeleteRequest.php index 5b6a5a28..a3a1371d 100644 --- a/src/Request/DeleteRequest.php +++ b/src/Request/DeleteRequest.php @@ -30,11 +30,13 @@ public function __construct(int $spaceId, int $indexId, array $key) ]; } + #[\Override] public function getType() : int { return RequestTypes::DELETE; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/EvaluateRequest.php b/src/Request/EvaluateRequest.php index fa7b8813..4a4f9b1e 100644 --- a/src/Request/EvaluateRequest.php +++ b/src/Request/EvaluateRequest.php @@ -29,11 +29,13 @@ public function __construct(string $expr, array $args = []) ]; } + #[\Override] public function getType() : int { return RequestTypes::EVALUATE; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/ExecuteRequest.php b/src/Request/ExecuteRequest.php index 61c304a3..c1819134 100644 --- a/src/Request/ExecuteRequest.php +++ b/src/Request/ExecuteRequest.php @@ -49,11 +49,13 @@ public static function fromStatementId(int $statementId, array $params = []) : s ]); } + #[\Override] public function getType() : int { return RequestTypes::EXECUTE; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/InsertRequest.php b/src/Request/InsertRequest.php index ee809ffd..75e64bc8 100644 --- a/src/Request/InsertRequest.php +++ b/src/Request/InsertRequest.php @@ -29,11 +29,13 @@ public function __construct(int $spaceId, array $tuple) ]; } + #[\Override] public function getType() : int { return RequestTypes::INSERT; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/PingRequest.php b/src/Request/PingRequest.php index 48b27336..1d2262ca 100644 --- a/src/Request/PingRequest.php +++ b/src/Request/PingRequest.php @@ -17,11 +17,13 @@ final class PingRequest implements Request { + #[\Override] public function getType() : int { return RequestTypes::PING; } + #[\Override] public function getBody() : array { return []; diff --git a/src/Request/PrepareRequest.php b/src/Request/PrepareRequest.php index 94a87e35..c71128f6 100644 --- a/src/Request/PrepareRequest.php +++ b/src/Request/PrepareRequest.php @@ -39,11 +39,13 @@ public static function fromStatementId(int $statementId) : self return new self([Keys::STMT_ID => $statementId]); } + #[\Override] public function getType() : int { return RequestTypes::PREPARE; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/ReplaceRequest.php b/src/Request/ReplaceRequest.php index 3c100c32..5b613e99 100644 --- a/src/Request/ReplaceRequest.php +++ b/src/Request/ReplaceRequest.php @@ -29,11 +29,13 @@ public function __construct(int $spaceId, array $tuple) ]; } + #[\Override] public function getType() : int { return RequestTypes::REPLACE; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/SelectRequest.php b/src/Request/SelectRequest.php index 6b7a7193..edd32ef9 100644 --- a/src/Request/SelectRequest.php +++ b/src/Request/SelectRequest.php @@ -33,11 +33,13 @@ public function __construct(int $spaceId, int $indexId, array $key, int $offset, ]; } + #[\Override] public function getType() : int { return RequestTypes::SELECT; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/UpdateRequest.php b/src/Request/UpdateRequest.php index dc0853d3..4c16b0b1 100644 --- a/src/Request/UpdateRequest.php +++ b/src/Request/UpdateRequest.php @@ -31,11 +31,13 @@ public function __construct(int $spaceId, int $indexId, array $key, array $opera ]; } + #[\Override] public function getType() : int { return RequestTypes::UPDATE; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/UpsertRequest.php b/src/Request/UpsertRequest.php index 4e9bf70a..ee303e41 100644 --- a/src/Request/UpsertRequest.php +++ b/src/Request/UpsertRequest.php @@ -30,11 +30,13 @@ public function __construct(int $spaceId, array $tuple, array $operations) ]; } + #[\Override] public function getType() : int { return RequestTypes::UPSERT; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/SqlQueryResult.php b/src/SqlQueryResult.php index b517ecf1..7a7f8a31 100644 --- a/src/SqlQueryResult.php +++ b/src/SqlQueryResult.php @@ -56,6 +56,7 @@ public function getLast() : ?array return $this->data ? \array_combine($this->keys, \end($this->data)) : null; } + #[\Override] public function getIterator() : \Generator { foreach ($this->data as $item) { @@ -63,16 +64,19 @@ public function getIterator() : \Generator } } + #[\Override] public function count() : int { return \count($this->data); } + #[\Override] public function offsetExists($offset) : bool { return isset($this->data[$offset]); } + #[\Override] public function offsetGet($offset) : array { if (!isset($this->data[$offset])) { @@ -82,11 +86,13 @@ public function offsetGet($offset) : array return \array_combine($this->keys, $this->data[$offset]); } + #[\Override] public function offsetSet($offset, $value) : void { throw new \BadMethodCallException(self::class.' object cannot be modified'); } + #[\Override] public function offsetUnset($offset) : void { throw new \BadMethodCallException(self::class.' object cannot be modified'); diff --git a/src/SqlUpdateResult.php b/src/SqlUpdateResult.php index 27ff604a..9b901695 100644 --- a/src/SqlUpdateResult.php +++ b/src/SqlUpdateResult.php @@ -22,6 +22,7 @@ public function __construct(array $info) $this->info = $info; } + #[\Override] public function count() : int { return $this->info[Keys::SQL_INFO_ROW_COUNT]; diff --git a/tests/PhpUnitCompat.php b/tests/PhpUnitCompat.php index 38c63620..19c5ea49 100644 --- a/tests/PhpUnitCompat.php +++ b/tests/PhpUnitCompat.php @@ -18,33 +18,4 @@ */ trait PhpUnitCompat { - /** - * TestCase::expectExceptionMessageRegExp() is deprecated since PHPUnit 8.4. - */ - public function expectExceptionMessageMatches(string $regularExpression) : void - { - is_callable(parent::class.'::expectExceptionMessageMatches') - ? parent::expectExceptionMessageMatches(...func_get_args()) - : parent::expectExceptionMessageRegExp(...func_get_args()); - } - - /** - * Assert::assertEquals()'s $delta, $maxDepth, $canonicalize parameters are deprecated since PHPUnit 8.0. - */ - public static function assertEqualsCanonicalizing($expected, $actual, string $message = '') : void - { - is_callable(parent::class.'::assertEqualsCanonicalizing') - ? parent::assertEqualsCanonicalizing($expected, $actual, $message) - : parent::assertEquals($expected, $actual, $message, 0.0, 10, true); - } - - /** - * Assert::assertRegExp() is deprecated since PHPUnit 9.1. - */ - public static function assertMatchesRegularExpression(string $pattern, string $string, string $message = '') : void - { - is_callable(parent::class.'::assertMatchesRegularExpression') - ? parent::assertMatchesRegularExpression(...func_get_args()) - : parent::assertRegExp(...func_get_args()); - } } From 165571929d496f74ed18ad24c8f282d6e1c5e0be Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Sat, 25 Jul 2026 20:11:01 +0200 Subject: [PATCH 02/34] Use ^8.2 for PHP constraint --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 1b07b29a..0a6d265e 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ } ], "require": { - "php": ">=8.2", + "php": "^8.2", "rybakit/msgpack": "^0.9", "symfony/uid": "^5.1|^6|^7" }, From 9ce1156a03a6910d826ad658042ee1f1c5f3c90c Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Sat, 25 Jul 2026 20:16:48 +0200 Subject: [PATCH 03/34] Remove PhpUnitCompat completely --- .../MessagePack/MessagePackTest.php | 2 +- tests/Integration/TestCase.php | 2 +- tests/PhpUnitCompat.php | 21 ------------------- tests/Unit/ClientFactoryTest.php | 2 +- .../Unit/Connection/StreamConnectionTest.php | 2 +- 5 files changed, 4 insertions(+), 25 deletions(-) delete mode 100644 tests/PhpUnitCompat.php diff --git a/tests/Integration/MessagePack/MessagePackTest.php b/tests/Integration/MessagePack/MessagePackTest.php index 4a6248cf..25534650 100755 --- a/tests/Integration/MessagePack/MessagePackTest.php +++ b/tests/Integration/MessagePack/MessagePackTest.php @@ -21,7 +21,7 @@ final class MessagePackTest extends TestCase { - use PhpUnitCompat; + /** * @dataProvider providePackUnpackData diff --git a/tests/Integration/TestCase.php b/tests/Integration/TestCase.php index 15a97e39..166a1924 100644 --- a/tests/Integration/TestCase.php +++ b/tests/Integration/TestCase.php @@ -25,7 +25,7 @@ abstract class TestCase extends BaseTestCase { - use PhpUnitCompat; + /** @var Client|null */ protected $client; diff --git a/tests/PhpUnitCompat.php b/tests/PhpUnitCompat.php deleted file mode 100644 index 19c5ea49..00000000 --- a/tests/PhpUnitCompat.php +++ /dev/null @@ -1,21 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace Tarantool\Client\Tests; - -/** - * Compatibility layer for legacy PHPUnit versions. - */ -trait PhpUnitCompat -{ -} diff --git a/tests/Unit/ClientFactoryTest.php b/tests/Unit/ClientFactoryTest.php index d437489d..99cba5bb 100644 --- a/tests/Unit/ClientFactoryTest.php +++ b/tests/Unit/ClientFactoryTest.php @@ -21,7 +21,7 @@ final class ClientFactoryTest extends TestCase { - use PhpUnitCompat; + public function testFromDefaultsCreatesClientWithPurePacker() : void { diff --git a/tests/Unit/Connection/StreamConnectionTest.php b/tests/Unit/Connection/StreamConnectionTest.php index 715e9c19..afb78604 100644 --- a/tests/Unit/Connection/StreamConnectionTest.php +++ b/tests/Unit/Connection/StreamConnectionTest.php @@ -19,7 +19,7 @@ final class StreamConnectionTest extends TestCase { - use PhpUnitCompat; + /** * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideConnectionArrayOptionsOfValidTypes From 54a34888cf1730543f69a53a07febe72bbe9c6b7 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Sat, 25 Jul 2026 20:31:11 +0200 Subject: [PATCH 04/34] Drop unsupported PHP versions from CI matrix --- .github/workflows/qa.yml | 34 +++++----------------------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index d56e5dd6..eb86492a 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -35,44 +35,20 @@ jobs: TNT_LISTEN_URI: /tmp/tarantool_client.sock - PHP_IMAGE: php:8.2-cli - - PHP_IMAGE: php:8.2-cli - TNT_LISTEN_URI: /tmp/tarantool_client.sock - - - PHP_IMAGE: php:8.1-cli - - PHP_IMAGE: php:8.1-cli - TNT_LISTEN_URI: /tmp/tarantool_client.sock - - - PHP_IMAGE: php:8.0-cli - - PHP_IMAGE: php:8.0-cli - TNT_LISTEN_URI: /tmp/tarantool_client.sock - - - PHP_IMAGE: php:7.4-cli - - PHP_IMAGE: php:7.4-cli - TNT_LISTEN_URI: /tmp/tarantool_client.sock - - - PHP_IMAGE: php:7.3-cli QA: 1 - - PHP_IMAGE: php:7.3-cli - TNT_LISTEN_URI: /tmp/tarantool_client.sock - - - PHP_IMAGE: php:7.2-cli - - PHP_IMAGE: php:7.2-cli + - PHP_IMAGE: php:8.2-cli TNT_LISTEN_URI: /tmp/tarantool_client.sock - COVERAGE_FILE: coverage.clover - # scrutinizer doesn't support PHP 8 - PHP_IMAGE: php:7.4-cli + PHP_IMAGE: php:8.2-cli - COVERAGE_FILE: coverage.clover - # scrutinizer doesn't support PHP 8 - PHP_IMAGE: php:7.4-cli + PHP_IMAGE: php:8.2-cli EXT_DISABLE_DECIMAL: true - COVERAGE_FILE: coverage.clover - # scrutinizer doesn't support PHP 8 - PHP_IMAGE: php:7.4-cli + PHP_IMAGE: php:8.2-cli TNT_LISTEN_URI: /tmp/tarantool_client.sock - COVERAGE_FILE: coverage.clover - # scrutinizer doesn't support PHP 8 - PHP_IMAGE: php:7.4-cli + PHP_IMAGE: php:8.2-cli # some tests are skipped on Tarantool > 2.8 TNT_IMAGE: tarantool/tarantool:2.8 From ef8f89771b0a19451f98e996626f4efccc2c4b52 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Sat, 25 Jul 2026 20:34:34 +0200 Subject: [PATCH 05/34] Fix composer repositories for CI --- composer.json | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index 0a6d265e..a504cf9d 100644 --- a/composer.json +++ b/composer.json @@ -50,14 +50,12 @@ "prefer-stable": true, "repositories": [ { - "type": "path", - "url": "/Users/gen/dev/php/phpunit-extras", - "options": { "symlink": true } + "type": "vcs", + "url": "https://github.com/rybakit/phpunit-extras" }, { - "type": "path", - "url": "/Users/gen/dev/php/tarantool-php/phpunit-extras", - "options": { "symlink": true } + "type": "vcs", + "url": "https://github.com/tarantool-php/phpunit-extras" } ], "extra": { From 6db5877b1586b759966ce05ae23f85bf8cebf998 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Sat, 25 Jul 2026 20:44:46 +0200 Subject: [PATCH 06/34] Use no-api for composer VCS repositories to prevent GitHub rate limits --- composer.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index a504cf9d..a5cc4961 100644 --- a/composer.json +++ b/composer.json @@ -51,11 +51,13 @@ "repositories": [ { "type": "vcs", - "url": "https://github.com/rybakit/phpunit-extras" + "url": "https://github.com/rybakit/phpunit-extras", + "no-api": true }, { "type": "vcs", - "url": "https://github.com/tarantool-php/phpunit-extras" + "url": "https://github.com/tarantool-php/phpunit-extras", + "no-api": true } ], "extra": { From 7105451a0283fc238cf01271dc93ee8cdcc07e39 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Sat, 25 Jul 2026 20:48:31 +0200 Subject: [PATCH 07/34] Fix code style issues for php-cs-fixer 3.0 --- .php-cs-fixer.dist.php | 5 +++ examples/custom_error/example.php | 2 +- examples/logging/example.php | 2 +- examples/protocol/delete.php | 5 ++- examples/protocol/insert.php | 5 ++- examples/protocol/replace.php | 5 ++- examples/protocol/select.php | 5 ++- examples/protocol/select_with_sorting.php | 5 ++- examples/protocol/update.php | 5 ++- examples/protocol/upsert.php | 5 ++- examples/user_defined_type/EmailExtension.php | 3 -- .../user_defined_type/example_decimal.php | 5 ++- examples/user_defined_type/example_email.php | 5 ++- examples/user_defined_type/example_uuid.php | 5 ++- src/Client.php | 15 --------- src/Connection/Greeting.php | 8 ++--- src/Connection/StreamConnection.php | 20 ++++++------ src/Dsn.php | 32 +++++++++---------- src/Error.php | 9 +----- src/Exception/CommunicationFailed.php | 2 +- src/Exception/RequestDenied.php | 2 +- src/Handler/DefaultHandler.php | 2 +- src/Handler/MiddlewareHandler.php | 4 +-- src/Middleware/CustomErrorMiddleware.php | 4 +-- src/Middleware/FirewallMiddleware.php | 12 +++---- src/Middleware/LoggingMiddleware.php | 6 ++-- src/Middleware/RetryMiddleware.php | 12 +++---- src/Packer/Extension/DecimalExtension.php | 16 +++++----- src/Packer/PacketLength.php | 2 +- src/Packer/PurePacker.php | 2 +- src/PreparedStatement.php | 9 ------ src/Request/AuthenticateRequest.php | 6 ++-- src/Response.php | 8 ----- src/Schema/Criteria.php | 4 +-- src/Schema/Operations.php | 2 -- src/Schema/Space.php | 4 +-- src/SqlQueryResult.php | 10 +++--- tests/GreetingDataProvider.php | 4 +-- tests/Integration/ClientBuilder.php | 8 ++--- tests/Integration/ClientMiddlewareTest.php | 2 +- tests/Integration/ExamplesTest.php | 2 +- .../MessagePack/MessagePackTest.php | 3 -- tests/Integration/TestCase.php | 3 -- tests/Unit/ClientFactoryTest.php | 3 -- .../Unit/Connection/StreamConnectionTest.php | 3 -- tests/Unit/Middleware/RetryMiddlewareTest.php | 1 + 46 files changed, 111 insertions(+), 171 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 29a475da..e349fe34 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -46,6 +46,11 @@ public function getPriority() : int return $this->fixer->getPriority(); } + public function getDefinition() : \PhpCsFixer\FixerDefinition\FixerDefinitionInterface + { + return $this->fixer->getDefinition(); + } + public function supports(\SplFileInfo $file) : bool { if (1 !== preg_match($this->pathRegex, $file->getRealPath())) { diff --git a/examples/custom_error/example.php b/examples/custom_error/example.php index b0ef4875..1b9e9114 100644 --- a/examples/custom_error/example.php +++ b/examples/custom_error/example.php @@ -31,7 +31,7 @@ reason = "User #99 not found", })'); } catch (UserNotFound $e) { - printf("%s: [%d] %s\n", get_class($e), $e->getCode(), $e->getMessage()); + printf("%s: [%d] %s\n", $e::class, $e->getCode(), $e->getMessage()); } /* OUTPUT diff --git a/examples/logging/example.php b/examples/logging/example.php index f7f9eb3b..8de894c3 100644 --- a/examples/logging/example.php +++ b/examples/logging/example.php @@ -19,7 +19,7 @@ $loader = require __DIR__.'/../bootstrap.php'; $loader->addPsr4('App\\', __DIR__); -$stream = new StreamHandler('php://stdout' /*, Logger::WARNING */); +$stream = new StreamHandler('php://stdout' /* , Logger::WARNING */); $logger = new Logger('example'); $logger->pushHandler($stream); diff --git a/examples/protocol/delete.php b/examples/protocol/delete.php index 9a278044..dc09dc75 100644 --- a/examples/protocol/delete.php +++ b/examples/protocol/delete.php @@ -17,7 +17,7 @@ $spaceName = 'example'; $client->evaluate( -<<getSpace($spaceName); $result1 = $space->delete([2]); diff --git a/examples/protocol/insert.php b/examples/protocol/insert.php index a17ed637..80fc4759 100644 --- a/examples/protocol/insert.php +++ b/examples/protocol/insert.php @@ -17,12 +17,11 @@ $spaceName = 'example'; $client->evaluate( -<<getSpace($spaceName); $result = $space->insert([1, 'foo', 'bar']); diff --git a/examples/protocol/replace.php b/examples/protocol/replace.php index 9e410ed7..b99837f7 100644 --- a/examples/protocol/replace.php +++ b/examples/protocol/replace.php @@ -17,14 +17,13 @@ $spaceName = 'example'; $client->evaluate( -<<getSpace($spaceName); $result1 = $space->replace([2, 'BAR']); diff --git a/examples/protocol/select.php b/examples/protocol/select.php index f9640ff2..9362ca1c 100644 --- a/examples/protocol/select.php +++ b/examples/protocol/select.php @@ -19,7 +19,7 @@ $spaceName = 'example'; $client->evaluate( -<<getSpace($spaceName); $result1 = $space->select(Criteria::key([1])); diff --git a/examples/protocol/select_with_sorting.php b/examples/protocol/select_with_sorting.php index b2ddb833..ab6a7c69 100644 --- a/examples/protocol/select_with_sorting.php +++ b/examples/protocol/select_with_sorting.php @@ -19,7 +19,7 @@ $spaceName = 'cars'; $client->evaluate( -<<getSpace($spaceName); diff --git a/examples/protocol/update.php b/examples/protocol/update.php index af51bd28..45453b89 100644 --- a/examples/protocol/update.php +++ b/examples/protocol/update.php @@ -19,7 +19,7 @@ $spaceName = 'example'; $client->evaluate( -<<getSpace($spaceName); diff --git a/examples/protocol/upsert.php b/examples/protocol/upsert.php index f2344ab9..a61d275e 100644 --- a/examples/protocol/upsert.php +++ b/examples/protocol/upsert.php @@ -20,7 +20,7 @@ $spaceName = 'example'; $client->evaluate( -<<getSpace($spaceName); $space->upsert([1, 'foo', 'bar'], Operations::set(1, 'baz')); diff --git a/examples/user_defined_type/EmailExtension.php b/examples/user_defined_type/EmailExtension.php index 8ab9df90..ba5cbf98 100644 --- a/examples/user_defined_type/EmailExtension.php +++ b/examples/user_defined_type/EmailExtension.php @@ -32,9 +32,6 @@ public function getType() : int return $this->type; } - /** - * @param mixed $value - */ #[\Override] public function pack(Packer $packer, $value) : ?string { diff --git a/examples/user_defined_type/example_decimal.php b/examples/user_defined_type/example_decimal.php index c80740e9..056b59b0 100644 --- a/examples/user_defined_type/example_decimal.php +++ b/examples/user_defined_type/example_decimal.php @@ -23,12 +23,11 @@ $spaceName = 'example'; $client->evaluate( -<<getSpace($spaceName); diff --git a/examples/user_defined_type/example_email.php b/examples/user_defined_type/example_email.php index 5cbf93ba..7611c76c 100644 --- a/examples/user_defined_type/example_email.php +++ b/examples/user_defined_type/example_email.php @@ -24,12 +24,11 @@ $spaceName = 'example'; $client->evaluate( -<<getSpace($spaceName); diff --git a/examples/user_defined_type/example_uuid.php b/examples/user_defined_type/example_uuid.php index 381268e8..1b9e0cd0 100644 --- a/examples/user_defined_type/example_uuid.php +++ b/examples/user_defined_type/example_uuid.php @@ -22,14 +22,13 @@ $spaceName = 'example'; $client->evaluate( -<<getSpace($spaceName); diff --git a/src/Client.php b/src/Client.php index e93fea27..4bdf6345 100644 --- a/src/Client.php +++ b/src/Client.php @@ -170,35 +170,23 @@ public function ping() : void $this->handler->handle(new PingRequest()); } - /** - * @param mixed ...$args - */ public function call(string $funcName, ...$args) : array { return $this->handler->handle(new CallRequest($funcName, $args)) ->getBodyField(Keys::DATA); } - /** - * @param mixed ...$args - */ public function evaluate(string $expr, ...$args) : array { return $this->handler->handle(new EvaluateRequest($expr, $args)) ->getBodyField(Keys::DATA); } - /** - * @param mixed ...$params - */ public function execute(string $sql, ...$params) : Response { return $this->handler->handle(ExecuteRequest::fromSql($sql, $params)); } - /** - * @param mixed ...$params - */ public function executeQuery(string $sql, ...$params) : SqlQueryResult { $response = $this->handler->handle(ExecuteRequest::fromSql($sql, $params)); @@ -209,9 +197,6 @@ public function executeQuery(string $sql, ...$params) : SqlQueryResult ); } - /** - * @param mixed ...$params - */ public function executeUpdate(string $sql, ...$params) : SqlUpdateResult { $response = $this->handler->handle(ExecuteRequest::fromSql($sql, $params)); diff --git a/src/Connection/Greeting.php b/src/Connection/Greeting.php index 8f6d0021..58cdce4c 100644 --- a/src/Connection/Greeting.php +++ b/src/Connection/Greeting.php @@ -41,7 +41,7 @@ private function __construct($greeting) public static function parse(string $greeting) : self { - if (0 === \strpos($greeting, 'Tarantool')) { + if (str_starts_with($greeting, 'Tarantool')) { return new self($greeting); } @@ -66,11 +66,11 @@ public function getSalt() : string throw new \BadMethodCallException('Salt is unknown for persistent connections'); } - if (false === $salt = \base64_decode(\substr($this->greeting, 64, 44), true)) { + if (false === $salt = base64_decode(substr($this->greeting, 64, 44), true)) { throw new UnexpectedResponse('Unable to decode salt'); } - $salt = \substr($salt, 0, 20); + $salt = substr($salt, 0, 20); if (isset($salt[19])) { return $this->salt = $salt; @@ -89,7 +89,7 @@ public function getServerVersion() : string throw new \BadMethodCallException('Server version is unknown for persistent connections'); } - return $this->serverVersion = \substr($this->greeting, 10, \strspn($this->greeting, '0123456789.', 10)); + return $this->serverVersion = substr($this->greeting, 10, strspn($this->greeting, '0123456789.', 10)); } public function equals(?self $greeting) : bool diff --git a/src/Connection/StreamConnection.php b/src/Connection/StreamConnection.php index 6f9c35a6..e7aeff53 100644 --- a/src/Connection/StreamConnection.php +++ b/src/Connection/StreamConnection.php @@ -53,7 +53,7 @@ private function __construct($uri, float $connectTimeout, float $socketTimeout, $this->persistent = $persistent; if ($tcpNoDelay) { - $this->streamContext = \stream_context_create(['socket' => ['tcp_nodelay' => true]]); + $this->streamContext = stream_context_create(['socket' => ['tcp_nodelay' => true]]); } } @@ -79,7 +79,7 @@ public static function createUds(string $uri, array $options = []) : self public static function create(string $uri, array $options = []) : self { - return 0 === \strpos($uri, 'unix://') + return str_starts_with($uri, 'unix://') ? self::createUds($uri, $options) : self::createTcp($uri, $options); } @@ -95,14 +95,14 @@ public function open() : Greeting ? \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_PERSISTENT : \STREAM_CLIENT_CONNECT; - $stream = $this->streamContext ? @\stream_socket_client( + $stream = $this->streamContext ? @stream_socket_client( $this->uri, $errorCode, $errorMessage, $this->connectTimeout, $flags, $this->streamContext - ) : @\stream_socket_client( + ) : @stream_socket_client( $this->uri, $errorCode, $errorMessage, @@ -116,11 +116,11 @@ public function open() : Greeting $socketTimeoutSeconds = (int) $this->socketTimeout; $socketTimeoutMicroSeconds = (int) (($this->socketTimeout - $socketTimeoutSeconds) * 1000000); - \stream_set_timeout($stream, $socketTimeoutSeconds, $socketTimeoutMicroSeconds); + stream_set_timeout($stream, $socketTimeoutSeconds, $socketTimeoutMicroSeconds); $this->stream = $stream; - if ($this->persistent && \ftell($stream)) { + if ($this->persistent && ftell($stream)) { return $this->greeting = Greeting::unknown(); } @@ -134,7 +134,7 @@ public function close() : void { if ($this->stream) { /** @psalm-suppress InvalidPropertyAssignmentValue */ - \fclose($this->stream); + fclose($this->stream); } $this->stream = null; @@ -154,7 +154,7 @@ public function send(string $data) : string throw new CommunicationFailed('Error writing request: connection closed'); } - if (!\fwrite($this->stream, $data)) { + if (!fwrite($this->stream, $data)) { throw CommunicationFailed::withLastPhpError('Error writing request'); } @@ -167,12 +167,12 @@ public function send(string $data) : string private function read(int $length, string $errorMessage) : string { /** @psalm-suppress PossiblyNullArgument */ - if ($data = \stream_get_contents($this->stream, $length)) { + if ($data = stream_get_contents($this->stream, $length)) { return $data; } /** @psalm-suppress PossiblyNullArgument */ - $meta = \stream_get_meta_data($this->stream); + $meta = stream_get_meta_data($this->stream); if ($meta['timed_out']) { throw new CommunicationFailed('Read timed out'); } diff --git a/src/Dsn.php b/src/Dsn.php index 8dcc527f..7f8633a6 100644 --- a/src/Dsn.php +++ b/src/Dsn.php @@ -52,11 +52,11 @@ private function __construct($connectionUri) public static function parse(string $dsn) : self { - if (0 === \strpos($dsn, 'unix://') && isset($dsn[7])) { + if (str_starts_with($dsn, 'unix://') && isset($dsn[7])) { return self::parseUds($dsn); } - if (false === $parsed = \parse_url($dsn)) { + if (false === $parsed = parse_url($dsn)) { self::throwParseError($dsn); } if (!isset($parsed['scheme'], $parsed['host']) || 'tcp' !== $parsed['scheme']) { @@ -72,12 +72,12 @@ public static function parse(string $dsn) : self $self->isTcp = true; if (isset($parsed['user'])) { - $self->username = \rawurldecode($parsed['user']); - $self->password = isset($parsed['pass']) ? \rawurldecode($parsed['pass']) : ''; + $self->username = rawurldecode($parsed['user']); + $self->password = isset($parsed['pass']) ? rawurldecode($parsed['pass']) : ''; } if (isset($parsed['query'])) { - \parse_str($parsed['query'], $self->options); + parse_str($parsed['query'], $self->options); } return $self; @@ -85,12 +85,12 @@ public static function parse(string $dsn) : self private static function parseUds(string $dsn) : self { - $parts = \explode('@', \substr($dsn, 7), 2); + $parts = explode('@', substr($dsn, 7), 2); if (isset($parts[1])) { - $parsed = \parse_url($parts[1]); - $authority = \explode(':', $parts[0]); + $parsed = parse_url($parts[1]); + $authority = explode(':', $parts[0]); } else { - $parsed = \parse_url($parts[0]); + $parsed = parse_url($parts[0]); } if (false === $parsed) { @@ -101,15 +101,15 @@ private static function parseUds(string $dsn) : self } $self = new self('unix://'.$parsed['path']); - $self->path = \rawurldecode($parsed['path']); + $self->path = rawurldecode($parsed['path']); if (isset($authority)) { - $self->username = \rawurldecode($authority[0]); - $self->password = isset($authority[1]) ? \rawurldecode($authority[1]) : ''; + $self->username = rawurldecode($authority[0]); + $self->password = isset($authority[1]) ? rawurldecode($authority[1]) : ''; } if (isset($parsed['query'])) { - \parse_str($parsed['query'], $self->options); + parse_str($parsed['query'], $self->options); } return $self; @@ -161,7 +161,7 @@ public function getBool(string $name, ?bool $default = null) : ?bool return $default; } - if (null === $value = \filter_var($this->options[$name], \FILTER_VALIDATE_BOOLEAN, \FILTER_NULL_ON_FAILURE)) { + if (null === $value = filter_var($this->options[$name], \FILTER_VALIDATE_BOOLEAN, \FILTER_NULL_ON_FAILURE)) { throw new \TypeError(\sprintf('DSN option "%s" must be of type bool', $name)); } @@ -174,7 +174,7 @@ public function getInt(string $name, ?int $default = null) : ?int return $default; } - if (false === $value = \filter_var($this->options[$name], \FILTER_VALIDATE_INT)) { + if (false === $value = filter_var($this->options[$name], \FILTER_VALIDATE_INT)) { throw new \TypeError(\sprintf('DSN option "%s" must be of type int', $name)); } @@ -187,7 +187,7 @@ public function getFloat(string $name, ?float $default = null) : ?float return $default; } - if (false === $value = \filter_var($this->options[$name], \FILTER_VALIDATE_FLOAT)) { + if (false === $value = filter_var($this->options[$name], \FILTER_VALIDATE_FLOAT)) { throw new \TypeError(\sprintf('DSN option "%s" must be of type float', $name)); } diff --git a/src/Error.php b/src/Error.php index f49155bd..485dbd0c 100644 --- a/src/Error.php +++ b/src/Error.php @@ -32,7 +32,7 @@ public function __construct( int $number, int $code, array $fields = [], - ?self $previous = null + ?self $previous = null, ) { $this->type = $type; $this->file = $file; @@ -138,9 +138,6 @@ public function getFields() : array return $this->fields; } - /** - * @return mixed - */ public function getField(string $name) { if (\array_key_exists($name, $this->fields)) { @@ -150,10 +147,6 @@ public function getField(string $name) throw new \OutOfRangeException(\sprintf('The field "%s" does not exist', $name)); } - /** - * @param mixed $default - * @return mixed - */ public function tryGetField(string $name, $default = null) { return \array_key_exists($name, $this->fields) ? $this->fields[$name] : $default; diff --git a/src/Exception/CommunicationFailed.php b/src/Exception/CommunicationFailed.php index bda6af40..6a221d01 100644 --- a/src/Exception/CommunicationFailed.php +++ b/src/Exception/CommunicationFailed.php @@ -17,7 +17,7 @@ final class CommunicationFailed extends \RuntimeException implements ClientExcep { public static function withLastPhpError(string $errorMessage) : self { - $error = \error_get_last(); + $error = error_get_last(); return new self($error ? \sprintf('%s: %s', $errorMessage, $error['message']) : $errorMessage); } diff --git a/src/Exception/RequestDenied.php b/src/Exception/RequestDenied.php index b1b8689c..37b0bbef 100644 --- a/src/Exception/RequestDenied.php +++ b/src/Exception/RequestDenied.php @@ -19,6 +19,6 @@ final class RequestDenied extends \RuntimeException implements ClientException { public static function fromObject(Request $request) : self { - return new self(\sprintf('Request "%s" is denied', \get_class($request))); + return new self(\sprintf('Request "%s" is denied', $request::class)); } } diff --git a/src/Handler/DefaultHandler.php b/src/Handler/DefaultHandler.php index 0c3c56e7..2d5af603 100644 --- a/src/Handler/DefaultHandler.php +++ b/src/Handler/DefaultHandler.php @@ -34,7 +34,7 @@ public function __construct(Connection $connection, Packer $packer) #[\Override] public function handle(Request $request) : Response { - $packet = $this->packer->pack($request, $sync = \mt_rand()); + $packet = $this->packer->pack($request, $sync = mt_rand()); $this->connection->open(); $packet = $this->connection->send($packet); diff --git a/src/Handler/MiddlewareHandler.php b/src/Handler/MiddlewareHandler.php index 3a690e81..7d169983 100644 --- a/src/Handler/MiddlewareHandler.php +++ b/src/Handler/MiddlewareHandler.php @@ -50,7 +50,7 @@ public static function append(Handler $handler, array $middleware) : Handler } $handler = clone $handler; - $handler->middleware = \array_merge($handler->middleware, $middleware); + $handler->middleware = array_merge($handler->middleware, $middleware); return $handler; } @@ -65,7 +65,7 @@ public static function prepend(Handler $handler, array $middleware) : Handler } $handler = clone $handler; - $handler->middleware = \array_merge($middleware, $handler->middleware); + $handler->middleware = array_merge($middleware, $handler->middleware); return $handler; } diff --git a/src/Middleware/CustomErrorMiddleware.php b/src/Middleware/CustomErrorMiddleware.php index 75a15304..14ec7e51 100644 --- a/src/Middleware/CustomErrorMiddleware.php +++ b/src/Middleware/CustomErrorMiddleware.php @@ -104,7 +104,7 @@ static function (Error $err, RequestFailed $ex) use ($mapping) : \Exception { */ public static function fromNamespace(string $namespace) : self { - $namespace = \rtrim($namespace, '\\').'\\'; + $namespace = rtrim($namespace, '\\').'\\'; return new self( static function (Error $err, RequestFailed $ex) use ($namespace) : \Exception { @@ -116,7 +116,7 @@ static function (Error $err, RequestFailed $ex) use ($namespace) : \Exception { $className = $namespace.$customType; /** @psalm-suppress UnsafeInstantiation */ - return \class_exists($className) + return class_exists($className) ? new $className($err->getMessage(), $err->getCode()) : $ex; } diff --git a/src/Middleware/FirewallMiddleware.php b/src/Middleware/FirewallMiddleware.php index c8a26f0b..9fc83595 100644 --- a/src/Middleware/FirewallMiddleware.php +++ b/src/Middleware/FirewallMiddleware.php @@ -33,8 +33,8 @@ final class FirewallMiddleware implements Middleware */ private function __construct($allowed, $denied) { - $this->allowed = $allowed ? \array_fill_keys($allowed, true) : []; - $this->denied = $denied ? \array_fill_keys($denied, true) : []; + $this->allowed = $allowed ? array_fill_keys($allowed, true) : []; + $this->denied = $denied ? array_fill_keys($denied, true) : []; } public static function allow(int $requestType, int ...$requestTypes) : self @@ -63,7 +63,7 @@ public function andAllow(int $requestType, int ...$requestTypes) : self { $new = clone $this; $new->allowed += $requestTypes - ? \array_fill_keys([-1 => $requestType] + $requestTypes, true) + ? array_fill_keys([-1 => $requestType] + $requestTypes, true) : [$requestType => true]; return $new; @@ -73,7 +73,7 @@ public function andAllowOnly(int $requestType, int ...$requestTypes) : self { $new = clone $this; $new->allowed = $requestTypes - ? \array_fill_keys([-1 => $requestType] + $requestTypes, true) + ? array_fill_keys([-1 => $requestType] + $requestTypes, true) : [$requestType => true]; return $new; @@ -83,7 +83,7 @@ public function andDeny(int $requestType, int ...$requestTypes) : self { $new = clone $this; $new->denied += $requestTypes - ? \array_fill_keys([-1 => $requestType] + $requestTypes, true) + ? array_fill_keys([-1 => $requestType] + $requestTypes, true) : [$requestType => true]; return $new; @@ -93,7 +93,7 @@ public function andDenyOnly(int $requestType, int ...$requestTypes) : self { $new = clone $this; $new->denied = $requestTypes - ? \array_fill_keys([-1 => $requestType] + $requestTypes, true) + ? array_fill_keys([-1 => $requestType] + $requestTypes, true) : [$requestType => true]; return $new; diff --git a/src/Middleware/LoggingMiddleware.php b/src/Middleware/LoggingMiddleware.php index c5e07020..ce8aadd0 100644 --- a/src/Middleware/LoggingMiddleware.php +++ b/src/Middleware/LoggingMiddleware.php @@ -37,14 +37,14 @@ public function process(Request $request, Handler $handler) : Response 'request' => $request, ]); - $start = \microtime(true); + $start = microtime(true); try { $response = $handler->handle($request); } catch (\Throwable $e) { $this->logger->error("Request \"$requestName\" failed", [ 'request' => $request, 'exception' => $e, - 'duration_ms' => \round((\microtime(true) - $start) * 1000), + 'duration_ms' => round((microtime(true) - $start) * 1000), ]); throw $e; @@ -53,7 +53,7 @@ public function process(Request $request, Handler $handler) : Response $this->logger->debug("Finished handling request \"$requestName\"", [ 'request' => $request, 'response' => $response, - 'duration_ms' => \round((\microtime(true) - $start) * 1000), + 'duration_ms' => round((microtime(true) - $start) * 1000), ]); return $response; diff --git a/src/Middleware/RetryMiddleware.php b/src/Middleware/RetryMiddleware.php index cd9fa3b2..23388f97 100644 --- a/src/Middleware/RetryMiddleware.php +++ b/src/Middleware/RetryMiddleware.php @@ -71,13 +71,13 @@ public function process(Request $request, Handler $handler) : Response { $retries = 0; - do { + while (true) { try { return $handler->handle($request); } catch (UnexpectedResponse $e) { $handler->getConnection()->close(); break; - } catch (ConnectionFailed | CommunicationFailed $e) { + } catch (ConnectionFailed|CommunicationFailed $e) { $handler->getConnection()->close(); goto retry; } catch (ClientException $e) { @@ -88,11 +88,11 @@ public function process(Request $request, Handler $handler) : Response if (null === $delayMs = ($this->getDelayMs)(++$retries, $e)) { break; } - $delayMs = \min($delayMs, self::MAX_DELAY_MS) / 2; - $delayMs += \mt_rand(0, $delayMs); - \usleep($delayMs * 1000); + $delayMs = min($delayMs, self::MAX_DELAY_MS) / 2; + $delayMs += mt_rand(0, $delayMs); + usleep($delayMs * 1000); } - } while (true); + } throw $e; } diff --git a/src/Packer/Extension/DecimalExtension.php b/src/Packer/Extension/DecimalExtension.php index 7b18d8c1..d47f05e1 100644 --- a/src/Packer/Extension/DecimalExtension.php +++ b/src/Packer/Extension/DecimalExtension.php @@ -41,13 +41,13 @@ public function pack(Packer $packer, $value) : ?string if ('-' === $data[0]) { $nibble = 'd'; - $data = \substr($data, 1); + $data = substr($data, 1); } else { $nibble = 'c'; } - $pieces = \explode('.', $data, 2); - $pieces[1] = \rtrim($pieces[1], '0'); + $pieces = explode('.', $data, 2); + $pieces[1] = rtrim($pieces[1], '0'); $data = "{$pieces[0]}{$pieces[1]}{$nibble}"; if (0 !== \strlen($data) % 2) { @@ -55,7 +55,7 @@ public function pack(Packer $packer, $value) : ?string } return $packer->packExt(self::TYPE, - $packer->packInt('' === $pieces[1] ? 0 : \strlen($pieces[1])).\hex2bin($data) + $packer->packInt('' === $pieces[1] ? 0 : \strlen($pieces[1])).hex2bin($data) ); } @@ -71,16 +71,16 @@ public function unpackExt(BufferUnpacker $unpacker, int $extLength) */ $scale = $unpacker->unpackInt(); $data = $unpacker->read($extLength - 1); - $data = \bin2hex($data); + $data = bin2hex($data); $sign = 'd' === $data[-1] ? '-' : ''; - $dec = \substr($data, 0, -1); + $dec = substr($data, 0, -1); if (0 !== $scale) { $length = \strlen($dec); $dec = ($length <= $scale) - ? \substr_replace($dec, '0.'.\str_repeat('0', $scale - $length), -$scale, 0) - : \substr_replace($dec, '.', -$scale, 0); + ? substr_replace($dec, '0.'.str_repeat('0', $scale - $length), -$scale, 0) + : substr_replace($dec, '.', -$scale, 0); } return new Decimal($sign.$dec, self::PRECISION); diff --git a/src/Packer/PacketLength.php b/src/Packer/PacketLength.php index c8572146..e7cea7a4 100644 --- a/src/Packer/PacketLength.php +++ b/src/Packer/PacketLength.php @@ -23,7 +23,7 @@ private function __construct() public static function pack(int $length) : string { - return \pack('CN', 0xce, $length); + return pack('CN', 0xCE, $length); } public static function unpack(string $data) : int diff --git a/src/Packer/PurePacker.php b/src/Packer/PurePacker.php index d6d9326d..b07aba39 100644 --- a/src/Packer/PurePacker.php +++ b/src/Packer/PurePacker.php @@ -72,7 +72,7 @@ public static function fromAvailableExtensions() : self public function pack(Request $request, int $sync) : string { // Hot path optimization - $packet = \pack('C*', 0x82, Keys::CODE, $request->getType(), Keys::SYNC). + $packet = pack('C*', 0x82, Keys::CODE, $request->getType(), Keys::SYNC). $this->packer->packInt($sync). $this->packer->packMap($request->getBody()); diff --git a/src/PreparedStatement.php b/src/PreparedStatement.php index 64ea5f47..68cb3dc9 100644 --- a/src/PreparedStatement.php +++ b/src/PreparedStatement.php @@ -34,9 +34,6 @@ public function __construct(Handler $handler, int $id, int $bindCount, array $bi $this->metadata = $metadata; } - /** - * @param mixed ...$params - */ public function execute(...$params) : Response { return $this->handler->handle( @@ -44,9 +41,6 @@ public function execute(...$params) : Response ); } - /** - * @param mixed ...$params - */ public function executeQuery(...$params) : SqlQueryResult { $response = $this->handler->handle( @@ -59,9 +53,6 @@ public function executeQuery(...$params) : SqlQueryResult ); } - /** - * @param mixed ...$params - */ public function executeUpdate(...$params) : SqlUpdateResult { $response = $this->handler->handle( diff --git a/src/Request/AuthenticateRequest.php b/src/Request/AuthenticateRequest.php index 4afc7120..1543c5e1 100644 --- a/src/Request/AuthenticateRequest.php +++ b/src/Request/AuthenticateRequest.php @@ -23,11 +23,11 @@ final class AuthenticateRequest implements Request public function __construct(string $salt, string $username, string $password = '') { - $hash1 = \sha1($password, true); - $hash2 = \sha1($hash1, true); + $hash1 = sha1($password, true); + $hash2 = sha1($hash1, true); $this->body = [ - Keys::TUPLE => ['chap-sha1', $hash1 ^ \sha1($salt.$hash2, true)], + Keys::TUPLE => ['chap-sha1', $hash1 ^ sha1($salt.$hash2, true)], Keys::USER_NAME => $username, ]; } diff --git a/src/Response.php b/src/Response.php index 5ce01423..d5296cf9 100644 --- a/src/Response.php +++ b/src/Response.php @@ -48,9 +48,6 @@ public function getSchemaId() : int return $this->header[Keys::SCHEMA_ID]; } - /** - * @return mixed - */ public function getBodyField(int $key) { if (\array_key_exists($key, $this->body)) { @@ -60,11 +57,6 @@ public function getBodyField(int $key) throw new \OutOfRangeException(\sprintf('The body key 0x%x does not exist', $key)); } - /** - * @param mixed $default - * - * @return mixed - */ public function tryGetBodyField(int $key, $default = null) { return \array_key_exists($key, $this->body) ? $this->body[$key] : $default; diff --git a/src/Schema/Criteria.php b/src/Schema/Criteria.php index 744023d0..d8523b2b 100644 --- a/src/Schema/Criteria.php +++ b/src/Schema/Criteria.php @@ -22,12 +22,12 @@ final class Criteria private $key = []; /** @var int */ - private $limit = \PHP_INT_MAX & 0xffffffff; + private $limit = \PHP_INT_MAX & 0xFFFFFFFF; /** @var int */ private $offset = 0; - /** @psalm-var null|IteratorTypes::* */ + /** @psalm-var IteratorTypes::*|null */ private $iteratorType; private function __construct() diff --git a/src/Schema/Operations.php b/src/Schema/Operations.php index 1fe1233e..050c0176 100644 --- a/src/Schema/Operations.php +++ b/src/Schema/Operations.php @@ -180,7 +180,6 @@ public function andDelete($field, int $value) : self /** * @param int|string $field - * @param mixed $value */ public static function set($field, $value) : self { @@ -189,7 +188,6 @@ public static function set($field, $value) : self /** * @param int|string $field - * @param mixed $value */ public function andSet($field, $value) : self { diff --git a/src/Schema/Space.php b/src/Schema/Space.php index 3742eab3..8faa7e84 100644 --- a/src/Schema/Space.php +++ b/src/Schema/Space.php @@ -88,8 +88,8 @@ public function replace(array $tuple) : array } /** - * @psalm-param non-empty-array $key * @param int|string $index + * @psalm-param non-empty-array $key */ public function update(array $key, Operations $operations, $index = 0) : array { @@ -113,8 +113,8 @@ public function upsert(array $tuple, Operations $operations) : void } /** - * @psalm-param non-empty-array $key * @param int|string $index + * @psalm-param non-empty-array $key */ public function delete(array $key, $index = 0) : array { diff --git a/src/SqlQueryResult.php b/src/SqlQueryResult.php index 7a7f8a31..f2c1f8f3 100644 --- a/src/SqlQueryResult.php +++ b/src/SqlQueryResult.php @@ -28,7 +28,7 @@ public function __construct(array $data, array $metadata) { $this->data = $data; $this->metadata = $metadata; - $this->keys = $metadata ? \array_column($metadata, 0) : []; + $this->keys = $metadata ? array_column($metadata, 0) : []; } public function getData() : array @@ -48,19 +48,19 @@ public function isEmpty() : bool public function getFirst() : ?array { - return $this->data ? \array_combine($this->keys, \reset($this->data)) : null; + return $this->data ? array_combine($this->keys, reset($this->data)) : null; } public function getLast() : ?array { - return $this->data ? \array_combine($this->keys, \end($this->data)) : null; + return $this->data ? array_combine($this->keys, end($this->data)) : null; } #[\Override] public function getIterator() : \Generator { foreach ($this->data as $item) { - yield \array_combine($this->keys, $item); + yield array_combine($this->keys, $item); } } @@ -83,7 +83,7 @@ public function offsetGet($offset) : array throw new \OutOfBoundsException(\sprintf('The offset "%s" does not exist', $offset)); } - return \array_combine($this->keys, $this->data[$offset]); + return array_combine($this->keys, $this->data[$offset]); } #[\Override] diff --git a/tests/GreetingDataProvider.php b/tests/GreetingDataProvider.php index 1a8af0e6..8637543d 100644 --- a/tests/GreetingDataProvider.php +++ b/tests/GreetingDataProvider.php @@ -76,8 +76,8 @@ private static function generateSalt() : string private static function generateUuid4() : string { $data = random_bytes(16); - $data[6] = \chr(\ord($data[6]) & 0x0f | 0x40); - $data[8] = \chr(\ord($data[8]) & 0x3f | 0x80); + $data[6] = \chr(\ord($data[6]) & 0x0F | 0x40); + $data[8] = \chr(\ord($data[8]) & 0x3F | 0x80); return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)); } diff --git a/tests/Integration/ClientBuilder.php b/tests/Integration/ClientBuilder.php index dcc7f9af..e47bf573 100755 --- a/tests/Integration/ClientBuilder.php +++ b/tests/Integration/ClientBuilder.php @@ -56,7 +56,7 @@ public function setConnectionOptions(array $options) : self public function isTcpConnection() : bool { - return 0 === strpos($this->uri, 'tcp:'); + return str_starts_with($this->uri, 'tcp:'); } public function setHost(string $host) : self @@ -77,13 +77,13 @@ public function setPort(int $port) : self public function setUri(string $uri) : self { - if (0 === strpos($uri, '/')) { + if (str_starts_with($uri, '/')) { $uri = 'unix://'.$uri; - } elseif (0 === strpos($uri, 'unix/:')) { + } elseif (str_starts_with($uri, 'unix/:')) { $uri = 'unix://'.substr($uri, 6); } elseif (!preg_match('/[\D]/', $uri)) { $uri = 'tcp://127.0.0.1:'.$uri; - } elseif (0 !== strpos($uri, 'tcp://') && (0 !== strpos($uri, 'unix://'))) { + } elseif (!str_starts_with($uri, 'tcp://') && (!str_starts_with($uri, 'unix://'))) { $uri = 'tcp://'.$uri; } diff --git a/tests/Integration/ClientMiddlewareTest.php b/tests/Integration/ClientMiddlewareTest.php index 98c039d5..432211f3 100644 --- a/tests/Integration/ClientMiddlewareTest.php +++ b/tests/Integration/ClientMiddlewareTest.php @@ -146,7 +146,7 @@ public function testThrowOnBrokenConnection() : void private static function createBrokenConnectionMiddleware() : Middleware { - return new class() implements Middleware { + return new class implements Middleware { private $count = 0; public function process(Request $request, Handler $handler) : Response diff --git a/tests/Integration/ExamplesTest.php b/tests/Integration/ExamplesTest.php index 24363b87..558fae73 100644 --- a/tests/Integration/ExamplesTest.php +++ b/tests/Integration/ExamplesTest.php @@ -25,7 +25,7 @@ public function testExample(string $filename) : void exec("php $filename $uri", $output, $exitCode); $flattenOutput = implode("\n", $output); - if (0 === strpos($flattenOutput, 'Unfulfilled requirement:')) { + if (str_starts_with($flattenOutput, 'Unfulfilled requirement:')) { self::markTestSkipped($flattenOutput); } diff --git a/tests/Integration/MessagePack/MessagePackTest.php b/tests/Integration/MessagePack/MessagePackTest.php index 25534650..17605985 100755 --- a/tests/Integration/MessagePack/MessagePackTest.php +++ b/tests/Integration/MessagePack/MessagePackTest.php @@ -17,12 +17,9 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; -use Tarantool\Client\Tests\PhpUnitCompat; final class MessagePackTest extends TestCase { - - /** * @dataProvider providePackUnpackData */ diff --git a/tests/Integration/TestCase.php b/tests/Integration/TestCase.php index 166a1924..cc2cf6a9 100644 --- a/tests/Integration/TestCase.php +++ b/tests/Integration/TestCase.php @@ -19,14 +19,11 @@ use Tarantool\Client\Exception\CommunicationFailed; use Tarantool\Client\Handler\Handler; use Tarantool\Client\Request\Request; -use Tarantool\Client\Tests\PhpUnitCompat; use Tarantool\PhpUnit\Annotation\Requirement\TarantoolVersionRequirement; use Tarantool\PhpUnit\TestCase as BaseTestCase; abstract class TestCase extends BaseTestCase { - - /** @var Client|null */ protected $client; diff --git a/tests/Unit/ClientFactoryTest.php b/tests/Unit/ClientFactoryTest.php index 99cba5bb..49e125c4 100644 --- a/tests/Unit/ClientFactoryTest.php +++ b/tests/Unit/ClientFactoryTest.php @@ -17,12 +17,9 @@ use Tarantool\Client\Client; use Tarantool\Client\Packer\Packer; use Tarantool\Client\Packer\PurePacker; -use Tarantool\Client\Tests\PhpUnitCompat; final class ClientFactoryTest extends TestCase { - - public function testFromDefaultsCreatesClientWithPurePacker() : void { $client = Client::fromDefaults(); diff --git a/tests/Unit/Connection/StreamConnectionTest.php b/tests/Unit/Connection/StreamConnectionTest.php index afb78604..853e35d6 100644 --- a/tests/Unit/Connection/StreamConnectionTest.php +++ b/tests/Unit/Connection/StreamConnectionTest.php @@ -15,12 +15,9 @@ use PHPUnit\Framework\TestCase; use Tarantool\Client\Connection\StreamConnection; -use Tarantool\Client\Tests\PhpUnitCompat; final class StreamConnectionTest extends TestCase { - - /** * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideConnectionArrayOptionsOfValidTypes * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideTcpExtraConnectionArrayOptionsOfValidTypes diff --git a/tests/Unit/Middleware/RetryMiddlewareTest.php b/tests/Unit/Middleware/RetryMiddlewareTest.php index b3f3721c..1416905c 100644 --- a/tests/Unit/Middleware/RetryMiddlewareTest.php +++ b/tests/Unit/Middleware/RetryMiddlewareTest.php @@ -79,6 +79,7 @@ public function testInfiniteRetriesBreak() : void $totalRetries = 0; $middleware = RetryMiddleware::custom(static function (int $retries) use (&$totalRetries) : int { $totalRetries = $retries; + // always returning a value other than null // leads to an infinite retry loop return 0; From 191d2e005c448928cd6ab11490839aab95b84c86 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Sun, 26 Jul 2026 11:27:55 +0200 Subject: [PATCH 08/34] Migrate docblock annotations to PHP attributes --- examples/logging/SlowRequestHandler.php | 32 ++++------- tests/Integration/BoxErrorTest.php | 9 +-- tests/Integration/BoxNullTest.php | 21 ++++--- tests/Integration/ClientMiddlewareTest.php | 8 +-- tests/Integration/ClientSpaceCachingTest.php | 5 +- tests/Integration/CompositeKeyTest.php | 11 ++-- .../Integration/Connection/ConnectionTest.php | 4 +- .../MessagePack/DecimalExtensionTest.php | 26 ++++----- .../MessagePack/ErrorExtensionTest.php | 3 +- .../MessagePack/MessagePackTest.php | 7 +-- .../MessagePack/UuidExtensionTest.php | 21 +++---- .../Integration/Requests/AuthenticateTest.php | 14 ++--- tests/Integration/Requests/DeleteTest.php | 17 +++--- tests/Integration/Requests/ExecuteTest.php | 56 +++++++------------ tests/Integration/Requests/InsertTest.php | 25 ++++----- tests/Integration/Requests/PrepareTest.php | 12 ++-- tests/Integration/Requests/ReplaceTest.php | 11 ++-- tests/Integration/Requests/SelectTest.php | 22 +++----- tests/Integration/Requests/UpdateTest.php | 13 ++--- tests/Integration/Requests/UpsertTest.php | 7 +-- 20 files changed, 136 insertions(+), 188 deletions(-) diff --git a/examples/logging/SlowRequestHandler.php b/examples/logging/SlowRequestHandler.php index 7b22ef16..5d866af4 100644 --- a/examples/logging/SlowRequestHandler.php +++ b/examples/logging/SlowRequestHandler.php @@ -15,7 +15,6 @@ use Monolog\Handler\HandlerInterface; use Monolog\Handler\HandlerWrapper; -use Monolog\Logger; use Tarantool\Client\RequestTypes; final class SlowRequestHandler extends HandlerWrapper @@ -23,34 +22,26 @@ final class SlowRequestHandler extends HandlerWrapper /** @var int */ private $thresholdMs; - /** @var int */ + /** @var \Monolog\Level */ private $level; - /** @var string */ - private $levelName; - - /** - * @param positive-int $thresholdMs - * @param Logger::DEBUG|Logger::INFO|Logger::NOTICE|Logger::WARNING|Logger::ERROR|Logger::CRITICAL|Logger::ALERT|Logger::EMERGENCY $level - */ - public function __construct(HandlerInterface $handler, int $thresholdMs, int $level = Logger::WARNING) + public function __construct(HandlerInterface $handler, int $thresholdMs, \Monolog\Level|int $level = \Monolog\Level::Warning) { parent::__construct($handler); $this->thresholdMs = $thresholdMs; - $this->level = $level; - $this->levelName = Logger::getLevelName($this->level); + $this->level = $level instanceof \Monolog\Level ? $level : \Monolog\Level::from($level); } #[\Override] - public function isHandling(array $record) : bool + public function isHandling(\Monolog\LogRecord $record) : bool { // Handle all levels return true; } #[\Override] - public function handle(array $record) : bool + public function handle(\Monolog\LogRecord $record) : bool { if (!isset($record['context']['duration_ms'], $record['context']['request'])) { return false; @@ -62,11 +53,12 @@ public function handle(array $record) : bool $request = $record['context']['request']; - return $this->handler->handle([ - 'level' => $this->level, - 'level_name' => $this->levelName, - 'message' => sprintf('Slow %s request detected (%d ms)', RequestTypes::getName($request->getType()), $record['context']['duration_ms']), - 'context' => ['request_body' => $request->getBody()], - ] + $record); + $newRecord = $record->with( + level: $this->level, + message: sprintf('Slow %s request detected (%d ms)', RequestTypes::getName($request->getType()), $record['context']['duration_ms']), + context: ['request_body' => $request->getBody()] + $record['context'] + ); + + return $this->handler->handle($newRecord); } } diff --git a/tests/Integration/BoxErrorTest.php b/tests/Integration/BoxErrorTest.php index 425197fa..63608482 100644 --- a/tests/Integration/BoxErrorTest.php +++ b/tests/Integration/BoxErrorTest.php @@ -13,6 +13,7 @@ namespace Tarantool\Client\Tests\Integration; +use PHPUnitExtras\Annotation\Attribute\Requires; use Tarantool\Client\Error; use Tarantool\Client\Exception\RequestFailed; @@ -27,9 +28,7 @@ public function testExceptionIsThrown() : void $this->client->evaluate('box.error({code = 42, reason = "Because I can"})'); } - /** - * @requires Tarantool >=2.4.1 - */ + #[Requires('Tarantool', '>=2.4.1')] public function testExceptionWithErrorIsThrown() : void { try { @@ -72,9 +71,7 @@ public function testExceptionWithErrorIsThrown() : void } } - /** - * @requires Tarantool >=2.4.1 - */ + #[Requires('Tarantool', '>=2.4.1')] public function testExceptionWithNestedErrorIsThrown() : void { try { diff --git a/tests/Integration/BoxNullTest.php b/tests/Integration/BoxNullTest.php index 66d93516..45350293 100644 --- a/tests/Integration/BoxNullTest.php +++ b/tests/Integration/BoxNullTest.php @@ -14,20 +14,19 @@ namespace Tarantool\Client\Tests\Integration; use Tarantool\Client\Schema\Criteria; +use Tarantool\PhpUnit\Annotation\Attribute\Lua; final class BoxNullTest extends TestCase { - /** - * @lua format = {} - * @lua format[1] = {name = 'foo', type = 'unsigned'} - * @lua format[2] = {name = 'bar', type = 'map', is_nullable = true} - * @lua format[3] = {name = 'baz', type = 'unsigned', is_nullable = true} - * @lua space = create_space('box_null', {format = format}) - * @lua space:create_index('pk') - * @lua space:insert{1, {a = 1}} - * @lua space:insert{2, {b = 2}, box.NULL} - * @lua space:insert{3, box.NULL, 300} - */ + #[Lua('format = {}')] + #[Lua('format[1] = {name = \'foo\', type = \'unsigned\'}')] + #[Lua('format[2] = {name = \'bar\', type = \'map\', is_nullable = true}')] + #[Lua('format[3] = {name = \'baz\', type = \'unsigned\', is_nullable = true}')] + #[Lua('space = create_space(\'box_null\', {format = format})')] + #[Lua('space:create_index(\'pk\')')] + #[Lua('space:insert{1, {a = 1}}')] + #[Lua('space:insert{2, {b = 2}, box.NULL}')] + #[Lua('space:insert{3, box.NULL, 300}')] public function testNull() : void { $space = $this->client->getSpace('box_null'); diff --git a/tests/Integration/ClientMiddlewareTest.php b/tests/Integration/ClientMiddlewareTest.php index 432211f3..c9c9f331 100644 --- a/tests/Integration/ClientMiddlewareTest.php +++ b/tests/Integration/ClientMiddlewareTest.php @@ -26,6 +26,7 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Schema\Space; use Tarantool\Client\Tests\SpyMiddleware; +use Tarantool\PhpUnit\Annotation\Attribute\Lua; final class ClientMiddlewareTest extends TestCase { @@ -52,11 +53,10 @@ public function testSpaceInheritsMiddleware() : void /** * @doesNotPerformAssertions - * - * @lua fiber = require('fiber') - * @lua function test() try_drop_user('foobar') fiber.sleep(.5) create_user('foobar', '') end - * @lua fiber.create(test) */ + #[Lua('fiber = require(\'fiber\')')] + #[Lua('function test() try_drop_user(\'foobar\') fiber.sleep(.5) create_user(\'foobar\', \'\') end')] + #[Lua('fiber.create(test)')] public function testAuthenticationRetrySucceeds() : void { $client = Client::fromOptions([ diff --git a/tests/Integration/ClientSpaceCachingTest.php b/tests/Integration/ClientSpaceCachingTest.php index c795a363..58e95f2a 100644 --- a/tests/Integration/ClientSpaceCachingTest.php +++ b/tests/Integration/ClientSpaceCachingTest.php @@ -14,10 +14,9 @@ namespace Tarantool\Client\Tests\Integration; use Tarantool\Client\Schema\Criteria; +use Tarantool\PhpUnit\Annotation\Attribute\Lua; -/** - * @lua create_space('test_space_caching'):create_index('primary', {type = 'tree', parts = {1, 'unsigned'}}) - */ +#[Lua('create_space(\'test_space_caching\'):create_index(\'primary\', {type = \'tree\', parts = {1, \'unsigned\'}})')] final class ClientSpaceCachingTest extends TestCase { public function testCacheSpace() : void diff --git a/tests/Integration/CompositeKeyTest.php b/tests/Integration/CompositeKeyTest.php index f29b694d..259c3d57 100755 --- a/tests/Integration/CompositeKeyTest.php +++ b/tests/Integration/CompositeKeyTest.php @@ -15,13 +15,12 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Schema\Operations; +use Tarantool\PhpUnit\Annotation\Attribute\Lua; -/** - * @lua space = create_space('composite_key') - * @lua space:create_index('primary', {type = 'tree', unique = true, parts = {1, 'unsigned', 2, 'unsigned'}}) - * @lua space:insert{2016, 10, 1} - * @lua space:insert{2016, 11, 0} - */ +#[Lua('space = create_space(\'composite_key\')')] +#[Lua('space:create_index(\'primary\', {type = \'tree\', unique = true, parts = {1, \'unsigned\', 2, \'unsigned\'}})')] +#[Lua('space:insert{2016, 10, 1}')] +#[Lua('space:insert{2016, 11, 0}')] final class CompositeKeyTest extends TestCase { public function testSelectByCompositeKey() : void diff --git a/tests/Integration/Connection/ConnectionTest.php b/tests/Integration/Connection/ConnectionTest.php index af7c5f92..afba311a 100644 --- a/tests/Integration/Connection/ConnectionTest.php +++ b/tests/Integration/Connection/ConnectionTest.php @@ -25,15 +25,15 @@ use Tarantool\Client\Tests\Integration\FakeServer\Handler\AtConnectionHandler; use Tarantool\Client\Tests\Integration\FakeServer\Handler\WriteHandler; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Annotation\Attribute\Lua; final class ConnectionTest extends TestCase { /** * @dataProvider provideAutoConnectData * @doesNotPerformAssertions - * - * @lua create_space('test_auto_connect'):create_index('primary', {type = 'tree', parts = {1, 'unsigned'}}) */ + #[Lua('create_space(\'test_auto_connect\'):create_index(\'primary\', {type = \'tree\', parts = {1, \'unsigned\'}})')] public function testAutoConnect(string $methodName, array $methodArgs, ?string $space = null) : void { $object = $space ? $this->client->getSpace($space) : $this->client; diff --git a/tests/Integration/MessagePack/DecimalExtensionTest.php b/tests/Integration/MessagePack/DecimalExtensionTest.php index d678bf64..bbd60438 100755 --- a/tests/Integration/MessagePack/DecimalExtensionTest.php +++ b/tests/Integration/MessagePack/DecimalExtensionTest.php @@ -14,23 +14,23 @@ namespace Tarantool\Client\Tests\Integration\MessagePack; use Decimal\Decimal; +use PHPUnit\Framework\Attributes\RequiresPhpExtension; +use PHPUnitExtras\Annotation\Attribute\Requires; use Tarantool\Client\Client; use Tarantool\Client\Packer\Extension\DecimalExtension; use Tarantool\Client\Packer\PurePacker; use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; - -/** - * @requires Tarantool >=2.3 - * @requires extension decimal - * - * @lua dec = require('decimal').new('18446744073709551615') - * @lua space = create_space('decimal_primary') - * @lua space:format({{name = 'id', type = 'decimal'}}) - * @lua space:create_index("primary", {parts = {1, 'decimal'}}) - * @lua space:insert({dec}) - */ +use Tarantool\PhpUnit\Annotation\Attribute\Lua; + +#[Lua('dec = require(\'decimal\').new(\'18446744073709551615\')')] +#[Lua('space = create_space(\'decimal_primary\')')] +#[Lua('space:format({{name = \'id\', type = \'decimal\'}})')] +#[Lua('space:create_index("primary", {parts = {1, \'decimal\'}})')] +#[Lua('space:insert({dec})')] +#[Requires('Tarantool', '>=2.3')] +#[RequiresPhpExtension('decimal')] final class DecimalExtensionTest extends TestCase { public const DECIMAL_BIG_INT = '18446744073709551615'; @@ -48,9 +48,7 @@ public function testBinarySelectByDecimalKeySucceeds() : void self::assertTrue($decimal->equals($result[0][0])); } - /** - * @requires Tarantool >=2.10-stable - */ + #[Requires('Tarantool', '>=2.10-stable')] public function testSqlSelectByDecimalKeySucceeds() : void { $client = self::createClientWithDecimalSupport(); diff --git a/tests/Integration/MessagePack/ErrorExtensionTest.php b/tests/Integration/MessagePack/ErrorExtensionTest.php index 9bcb2598..e4ca775e 100755 --- a/tests/Integration/MessagePack/ErrorExtensionTest.php +++ b/tests/Integration/MessagePack/ErrorExtensionTest.php @@ -13,6 +13,7 @@ namespace Tarantool\Client\Tests\Integration\MessagePack; +use PHPUnitExtras\Annotation\Attribute\Requires; use Tarantool\Client\Client; use Tarantool\Client\Error; use Tarantool\Client\Packer\Extension\ErrorExtension; @@ -23,9 +24,9 @@ final class ErrorExtensionTest extends TestCase { /** - * @requires Tarantool >=2.4.1 <2.10 * @see https://github.com/tarantool/tarantool/issues/6428 */ + #[Requires('Tarantool', '>=2.4.1 <2.10')] public function testLuaPackingAndUnpacking() : void { $client = self::createClientWithExtendedErrorSupport(); diff --git a/tests/Integration/MessagePack/MessagePackTest.php b/tests/Integration/MessagePack/MessagePackTest.php index 17605985..8d4e1182 100755 --- a/tests/Integration/MessagePack/MessagePackTest.php +++ b/tests/Integration/MessagePack/MessagePackTest.php @@ -17,6 +17,7 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Annotation\Attribute\Lua; final class MessagePackTest extends TestCase { @@ -65,10 +66,8 @@ public function testPackUnpackMultiDimensionalArray() : void self::assertEqualsCanonicalizing($array, $result); } - /** - * @lua space = create_space('custom_type') - * @lua space:create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) - */ + #[Lua('space = create_space(\'custom_type\')')] + #[Lua('space:create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] public function testCustomType() : void { $client = ClientBuilder::createFromEnv() diff --git a/tests/Integration/MessagePack/UuidExtensionTest.php b/tests/Integration/MessagePack/UuidExtensionTest.php index 6dba4fa3..88c5320a 100755 --- a/tests/Integration/MessagePack/UuidExtensionTest.php +++ b/tests/Integration/MessagePack/UuidExtensionTest.php @@ -13,6 +13,7 @@ namespace Tarantool\Client\Tests\Integration\MessagePack; +use PHPUnitExtras\Annotation\Attribute\Requires; use Symfony\Component\Uid\Uuid; use Tarantool\Client\Client; use Tarantool\Client\Packer\Extension\UuidExtension; @@ -20,16 +21,14 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Annotation\Attribute\Lua; -/** - * @requires Tarantool >=2.4 - * - * @lua uuid = require('uuid').fromstr('64d22e4d-ac92-4a23-899a-e59f34af5479') - * @lua space = create_space('uuid_primary') - * @lua space:format({{name = 'id', type = 'uuid'}}) - * @lua space:create_index("primary", {parts = {1, 'uuid'}}) - * @lua space:insert({uuid}) - */ +#[Lua('uuid = require(\'uuid\').fromstr(\'64d22e4d-ac92-4a23-899a-e59f34af5479\')')] +#[Lua('space = create_space(\'uuid_primary\')')] +#[Lua('space:format({{name = \'id\', type = \'uuid\'}})')] +#[Lua('space:create_index("primary", {parts = {1, \'uuid\'}})')] +#[Lua('space:insert({uuid})')] +#[Requires('Tarantool', '>=2.4')] final class UuidExtensionTest extends TestCase { private const UUID_RFC4122 = '64d22e4d-ac92-4a23-899a-e59f34af5479'; @@ -46,9 +45,7 @@ public function testBinarySelectByUuidKeySucceeds() : void self::assertTrue($uuid->equals($result[0][0])); } - /** - * @requires Tarantool >=2.10-stable - */ + #[Requires('Tarantool', '>=2.10-stable')] public function testSqlSelectByUuidKeySucceeds() : void { $client = self::createClientWithUuidSupport(); diff --git a/tests/Integration/Requests/AuthenticateTest.php b/tests/Integration/Requests/AuthenticateTest.php index 9a175159..84e28e6c 100644 --- a/tests/Integration/Requests/AuthenticateTest.php +++ b/tests/Integration/Requests/AuthenticateTest.php @@ -16,17 +16,17 @@ use Tarantool\Client\Exception\RequestFailed; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Annotation\Attribute\Lua; final class AuthenticateTest extends TestCase { /** * @doesNotPerformAssertions * @dataProvider provideValidCredentials - * - * @lua create_user('user_foo', 'foo') - * @lua create_user('user_empty', '') - * @lua create_user('user_big', '123456789012345678901234567890123456789012345678901234567890') */ + #[Lua('create_user(\'user_foo\', \'foo\')')] + #[Lua('create_user(\'user_empty\', \'\')')] + #[Lua('create_user(\'user_big\', \'123456789012345678901234567890123456789012345678901234567890\')')] public function testAuthenticateWithValidCredentials(string $username, string $password) : void { $client = ClientBuilder::createFromEnv()->setOptions([ @@ -73,10 +73,8 @@ public function provideInvalidCredentials() : iterable ]; } - /** - * @lua create_user('user_foo', 'foo') - * @lua create_space('test_auth_reconnect'):create_index('primary', {type = 'tree', parts = {1, 'unsigned'}}) - */ + #[Lua('create_user(\'user_foo\', \'foo\')')] + #[Lua('create_space(\'test_auth_reconnect\'):create_index(\'primary\', {type = \'tree\', parts = {1, \'unsigned\'}})')] public function testUseCredentialsAfterReconnect() : void { $client = ClientBuilder::createFromEnv()->setOptions([ diff --git a/tests/Integration/Requests/DeleteTest.php b/tests/Integration/Requests/DeleteTest.php index 117add69..7379b3a5 100755 --- a/tests/Integration/Requests/DeleteTest.php +++ b/tests/Integration/Requests/DeleteTest.php @@ -15,15 +15,14 @@ use Tarantool\Client\Exception\RequestFailed; use Tarantool\Client\Tests\Integration\TestCase; - -/** - * @lua space = create_space('request_delete') - * @lua space:create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) - * @lua space:create_index('secondary', {type = 'tree', parts = {2, 'str'}}) - * @lua space:insert{3, 'delete_me_1'} - * @lua space:insert{4, 'delete_me_2'} - * @lua space:insert{5, 'delete_me_3'} - */ +use Tarantool\PhpUnit\Annotation\Attribute\Lua; + +#[Lua('space = create_space(\'request_delete\')')] +#[Lua('space:create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] +#[Lua('space:create_index(\'secondary\', {type = \'tree\', parts = {2, \'str\'}})')] +#[Lua('space:insert{3, \'delete_me_1\'}')] +#[Lua('space:insert{4, \'delete_me_2\'}')] +#[Lua('space:insert{5, \'delete_me_3\'}')] final class DeleteTest extends TestCase { public function testDelete() : void diff --git a/tests/Integration/Requests/ExecuteTest.php b/tests/Integration/Requests/ExecuteTest.php index 7c863127..0b7aa3fa 100644 --- a/tests/Integration/Requests/ExecuteTest.php +++ b/tests/Integration/Requests/ExecuteTest.php @@ -13,23 +13,20 @@ namespace Tarantool\Client\Tests\Integration\Requests; +use PHPUnitExtras\Annotation\Attribute\Requires; use Tarantool\Client\Keys; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Annotation\Attribute\Sql; -/** - * @requires Tarantool >=2 - * - * @sql DROP TABLE IF EXISTS exec_query - * @sql CREATE TABLE exec_query (id INTEGER PRIMARY KEY, name VARCHAR(50)) - * @sql INSERT INTO exec_query VALUES (1, 'A'), (2, 'B') - */ +#[Sql('DROP TABLE IF EXISTS exec_query')] +#[Sql('CREATE TABLE exec_query (id INTEGER PRIMARY KEY, name VARCHAR(50))')] +#[Sql('INSERT INTO exec_query VALUES (1, \'A\'), (2, \'B\')')] +#[Requires('Tarantool', '>=2')] final class ExecuteTest extends TestCase { - /** - * @sql DROP TABLE IF EXISTS exec_update - * @sql CREATE TABLE exec_update (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(50)) - */ + #[Sql('DROP TABLE IF EXISTS exec_update')] + #[Sql('CREATE TABLE exec_update (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(50))')] public function testExecuteInsertsRows() : void { $response = $this->client->execute( @@ -52,10 +49,8 @@ public function testExecuteFetchesAllRows() : void self::assertSame([[1, 'A'], [2, 'B']], $response->getBodyField(Keys::DATA)); } - /** - * @sql DROP TABLE IF EXISTS exec_update - * @sql CREATE TABLE exec_update (id INTEGER PRIMARY KEY, name VARCHAR(50)) - */ + #[Sql('DROP TABLE IF EXISTS exec_update')] + #[Sql('CREATE TABLE exec_update (id INTEGER PRIMARY KEY, name VARCHAR(50))')] public function testExecuteUpdateInsertsRows() : void { $result = $this->client->executeUpdate( @@ -67,10 +62,8 @@ public function testExecuteUpdateInsertsRows() : void self::assertSame(2, $result->count()); } - /** - * @sql DROP TABLE IF EXISTS exec_update - * @sql CREATE TABLE exec_update (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(50)) - */ + #[Sql('DROP TABLE IF EXISTS exec_update')] + #[Sql('CREATE TABLE exec_update (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(50))')] public function testExecuteUpdateInsertsRowsWithAutoIncrementedIds() : void { $result = $this->client->executeUpdate("INSERT INTO exec_update VALUES (100, 'A'), (null, 'B'), (120, 'C'), (null, 'D')"); @@ -79,11 +72,9 @@ public function testExecuteUpdateInsertsRowsWithAutoIncrementedIds() : void self::assertSame(4, $result->count()); } - /** - * @sql DROP TABLE IF EXISTS exec_update - * @sql CREATE TABLE exec_update (id INTEGER PRIMARY KEY, name VARCHAR(50)) - * @sql INSERT INTO exec_update VALUES (1, 'A'), (2, 'B') - */ + #[Sql('DROP TABLE IF EXISTS exec_update')] + #[Sql('CREATE TABLE exec_update (id INTEGER PRIMARY KEY, name VARCHAR(50))')] + #[Sql('INSERT INTO exec_update VALUES (1, \'A\'), (2, \'B\')')] public function testExecuteUpdateUpdatesRow() : void { $result = $this->client->executeUpdate('UPDATE exec_update SET name = ? WHERE id = ?', 'BB', 2); @@ -151,11 +142,9 @@ public function testExecuteQueryBindsMixedParametersAndSubstitutesPositionalOnes self::assertSame(1, $result->count()); } - /** - * @sql DROP TABLE IF EXISTS %target_method% - * @sql CREATE TABLE %target_method% (ID INTEGER PRIMARY KEY, NAME VARCHAR(50)) - * @sql INSERT INTO %target_method% VALUES (1, 'A'), (2, 'B') - */ + #[Sql('DROP TABLE IF EXISTS %target_method%')] + #[Sql('CREATE TABLE %target_method% (ID INTEGER PRIMARY KEY, NAME VARCHAR(50))')] + #[Sql('INSERT INTO %target_method% VALUES (1, \'A\'), (2, \'B\')')] public function testSqlQueryResultHoldsMetadata() : void { $client = ClientBuilder::createFromEnv()->build(); @@ -172,12 +161,9 @@ public function testSqlQueryResultHoldsMetadata() : void ]], $response->getMetadata()); } - /** - * @requires Tarantool >=2.6 - * - * @sql DROP TABLE IF EXISTS %target_method% - * @sql CREATE TABLE %target_method% (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME VARCHAR(50) COLLATE "unicode_ci") - */ + #[Sql('DROP TABLE IF EXISTS %target_method%')] + #[Sql('CREATE TABLE %target_method% (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME VARCHAR(50) COLLATE "unicode_ci")')] + #[Requires('Tarantool', '>=2.6')] public function testSqlQueryResultHoldsExtendedMetadata() : void { $client = ClientBuilder::createFromEnv()->build(); diff --git a/tests/Integration/Requests/InsertTest.php b/tests/Integration/Requests/InsertTest.php index 9a0cc0f5..a944e7cb 100755 --- a/tests/Integration/Requests/InsertTest.php +++ b/tests/Integration/Requests/InsertTest.php @@ -15,15 +15,15 @@ use Tarantool\Client\Exception\RequestFailed; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Annotation\Attribute\Lua; final class InsertTest extends TestCase { /** * @dataProvider provideInsertData - * - * @lua create_space('request_insert_str'):create_index('primary', {type = 'hash', parts = {1, 'str'}}) - * @lua create_space('request_insert_num'):create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) */ + #[Lua('create_space(\'request_insert_str\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'str\'}})')] + #[Lua('create_space(\'request_insert_num\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] public function testInsert(string $spaceName, array $values) : void { $space = $this->client->getSpace($spaceName); @@ -47,10 +47,9 @@ public function provideInsertData() : iterable /** * @dataProvider provideInsertDataWithMismatchedTypes - * - * @lua create_space('request_insert_str'):create_index('primary', {type = 'hash', parts = {1, 'str'}}) - * @lua create_space('request_insert_num'):create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) */ + #[Lua('create_space(\'request_insert_str\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'str\'}})')] + #[Lua('create_space(\'request_insert_num\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] public function testInsertTypeMismatchedValues(string $spaceName, array $values) : void { $space = $this->client->getSpace($spaceName); @@ -74,11 +73,9 @@ public function provideInsertDataWithMismatchedTypes() : iterable ]; } - /** - * @lua space = create_space('request_insert_dup_key') - * @lua space:create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) - * @lua space:insert{1, 'foobar'} - */ + #[Lua('space = create_space(\'request_insert_dup_key\')')] + #[Lua('space:create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] + #[Lua('space:insert{1, \'foobar\'}')] public function testInsertDuplicateKey() : void { $space = $this->client->getSpace('request_insert_dup_key'); @@ -89,10 +86,8 @@ public function testInsertDuplicateKey() : void $space->insert([1, 'bazqux']); } - /** - * @lua space = create_space('request_insert_empty_tuple') - * @lua space:create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) - */ + #[Lua('space = create_space(\'request_insert_empty_tuple\')')] + #[Lua('space:create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] public function testInsertEmptyTuple() : void { $space = $this->client->getSpace('request_insert_empty_tuple'); diff --git a/tests/Integration/Requests/PrepareTest.php b/tests/Integration/Requests/PrepareTest.php index 9c1d8c5f..5ca2c645 100644 --- a/tests/Integration/Requests/PrepareTest.php +++ b/tests/Integration/Requests/PrepareTest.php @@ -13,13 +13,13 @@ namespace Tarantool\Client\Tests\Integration\Requests; +use PHPUnitExtras\Annotation\Attribute\Requires; use Tarantool\Client\Exception\RequestFailed; use Tarantool\Client\PreparedStatement; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Annotation\Attribute\Sql; -/** - * @requires Tarantool >=2.3.2 - */ +#[Requires('Tarantool', '>=2.3.2')] final class PrepareTest extends TestCase { public function testPreparePreparesSqlStatement() : void @@ -62,10 +62,8 @@ public function testExecuteQueryReturnsResult() : void } } - /** - * @sql DROP TABLE IF EXISTS prepare_execute - * @sql CREATE TABLE prepare_execute (id INTEGER PRIMARY KEY, name VARCHAR(50)) - */ + #[Sql('DROP TABLE IF EXISTS prepare_execute')] + #[Sql('CREATE TABLE prepare_execute (id INTEGER PRIMARY KEY, name VARCHAR(50))')] public function testExecuteUpdateUpdatesRows() : void { $stmt = $this->client->prepare('INSERT INTO prepare_execute VALUES(:id, :name)'); diff --git a/tests/Integration/Requests/ReplaceTest.php b/tests/Integration/Requests/ReplaceTest.php index b652efb3..889c3257 100755 --- a/tests/Integration/Requests/ReplaceTest.php +++ b/tests/Integration/Requests/ReplaceTest.php @@ -16,13 +16,12 @@ use Tarantool\Client\Exception\RequestFailed; use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Annotation\Attribute\Lua; -/** - * @lua space = create_space('request_replace') - * @lua space:create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) - * @lua space:create_index('secondary', {type = 'tree', parts = {2, 'str'}}) - * @lua space:insert{2, 'replace_me'} - */ +#[Lua('space = create_space(\'request_replace\')')] +#[Lua('space:create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] +#[Lua('space:create_index(\'secondary\', {type = \'tree\', parts = {2, \'str\'}})')] +#[Lua('space:insert{2, \'replace_me\'}')] final class ReplaceTest extends TestCase { public function testReplace() : void diff --git a/tests/Integration/Requests/SelectTest.php b/tests/Integration/Requests/SelectTest.php index c5ecfd36..0eae3347 100755 --- a/tests/Integration/Requests/SelectTest.php +++ b/tests/Integration/Requests/SelectTest.php @@ -16,17 +16,17 @@ use Tarantool\Client\Exception\RequestFailed; use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Annotation\Attribute\Lua; final class SelectTest extends TestCase { /** * @dataProvider provideSelectData - * - * @lua space = create_space('request_select') - * @lua space:create_index('primary', {type = 'tree', unique = true, parts = {1, 'unsigned'}}) - * @lua space:create_index('secondary', {type = 'tree', unique = false, parts = {2, 'unsigned', 3, 'str'}}) - * @lua for i = 1, 100 do space:replace{i, i * 2 % 5, 'tuple_' .. i} end */ + #[Lua('space = create_space(\'request_select\')')] + #[Lua('space:create_index(\'primary\', {type = \'tree\', unique = true, parts = {1, \'unsigned\'}})')] + #[Lua('space:create_index(\'secondary\', {type = \'tree\', unique = false, parts = {2, \'unsigned\', 3, \'str\'}})')] + #[Lua('for i = 1, 100 do space:replace{i, i * 2 % 5, \'tuple_\' .. i} end')] public function testSelect(int $expectedCount, Criteria $criteria) : void { $space = $this->client->getSpace('request_select'); @@ -55,9 +55,7 @@ public function provideSelectData() : iterable ]; } - /** - * @lua create_space('request_select'):create_index('primary', {type = 'tree', parts = {1, 'unsigned'}}) - */ + #[Lua('create_space(\'request_select\'):create_index(\'primary\', {type = \'tree\', parts = {1, \'unsigned\'}})')] public function testSelectEmpty() : void { $space = $this->client->getSpace('request_select'); @@ -65,9 +63,7 @@ public function testSelectEmpty() : void self::assertEmpty($space->select(Criteria::key([]))); } - /** - * @lua create_space('request_select'):create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) - */ + #[Lua('create_space(\'request_select\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] public function testSelectWithNonExistingIndexName() : void { $space = $this->client->getSpace('request_select'); @@ -78,9 +74,7 @@ public function testSelectWithNonExistingIndexName() : void $space->select(Criteria::key([1])->andIndex('non_existing_index')); } - /** - * @lua create_space('request_select'):create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) - */ + #[Lua('create_space(\'request_select\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] public function testSelectWithNonExistingIndexId() : void { $space = $this->client->getSpace('request_select'); diff --git a/tests/Integration/Requests/UpdateTest.php b/tests/Integration/Requests/UpdateTest.php index 550ad862..7150766b 100755 --- a/tests/Integration/Requests/UpdateTest.php +++ b/tests/Integration/Requests/UpdateTest.php @@ -17,14 +17,13 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Schema\Operations; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Annotation\Attribute\Lua; -/** - * @lua space = create_space('request_update') - * @lua space:create_index('primary', {type = 'tree', unique = true, parts = {1, 'unsigned'}}) - * @lua space:create_index('secondary', {type = 'tree', unique = false, parts = {2, 'unsigned', 3, 'str'}}) - * @lua space:replace{1, 2, 'tuple_1'} - * @lua space:replace{2, 4, 'tuple_2'} - */ +#[Lua('space = create_space(\'request_update\')')] +#[Lua('space:create_index(\'primary\', {type = \'tree\', unique = true, parts = {1, \'unsigned\'}})')] +#[Lua('space:create_index(\'secondary\', {type = \'tree\', unique = false, parts = {2, \'unsigned\', 3, \'str\'}})')] +#[Lua('space:replace{1, 2, \'tuple_1\'}')] +#[Lua('space:replace{2, 4, \'tuple_2\'}')] final class UpdateTest extends TestCase { /** diff --git a/tests/Integration/Requests/UpsertTest.php b/tests/Integration/Requests/UpsertTest.php index 7374d334..de1452a8 100755 --- a/tests/Integration/Requests/UpsertTest.php +++ b/tests/Integration/Requests/UpsertTest.php @@ -17,11 +17,10 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Schema\Operations; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Annotation\Attribute\Lua; -/** - * @lua space = create_space('request_upsert') - * @lua space:create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) - */ +#[Lua('space = create_space(\'request_upsert\')')] +#[Lua('space:create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] final class UpsertTest extends TestCase { public function testUpsert() : void From f74d6e127ed870457a326971cc9577ab0ded8512 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Thu, 20 Aug 2026 22:13:39 +0200 Subject: [PATCH 09/34] chore: require PHP 8.2 and PHPUnit 10 --- composer.json | 2 +- .../user_defined_type/example_decimal.php | 2 +- phpunit.xml.dist | 15 ++--- src/Packer/Extension/DecimalExtension.php | 5 +- tests/Integration/ClientMiddlewareTest.php | 8 +-- .../Integration/Connection/ConnectionTest.php | 8 +-- .../Connection/ParseGreetingTest.php | 8 +-- tests/Integration/ExamplesTest.php | 6 +- .../MessagePack/DecimalExtensionTest.php | 37 +++++++----- .../MessagePack/MessagePackTest.php | 17 +++--- tests/Integration/PacketSyncTest.php | 6 +- .../Integration/Requests/AuthenticateTest.php | 14 ++--- tests/Integration/Requests/InsertTest.php | 12 ++-- tests/Integration/Requests/PingTest.php | 4 +- tests/Integration/Requests/SelectTest.php | 6 +- tests/Integration/Requests/UpdateTest.php | 12 ++-- tests/Integration/TestCase.php | 5 +- tests/Unit/ClientFactoryTest.php | 24 +++----- tests/Unit/Connection/GreetingTest.php | 10 +--- .../Unit/Connection/StreamConnectionTest.php | 24 +++----- tests/Unit/DsnTest.php | 60 +++++++------------ .../Middleware/FirewallMiddlewareTest.php | 6 +- tests/Unit/OptionsProvider.php | 2 +- tests/Unit/Packer/PurePackerTest.php | 6 +- tests/Unit/Schema/CriteriaTest.php | 10 +--- 25 files changed, 117 insertions(+), 192 deletions(-) diff --git a/composer.json b/composer.json index a5cc4961..421126e7 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ ], "require": { "php": "^8.2", - "rybakit/msgpack": "^0.9", + "rybakit/msgpack": "^0.10", "symfony/uid": "^5.1|^6|^7" }, "require-dev": { diff --git a/examples/user_defined_type/example_decimal.php b/examples/user_defined_type/example_decimal.php index 056b59b0..8f1b55b9 100644 --- a/examples/user_defined_type/example_decimal.php +++ b/examples/user_defined_type/example_decimal.php @@ -31,7 +31,7 @@ $space = $client->getSpace($spaceName); -$result1 = $space->insert([3, new Decimal('1.000000099')]); +$result1 = $space->insert([3, Decimal::valueOf('1.000000099')]); $result2 = $space->select(Criteria::key([3])); printf("Result 1: %s\n", $result1[0][1]->toString()); diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 044d61c9..423c5824 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,16 +1,11 @@ @@ -33,9 +28,9 @@ - - + + src - - + + diff --git a/src/Packer/Extension/DecimalExtension.php b/src/Packer/Extension/DecimalExtension.php index d47f05e1..5a9aec55 100644 --- a/src/Packer/Extension/DecimalExtension.php +++ b/src/Packer/Extension/DecimalExtension.php @@ -75,6 +75,9 @@ public function unpackExt(BufferUnpacker $unpacker, int $extLength) $sign = 'd' === $data[-1] ? '-' : ''; $dec = substr($data, 0, -1); + if (\strlen($dec) > 1 && 1 === \strlen($dec) % 2 && '0' === $dec[0]) { + $dec = substr($dec, 1); + } if (0 !== $scale) { $length = \strlen($dec); @@ -83,6 +86,6 @@ public function unpackExt(BufferUnpacker $unpacker, int $extLength) : substr_replace($dec, '.', -$scale, 0); } - return new Decimal($sign.$dec, self::PRECISION); + return Decimal::valueOf($sign.$dec, self::PRECISION); } } diff --git a/tests/Integration/ClientMiddlewareTest.php b/tests/Integration/ClientMiddlewareTest.php index c9c9f331..91ca254b 100644 --- a/tests/Integration/ClientMiddlewareTest.php +++ b/tests/Integration/ClientMiddlewareTest.php @@ -51,9 +51,7 @@ public function testSpaceInheritsMiddleware() : void self::assertSame([1, 1, 1], $middleware->getTraceLogArray()); } - /** - * @doesNotPerformAssertions - */ + #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] #[Lua('fiber = require(\'fiber\')')] #[Lua('function test() try_drop_user(\'foobar\') fiber.sleep(.5) create_user(\'foobar\', \'\') end')] #[Lua('fiber.create(test)')] @@ -115,9 +113,7 @@ public function testNoRetriesOnUnexpectedResponse() : void $client->ping(); } - /** - * @doesNotPerformAssertions - */ + #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] public function testReconnectOnBrokenConnection() : void { $clientBuilder = ClientBuilder::createFromEnv(); diff --git a/tests/Integration/Connection/ConnectionTest.php b/tests/Integration/Connection/ConnectionTest.php index afba311a..d3252e48 100644 --- a/tests/Integration/Connection/ConnectionTest.php +++ b/tests/Integration/Connection/ConnectionTest.php @@ -29,10 +29,8 @@ final class ConnectionTest extends TestCase { - /** - * @dataProvider provideAutoConnectData - * @doesNotPerformAssertions - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideAutoConnectData')] + #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] #[Lua('create_space(\'test_auto_connect\'):create_index(\'primary\', {type = \'tree\', parts = {1, \'unsigned\'}})')] public function testAutoConnect(string $methodName, array $methodArgs, ?string $space = null) : void { @@ -42,7 +40,7 @@ public function testAutoConnect(string $methodName, array $methodArgs, ?string $ $object->$methodName(...$methodArgs); } - public function provideAutoConnectData() : iterable + public static function provideAutoConnectData() : iterable { return [ ['ping', []], diff --git a/tests/Integration/Connection/ParseGreetingTest.php b/tests/Integration/Connection/ParseGreetingTest.php index 93e5c4be..db639fd5 100644 --- a/tests/Integration/Connection/ParseGreetingTest.php +++ b/tests/Integration/Connection/ParseGreetingTest.php @@ -21,9 +21,7 @@ final class ParseGreetingTest extends TestCase { - /** - * @dataProvider \Tarantool\Client\Tests\GreetingDataProvider::provideGreetingsWithInvalidServerName - */ + #[\PHPUnit\Framework\Attributes\DataProviderExternal(\Tarantool\Client\Tests\GreetingDataProvider::class, 'provideGreetingsWithInvalidServerName')] public function testParseGreetingWithInvalidServerName(string $greeting) : void { $clientBuilder = ClientBuilder::createForFakeServer(); @@ -52,9 +50,7 @@ public function testParseGreetingWithInvalidServerName(string $greeting) : void self::fail(); } - /** - * @dataProvider \Tarantool\Client\Tests\GreetingDataProvider::provideGreetingsWithInvalidSalt - */ + #[\PHPUnit\Framework\Attributes\DataProviderExternal(\Tarantool\Client\Tests\GreetingDataProvider::class, 'provideGreetingsWithInvalidSalt')] public function testParseGreetingWithInvalidSalt(string $greeting) : void { $clientBuilder = ClientBuilder::createForFakeServer(); diff --git a/tests/Integration/ExamplesTest.php b/tests/Integration/ExamplesTest.php index 558fae73..10ae9ddb 100644 --- a/tests/Integration/ExamplesTest.php +++ b/tests/Integration/ExamplesTest.php @@ -15,9 +15,7 @@ final class ExamplesTest extends TestCase { - /** - * @dataProvider provideExampleData - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideExampleData')] public function testExample(string $filename) : void { $uri = ClientBuilder::createFromEnv()->getUri(); @@ -37,7 +35,7 @@ public function testExample(string $filename) : void } } - public function provideExampleData() : iterable + public static function provideExampleData() : iterable { $dir = dirname(__DIR__, 2).'/examples'; foreach (glob("$dir/{**/*,*}.php", GLOB_BRACE) as $filename) { diff --git a/tests/Integration/MessagePack/DecimalExtensionTest.php b/tests/Integration/MessagePack/DecimalExtensionTest.php index bbd60438..9393c873 100755 --- a/tests/Integration/MessagePack/DecimalExtensionTest.php +++ b/tests/Integration/MessagePack/DecimalExtensionTest.php @@ -14,6 +14,8 @@ namespace Tarantool\Client\Tests\Integration\MessagePack; use Decimal\Decimal; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DataProviderExternal; use PHPUnit\Framework\Attributes\RequiresPhpExtension; use PHPUnitExtras\Annotation\Attribute\Requires; use Tarantool\Client\Client; @@ -22,6 +24,7 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\Client\Tests\PackerDataProvider; use Tarantool\PhpUnit\Annotation\Attribute\Lua; #[Lua('dec = require(\'decimal\').new(\'18446744073709551615\')')] @@ -40,12 +43,12 @@ public function testBinarySelectByDecimalKeySucceeds() : void { $client = self::createClientWithDecimalSupport(); - $decimal = new Decimal(self::DECIMAL_BIG_INT, self::TARANTOOL_DECIMAL_PRECISION); + $decimal = Decimal::valueOf(self::DECIMAL_BIG_INT, self::TARANTOOL_DECIMAL_PRECISION); $space = $client->getSpace('decimal_primary'); $result = $space->select(Criteria::key([$decimal])); self::assertTrue(isset($result[0][0])); - self::assertTrue($decimal->equals($result[0][0])); + self::assertEquals($decimal, $result[0][0]); } #[Requires('Tarantool', '>=2.10-stable')] @@ -53,31 +56,32 @@ public function testSqlSelectByDecimalKeySucceeds() : void { $client = self::createClientWithDecimalSupport(); - $decimal = new Decimal(self::DECIMAL_BIG_INT, self::TARANTOOL_DECIMAL_PRECISION); + $decimal = Decimal::valueOf(self::DECIMAL_BIG_INT, self::TARANTOOL_DECIMAL_PRECISION); $result = $client->executeQuery('SELECT * FROM "decimal_primary" WHERE "id" = ?', $decimal); self::assertFalse($result->isEmpty()); - self::assertTrue($decimal->equals($result->getFirst()['id'])); + self::assertEquals($decimal, $result->getFirst()['id']); } - /** - * @dataProvider provideDecimalStrings - */ + #[DataProvider('provideDecimalStrings')] public function testLuaPackingAndUnpacking(string $decimalString) : void { $client = self::createClientWithDecimalSupport(); [$decimal] = $client->evaluate('return require("decimal").new(...)', $decimalString); - self::assertTrue($decimal->equals($decimalString)); + self::assertSame( + self::normalizeDecimalString($decimalString), + $decimal->toFixed(self::TARANTOOL_DECIMAL_PRECISION) + ); [$isEqual] = $client->evaluate( sprintf("return require('decimal').new('%s') == ...", $decimalString), - new Decimal($decimalString, self::TARANTOOL_DECIMAL_PRECISION) + Decimal::valueOf($decimalString, self::TARANTOOL_DECIMAL_PRECISION) ); self::assertTrue($isEqual); } - public function provideDecimalStrings() : iterable + public static function provideDecimalStrings() : iterable { return [ ['0'], @@ -107,12 +111,10 @@ public function testBigIntegerUnpacksToDecimal() : void [$number] = $client->evaluate('return 18446744073709551615ULL'); self::assertInstanceOf(Decimal::class, $number); - self::assertTrue((new Decimal('18446744073709551615'))->equals($number)); + self::assertEquals(Decimal::valueOf('18446744073709551615'), $number); } - /** - * @dataProvider \Tarantool\Client\Tests\PackerDataProvider::providePurePackerWithDefaultSettings() - */ + #[DataProviderExternal(PackerDataProvider::class, 'providePurePackerWithDefaultSettings')] public function testPurePackerUnpacksBigIntToDecimal(PurePacker $packer) : void { $client = ClientBuilder::createFromEnv() @@ -122,7 +124,7 @@ public function testPurePackerUnpacksBigIntToDecimal(PurePacker $packer) : void [$number] = $client->evaluate(sprintf('return %sULL', self::DECIMAL_BIG_INT)); self::assertInstanceOf(Decimal::class, $number); - self::assertTrue((new Decimal(self::DECIMAL_BIG_INT))->equals($number)); + self::assertEquals(Decimal::valueOf(self::DECIMAL_BIG_INT), $number); } private static function createClientWithDecimalSupport() : Client @@ -133,4 +135,9 @@ private static function createClientWithDecimalSupport() : Client }) ->build(); } + + private static function normalizeDecimalString(string $decimal) : string + { + return Decimal::valueOf($decimal, self::TARANTOOL_DECIMAL_PRECISION)->toFixed(self::TARANTOOL_DECIMAL_PRECISION); + } } diff --git a/tests/Integration/MessagePack/MessagePackTest.php b/tests/Integration/MessagePack/MessagePackTest.php index 8d4e1182..5041e48a 100755 --- a/tests/Integration/MessagePack/MessagePackTest.php +++ b/tests/Integration/MessagePack/MessagePackTest.php @@ -13,23 +13,25 @@ namespace Tarantool\Client\Tests\Integration\MessagePack; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnitExtras\Annotation\Attribute\Requires; use Tarantool\Client\Packer\PurePacker; use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\Client\Tests\PackerDataProvider; use Tarantool\PhpUnit\Annotation\Attribute\Lua; final class MessagePackTest extends TestCase { - /** - * @dataProvider providePackUnpackData - */ + #[DataProvider('providePackUnpackData')] public function testPackUnpack($arg) : void { self::assertSame([$arg], $this->client->evaluate('return ...', $arg)); } - public function providePackUnpackData() : iterable + public static function providePackUnpackData() : iterable { return [ [[]], @@ -84,11 +86,8 @@ public function testCustomType() : void self::assertEquals($date, $space->select(Criteria::key([100]))[0][1]); } - /** - * @requires condition env.EXT_DISABLE_DECIMAL - * - * @dataProvider \Tarantool\Client\Tests\PackerDataProvider::providePurePackerWithDefaultSettings() - */ + #[Requires('luaCondition', 'os.getenv("EXT_DISABLE_DECIMAL")')] + #[DataProviderExternal(PackerDataProvider::class, 'providePurePackerWithDefaultSettings')] public function testPurePackerUnpacksBigIntToString(PurePacker $packer) : void { $client = ClientBuilder::createFromEnv() diff --git a/tests/Integration/PacketSyncTest.php b/tests/Integration/PacketSyncTest.php index 9454cfcd..1e4e46d2 100755 --- a/tests/Integration/PacketSyncTest.php +++ b/tests/Integration/PacketSyncTest.php @@ -17,9 +17,7 @@ final class PacketSyncTest extends TestCase { - /** - * @dataProvider provideValidSync - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideValidSync')] public function testSameSync(int $sync) : void { $handler = $this->client->getHandler(); @@ -35,7 +33,7 @@ public function testSameSync(int $sync) : void self::assertSame($sync, $response->getSync()); } - public function provideValidSync() : iterable + public static function provideValidSync() : iterable { return [ [0], diff --git a/tests/Integration/Requests/AuthenticateTest.php b/tests/Integration/Requests/AuthenticateTest.php index 84e28e6c..9c104d79 100644 --- a/tests/Integration/Requests/AuthenticateTest.php +++ b/tests/Integration/Requests/AuthenticateTest.php @@ -20,10 +20,8 @@ final class AuthenticateTest extends TestCase { - /** - * @doesNotPerformAssertions - * @dataProvider provideValidCredentials - */ + #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] + #[\PHPUnit\Framework\Attributes\DataProvider('provideValidCredentials')] #[Lua('create_user(\'user_foo\', \'foo\')')] #[Lua('create_user(\'user_empty\', \'\')')] #[Lua('create_user(\'user_big\', \'123456789012345678901234567890123456789012345678901234567890\')')] @@ -37,7 +35,7 @@ public function testAuthenticateWithValidCredentials(string $username, string $p $client->ping(); } - public function provideValidCredentials() : iterable + public static function provideValidCredentials() : iterable { return [ ['guest', ''], @@ -47,9 +45,7 @@ public function provideValidCredentials() : iterable ]; } - /** - * @dataProvider provideInvalidCredentials - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideInvalidCredentials')] public function testAuthenticateWithInvalidCredentials(string $errorMessagePattern, $username, $password) : void { $client = ClientBuilder::createFromEnv()->setOptions([ @@ -65,7 +61,7 @@ public function testAuthenticateWithInvalidCredentials(string $errorMessagePatte } } - public function provideInvalidCredentials() : iterable + public static function provideInvalidCredentials() : iterable { return [ ["/(User 'non_existing_user' is not found|User not found or supplied credentials are invalid)/", 'non_existing_user', 'password'], diff --git a/tests/Integration/Requests/InsertTest.php b/tests/Integration/Requests/InsertTest.php index a944e7cb..8e318cbd 100755 --- a/tests/Integration/Requests/InsertTest.php +++ b/tests/Integration/Requests/InsertTest.php @@ -19,9 +19,7 @@ final class InsertTest extends TestCase { - /** - * @dataProvider provideInsertData - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideInsertData')] #[Lua('create_space(\'request_insert_str\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'str\'}})')] #[Lua('create_space(\'request_insert_num\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] public function testInsert(string $spaceName, array $values) : void @@ -32,7 +30,7 @@ public function testInsert(string $spaceName, array $values) : void self::assertSame([$values], $result); } - public function provideInsertData() : iterable + public static function provideInsertData() : iterable { return [ ['request_insert_str', ['']], @@ -45,9 +43,7 @@ public function provideInsertData() : iterable ]; } - /** - * @dataProvider provideInsertDataWithMismatchedTypes - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideInsertDataWithMismatchedTypes')] #[Lua('create_space(\'request_insert_str\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'str\'}})')] #[Lua('create_space(\'request_insert_num\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] public function testInsertTypeMismatchedValues(string $spaceName, array $values) : void @@ -60,7 +56,7 @@ public function testInsertTypeMismatchedValues(string $spaceName, array $values) $space->insert($values); } - public function provideInsertDataWithMismatchedTypes() : iterable + public static function provideInsertDataWithMismatchedTypes() : iterable { return [ ['request_insert_str', [null]], diff --git a/tests/Integration/Requests/PingTest.php b/tests/Integration/Requests/PingTest.php index 5d8b7bf8..3154432e 100644 --- a/tests/Integration/Requests/PingTest.php +++ b/tests/Integration/Requests/PingTest.php @@ -17,9 +17,7 @@ final class PingTest extends TestCase { - /** - * @doesNotPerformAssertions - */ + #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] public function testPing() : void { $this->client->ping(); diff --git a/tests/Integration/Requests/SelectTest.php b/tests/Integration/Requests/SelectTest.php index 0eae3347..f39d80a8 100755 --- a/tests/Integration/Requests/SelectTest.php +++ b/tests/Integration/Requests/SelectTest.php @@ -20,9 +20,7 @@ final class SelectTest extends TestCase { - /** - * @dataProvider provideSelectData - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideSelectData')] #[Lua('space = create_space(\'request_select\')')] #[Lua('space:create_index(\'primary\', {type = \'tree\', unique = true, parts = {1, \'unsigned\'}})')] #[Lua('space:create_index(\'secondary\', {type = \'tree\', unique = false, parts = {2, \'unsigned\', 3, \'str\'}})')] @@ -35,7 +33,7 @@ public function testSelect(int $expectedCount, Criteria $criteria) : void self::assertCount($expectedCount, $result); } - public function provideSelectData() : iterable + public static function provideSelectData() : iterable { return [ [100, Criteria::key([])], diff --git a/tests/Integration/Requests/UpdateTest.php b/tests/Integration/Requests/UpdateTest.php index 7150766b..91656e9b 100755 --- a/tests/Integration/Requests/UpdateTest.php +++ b/tests/Integration/Requests/UpdateTest.php @@ -26,18 +26,16 @@ #[Lua('space:replace{2, 4, \'tuple_2\'}')] final class UpdateTest extends TestCase { - /** - * @dataProvider provideUpdateData - */ - public function testUpdate(Operations $operations, array $expectedResult) : void + public function testUpdate() : void { $space = $this->client->getSpace('request_update'); - $result = $space->update([1], $operations); - self::assertSame($expectedResult, $result); + foreach (self::provideUpdateData() as [$operations, $expectedResult]) { + self::assertSame($expectedResult, $space->update([1], $operations)); + } } - public function provideUpdateData() : iterable + public static function provideUpdateData() : iterable { return [ [ diff --git a/tests/Integration/TestCase.php b/tests/Integration/TestCase.php index cc2cf6a9..f62bd64f 100644 --- a/tests/Integration/TestCase.php +++ b/tests/Integration/TestCase.php @@ -27,9 +27,7 @@ abstract class TestCase extends BaseTestCase /** @var Client|null */ protected $client; - /** - * @before - */ + #[\PHPUnit\Framework\Attributes\Before] protected function getClient() : Client { return $this->client @@ -59,7 +57,6 @@ final protected static function triggerUnexpectedResponse(Handler $handler, Requ final public static function getRawStream(StreamConnection $connection) { $prop = (new \ReflectionObject($connection))->getProperty('stream'); - $prop->setAccessible(true); return $prop->getValue($connection); } diff --git a/tests/Unit/ClientFactoryTest.php b/tests/Unit/ClientFactoryTest.php index 49e125c4..eef99d22 100644 --- a/tests/Unit/ClientFactoryTest.php +++ b/tests/Unit/ClientFactoryTest.php @@ -57,20 +57,16 @@ public function testFromDsnCreatesClientWithCustomPacker() : void self::assertSame($packer, $client->getHandler()->getPacker()); } - /** - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideClientArrayOptionsOfValidTypes - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideTcpExtraConnectionArrayOptionsOfValidTypes - * @doesNotPerformAssertions - */ + #[\PHPUnit\Framework\Attributes\DataProviderExternal(OptionsProvider::class, 'provideClientArrayOptionsOfValidTypes')] + #[\PHPUnit\Framework\Attributes\DataProviderExternal(OptionsProvider::class, 'provideTcpExtraConnectionArrayOptionsOfValidTypes')] + #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] public function testFromOptionsAcceptsOptionOfValidType(string $optionName, $optionValue, array $extraOptions = []) : void { Client::fromOptions([$optionName => $optionValue] + $extraOptions); } - /** - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideClientArrayOptionsOfInvalidTypes - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideTcpExtraConnectionArrayOptionsOfInvalidTypes - */ + #[\PHPUnit\Framework\Attributes\DataProviderExternal(OptionsProvider::class, 'provideClientArrayOptionsOfInvalidTypes')] + #[\PHPUnit\Framework\Attributes\DataProviderExternal(OptionsProvider::class, 'provideTcpExtraConnectionArrayOptionsOfInvalidTypes')] public function testFromOptionsRejectsOptionOfInvalidType(string $optionName, $optionValue, string $expectedType, array $extraOptions = []) : void { $this->expectException(\TypeError::class); @@ -79,18 +75,14 @@ public function testFromOptionsRejectsOptionOfInvalidType(string $optionName, $o Client::fromOptions([$optionName => $optionValue] + $extraOptions); } - /** - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideClientDsnOptionsOfValidTypes - * @doesNotPerformAssertions - */ + #[\PHPUnit\Framework\Attributes\DataProviderExternal(OptionsProvider::class, 'provideClientDsnOptionsOfValidTypes')] + #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] public function testFromDsnAcceptsOptionOfValidType(string $query) : void { Client::fromDsn("tcp://tnt/?$query"); } - /** - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideClientDsnOptionsOfInvalidTypes - */ + #[\PHPUnit\Framework\Attributes\DataProviderExternal(OptionsProvider::class, 'provideClientDsnOptionsOfInvalidTypes')] public function testFromDsnRejectsOptionOfInvalidType(string $query, string $optionName, string $expectedType) : void { $this->expectException(\TypeError::class); diff --git a/tests/Unit/Connection/GreetingTest.php b/tests/Unit/Connection/GreetingTest.php index ff3b37b7..86175567 100644 --- a/tests/Unit/Connection/GreetingTest.php +++ b/tests/Unit/Connection/GreetingTest.php @@ -19,17 +19,13 @@ final class GreetingTest extends TestCase { - /** - * @dataProvider \Tarantool\Client\Tests\GreetingDataProvider::provideValidGreetings - */ + #[\PHPUnit\Framework\Attributes\DataProviderExternal(GreetingDataProvider::class, 'provideValidGreetings')] public function testGetSalt(string $greeting, string $salt) : void { self::assertSame($salt, Greeting::parse($greeting)->getSalt()); } - /** - * @dataProvider provideServerVersionData - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideServerVersionData')] public function testGetServerVersion(string $greeting, string $expectedVersion) : void { $greeting = Greeting::parse($greeting); @@ -37,7 +33,7 @@ public function testGetServerVersion(string $greeting, string $expectedVersion) self::assertSame($expectedVersion, $greeting->getServerVersion()); } - public function provideServerVersionData() : iterable + public static function provideServerVersionData() : iterable { return [ [GreetingDataProvider::generateGreeting('foobar'), ''], diff --git a/tests/Unit/Connection/StreamConnectionTest.php b/tests/Unit/Connection/StreamConnectionTest.php index 853e35d6..d2f4b1fe 100644 --- a/tests/Unit/Connection/StreamConnectionTest.php +++ b/tests/Unit/Connection/StreamConnectionTest.php @@ -18,29 +18,23 @@ final class StreamConnectionTest extends TestCase { - /** - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideConnectionArrayOptionsOfValidTypes - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideTcpExtraConnectionArrayOptionsOfValidTypes - * @doesNotPerformAssertions - */ + #[\PHPUnit\Framework\Attributes\DataProviderExternal(\Tarantool\Client\Tests\Unit\OptionsProvider::class, 'provideConnectionArrayOptionsOfValidTypes')] + #[\PHPUnit\Framework\Attributes\DataProviderExternal(\Tarantool\Client\Tests\Unit\OptionsProvider::class, 'provideTcpExtraConnectionArrayOptionsOfValidTypes')] + #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] public function testCreateTcpAcceptsOptionOfValidType(string $optionName, $optionValue) : void { StreamConnection::createTcp(StreamConnection::DEFAULT_TCP_URI, [$optionName => $optionValue]); } - /** - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideConnectionArrayOptionsOfValidTypes - * @doesNotPerformAssertions - */ + #[\PHPUnit\Framework\Attributes\DataProviderExternal(\Tarantool\Client\Tests\Unit\OptionsProvider::class, 'provideConnectionArrayOptionsOfValidTypes')] + #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] public function testCreateUdsAcceptsOptionOfValidType(string $optionName, $optionValue) : void { StreamConnection::createUds('unix:///socket.sock', [$optionName => $optionValue]); } - /** - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideConnectionArrayOptionsOfInvalidTypes - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideTcpExtraConnectionArrayOptionsOfInvalidTypes - */ + #[\PHPUnit\Framework\Attributes\DataProviderExternal(\Tarantool\Client\Tests\Unit\OptionsProvider::class, 'provideConnectionArrayOptionsOfInvalidTypes')] + #[\PHPUnit\Framework\Attributes\DataProviderExternal(\Tarantool\Client\Tests\Unit\OptionsProvider::class, 'provideTcpExtraConnectionArrayOptionsOfInvalidTypes')] public function testCreateTcpRejectsOptionOfInvalidType(string $optionName, $optionValue, string $expectedType) : void { $this->expectException(\TypeError::class); @@ -49,9 +43,7 @@ public function testCreateTcpRejectsOptionOfInvalidType(string $optionName, $opt StreamConnection::createTcp(StreamConnection::DEFAULT_TCP_URI, [$optionName => $optionValue]); } - /** - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideConnectionArrayOptionsOfInvalidTypes - */ + #[\PHPUnit\Framework\Attributes\DataProviderExternal(\Tarantool\Client\Tests\Unit\OptionsProvider::class, 'provideConnectionArrayOptionsOfInvalidTypes')] public function testCreateUdsRejectsOptionOfInvalidType(string $optionName, $optionValue, string $expectedType) : void { $this->expectException(\TypeError::class); diff --git a/tests/Unit/DsnTest.php b/tests/Unit/DsnTest.php index 3d2fd9f2..70e06942 100644 --- a/tests/Unit/DsnTest.php +++ b/tests/Unit/DsnTest.php @@ -18,9 +18,7 @@ final class DsnTest extends TestCase { - /** - * @dataProvider provideValidTcpDsns - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideValidTcpDsns')] public function testParseValidTcpDsn(string $dsn, array $expectedResult) : void { $dsn = Dsn::parse($dsn); @@ -36,7 +34,7 @@ public function testParseValidTcpDsn(string $dsn, array $expectedResult) : void } } - public function provideValidTcpDsns() : iterable + public static function provideValidTcpDsns() : iterable { return [ ['tcp://127.0.0.1', ['uri' => 'tcp://127.0.0.1:3301', 'host' => '127.0.0.1', 'port' => 3301]], @@ -53,9 +51,7 @@ public function provideValidTcpDsns() : iterable ]; } - /** - * @dataProvider provideValidUdsDsns - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideValidUdsDsns')] public function testParseValidUdsDsn(string $dsn, array $expected) : void { $dsn = Dsn::parse($dsn); @@ -71,7 +67,7 @@ public function testParseValidUdsDsn(string $dsn, array $expected) : void } } - public function provideValidUdsDsns() : iterable + public static function provideValidUdsDsns() : iterable { return [ ['unix:///path/to/socket.sock', ['uri' => 'unix:///path/to/socket.sock', 'path' => '/path/to/socket.sock']], @@ -83,9 +79,7 @@ public function provideValidUdsDsns() : iterable ]; } - /** - * @dataProvider provideInvalidDsns - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideInvalidDsns')] public function testParseInvalidDsn(string $nonDsn) : void { $this->expectException(\InvalidArgumentException::class); @@ -93,7 +87,7 @@ public function testParseInvalidDsn(string $nonDsn) : void Dsn::parse($nonDsn); } - public function provideInvalidDsns() : iterable + public static function provideInvalidDsns() : iterable { return [ [''], @@ -116,16 +110,14 @@ public function provideInvalidDsns() : iterable ]; } - /** - * @dataProvider provideStringOptions - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideStringOptions')] public function testGetString(string $dsn, string $option, ?string $expectedValue) : void { $dsn = Dsn::parse($dsn); self::assertSame($expectedValue, $dsn->getString($option)); } - public function provideStringOptions() : iterable + public static function provideStringOptions() : iterable { return [ ['tcp://host/?foo=bar', 'foo', 'bar'], @@ -151,16 +143,14 @@ public function testGetStringDefault() : void self::assertSame('qux', $dsn->getString('baz', 'qux')); } - /** - * @dataProvider provideIntOptions - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideIntOptions')] public function testGetInt(string $dsn, string $option, $expectedValue) : void { $dsn = Dsn::parse($dsn); self::assertSame($expectedValue, $dsn->getInt($option)); } - public function provideIntOptions() : iterable + public static function provideIntOptions() : iterable { return [ ['tcp://host/?foo=42', 'foo', 42], @@ -178,9 +168,7 @@ public function testGetIntDefault() : void self::assertSame(42, $dsn->getInt('baz', 42)); } - /** - * @dataProvider provideNonIntOptions - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideNonIntOptions')] public function testGetNonInt(string $dsn, string $option) : void { $dsn = Dsn::parse($dsn); @@ -190,7 +178,7 @@ public function testGetNonInt(string $dsn, string $option) : void $dsn->getInt($option); } - public function provideNonIntOptions() : iterable + public static function provideNonIntOptions() : iterable { return [ ['tcp://host/?foo=bar', 'foo'], @@ -204,16 +192,14 @@ public function provideNonIntOptions() : iterable ]; } - /** - * @dataProvider provideFloatOptions - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideFloatOptions')] public function testGetFloat(string $dsn, string $option, $expectedValue) : void { $dsn = Dsn::parse($dsn); self::assertSame($expectedValue, $dsn->getFloat($option)); } - public function provideFloatOptions() : iterable + public static function provideFloatOptions() : iterable { return [ ['tcp://host/?foo=42', 'foo', 42.0], @@ -233,9 +219,7 @@ public function testGetFloatDefault() : void self::assertSame(42.3, $dsn->getFloat('baz', 42.3)); } - /** - * @dataProvider provideNonFloatOptions - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideNonFloatOptions')] public function testGetNonFloat(string $dsn, string $option) : void { $dsn = Dsn::parse($dsn); @@ -245,7 +229,7 @@ public function testGetNonFloat(string $dsn, string $option) : void $dsn->getFloat($option); } - public function provideNonFloatOptions() : iterable + public static function provideNonFloatOptions() : iterable { return [ ['tcp://host/?foo=bar', 'foo'], @@ -257,16 +241,14 @@ public function provideNonFloatOptions() : iterable ]; } - /** - * @dataProvider provideBoolOptions - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideBoolOptions')] public function testGetBool(string $dsn, string $option, ?bool $expectedValue) : void { $dsn = Dsn::parse($dsn); self::assertSame($expectedValue, $dsn->getBool($option)); } - public function provideBoolOptions() : iterable + public static function provideBoolOptions() : iterable { return [ ['tcp://host/?foo=true', 'foo', true], @@ -294,9 +276,7 @@ public function testGetBoolDefault() : void self::assertTrue($dsn->getBool('baz', true)); } - /** - * @dataProvider provideNonBoolOptions - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideNonBoolOptions')] public function testGetNonBool(string $dsn, string $option) : void { $dsn = Dsn::parse($dsn); @@ -306,7 +286,7 @@ public function testGetNonBool(string $dsn, string $option) : void $dsn->getBool($option); } - public function provideNonBoolOptions() : iterable + public static function provideNonBoolOptions() : iterable { return [ ['tcp://host/?foo=bar', 'foo'], diff --git a/tests/Unit/Middleware/FirewallMiddlewareTest.php b/tests/Unit/Middleware/FirewallMiddlewareTest.php index 757f3c97..5106b410 100644 --- a/tests/Unit/Middleware/FirewallMiddlewareTest.php +++ b/tests/Unit/Middleware/FirewallMiddlewareTest.php @@ -168,9 +168,7 @@ public function testAndDenyOnlyForbids() : void $middleware->process(new CallRequest('foo'), $this->handler); } - /** - * @dataProvider provideBlacklistPriorityData - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideBlacklistPriorityData')] public function testDenyHasPriority(Middleware $middleware) : void { $this->expectException(RequestDenied::class); @@ -179,7 +177,7 @@ public function testDenyHasPriority(Middleware $middleware) : void $middleware->process(new PingRequest(), $this->handler); } - public function provideBlacklistPriorityData() : iterable + public static function provideBlacklistPriorityData() : iterable { yield [FirewallMiddleware::allow(RequestTypes::PING)->andDeny(RequestTypes::PING)]; yield [FirewallMiddleware::deny(RequestTypes::PING)->andAllow(RequestTypes::PING)]; diff --git a/tests/Unit/OptionsProvider.php b/tests/Unit/OptionsProvider.php index 39b31389..c41f5bfb 100644 --- a/tests/Unit/OptionsProvider.php +++ b/tests/Unit/OptionsProvider.php @@ -38,7 +38,7 @@ public static function provideConnectionArrayOptionsOfInvalidTypes() : array ]; } - public function provideTcpExtraConnectionArrayOptionsOfValidTypes() : array + public static function provideTcpExtraConnectionArrayOptionsOfValidTypes() : array { return [ ['tcp_nodelay', false], diff --git a/tests/Unit/Packer/PurePackerTest.php b/tests/Unit/Packer/PurePackerTest.php index bffb9c1a..2ba45598 100644 --- a/tests/Unit/Packer/PurePackerTest.php +++ b/tests/Unit/Packer/PurePackerTest.php @@ -30,9 +30,7 @@ protected function setUp() : void $this->packer = new PurePacker(); } - /** - * @dataProvider provideBadUnpackData - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideBadUnpackData')] public function testThrowExceptionOnBadUnpackData(string $data) : void { $this->expectException(UnpackingFailedException::class); @@ -40,7 +38,7 @@ public function testThrowExceptionOnBadUnpackData(string $data) : void $this->packer->unpack($data)->tryGetBodyField(Keys::DATA); } - public function provideBadUnpackData() : iterable + public static function provideBadUnpackData() : iterable { return [ [''], diff --git a/tests/Unit/Schema/CriteriaTest.php b/tests/Unit/Schema/CriteriaTest.php index 83070055..c88166d9 100644 --- a/tests/Unit/Schema/CriteriaTest.php +++ b/tests/Unit/Schema/CriteriaTest.php @@ -79,9 +79,7 @@ public function testAndIterator() : void self::assertSame(IteratorTypes::GE, Criteria::iterator(IteratorTypes::ALL)->andIterator(IteratorTypes::GE)->getIterator()); } - /** - * @dataProvider provideIteratorTypes - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideIteratorTypes')] public function testIteratorTypeByName(string $name) : void { $method = str_replace('_', '', $name).'iterator'; @@ -90,9 +88,7 @@ public function testIteratorTypeByName(string $name) : void self::assertSame(constant(IteratorTypes::class.'::'.$name), $criteria->getIterator()); } - /** - * @dataProvider provideIteratorTypes - */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideIteratorTypes')] public function testAndIteratorTypeByName(string $name) : void { // Make sure we don't assign the same iterator twice @@ -103,7 +99,7 @@ public function testAndIteratorTypeByName(string $name) : void self::assertSame(constant(IteratorTypes::class.'::'.$name), $criteria->$andMethod()->getIterator()); } - public function provideIteratorTypes() : iterable + public static function provideIteratorTypes() : iterable { return [ ['EQ'], From 53200a7991d5210816d722611b4781d5bc68aefc Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Thu, 20 Aug 2026 22:39:58 +0200 Subject: [PATCH 10/34] ci: fix phpunit 10 migration checks --- psalm.xml | 21 +++++++++++++++++++ .../MessagePack/DecimalExtensionTest.php | 4 ++-- .../MessagePack/UuidExtensionTest.php | 2 +- tests/Integration/Requests/ExecuteTest.php | 4 ++-- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/psalm.xml b/psalm.xml index bd18c5d6..10fed869 100644 --- a/psalm.xml +++ b/psalm.xml @@ -12,6 +12,7 @@ + @@ -32,10 +33,30 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/tests/Integration/MessagePack/DecimalExtensionTest.php b/tests/Integration/MessagePack/DecimalExtensionTest.php index 9393c873..2195778c 100755 --- a/tests/Integration/MessagePack/DecimalExtensionTest.php +++ b/tests/Integration/MessagePack/DecimalExtensionTest.php @@ -27,13 +27,13 @@ use Tarantool\Client\Tests\PackerDataProvider; use Tarantool\PhpUnit\Annotation\Attribute\Lua; +#[Requires('Tarantool', '>=2.3')] +#[RequiresPhpExtension('decimal')] #[Lua('dec = require(\'decimal\').new(\'18446744073709551615\')')] #[Lua('space = create_space(\'decimal_primary\')')] #[Lua('space:format({{name = \'id\', type = \'decimal\'}})')] #[Lua('space:create_index("primary", {parts = {1, \'decimal\'}})')] #[Lua('space:insert({dec})')] -#[Requires('Tarantool', '>=2.3')] -#[RequiresPhpExtension('decimal')] final class DecimalExtensionTest extends TestCase { public const DECIMAL_BIG_INT = '18446744073709551615'; diff --git a/tests/Integration/MessagePack/UuidExtensionTest.php b/tests/Integration/MessagePack/UuidExtensionTest.php index 88c5320a..8dc74907 100755 --- a/tests/Integration/MessagePack/UuidExtensionTest.php +++ b/tests/Integration/MessagePack/UuidExtensionTest.php @@ -23,12 +23,12 @@ use Tarantool\Client\Tests\Integration\TestCase; use Tarantool\PhpUnit\Annotation\Attribute\Lua; +#[Requires('Tarantool', '>=2.4')] #[Lua('uuid = require(\'uuid\').fromstr(\'64d22e4d-ac92-4a23-899a-e59f34af5479\')')] #[Lua('space = create_space(\'uuid_primary\')')] #[Lua('space:format({{name = \'id\', type = \'uuid\'}})')] #[Lua('space:create_index("primary", {parts = {1, \'uuid\'}})')] #[Lua('space:insert({uuid})')] -#[Requires('Tarantool', '>=2.4')] final class UuidExtensionTest extends TestCase { private const UUID_RFC4122 = '64d22e4d-ac92-4a23-899a-e59f34af5479'; diff --git a/tests/Integration/Requests/ExecuteTest.php b/tests/Integration/Requests/ExecuteTest.php index 0b7aa3fa..f3d2e96f 100644 --- a/tests/Integration/Requests/ExecuteTest.php +++ b/tests/Integration/Requests/ExecuteTest.php @@ -19,10 +19,10 @@ use Tarantool\Client\Tests\Integration\TestCase; use Tarantool\PhpUnit\Annotation\Attribute\Sql; +#[Requires('Tarantool', '>=2')] #[Sql('DROP TABLE IF EXISTS exec_query')] #[Sql('CREATE TABLE exec_query (id INTEGER PRIMARY KEY, name VARCHAR(50))')] #[Sql('INSERT INTO exec_query VALUES (1, \'A\'), (2, \'B\')')] -#[Requires('Tarantool', '>=2')] final class ExecuteTest extends TestCase { #[Sql('DROP TABLE IF EXISTS exec_update')] @@ -161,9 +161,9 @@ public function testSqlQueryResultHoldsMetadata() : void ]], $response->getMetadata()); } + #[Requires('Tarantool', '>=2.6')] #[Sql('DROP TABLE IF EXISTS %target_method%')] #[Sql('CREATE TABLE %target_method% (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME VARCHAR(50) COLLATE "unicode_ci")')] - #[Requires('Tarantool', '>=2.6')] public function testSqlQueryResultHoldsExtendedMetadata() : void { $client = ClientBuilder::createFromEnv()->build(); From 5bbe7cde9da61c556845db864dfc88d7fa3db3b4 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Tue, 29 Sep 2026 21:33:31 +0200 Subject: [PATCH 11/34] chore: migrate tests to stable phpunit extras --- README.md | 2 ++ composer.json | 18 +++------------- tests/Integration/BoxErrorTest.php | 6 +++--- tests/Integration/BoxNullTest.php | 2 +- tests/Integration/ClientMiddlewareTest.php | 7 ++++--- tests/Integration/ClientSpaceCachingTest.php | 2 +- tests/Integration/CompositeKeyTest.php | 2 +- .../Integration/Connection/ConnectionTest.php | 8 ++++--- .../Connection/ParseGreetingTest.php | 6 ++++-- tests/Integration/ExamplesTest.php | 4 +++- .../MessagePack/DecimalExtensionTest.php | 8 +++---- .../MessagePack/ErrorExtensionTest.php | 4 ++-- .../MessagePack/MessagePackTest.php | 6 +++--- .../MessagePack/UuidExtensionTest.php | 8 +++---- tests/Integration/PacketSyncTest.php | 3 ++- .../Integration/Requests/AuthenticateTest.php | 10 +++++---- tests/Integration/Requests/DeleteTest.php | 2 +- tests/Integration/Requests/ExecuteTest.php | 8 +++---- tests/Integration/Requests/InsertTest.php | 7 ++++--- tests/Integration/Requests/PingTest.php | 3 ++- tests/Integration/Requests/PrepareTest.php | 6 +++--- tests/Integration/Requests/ReplaceTest.php | 2 +- tests/Integration/Requests/SelectTest.php | 5 +++-- tests/Integration/Requests/UpdateTest.php | 2 +- tests/Integration/Requests/UpsertTest.php | 2 +- tests/Integration/TestCase.php | 19 ++++++++++++++--- tests/Unit/ClientFactoryTest.php | 18 +++++++++------- tests/Unit/Connection/GreetingTest.php | 6 ++++-- .../Unit/Connection/StreamConnectionTest.php | 19 ++++++++++------- tests/Unit/DsnTest.php | 21 ++++++++++--------- .../Middleware/FirewallMiddlewareTest.php | 3 ++- tests/Unit/Packer/PurePackerTest.php | 3 ++- tests/Unit/Schema/CriteriaTest.php | 5 +++-- 33 files changed, 127 insertions(+), 100 deletions(-) diff --git a/README.md b/README.md index 199530e8..f3d480b1 100755 --- a/README.md +++ b/README.md @@ -38,6 +38,8 @@ A pure PHP client for [Tarantool](https://www.tarantool.io/en/developers/) 1.7.1 ## Installation +This release requires PHP 8.2 or newer and `rybakit/msgpack` 0.11.2 or newer. + The recommended way to install the library is through [Composer](http://getcomposer.org): ```bash diff --git a/composer.json b/composer.json index 421126e7..74ac7f0a 100644 --- a/composer.json +++ b/composer.json @@ -12,17 +12,18 @@ ], "require": { "php": "^8.2", - "rybakit/msgpack": "^0.10", + "rybakit/msgpack": "^0.11.2", "symfony/uid": "^5.1|^6|^7" }, "require-dev": { "ext-json": "*", "ext-sockets": "*", + "composer/semver": "^3.3", "friendsofphp/php-cs-fixer": "^3.0", "monolog/monolog": "^3.0", "phpunit/phpunit": "^10.5", "psr/log": "^3.0", - "tarantool/phpunit-extras": "dev-feature/php82-phpunit10-attributes-migration", + "tarantool/phpunit-extras": "^0.3.0", "vimeo/psalm": "^5.23|^6" }, "suggest": { @@ -46,20 +47,7 @@ }, "sort-packages": true }, - "minimum-stability": "dev", "prefer-stable": true, - "repositories": [ - { - "type": "vcs", - "url": "https://github.com/rybakit/phpunit-extras", - "no-api": true - }, - { - "type": "vcs", - "url": "https://github.com/tarantool-php/phpunit-extras", - "no-api": true - } - ], "extra": { "branch-alias": { "dev-master": "0.10.x-dev" diff --git a/tests/Integration/BoxErrorTest.php b/tests/Integration/BoxErrorTest.php index 63608482..c1dc948a 100644 --- a/tests/Integration/BoxErrorTest.php +++ b/tests/Integration/BoxErrorTest.php @@ -13,9 +13,9 @@ namespace Tarantool\Client\Tests\Integration; -use PHPUnitExtras\Annotation\Attribute\Requires; use Tarantool\Client\Error; use Tarantool\Client\Exception\RequestFailed; +use Tarantool\PhpUnit\Attribute\RequiresTarantool; final class BoxErrorTest extends TestCase { @@ -28,7 +28,7 @@ public function testExceptionIsThrown() : void $this->client->evaluate('box.error({code = 42, reason = "Because I can"})'); } - #[Requires('Tarantool', '>=2.4.1')] + #[RequiresTarantool('>=2.4.1')] public function testExceptionWithErrorIsThrown() : void { try { @@ -71,7 +71,7 @@ public function testExceptionWithErrorIsThrown() : void } } - #[Requires('Tarantool', '>=2.4.1')] + #[RequiresTarantool('>=2.4.1')] public function testExceptionWithNestedErrorIsThrown() : void { try { diff --git a/tests/Integration/BoxNullTest.php b/tests/Integration/BoxNullTest.php index 45350293..a76cfcc2 100644 --- a/tests/Integration/BoxNullTest.php +++ b/tests/Integration/BoxNullTest.php @@ -14,7 +14,7 @@ namespace Tarantool\Client\Tests\Integration; use Tarantool\Client\Schema\Criteria; -use Tarantool\PhpUnit\Annotation\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\Lua; final class BoxNullTest extends TestCase { diff --git a/tests/Integration/ClientMiddlewareTest.php b/tests/Integration/ClientMiddlewareTest.php index 91ca254b..9738be08 100644 --- a/tests/Integration/ClientMiddlewareTest.php +++ b/tests/Integration/ClientMiddlewareTest.php @@ -13,6 +13,7 @@ namespace Tarantool\Client\Tests\Integration; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; use Tarantool\Client\Client; use Tarantool\Client\Exception\CommunicationFailed; use Tarantool\Client\Exception\RequestFailed; @@ -26,7 +27,7 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Schema\Space; use Tarantool\Client\Tests\SpyMiddleware; -use Tarantool\PhpUnit\Annotation\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\Lua; final class ClientMiddlewareTest extends TestCase { @@ -51,7 +52,7 @@ public function testSpaceInheritsMiddleware() : void self::assertSame([1, 1, 1], $middleware->getTraceLogArray()); } - #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] + #[DoesNotPerformAssertions] #[Lua('fiber = require(\'fiber\')')] #[Lua('function test() try_drop_user(\'foobar\') fiber.sleep(.5) create_user(\'foobar\', \'\') end')] #[Lua('fiber.create(test)')] @@ -113,7 +114,7 @@ public function testNoRetriesOnUnexpectedResponse() : void $client->ping(); } - #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] + #[DoesNotPerformAssertions] public function testReconnectOnBrokenConnection() : void { $clientBuilder = ClientBuilder::createFromEnv(); diff --git a/tests/Integration/ClientSpaceCachingTest.php b/tests/Integration/ClientSpaceCachingTest.php index 58e95f2a..5dd6260a 100644 --- a/tests/Integration/ClientSpaceCachingTest.php +++ b/tests/Integration/ClientSpaceCachingTest.php @@ -14,7 +14,7 @@ namespace Tarantool\Client\Tests\Integration; use Tarantool\Client\Schema\Criteria; -use Tarantool\PhpUnit\Annotation\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\Lua; #[Lua('create_space(\'test_space_caching\'):create_index(\'primary\', {type = \'tree\', parts = {1, \'unsigned\'}})')] final class ClientSpaceCachingTest extends TestCase diff --git a/tests/Integration/CompositeKeyTest.php b/tests/Integration/CompositeKeyTest.php index 259c3d57..18d242ef 100755 --- a/tests/Integration/CompositeKeyTest.php +++ b/tests/Integration/CompositeKeyTest.php @@ -15,7 +15,7 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Schema\Operations; -use Tarantool\PhpUnit\Annotation\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\Lua; #[Lua('space = create_space(\'composite_key\')')] #[Lua('space:create_index(\'primary\', {type = \'tree\', unique = true, parts = {1, \'unsigned\', 2, \'unsigned\'}})')] diff --git a/tests/Integration/Connection/ConnectionTest.php b/tests/Integration/Connection/ConnectionTest.php index d3252e48..626e72cd 100644 --- a/tests/Integration/Connection/ConnectionTest.php +++ b/tests/Integration/Connection/ConnectionTest.php @@ -13,6 +13,8 @@ namespace Tarantool\Client\Tests\Integration\Connection; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; use Tarantool\Client\Exception\CommunicationFailed; use Tarantool\Client\Exception\ConnectionFailed; use Tarantool\Client\Exception\UnexpectedResponse; @@ -25,12 +27,12 @@ use Tarantool\Client\Tests\Integration\FakeServer\Handler\AtConnectionHandler; use Tarantool\Client\Tests\Integration\FakeServer\Handler\WriteHandler; use Tarantool\Client\Tests\Integration\TestCase; -use Tarantool\PhpUnit\Annotation\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\Lua; final class ConnectionTest extends TestCase { - #[\PHPUnit\Framework\Attributes\DataProvider('provideAutoConnectData')] - #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] + #[DataProvider('provideAutoConnectData')] + #[DoesNotPerformAssertions] #[Lua('create_space(\'test_auto_connect\'):create_index(\'primary\', {type = \'tree\', parts = {1, \'unsigned\'}})')] public function testAutoConnect(string $methodName, array $methodArgs, ?string $space = null) : void { diff --git a/tests/Integration/Connection/ParseGreetingTest.php b/tests/Integration/Connection/ParseGreetingTest.php index db639fd5..9b1d8b2b 100644 --- a/tests/Integration/Connection/ParseGreetingTest.php +++ b/tests/Integration/Connection/ParseGreetingTest.php @@ -13,7 +13,9 @@ namespace Tarantool\Client\Tests\Integration\Connection; +use PHPUnit\Framework\Attributes\DataProviderExternal; use Tarantool\Client\Exception\CommunicationFailed; +use Tarantool\Client\Tests\GreetingDataProvider; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\FakeServer\FakeServerBuilder; use Tarantool\Client\Tests\Integration\FakeServer\Handler\WriteHandler; @@ -21,7 +23,7 @@ final class ParseGreetingTest extends TestCase { - #[\PHPUnit\Framework\Attributes\DataProviderExternal(\Tarantool\Client\Tests\GreetingDataProvider::class, 'provideGreetingsWithInvalidServerName')] + #[DataProviderExternal(GreetingDataProvider::class, 'provideGreetingsWithInvalidServerName')] public function testParseGreetingWithInvalidServerName(string $greeting) : void { $clientBuilder = ClientBuilder::createForFakeServer(); @@ -50,7 +52,7 @@ public function testParseGreetingWithInvalidServerName(string $greeting) : void self::fail(); } - #[\PHPUnit\Framework\Attributes\DataProviderExternal(\Tarantool\Client\Tests\GreetingDataProvider::class, 'provideGreetingsWithInvalidSalt')] + #[DataProviderExternal(GreetingDataProvider::class, 'provideGreetingsWithInvalidSalt')] public function testParseGreetingWithInvalidSalt(string $greeting) : void { $clientBuilder = ClientBuilder::createForFakeServer(); diff --git a/tests/Integration/ExamplesTest.php b/tests/Integration/ExamplesTest.php index 10ae9ddb..d49aa4d3 100644 --- a/tests/Integration/ExamplesTest.php +++ b/tests/Integration/ExamplesTest.php @@ -13,9 +13,11 @@ namespace Tarantool\Client\Tests\Integration; +use PHPUnit\Framework\Attributes\DataProvider; + final class ExamplesTest extends TestCase { - #[\PHPUnit\Framework\Attributes\DataProvider('provideExampleData')] + #[DataProvider('provideExampleData')] public function testExample(string $filename) : void { $uri = ClientBuilder::createFromEnv()->getUri(); diff --git a/tests/Integration/MessagePack/DecimalExtensionTest.php b/tests/Integration/MessagePack/DecimalExtensionTest.php index 2195778c..1ec9683b 100755 --- a/tests/Integration/MessagePack/DecimalExtensionTest.php +++ b/tests/Integration/MessagePack/DecimalExtensionTest.php @@ -17,7 +17,6 @@ use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\DataProviderExternal; use PHPUnit\Framework\Attributes\RequiresPhpExtension; -use PHPUnitExtras\Annotation\Attribute\Requires; use Tarantool\Client\Client; use Tarantool\Client\Packer\Extension\DecimalExtension; use Tarantool\Client\Packer\PurePacker; @@ -25,9 +24,10 @@ use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; use Tarantool\Client\Tests\PackerDataProvider; -use Tarantool\PhpUnit\Annotation\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\RequiresTarantool; -#[Requires('Tarantool', '>=2.3')] +#[RequiresTarantool('>=2.3')] #[RequiresPhpExtension('decimal')] #[Lua('dec = require(\'decimal\').new(\'18446744073709551615\')')] #[Lua('space = create_space(\'decimal_primary\')')] @@ -51,7 +51,7 @@ public function testBinarySelectByDecimalKeySucceeds() : void self::assertEquals($decimal, $result[0][0]); } - #[Requires('Tarantool', '>=2.10-stable')] + #[RequiresTarantool('>=2.10-stable')] public function testSqlSelectByDecimalKeySucceeds() : void { $client = self::createClientWithDecimalSupport(); diff --git a/tests/Integration/MessagePack/ErrorExtensionTest.php b/tests/Integration/MessagePack/ErrorExtensionTest.php index e4ca775e..12941b84 100755 --- a/tests/Integration/MessagePack/ErrorExtensionTest.php +++ b/tests/Integration/MessagePack/ErrorExtensionTest.php @@ -13,20 +13,20 @@ namespace Tarantool\Client\Tests\Integration\MessagePack; -use PHPUnitExtras\Annotation\Attribute\Requires; use Tarantool\Client\Client; use Tarantool\Client\Error; use Tarantool\Client\Packer\Extension\ErrorExtension; use Tarantool\Client\Packer\PurePacker; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Attribute\RequiresTarantool; final class ErrorExtensionTest extends TestCase { /** * @see https://github.com/tarantool/tarantool/issues/6428 */ - #[Requires('Tarantool', '>=2.4.1 <2.10')] + #[RequiresTarantool('>=2.4.1 <2.10')] public function testLuaPackingAndUnpacking() : void { $client = self::createClientWithExtendedErrorSupport(); diff --git a/tests/Integration/MessagePack/MessagePackTest.php b/tests/Integration/MessagePack/MessagePackTest.php index 5041e48a..04385fbd 100755 --- a/tests/Integration/MessagePack/MessagePackTest.php +++ b/tests/Integration/MessagePack/MessagePackTest.php @@ -15,13 +15,13 @@ use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\DataProviderExternal; -use PHPUnitExtras\Annotation\Attribute\Requires; use Tarantool\Client\Packer\PurePacker; use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; use Tarantool\Client\Tests\PackerDataProvider; -use Tarantool\PhpUnit\Annotation\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\RequiresIfLua; final class MessagePackTest extends TestCase { @@ -86,7 +86,7 @@ public function testCustomType() : void self::assertEquals($date, $space->select(Criteria::key([100]))[0][1]); } - #[Requires('luaCondition', 'os.getenv("EXT_DISABLE_DECIMAL")')] + #[RequiresIfLua('os.getenv("EXT_DISABLE_DECIMAL")')] #[DataProviderExternal(PackerDataProvider::class, 'providePurePackerWithDefaultSettings')] public function testPurePackerUnpacksBigIntToString(PurePacker $packer) : void { diff --git a/tests/Integration/MessagePack/UuidExtensionTest.php b/tests/Integration/MessagePack/UuidExtensionTest.php index 8dc74907..a64fe651 100755 --- a/tests/Integration/MessagePack/UuidExtensionTest.php +++ b/tests/Integration/MessagePack/UuidExtensionTest.php @@ -13,7 +13,6 @@ namespace Tarantool\Client\Tests\Integration\MessagePack; -use PHPUnitExtras\Annotation\Attribute\Requires; use Symfony\Component\Uid\Uuid; use Tarantool\Client\Client; use Tarantool\Client\Packer\Extension\UuidExtension; @@ -21,9 +20,10 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; -use Tarantool\PhpUnit\Annotation\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\RequiresTarantool; -#[Requires('Tarantool', '>=2.4')] +#[RequiresTarantool('>=2.4')] #[Lua('uuid = require(\'uuid\').fromstr(\'64d22e4d-ac92-4a23-899a-e59f34af5479\')')] #[Lua('space = create_space(\'uuid_primary\')')] #[Lua('space:format({{name = \'id\', type = \'uuid\'}})')] @@ -45,7 +45,7 @@ public function testBinarySelectByUuidKeySucceeds() : void self::assertTrue($uuid->equals($result[0][0])); } - #[Requires('Tarantool', '>=2.10-stable')] + #[RequiresTarantool('>=2.10-stable')] public function testSqlSelectByUuidKeySucceeds() : void { $client = self::createClientWithUuidSupport(); diff --git a/tests/Integration/PacketSyncTest.php b/tests/Integration/PacketSyncTest.php index 1e4e46d2..6682e407 100755 --- a/tests/Integration/PacketSyncTest.php +++ b/tests/Integration/PacketSyncTest.php @@ -13,11 +13,12 @@ namespace Tarantool\Client\Tests\Integration; +use PHPUnit\Framework\Attributes\DataProvider; use Tarantool\Client\Request\PingRequest; final class PacketSyncTest extends TestCase { - #[\PHPUnit\Framework\Attributes\DataProvider('provideValidSync')] + #[DataProvider('provideValidSync')] public function testSameSync(int $sync) : void { $handler = $this->client->getHandler(); diff --git a/tests/Integration/Requests/AuthenticateTest.php b/tests/Integration/Requests/AuthenticateTest.php index 9c104d79..fa9ec446 100644 --- a/tests/Integration/Requests/AuthenticateTest.php +++ b/tests/Integration/Requests/AuthenticateTest.php @@ -13,15 +13,17 @@ namespace Tarantool\Client\Tests\Integration\Requests; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; use Tarantool\Client\Exception\RequestFailed; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; -use Tarantool\PhpUnit\Annotation\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\Lua; final class AuthenticateTest extends TestCase { - #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] - #[\PHPUnit\Framework\Attributes\DataProvider('provideValidCredentials')] + #[DoesNotPerformAssertions] + #[DataProvider('provideValidCredentials')] #[Lua('create_user(\'user_foo\', \'foo\')')] #[Lua('create_user(\'user_empty\', \'\')')] #[Lua('create_user(\'user_big\', \'123456789012345678901234567890123456789012345678901234567890\')')] @@ -45,7 +47,7 @@ public static function provideValidCredentials() : iterable ]; } - #[\PHPUnit\Framework\Attributes\DataProvider('provideInvalidCredentials')] + #[DataProvider('provideInvalidCredentials')] public function testAuthenticateWithInvalidCredentials(string $errorMessagePattern, $username, $password) : void { $client = ClientBuilder::createFromEnv()->setOptions([ diff --git a/tests/Integration/Requests/DeleteTest.php b/tests/Integration/Requests/DeleteTest.php index 7379b3a5..6f85d549 100755 --- a/tests/Integration/Requests/DeleteTest.php +++ b/tests/Integration/Requests/DeleteTest.php @@ -15,7 +15,7 @@ use Tarantool\Client\Exception\RequestFailed; use Tarantool\Client\Tests\Integration\TestCase; -use Tarantool\PhpUnit\Annotation\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\Lua; #[Lua('space = create_space(\'request_delete\')')] #[Lua('space:create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] diff --git a/tests/Integration/Requests/ExecuteTest.php b/tests/Integration/Requests/ExecuteTest.php index f3d2e96f..a4fa2493 100644 --- a/tests/Integration/Requests/ExecuteTest.php +++ b/tests/Integration/Requests/ExecuteTest.php @@ -13,13 +13,13 @@ namespace Tarantool\Client\Tests\Integration\Requests; -use PHPUnitExtras\Annotation\Attribute\Requires; use Tarantool\Client\Keys; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; -use Tarantool\PhpUnit\Annotation\Attribute\Sql; +use Tarantool\PhpUnit\Attribute\RequiresTarantool; +use Tarantool\PhpUnit\Attribute\Sql; -#[Requires('Tarantool', '>=2')] +#[RequiresTarantool('>=2')] #[Sql('DROP TABLE IF EXISTS exec_query')] #[Sql('CREATE TABLE exec_query (id INTEGER PRIMARY KEY, name VARCHAR(50))')] #[Sql('INSERT INTO exec_query VALUES (1, \'A\'), (2, \'B\')')] @@ -161,7 +161,7 @@ public function testSqlQueryResultHoldsMetadata() : void ]], $response->getMetadata()); } - #[Requires('Tarantool', '>=2.6')] + #[RequiresTarantool('>=2.6')] #[Sql('DROP TABLE IF EXISTS %target_method%')] #[Sql('CREATE TABLE %target_method% (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME VARCHAR(50) COLLATE "unicode_ci")')] public function testSqlQueryResultHoldsExtendedMetadata() : void diff --git a/tests/Integration/Requests/InsertTest.php b/tests/Integration/Requests/InsertTest.php index 8e318cbd..4cbc4c31 100755 --- a/tests/Integration/Requests/InsertTest.php +++ b/tests/Integration/Requests/InsertTest.php @@ -13,13 +13,14 @@ namespace Tarantool\Client\Tests\Integration\Requests; +use PHPUnit\Framework\Attributes\DataProvider; use Tarantool\Client\Exception\RequestFailed; use Tarantool\Client\Tests\Integration\TestCase; -use Tarantool\PhpUnit\Annotation\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\Lua; final class InsertTest extends TestCase { - #[\PHPUnit\Framework\Attributes\DataProvider('provideInsertData')] + #[DataProvider('provideInsertData')] #[Lua('create_space(\'request_insert_str\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'str\'}})')] #[Lua('create_space(\'request_insert_num\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] public function testInsert(string $spaceName, array $values) : void @@ -43,7 +44,7 @@ public static function provideInsertData() : iterable ]; } - #[\PHPUnit\Framework\Attributes\DataProvider('provideInsertDataWithMismatchedTypes')] + #[DataProvider('provideInsertDataWithMismatchedTypes')] #[Lua('create_space(\'request_insert_str\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'str\'}})')] #[Lua('create_space(\'request_insert_num\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] public function testInsertTypeMismatchedValues(string $spaceName, array $values) : void diff --git a/tests/Integration/Requests/PingTest.php b/tests/Integration/Requests/PingTest.php index 3154432e..bbb70ead 100644 --- a/tests/Integration/Requests/PingTest.php +++ b/tests/Integration/Requests/PingTest.php @@ -13,11 +13,12 @@ namespace Tarantool\Client\Tests\Integration\Requests; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; use Tarantool\Client\Tests\Integration\TestCase; final class PingTest extends TestCase { - #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] + #[DoesNotPerformAssertions] public function testPing() : void { $this->client->ping(); diff --git a/tests/Integration/Requests/PrepareTest.php b/tests/Integration/Requests/PrepareTest.php index 5ca2c645..04684ab9 100644 --- a/tests/Integration/Requests/PrepareTest.php +++ b/tests/Integration/Requests/PrepareTest.php @@ -13,13 +13,13 @@ namespace Tarantool\Client\Tests\Integration\Requests; -use PHPUnitExtras\Annotation\Attribute\Requires; use Tarantool\Client\Exception\RequestFailed; use Tarantool\Client\PreparedStatement; use Tarantool\Client\Tests\Integration\TestCase; -use Tarantool\PhpUnit\Annotation\Attribute\Sql; +use Tarantool\PhpUnit\Attribute\RequiresTarantool; +use Tarantool\PhpUnit\Attribute\Sql; -#[Requires('Tarantool', '>=2.3.2')] +#[RequiresTarantool('>=2.3.2')] final class PrepareTest extends TestCase { public function testPreparePreparesSqlStatement() : void diff --git a/tests/Integration/Requests/ReplaceTest.php b/tests/Integration/Requests/ReplaceTest.php index 889c3257..b058aff7 100755 --- a/tests/Integration/Requests/ReplaceTest.php +++ b/tests/Integration/Requests/ReplaceTest.php @@ -16,7 +16,7 @@ use Tarantool\Client\Exception\RequestFailed; use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Tests\Integration\TestCase; -use Tarantool\PhpUnit\Annotation\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\Lua; #[Lua('space = create_space(\'request_replace\')')] #[Lua('space:create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] diff --git a/tests/Integration/Requests/SelectTest.php b/tests/Integration/Requests/SelectTest.php index f39d80a8..a320840a 100755 --- a/tests/Integration/Requests/SelectTest.php +++ b/tests/Integration/Requests/SelectTest.php @@ -13,14 +13,15 @@ namespace Tarantool\Client\Tests\Integration\Requests; +use PHPUnit\Framework\Attributes\DataProvider; use Tarantool\Client\Exception\RequestFailed; use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Tests\Integration\TestCase; -use Tarantool\PhpUnit\Annotation\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\Lua; final class SelectTest extends TestCase { - #[\PHPUnit\Framework\Attributes\DataProvider('provideSelectData')] + #[DataProvider('provideSelectData')] #[Lua('space = create_space(\'request_select\')')] #[Lua('space:create_index(\'primary\', {type = \'tree\', unique = true, parts = {1, \'unsigned\'}})')] #[Lua('space:create_index(\'secondary\', {type = \'tree\', unique = false, parts = {2, \'unsigned\', 3, \'str\'}})')] diff --git a/tests/Integration/Requests/UpdateTest.php b/tests/Integration/Requests/UpdateTest.php index 91656e9b..9f69c681 100755 --- a/tests/Integration/Requests/UpdateTest.php +++ b/tests/Integration/Requests/UpdateTest.php @@ -17,7 +17,7 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Schema\Operations; use Tarantool\Client\Tests\Integration\TestCase; -use Tarantool\PhpUnit\Annotation\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\Lua; #[Lua('space = create_space(\'request_update\')')] #[Lua('space:create_index(\'primary\', {type = \'tree\', unique = true, parts = {1, \'unsigned\'}})')] diff --git a/tests/Integration/Requests/UpsertTest.php b/tests/Integration/Requests/UpsertTest.php index de1452a8..6d1c4fa7 100755 --- a/tests/Integration/Requests/UpsertTest.php +++ b/tests/Integration/Requests/UpsertTest.php @@ -17,7 +17,7 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Schema\Operations; use Tarantool\Client\Tests\Integration\TestCase; -use Tarantool\PhpUnit\Annotation\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\Lua; #[Lua('space = create_space(\'request_upsert\')')] #[Lua('space:create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] diff --git a/tests/Integration/TestCase.php b/tests/Integration/TestCase.php index f62bd64f..1321ad64 100644 --- a/tests/Integration/TestCase.php +++ b/tests/Integration/TestCase.php @@ -13,13 +13,14 @@ namespace Tarantool\Client\Tests\Integration; +use Composer\Semver\Semver; +use PHPUnit\Framework\Attributes\Before; use Tarantool\Client\Client; use Tarantool\Client\Connection\Connection; use Tarantool\Client\Connection\StreamConnection; use Tarantool\Client\Exception\CommunicationFailed; use Tarantool\Client\Handler\Handler; use Tarantool\Client\Request\Request; -use Tarantool\PhpUnit\Annotation\Requirement\TarantoolVersionRequirement; use Tarantool\PhpUnit\TestCase as BaseTestCase; abstract class TestCase extends BaseTestCase @@ -27,7 +28,7 @@ abstract class TestCase extends BaseTestCase /** @var Client|null */ protected $client; - #[\PHPUnit\Framework\Attributes\Before] + #[Before] protected function getClient() : Client { return $this->client @@ -36,7 +37,19 @@ protected function getClient() : Client final protected function tarantoolVersionSatisfies(string $constraints) : bool { - return null === (new TarantoolVersionRequirement($this->getClient()))->check($constraints); + $version = $this->getClient()->call('box.info')[0]['version']; + if (!\is_string($version)) { + throw new \UnexpectedValueException('Tarantool version must be a string'); + } + + // Normalize 2.2.1-3-g878e2a42c to 2.2.1.3. + $version = (string) preg_replace('/-(\d+)-[^-]+$/', '.$1', $version); + + // Treat "entrypoint" versions as "dev", + // so 2.11.0-entrypoint.8 becomes 2.11.0-dev+entrypoint.8. + $version = (string) preg_replace('/(\d)-entrypoint/', '$1-dev+entrypoint', $version); + + return Semver::satisfies($version, $constraints); } final protected static function triggerUnexpectedResponse(Handler $handler, Request $initialRequest, int $sync = 0) : Connection diff --git a/tests/Unit/ClientFactoryTest.php b/tests/Unit/ClientFactoryTest.php index eef99d22..c7a16b8a 100644 --- a/tests/Unit/ClientFactoryTest.php +++ b/tests/Unit/ClientFactoryTest.php @@ -13,6 +13,8 @@ namespace Tarantool\Client\Tests\Unit; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; use PHPUnit\Framework\TestCase; use Tarantool\Client\Client; use Tarantool\Client\Packer\Packer; @@ -57,16 +59,16 @@ public function testFromDsnCreatesClientWithCustomPacker() : void self::assertSame($packer, $client->getHandler()->getPacker()); } - #[\PHPUnit\Framework\Attributes\DataProviderExternal(OptionsProvider::class, 'provideClientArrayOptionsOfValidTypes')] - #[\PHPUnit\Framework\Attributes\DataProviderExternal(OptionsProvider::class, 'provideTcpExtraConnectionArrayOptionsOfValidTypes')] - #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] + #[DataProviderExternal(OptionsProvider::class, 'provideClientArrayOptionsOfValidTypes')] + #[DataProviderExternal(OptionsProvider::class, 'provideTcpExtraConnectionArrayOptionsOfValidTypes')] + #[DoesNotPerformAssertions] public function testFromOptionsAcceptsOptionOfValidType(string $optionName, $optionValue, array $extraOptions = []) : void { Client::fromOptions([$optionName => $optionValue] + $extraOptions); } - #[\PHPUnit\Framework\Attributes\DataProviderExternal(OptionsProvider::class, 'provideClientArrayOptionsOfInvalidTypes')] - #[\PHPUnit\Framework\Attributes\DataProviderExternal(OptionsProvider::class, 'provideTcpExtraConnectionArrayOptionsOfInvalidTypes')] + #[DataProviderExternal(OptionsProvider::class, 'provideClientArrayOptionsOfInvalidTypes')] + #[DataProviderExternal(OptionsProvider::class, 'provideTcpExtraConnectionArrayOptionsOfInvalidTypes')] public function testFromOptionsRejectsOptionOfInvalidType(string $optionName, $optionValue, string $expectedType, array $extraOptions = []) : void { $this->expectException(\TypeError::class); @@ -75,14 +77,14 @@ public function testFromOptionsRejectsOptionOfInvalidType(string $optionName, $o Client::fromOptions([$optionName => $optionValue] + $extraOptions); } - #[\PHPUnit\Framework\Attributes\DataProviderExternal(OptionsProvider::class, 'provideClientDsnOptionsOfValidTypes')] - #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] + #[DataProviderExternal(OptionsProvider::class, 'provideClientDsnOptionsOfValidTypes')] + #[DoesNotPerformAssertions] public function testFromDsnAcceptsOptionOfValidType(string $query) : void { Client::fromDsn("tcp://tnt/?$query"); } - #[\PHPUnit\Framework\Attributes\DataProviderExternal(OptionsProvider::class, 'provideClientDsnOptionsOfInvalidTypes')] + #[DataProviderExternal(OptionsProvider::class, 'provideClientDsnOptionsOfInvalidTypes')] public function testFromDsnRejectsOptionOfInvalidType(string $query, string $optionName, string $expectedType) : void { $this->expectException(\TypeError::class); diff --git a/tests/Unit/Connection/GreetingTest.php b/tests/Unit/Connection/GreetingTest.php index 86175567..ca815126 100644 --- a/tests/Unit/Connection/GreetingTest.php +++ b/tests/Unit/Connection/GreetingTest.php @@ -13,19 +13,21 @@ namespace Tarantool\Client\Tests\Unit\Connection; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DataProviderExternal; use PHPUnit\Framework\TestCase; use Tarantool\Client\Connection\Greeting; use Tarantool\Client\Tests\GreetingDataProvider; final class GreetingTest extends TestCase { - #[\PHPUnit\Framework\Attributes\DataProviderExternal(GreetingDataProvider::class, 'provideValidGreetings')] + #[DataProviderExternal(GreetingDataProvider::class, 'provideValidGreetings')] public function testGetSalt(string $greeting, string $salt) : void { self::assertSame($salt, Greeting::parse($greeting)->getSalt()); } - #[\PHPUnit\Framework\Attributes\DataProvider('provideServerVersionData')] + #[DataProvider('provideServerVersionData')] public function testGetServerVersion(string $greeting, string $expectedVersion) : void { $greeting = Greeting::parse($greeting); diff --git a/tests/Unit/Connection/StreamConnectionTest.php b/tests/Unit/Connection/StreamConnectionTest.php index d2f4b1fe..4f20ca0d 100644 --- a/tests/Unit/Connection/StreamConnectionTest.php +++ b/tests/Unit/Connection/StreamConnectionTest.php @@ -13,28 +13,31 @@ namespace Tarantool\Client\Tests\Unit\Connection; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; use PHPUnit\Framework\TestCase; use Tarantool\Client\Connection\StreamConnection; +use Tarantool\Client\Tests\Unit\OptionsProvider; final class StreamConnectionTest extends TestCase { - #[\PHPUnit\Framework\Attributes\DataProviderExternal(\Tarantool\Client\Tests\Unit\OptionsProvider::class, 'provideConnectionArrayOptionsOfValidTypes')] - #[\PHPUnit\Framework\Attributes\DataProviderExternal(\Tarantool\Client\Tests\Unit\OptionsProvider::class, 'provideTcpExtraConnectionArrayOptionsOfValidTypes')] - #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] + #[DataProviderExternal(OptionsProvider::class, 'provideConnectionArrayOptionsOfValidTypes')] + #[DataProviderExternal(OptionsProvider::class, 'provideTcpExtraConnectionArrayOptionsOfValidTypes')] + #[DoesNotPerformAssertions] public function testCreateTcpAcceptsOptionOfValidType(string $optionName, $optionValue) : void { StreamConnection::createTcp(StreamConnection::DEFAULT_TCP_URI, [$optionName => $optionValue]); } - #[\PHPUnit\Framework\Attributes\DataProviderExternal(\Tarantool\Client\Tests\Unit\OptionsProvider::class, 'provideConnectionArrayOptionsOfValidTypes')] - #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] + #[DataProviderExternal(OptionsProvider::class, 'provideConnectionArrayOptionsOfValidTypes')] + #[DoesNotPerformAssertions] public function testCreateUdsAcceptsOptionOfValidType(string $optionName, $optionValue) : void { StreamConnection::createUds('unix:///socket.sock', [$optionName => $optionValue]); } - #[\PHPUnit\Framework\Attributes\DataProviderExternal(\Tarantool\Client\Tests\Unit\OptionsProvider::class, 'provideConnectionArrayOptionsOfInvalidTypes')] - #[\PHPUnit\Framework\Attributes\DataProviderExternal(\Tarantool\Client\Tests\Unit\OptionsProvider::class, 'provideTcpExtraConnectionArrayOptionsOfInvalidTypes')] + #[DataProviderExternal(OptionsProvider::class, 'provideConnectionArrayOptionsOfInvalidTypes')] + #[DataProviderExternal(OptionsProvider::class, 'provideTcpExtraConnectionArrayOptionsOfInvalidTypes')] public function testCreateTcpRejectsOptionOfInvalidType(string $optionName, $optionValue, string $expectedType) : void { $this->expectException(\TypeError::class); @@ -43,7 +46,7 @@ public function testCreateTcpRejectsOptionOfInvalidType(string $optionName, $opt StreamConnection::createTcp(StreamConnection::DEFAULT_TCP_URI, [$optionName => $optionValue]); } - #[\PHPUnit\Framework\Attributes\DataProviderExternal(\Tarantool\Client\Tests\Unit\OptionsProvider::class, 'provideConnectionArrayOptionsOfInvalidTypes')] + #[DataProviderExternal(OptionsProvider::class, 'provideConnectionArrayOptionsOfInvalidTypes')] public function testCreateUdsRejectsOptionOfInvalidType(string $optionName, $optionValue, string $expectedType) : void { $this->expectException(\TypeError::class); diff --git a/tests/Unit/DsnTest.php b/tests/Unit/DsnTest.php index 70e06942..6bbb6c06 100644 --- a/tests/Unit/DsnTest.php +++ b/tests/Unit/DsnTest.php @@ -13,12 +13,13 @@ namespace Tarantool\Client\Tests\Unit; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Tarantool\Client\Dsn; final class DsnTest extends TestCase { - #[\PHPUnit\Framework\Attributes\DataProvider('provideValidTcpDsns')] + #[DataProvider('provideValidTcpDsns')] public function testParseValidTcpDsn(string $dsn, array $expectedResult) : void { $dsn = Dsn::parse($dsn); @@ -51,7 +52,7 @@ public static function provideValidTcpDsns() : iterable ]; } - #[\PHPUnit\Framework\Attributes\DataProvider('provideValidUdsDsns')] + #[DataProvider('provideValidUdsDsns')] public function testParseValidUdsDsn(string $dsn, array $expected) : void { $dsn = Dsn::parse($dsn); @@ -79,7 +80,7 @@ public static function provideValidUdsDsns() : iterable ]; } - #[\PHPUnit\Framework\Attributes\DataProvider('provideInvalidDsns')] + #[DataProvider('provideInvalidDsns')] public function testParseInvalidDsn(string $nonDsn) : void { $this->expectException(\InvalidArgumentException::class); @@ -110,7 +111,7 @@ public static function provideInvalidDsns() : iterable ]; } - #[\PHPUnit\Framework\Attributes\DataProvider('provideStringOptions')] + #[DataProvider('provideStringOptions')] public function testGetString(string $dsn, string $option, ?string $expectedValue) : void { $dsn = Dsn::parse($dsn); @@ -143,7 +144,7 @@ public function testGetStringDefault() : void self::assertSame('qux', $dsn->getString('baz', 'qux')); } - #[\PHPUnit\Framework\Attributes\DataProvider('provideIntOptions')] + #[DataProvider('provideIntOptions')] public function testGetInt(string $dsn, string $option, $expectedValue) : void { $dsn = Dsn::parse($dsn); @@ -168,7 +169,7 @@ public function testGetIntDefault() : void self::assertSame(42, $dsn->getInt('baz', 42)); } - #[\PHPUnit\Framework\Attributes\DataProvider('provideNonIntOptions')] + #[DataProvider('provideNonIntOptions')] public function testGetNonInt(string $dsn, string $option) : void { $dsn = Dsn::parse($dsn); @@ -192,7 +193,7 @@ public static function provideNonIntOptions() : iterable ]; } - #[\PHPUnit\Framework\Attributes\DataProvider('provideFloatOptions')] + #[DataProvider('provideFloatOptions')] public function testGetFloat(string $dsn, string $option, $expectedValue) : void { $dsn = Dsn::parse($dsn); @@ -219,7 +220,7 @@ public function testGetFloatDefault() : void self::assertSame(42.3, $dsn->getFloat('baz', 42.3)); } - #[\PHPUnit\Framework\Attributes\DataProvider('provideNonFloatOptions')] + #[DataProvider('provideNonFloatOptions')] public function testGetNonFloat(string $dsn, string $option) : void { $dsn = Dsn::parse($dsn); @@ -241,7 +242,7 @@ public static function provideNonFloatOptions() : iterable ]; } - #[\PHPUnit\Framework\Attributes\DataProvider('provideBoolOptions')] + #[DataProvider('provideBoolOptions')] public function testGetBool(string $dsn, string $option, ?bool $expectedValue) : void { $dsn = Dsn::parse($dsn); @@ -276,7 +277,7 @@ public function testGetBoolDefault() : void self::assertTrue($dsn->getBool('baz', true)); } - #[\PHPUnit\Framework\Attributes\DataProvider('provideNonBoolOptions')] + #[DataProvider('provideNonBoolOptions')] public function testGetNonBool(string $dsn, string $option) : void { $dsn = Dsn::parse($dsn); diff --git a/tests/Unit/Middleware/FirewallMiddlewareTest.php b/tests/Unit/Middleware/FirewallMiddlewareTest.php index 5106b410..a22abe7b 100644 --- a/tests/Unit/Middleware/FirewallMiddlewareTest.php +++ b/tests/Unit/Middleware/FirewallMiddlewareTest.php @@ -13,6 +13,7 @@ namespace Tarantool\Client\Tests\Unit\Middleware; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Tarantool\Client\Exception\RequestDenied; @@ -168,7 +169,7 @@ public function testAndDenyOnlyForbids() : void $middleware->process(new CallRequest('foo'), $this->handler); } - #[\PHPUnit\Framework\Attributes\DataProvider('provideBlacklistPriorityData')] + #[DataProvider('provideBlacklistPriorityData')] public function testDenyHasPriority(Middleware $middleware) : void { $this->expectException(RequestDenied::class); diff --git a/tests/Unit/Packer/PurePackerTest.php b/tests/Unit/Packer/PurePackerTest.php index 2ba45598..c3d59fae 100644 --- a/tests/Unit/Packer/PurePackerTest.php +++ b/tests/Unit/Packer/PurePackerTest.php @@ -14,6 +14,7 @@ namespace Tarantool\Client\Tests\Unit\Packer; use MessagePack\Exception\UnpackingFailedException; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Tarantool\Client\Keys; use Tarantool\Client\Packer\Packer; @@ -30,7 +31,7 @@ protected function setUp() : void $this->packer = new PurePacker(); } - #[\PHPUnit\Framework\Attributes\DataProvider('provideBadUnpackData')] + #[DataProvider('provideBadUnpackData')] public function testThrowExceptionOnBadUnpackData(string $data) : void { $this->expectException(UnpackingFailedException::class); diff --git a/tests/Unit/Schema/CriteriaTest.php b/tests/Unit/Schema/CriteriaTest.php index c88166d9..fe9e2efe 100644 --- a/tests/Unit/Schema/CriteriaTest.php +++ b/tests/Unit/Schema/CriteriaTest.php @@ -13,6 +13,7 @@ namespace Tarantool\Client\Tests\Unit\Schema; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Schema\IteratorTypes; @@ -79,7 +80,7 @@ public function testAndIterator() : void self::assertSame(IteratorTypes::GE, Criteria::iterator(IteratorTypes::ALL)->andIterator(IteratorTypes::GE)->getIterator()); } - #[\PHPUnit\Framework\Attributes\DataProvider('provideIteratorTypes')] + #[DataProvider('provideIteratorTypes')] public function testIteratorTypeByName(string $name) : void { $method = str_replace('_', '', $name).'iterator'; @@ -88,7 +89,7 @@ public function testIteratorTypeByName(string $name) : void self::assertSame(constant(IteratorTypes::class.'::'.$name), $criteria->getIterator()); } - #[\PHPUnit\Framework\Attributes\DataProvider('provideIteratorTypes')] + #[DataProvider('provideIteratorTypes')] public function testAndIteratorTypeByName(string $name) : void { // Make sure we don't assign the same iterator twice From 34bc212624f95c78a48ca2ee704ead68945ef8e4 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Tue, 29 Sep 2026 21:38:22 +0200 Subject: [PATCH 12/34] ci: upgrade checkout action to v7 --- .github/workflows/qa.yml | 2 +- .github/workflows/reusable_qa.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index eb86492a..37376085 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -55,7 +55,7 @@ jobs: runs-on: ${{ matrix.operating-system }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Build docker image env: ${{ matrix.env }} diff --git a/.github/workflows/reusable_qa.yml b/.github/workflows/reusable_qa.yml index 197d83c0..5327e5c5 100644 --- a/.github/workflows/reusable_qa.yml +++ b/.github/workflows/reusable_qa.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Clone the tarantool-php/client connector - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: repository: tarantool-php/client From 0788f272abc4c59980f39995f42b65a6ae636458 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Tue, 29 Sep 2026 21:40:41 +0200 Subject: [PATCH 13/34] ci: avoid duplicate QA runs for pull requests --- .github/workflows/qa.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index 37376085..4d1fa6c1 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -1,6 +1,8 @@ name: QA on: push: + branches: + - master pull_request: workflow_dispatch: schedule: From 49ad3b9984c6187288c65c995f274b123cf73fcb Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Tue, 29 Sep 2026 21:50:40 +0200 Subject: [PATCH 14/34] refactor: modernize PHP examples --- examples/bootstrap.php | 8 +++---- examples/logging/SlowRequestHandler.php | 21 ++++++++++--------- .../tarantool16_call/LegacyCallRequest.php | 4 ++-- examples/user_defined_type/Email.php | 5 +---- examples/user_defined_type/EmailExtension.php | 7 ++----- 5 files changed, 19 insertions(+), 26 deletions(-) diff --git a/examples/bootstrap.php b/examples/bootstrap.php index 77df1719..0e9b3b34 100644 --- a/examples/bootstrap.php +++ b/examples/bootstrap.php @@ -42,8 +42,7 @@ function ensure_server_version_at_least(string $version, Client $client) : void return; } - /** @psalm-suppress PossiblyUndefinedArrayOffset */ - requirement_exit('Tarantool version >= %s is required to run "%s"', $version, $_SERVER['SCRIPT_FILENAME']); + requirement_exit('Tarantool version >= %s is required to run "%s"', $version, $_SERVER['SCRIPT_FILENAME'] ?? ''); } function ensure_extension(string $name) : void @@ -52,11 +51,10 @@ function ensure_extension(string $name) : void return; } - /** @psalm-suppress PossiblyUndefinedArrayOffset */ - requirement_exit('PHP extension "%s" is required to run "%s"', $name, $_SERVER['SCRIPT_FILENAME']); + requirement_exit('PHP extension "%s" is required to run "%s"', $name, $_SERVER['SCRIPT_FILENAME'] ?? ''); } -function requirement_exit(string $message, ...$args) : void +function requirement_exit(string $message, mixed ...$args) : never { echo "Unfulfilled requirement:\n"; echo $args ? sprintf($message, ...$args) : $message, "\n"; diff --git a/examples/logging/SlowRequestHandler.php b/examples/logging/SlowRequestHandler.php index 5d866af4..86ce9f8e 100644 --- a/examples/logging/SlowRequestHandler.php +++ b/examples/logging/SlowRequestHandler.php @@ -15,33 +15,34 @@ use Monolog\Handler\HandlerInterface; use Monolog\Handler\HandlerWrapper; +use Monolog\Level; +use Monolog\LogRecord; use Tarantool\Client\RequestTypes; final class SlowRequestHandler extends HandlerWrapper { - /** @var int */ - private $thresholdMs; + private readonly Level $level; - /** @var \Monolog\Level */ - private $level; - - public function __construct(HandlerInterface $handler, int $thresholdMs, \Monolog\Level|int $level = \Monolog\Level::Warning) + public function __construct( + HandlerInterface $handler, + private readonly int $thresholdMs, + Level|int $level = Level::Warning + ) { parent::__construct($handler); - $this->thresholdMs = $thresholdMs; - $this->level = $level instanceof \Monolog\Level ? $level : \Monolog\Level::from($level); + $this->level = $level instanceof Level ? $level : Level::from($level); } #[\Override] - public function isHandling(\Monolog\LogRecord $record) : bool + public function isHandling(LogRecord $record) : bool { // Handle all levels return true; } #[\Override] - public function handle(\Monolog\LogRecord $record) : bool + public function handle(LogRecord $record) : bool { if (!isset($record['context']['duration_ms'], $record['context']['request'])) { return false; diff --git a/examples/tarantool16_call/LegacyCallRequest.php b/examples/tarantool16_call/LegacyCallRequest.php index 308dcc6a..aef50752 100644 --- a/examples/tarantool16_call/LegacyCallRequest.php +++ b/examples/tarantool16_call/LegacyCallRequest.php @@ -21,12 +21,12 @@ final class LegacyCallRequest implements Request private const TYPE = 6; /** @var non-empty-array */ - private $body; + private readonly array $body; /** * @param non-empty-array $body */ - private function __construct($body) + private function __construct(array $body) { $this->body = $body; } diff --git a/examples/user_defined_type/Email.php b/examples/user_defined_type/Email.php index 9d37c2ad..edfe2915 100644 --- a/examples/user_defined_type/Email.php +++ b/examples/user_defined_type/Email.php @@ -15,11 +15,8 @@ final class Email { - private $value; - - public function __construct(string $value) + public function __construct(private readonly string $value) { - $this->value = $value; } public function equals(self $email) : bool diff --git a/examples/user_defined_type/EmailExtension.php b/examples/user_defined_type/EmailExtension.php index ba5cbf98..964b8fe6 100644 --- a/examples/user_defined_type/EmailExtension.php +++ b/examples/user_defined_type/EmailExtension.php @@ -19,11 +19,8 @@ final class EmailExtension implements Extension { - private $type; - - public function __construct(int $type) + public function __construct(private readonly int $type) { - $this->type = $type; } #[\Override] @@ -33,7 +30,7 @@ public function getType() : int } #[\Override] - public function pack(Packer $packer, $value) : ?string + public function pack(Packer $packer, mixed $value) : ?string { if (!$value instanceof Email) { return null; From 655dcf71a1cdbeadf7f965cd1709d8739d70ec0f Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Tue, 29 Sep 2026 21:56:02 +0200 Subject: [PATCH 15/34] refactor: type test fixtures --- examples/logging/SlowRequestHandler.php | 5 ++--- tests/Integration/ClientBuilder.php | 8 ++++---- tests/Integration/MessagePack/DateTimeExtension.php | 2 +- tests/Integration/TestCase.php | 3 +-- tests/SpyMiddleware.php | 8 ++++---- tests/Unit/Handler/MiddlewareHandlerTest.php | 12 +++--------- tests/Unit/Middleware/CustomErrorMiddlewareTest.php | 5 +---- tests/Unit/Middleware/FirewallMiddlewareTest.php | 5 +---- tests/Unit/Middleware/RetryMiddlewareTest.php | 12 +++--------- tests/Unit/Packer/PurePackerTest.php | 3 +-- 10 files changed, 21 insertions(+), 42 deletions(-) diff --git a/examples/logging/SlowRequestHandler.php b/examples/logging/SlowRequestHandler.php index 86ce9f8e..b1e103ba 100644 --- a/examples/logging/SlowRequestHandler.php +++ b/examples/logging/SlowRequestHandler.php @@ -26,9 +26,8 @@ final class SlowRequestHandler extends HandlerWrapper public function __construct( HandlerInterface $handler, private readonly int $thresholdMs, - Level|int $level = Level::Warning - ) - { + Level|int $level = Level::Warning, + ) { parent::__construct($handler); $this->level = $level instanceof Level ? $level : Level::from($level); diff --git a/tests/Integration/ClientBuilder.php b/tests/Integration/ClientBuilder.php index e47bf573..7f80253e 100755 --- a/tests/Integration/ClientBuilder.php +++ b/tests/Integration/ClientBuilder.php @@ -28,10 +28,10 @@ final class ClientBuilder private const DEFAULT_TCP_HOST = '127.0.0.1'; private const DEFAULT_TCP_PORT = 3301; - private $packerFactory; - private $uri; - private $options = []; - private $connectionOptions = []; + private ?\Closure $packerFactory = null; + private ?string $uri = null; + private array $options = []; + private array $connectionOptions = []; public function setPackerFactory(\Closure $factory) : self { diff --git a/tests/Integration/MessagePack/DateTimeExtension.php b/tests/Integration/MessagePack/DateTimeExtension.php index 42111451..6bc88cc4 100644 --- a/tests/Integration/MessagePack/DateTimeExtension.php +++ b/tests/Integration/MessagePack/DateTimeExtension.php @@ -19,7 +19,7 @@ class DateTimeExtension implements Extension { - private $type; + private readonly int $type; public function __construct(int $type) { diff --git a/tests/Integration/TestCase.php b/tests/Integration/TestCase.php index 1321ad64..fa5a063c 100644 --- a/tests/Integration/TestCase.php +++ b/tests/Integration/TestCase.php @@ -25,8 +25,7 @@ abstract class TestCase extends BaseTestCase { - /** @var Client|null */ - protected $client; + protected ?Client $client = null; #[Before] protected function getClient() : Client diff --git a/tests/SpyMiddleware.php b/tests/SpyMiddleware.php index eb05062a..6fdc73ce 100644 --- a/tests/SpyMiddleware.php +++ b/tests/SpyMiddleware.php @@ -20,16 +20,16 @@ final class SpyMiddleware implements Middleware { - private $traceLog; - private $getTraceValue; + private \ArrayObject $traceLog; + private \Closure $getTraceValue; private function __construct(\Closure $getTraceValue, ?\ArrayObject $traceLog = null) { $this->getTraceValue = $getTraceValue; - $this->traceLog = $traceLog ?: new \ArrayObject(); + $this->traceLog = $traceLog ?? new \ArrayObject(); } - public static function fromTraceId($traceId, ?\ArrayObject $traceLog = null) : self + public static function fromTraceId(mixed $traceId, ?\ArrayObject $traceLog = null) : self { return new self(static function () use ($traceId) { return $traceId; diff --git a/tests/Unit/Handler/MiddlewareHandlerTest.php b/tests/Unit/Handler/MiddlewareHandlerTest.php index 693ac4f1..8fa28e96 100644 --- a/tests/Unit/Handler/MiddlewareHandlerTest.php +++ b/tests/Unit/Handler/MiddlewareHandlerTest.php @@ -24,15 +24,9 @@ final class MiddlewareHandlerTest extends TestCase { use TestDoubleClient; - /** - * @var Request - */ - private $request; - - /** - * @var Handler - */ - private $handler; + private Request $request; + + private Handler $handler; protected function setUp() : void { diff --git a/tests/Unit/Middleware/CustomErrorMiddlewareTest.php b/tests/Unit/Middleware/CustomErrorMiddlewareTest.php index ba84d17a..b875f5b5 100644 --- a/tests/Unit/Middleware/CustomErrorMiddlewareTest.php +++ b/tests/Unit/Middleware/CustomErrorMiddlewareTest.php @@ -26,10 +26,7 @@ final class CustomErrorMiddlewareTest extends TestCase { - /** - * @var Handler|MockObject - */ - private $handler; + private Handler&MockObject $handler; protected function setUp() : void { diff --git a/tests/Unit/Middleware/FirewallMiddlewareTest.php b/tests/Unit/Middleware/FirewallMiddlewareTest.php index a22abe7b..76a86a87 100644 --- a/tests/Unit/Middleware/FirewallMiddlewareTest.php +++ b/tests/Unit/Middleware/FirewallMiddlewareTest.php @@ -31,10 +31,7 @@ final class FirewallMiddlewareTest extends TestCase { - /** - * @var Handler|MockObject - */ - private $handler; + private Handler&MockObject $handler; protected function setUp() : void { diff --git a/tests/Unit/Middleware/RetryMiddlewareTest.php b/tests/Unit/Middleware/RetryMiddlewareTest.php index 1416905c..8579ac84 100644 --- a/tests/Unit/Middleware/RetryMiddlewareTest.php +++ b/tests/Unit/Middleware/RetryMiddlewareTest.php @@ -24,15 +24,9 @@ final class RetryMiddlewareTest extends TestCase { - /** - * @var Request|MockObject - */ - private $request; - - /** - * @var Handler|MockObject - */ - private $handler; + private Request&MockObject $request; + + private Handler&MockObject $handler; protected function setUp() : void { diff --git a/tests/Unit/Packer/PurePackerTest.php b/tests/Unit/Packer/PurePackerTest.php index c3d59fae..ff2f94c3 100644 --- a/tests/Unit/Packer/PurePackerTest.php +++ b/tests/Unit/Packer/PurePackerTest.php @@ -23,8 +23,7 @@ final class PurePackerTest extends TestCase { - /** @var Packer */ - private $packer; + private Packer $packer; protected function setUp() : void { From 34a1e62a9695a1da9da8ea36451e8e7716b91091 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Tue, 29 Sep 2026 22:00:20 +0200 Subject: [PATCH 16/34] refactor: add native source types --- src/Client.php | 3 +-- src/Connection/Greeting.php | 17 +++++------------ src/Handler/MiddlewareHandler.php | 15 +++++---------- src/Packer/PurePacker.php | 6 ++---- src/Schema/Criteria.php | 28 ++++++++-------------------- 5 files changed, 21 insertions(+), 48 deletions(-) diff --git a/src/Client.php b/src/Client.php index 4bdf6345..a7b63c55 100644 --- a/src/Client.php +++ b/src/Client.php @@ -33,8 +33,7 @@ final class Client { - /** @var Handler */ - private $handler; + private Handler $handler; /** @var array */ private $spaces = []; diff --git a/src/Connection/Greeting.php b/src/Connection/Greeting.php index 58cdce4c..8e137a1b 100644 --- a/src/Connection/Greeting.php +++ b/src/Connection/Greeting.php @@ -19,22 +19,15 @@ final class Greeting { public const SIZE_BYTES = 128; - /** @var string */ - private $greeting; + private string $greeting; - /** @var string|null */ - private $salt; + private ?string $salt = null; - /** @var string|null */ - private $serverVersion; + private ?string $serverVersion = null; - /** @var bool */ - private $unknown = false; + private bool $unknown = false; - /** - * @param string $greeting - */ - private function __construct($greeting) + private function __construct(string $greeting) { $this->greeting = $greeting; } diff --git a/src/Handler/MiddlewareHandler.php b/src/Handler/MiddlewareHandler.php index 7d169983..c2e9bff7 100644 --- a/src/Handler/MiddlewareHandler.php +++ b/src/Handler/MiddlewareHandler.php @@ -21,20 +21,15 @@ final class MiddlewareHandler implements Handler { - /** @var Handler */ - private $handler; + private Handler $handler; /** @var Middleware[] */ - private $middleware; + private array $middleware; - /** @var int */ - private $index = 0; + private int $index = 0; - /** - * @param Handler $handler - * @param Middleware[] $middleware - */ - private function __construct($handler, $middleware) + /** @param Middleware[] $middleware */ + private function __construct(Handler $handler, array $middleware) { $this->handler = $handler; $this->middleware = $middleware; diff --git a/src/Packer/PurePacker.php b/src/Packer/PurePacker.php index b07aba39..01f0bbb5 100644 --- a/src/Packer/PurePacker.php +++ b/src/Packer/PurePacker.php @@ -28,11 +28,9 @@ final class PurePacker implements ClientPacker { - /** @var Packer */ - private $packer; + private Packer $packer; - /** @var BufferUnpacker */ - private $unpacker; + private BufferUnpacker $unpacker; public function __construct(?Packer $packer = null, ?BufferUnpacker $unpacker = null) { diff --git a/src/Schema/Criteria.php b/src/Schema/Criteria.php index d8523b2b..99c9a6ed 100644 --- a/src/Schema/Criteria.php +++ b/src/Schema/Criteria.php @@ -15,29 +15,23 @@ final class Criteria { - /** @var int|string */ - private $index = 0; + private int|string $index = 0; /** @var array */ - private $key = []; + private array $key = []; - /** @var int */ - private $limit = \PHP_INT_MAX & 0xFFFFFFFF; + private int $limit = \PHP_INT_MAX & 0xFFFFFFFF; - /** @var int */ - private $offset = 0; + private int $offset = 0; /** @psalm-var IteratorTypes::*|null */ - private $iteratorType; + private ?int $iteratorType = null; private function __construct() { } - /** - * @param int|string $index - */ - public static function index($index) : self + public static function index(int|string $index) : self { $self = new self(); $self->index = $index; @@ -45,10 +39,7 @@ public static function index($index) : self return $self; } - /** - * @param int|string $index - */ - public function andIndex($index) : self + public function andIndex(int|string $index) : self { $new = clone $this; $new->index = $index; @@ -56,10 +47,7 @@ public function andIndex($index) : self return $new; } - /** - * @return int|string - */ - public function getIndex() + public function getIndex() : int|string { return $this->index; } From d9bc07202f0db940fb344467091bb0f185016c92 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Tue, 29 Sep 2026 22:05:08 +0200 Subject: [PATCH 17/34] ci: test newer PHP and Tarantool versions --- .github/workflows/qa.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index 4d1fa6c1..e8680728 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -18,6 +18,12 @@ jobs: matrix: operating-system: [ubuntu-latest] env: + - TNT_IMAGE: tarantool/tarantool:3.7 + - TNT_IMAGE: tarantool/tarantool:3.6 + - TNT_IMAGE: tarantool/tarantool:3.5 + - TNT_IMAGE: tarantool/tarantool:3.4 + - TNT_IMAGE: tarantool/tarantool:3.3 + - TNT_IMAGE: tarantool/tarantool:3.2 - TNT_IMAGE: tarantool/tarantool:3.0 - TNT_IMAGE: tarantool/tarantool:2.11 - TNT_IMAGE: tarantool/tarantool:2.10 @@ -33,6 +39,8 @@ jobs: - TNT_IMAGE: tarantool/tarantool:1.9 - TNT_IMAGE: tarantool/tarantool:1.7 + - PHP_IMAGE: php:8.5-cli + - PHP_IMAGE: php:8.4-cli - PHP_IMAGE: php:8.3-cli TNT_LISTEN_URI: /tmp/tarantool_client.sock From 526255819f82af9ec644d9125dc0a341e54e3538 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Tue, 29 Sep 2026 22:11:23 +0200 Subject: [PATCH 18/34] docs: clarify supported Tarantool versions --- README.md | 63 +++++++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index f3d480b1..8c4164e9 100755 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Code Coverage](https://scrutinizer-ci.com/g/tarantool-php/client/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/tarantool-php/client/?branch=master) [![Telegram](https://img.shields.io/badge/Telegram-join%20chat-blue.svg)](https://t.me/tarantool_php) -A pure PHP client for [Tarantool](https://www.tarantool.io/en/developers/) 1.7.1 or above. +A pure PHP client for [Tarantool](https://www.tarantool.io/en/developers/) 1.7.1 and later, including the 2.x and 3.x series. ## Features @@ -46,10 +46,10 @@ The recommended way to install the library is through [Composer](http://getcompo composer require tarantool/client ``` -In order to use the [Decimal](https://www.tarantool.io/en/doc/latest/dev_guide/internals/msgpack_extensions/#the-decimal-type) -type that was added in Tarantool 2.3, you additionally need to install the [decimal](http://php-decimal.io/#installation) -extension. Also, to improve performance when working with the [UUID](https://www.tarantool.io/en/doc/latest/dev_guide/internals/msgpack_extensions/#the-uuid-type) -type, which is available since Tarantool 2.4, it is recommended to additionally install the [uuid](https://pecl.php.net/package/uuid) extension. +To use the [Decimal](https://www.tarantool.io/en/doc/latest/dev_guide/internals/msgpack_extensions/#the-decimal-type) +type added in Tarantool 2.3, install the [decimal](http://php-decimal.io/#installation) +extension. To improve performance when working with the [UUID](https://www.tarantool.io/en/doc/latest/dev_guide/internals/msgpack_extensions/#the-uuid-type) +type, available since Tarantool 2.4, you can also install the [uuid](https://pecl.php.net/package/uuid) extension. ## Creating a client @@ -62,9 +62,9 @@ use Tarantool\Client\Client; $client = Client::fromDefaults(); ``` -The client will be configured to connect to `127.0.0.1` on port `3301` with the default stream connection options. -Also, the best available msgpack package will be chosen automatically. A custom configuration can be accomplished -by one of several methods listed. +The client connects to `127.0.0.1` on port `3301` using the default stream connection options. +It also selects the best available MessagePack package automatically. You can configure the client in several ways, +as described below. #### DSN string @@ -113,18 +113,18 @@ The following options are available: Name | Type | Default | Description --- | :---: | :---: | --- *uri* | string | 'tcp://127.0.0.1:3301' | The connection uri that is used to create a `StreamConnection` object. -*connect_timeout* | float | 5.0 | The number of seconds that the client waits for a connect to a Tarantool server before throwing a `ConnectionFailed` exception. -*socket_timeout* | float | 5.0 | The number of seconds that the client waits for a respond from a Tarantool server before throwing a `CommunicationFailed` exception. +*connect_timeout* | float | 5.0 | The number of seconds that the client waits to connect to a Tarantool server before throwing a `ConnectionFailed` exception. +*socket_timeout* | float | 5.0 | The number of seconds that the client waits for a response from a Tarantool server before throwing a `CommunicationFailed` exception. *tcp_nodelay* | boolean | true | Whether the Nagle algorithm is disabled on a TCP connection. *persistent* | boolean | false | Whether to use a persistent connection. *username* | string | | The username for the user being authenticated. *password* | string | '' | The password for the user being authenticated. If the username is not set, this option will be ignored. -*max_retries* | integer | 0 | The number of times the client retries unsuccessful request. If set to 0, the client does not try to resend the request after the initial unsuccessful attempt. +*max_retries* | integer | 0 | The number of times the client retries an unsuccessful request. If set to 0, the client does not retry after the initial unsuccessful attempt. #### Custom build -For more deep customisation, you can build a client from the ground up: +For more extensive customization, you can build a client from the ground up: ```php use MessagePack\BufferUnpacker; @@ -160,8 +160,8 @@ $client = new Client($handler); ## Handlers -A handler is a function which transforms a request into a response. Once you have created a handler object, -you can make requests to Tarantool, for example: +A handler transforms a request into a response. Once you have created a handler object, +you can use it to send requests to Tarantool, for example: ```php use Tarantool\Client\Keys; @@ -182,9 +182,9 @@ The library ships with two handlers: ## Middleware -Middleware is the suggested way to extend the client with custom functionality. There are several middleware classes -implemented to address the common use cases, like authentification, logging and [more](src/Middleware). -The usage is straightforward: +Middleware is the recommended way to extend the client with custom functionality. The library includes middleware +for common use cases, such as authentication and logging. See the full list in [`src/Middleware`](src/Middleware). +Usage is straightforward: ```php use Tarantool\Client\Client; @@ -195,7 +195,7 @@ $client = Client::fromDefaults()->withMiddleware( ); ``` -You may also assign multiple middleware to the client (they will be executed in [FIFO](https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)) order): +You can also add multiple middleware components to the client. They execute in [FIFO](https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)) order: ```php use Tarantool\Client\Client; @@ -212,8 +212,8 @@ $client = Client::fromDefaults()->withMiddleware( ); ``` -Please be aware that the order in which you add the middleware does matter. The same middleware, -placed in different order, can give very different or sometimes unexpected behavior. +The order in which you add middleware matters. The same middleware, +placed in a different order, can produce different or sometimes unexpected behavior. To illustrate, consider the following configurations: ```php @@ -406,7 +406,7 @@ $space->upsert([1, 'foo', 'bar'], Operations::set(2, 'qux')); // Since Tarantool 2.3 you can refer to tuple fields by name: // $space->upsert([1, 'foo', 'bar'], Operations::set('name1', 'baz')); -// $space->upsert([1, 'foo', 'bar'], Operations::set('name2'', 'qux')); +// $space->upsert([1, 'foo', 'bar'], Operations::set('name2', 'qux')); ``` *Space data* @@ -565,9 +565,9 @@ Result 3: [3] ### SQL protocol -The following are examples of SQL protocol requests. For more detailed information and examples please see +The following are examples of SQL protocol requests. For more detailed information and examples, please see the [official documentation](https://www.tarantool.io/en/doc/latest/reference/reference_sql/sql/). -*Note that SQL is supported only as of Tarantool 2.0.* +*SQL is supported starting with Tarantool 2.0.*
Execute
@@ -604,8 +604,8 @@ Result 3: [1,{"id":1,"email":"foo@example.com"}] Result 4: [{"id":1,"email":"foo@example.com"},{"id":2,"email":"bar@example.com"}] ``` -If you need to execute a dynamic SQL statement whose type you don't know, you can use the generic method `execute()`. -This method returns a Response object with the body containing either an array of result set rows or an array +If you need to execute a dynamic SQL statement and do not know its type, use the generic `execute()` method. +It returns a `Response` object whose body contains either an array of result-set rows or an array with information about the changed rows: ```php @@ -662,10 +662,9 @@ $space->insert([42, Money::EUR(500)]); [[$id, $money]] = $space->select(Criteria::key([42])); ``` -This can be achieved by extending the MessagePack type system with your own types. To do this, you need to write -a MessagePack extension that converts your objects into MessagePack structures and back (for more details, read -the msgpack.php's [README](https://github.com/rybakit/msgpack.php#custom-types)). Once you have implemented -your extension, you should register it with the packer object: +You can do this by extending the MessagePack type system with your own types. Write a MessagePack extension +that converts your objects to and from MessagePack structures (see the msgpack.php [README](https://github.com/rybakit/msgpack.php#custom-types) for details). +Once you have implemented the extension, register it with the packer object: ```php $packer = PurePacker::fromExtensions(new MoneyExtension()); @@ -697,14 +696,14 @@ To run all tests: vendor/bin/phpunit ``` -If you already have Docker installed, you can run the tests in a docker container. -First, create a container: +If you already have Docker installed, you can run the tests in a Docker container. +First, build the Docker image: ```bash ./dockerfile.sh | docker build -t client - ``` -The command above will create a container named `client` with PHP 8.3 runtime. +The command above builds an image named `client` with the PHP 8.3 runtime. You may change the default runtime by defining the `PHP_IMAGE` environment variable: ```bash From 464a5f50cc94584cfc385c63126db4965a662894 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Tue, 29 Sep 2026 22:13:41 +0200 Subject: [PATCH 19/34] ci: pin runner to Ubuntu 24.04 --- .github/workflows/qa.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index e8680728..69cba7ad 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: false matrix: - operating-system: [ubuntu-latest] + operating-system: [ubuntu-24.04] env: - TNT_IMAGE: tarantool/tarantool:3.7 - TNT_IMAGE: tarantool/tarantool:3.6 From 6e2344cad490a03fb188af8af1e3ead0d94e7382 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Tue, 29 Sep 2026 22:19:19 +0200 Subject: [PATCH 20/34] deps: allow Symfony UID 8 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 74ac7f0a..faa6989d 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "require": { "php": "^8.2", "rybakit/msgpack": "^0.11.2", - "symfony/uid": "^5.1|^6|^7" + "symfony/uid": "^5.1|^6|^7|^8" }, "require-dev": { "ext-json": "*", From 6ee9b8f12c4bc75d00e6d027a29e8c68dcba8b84 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Wed, 30 Sep 2026 00:20:09 +0200 Subject: [PATCH 21/34] chore: remove Scrutinizer integration --- .gitattributes | 1 - .github/workflows/qa.yml | 17 +++++++++++++---- .scrutinizer.yml | 28 ---------------------------- README.md | 2 -- 4 files changed, 13 insertions(+), 35 deletions(-) delete mode 100644 .scrutinizer.yml diff --git a/.gitattributes b/.gitattributes index 0b1a9bf2..9c56fa5e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,7 +4,6 @@ tests export-ignore .gitattributes export-ignore .gitignore export-ignore .php-cs-fixer.dist.php export-ignore -.scrutinizer.yml export-ignore dockerfile.sh export-ignore phpunit.xml.dist export-ignore psalm.xml export-ignore diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index 69cba7ad..e7413ac0 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -10,6 +10,10 @@ on: jobs: tests: + permissions: + actions: read + contents: read + statuses: write env: TNT_IMAGE: tarantool/tarantool:3.1 PHP_IMAGE: php:8.3-cli @@ -86,9 +90,14 @@ jobs: docker run --net=tarantool-php --rm -v $PWD:/client -w /client client php vendor/bin/php-cs-fixer fix --dry-run --diff --verbose . docker run --net=tarantool-php --rm -v $PWD:/client -w /client client php vendor/bin/psalm - - name: Upload code coverage to Scrutinizer + - name: Add code coverage report to workflow summary env: ${{ matrix.env }} if: ${{ env.COVERAGE_FILE }} - run: | - curl -sSOL https://scrutinizer-ci.com/ocular.phar - docker run --net=tarantool-php --rm -v $PWD:/client -w /client client php ocular.phar code-coverage:upload --format=php-clover "$COVERAGE_FILE" + uses: getsentry/coverage-action@0.3.8 + with: + token: ${{ secrets.GITHUB_TOKEN }} + files: ${{ env.COVERAGE_FILE }} + coverage-format: clover + disable-search: true + enable-tests: false + name: coverage-${{ strategy.job-index }} diff --git a/.scrutinizer.yml b/.scrutinizer.yml deleted file mode 100644 index e5562954..00000000 --- a/.scrutinizer.yml +++ /dev/null @@ -1,28 +0,0 @@ -checks: - php: true - -tools: - php_mess_detector: true - php_cpd: true - php_loc: - excluded_dirs: [vendor] - php_pdepend: - excluded_dirs: [vendor] - external_code_coverage: - runs: 4 - -build: - environment: - variables: - COMPOSER_ROOT_VERSION: dev-master - apt_packages: - - libmpdec-dev - php: - version: 7.4 - pecl_extensions: - - decimal - nodes: - analysis: - tests: - override: - - php-scrutinizer-run diff --git a/README.md b/README.md index 8c4164e9..88d29f32 100755 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # PHP client for Tarantool [![Quality Assurance](https://github.com/tarantool-php/client/workflows/QA/badge.svg)](https://github.com/tarantool-php/client/actions?query=workflow%3AQA) -[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/tarantool-php/client/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/tarantool-php/client/?branch=master) -[![Code Coverage](https://scrutinizer-ci.com/g/tarantool-php/client/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/tarantool-php/client/?branch=master) [![Telegram](https://img.shields.io/badge/Telegram-join%20chat-blue.svg)](https://t.me/tarantool_php) A pure PHP client for [Tarantool](https://www.tarantool.io/en/developers/) 1.7.1 and later, including the 2.x and 3.x series. From b715b6389dfd7c46ad1f429d27c6a4985f82b11c Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Wed, 30 Sep 2026 00:33:27 +0200 Subject: [PATCH 22/34] ci: run transport coverage on default PHP --- .github/workflows/qa.yml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index e7413ac0..4c800e09 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -45,24 +45,20 @@ jobs: - PHP_IMAGE: php:8.5-cli - PHP_IMAGE: php:8.4-cli - - PHP_IMAGE: php:8.3-cli - TNT_LISTEN_URI: /tmp/tarantool_client.sock - PHP_IMAGE: php:8.2-cli QA: 1 - - PHP_IMAGE: php:8.2-cli - TNT_LISTEN_URI: /tmp/tarantool_client.sock - COVERAGE_FILE: coverage.clover - PHP_IMAGE: php:8.2-cli + PHP_IMAGE: php:8.3-cli - COVERAGE_FILE: coverage.clover - PHP_IMAGE: php:8.2-cli + PHP_IMAGE: php:8.3-cli EXT_DISABLE_DECIMAL: true - COVERAGE_FILE: coverage.clover - PHP_IMAGE: php:8.2-cli + PHP_IMAGE: php:8.3-cli TNT_LISTEN_URI: /tmp/tarantool_client.sock - COVERAGE_FILE: coverage.clover - PHP_IMAGE: php:8.2-cli + PHP_IMAGE: php:8.3-cli # some tests are skipped on Tarantool > 2.8 TNT_IMAGE: tarantool/tarantool:2.8 From 731a45b2ae35223336d0b74add61b1e6463053ca Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Wed, 30 Sep 2026 00:43:05 +0200 Subject: [PATCH 23/34] ci: align coverage paths with checkout --- .github/workflows/qa.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index 4c800e09..f16f91b6 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -77,7 +77,7 @@ jobs: docker network create tarantool-php docker run --net=tarantool-php --rm $TNT_IMAGE sh -c "tarantool --version" docker run --net=tarantool-php -d --name=tarantool -v /tmp:/tmp -v $PWD/tests/Integration/client.lua:/client.lua -e TNT_LISTEN_URI=$TNT_LISTEN_URI $TNT_IMAGE tarantool /client.lua - docker run --net=tarantool-php --rm -v /tmp:/tmp -v $PWD:/client -w /client -e COMPOSER_ROOT_VERSION=dev-master client + docker run --net=tarantool-php --rm -v /tmp:/tmp -v "$GITHUB_WORKSPACE:$GITHUB_WORKSPACE" -w "$GITHUB_WORKSPACE" -e COMPOSER_ROOT_VERSION=dev-master client - name: Check code quality env: ${{ matrix.env }} From 86f66b3eee314052880cfa5be8114879cc21b2fd Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Wed, 30 Sep 2026 00:49:18 +0200 Subject: [PATCH 24/34] ci: use Cobertura for coverage summaries --- .github/workflows/qa.yml | 10 +++++----- dockerfile.sh | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index f16f91b6..34cd463f 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -49,15 +49,15 @@ jobs: - PHP_IMAGE: php:8.2-cli QA: 1 - - COVERAGE_FILE: coverage.clover + - COVERAGE_FILE: coverage.xml PHP_IMAGE: php:8.3-cli - - COVERAGE_FILE: coverage.clover + - COVERAGE_FILE: coverage.xml PHP_IMAGE: php:8.3-cli EXT_DISABLE_DECIMAL: true - - COVERAGE_FILE: coverage.clover + - COVERAGE_FILE: coverage.xml PHP_IMAGE: php:8.3-cli TNT_LISTEN_URI: /tmp/tarantool_client.sock - - COVERAGE_FILE: coverage.clover + - COVERAGE_FILE: coverage.xml PHP_IMAGE: php:8.3-cli # some tests are skipped on Tarantool > 2.8 TNT_IMAGE: tarantool/tarantool:2.8 @@ -93,7 +93,7 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} files: ${{ env.COVERAGE_FILE }} - coverage-format: clover + coverage-format: cobertura disable-search: true enable-tests: false name: coverage-${{ strategy.job-index }} diff --git a/dockerfile.sh b/dockerfile.sh index ee910f5c..11c210f4 100755 --- a/dockerfile.sh +++ b/dockerfile.sh @@ -51,5 +51,5 @@ ENV PATH=~/.composer/vendor/bin:\$PATH ENV TNT_LISTEN_URI=$TNT_LISTEN_URI CMD if [ ! -f composer.lock ]; then composer install; fi && \\ - vendor/bin/phpunit ${COVERAGE_FILE:+ --coverage-text --coverage-clover=}$COVERAGE_FILE + vendor/bin/phpunit ${COVERAGE_FILE:+ --coverage-text --coverage-cobertura=}$COVERAGE_FILE " From 4d3fcd4315433be497b99867e6512506b4134d3c Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Wed, 30 Sep 2026 01:06:54 +0200 Subject: [PATCH 25/34] ci: aggregate coverage across test matrix --- .github/workflows/qa.yml | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index 34cd463f..46cfc6a1 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -13,7 +13,6 @@ jobs: permissions: actions: read contents: read - statuses: write env: TNT_IMAGE: tarantool/tarantool:3.1 PHP_IMAGE: php:8.3-cli @@ -86,14 +85,36 @@ jobs: docker run --net=tarantool-php --rm -v $PWD:/client -w /client client php vendor/bin/php-cs-fixer fix --dry-run --diff --verbose . docker run --net=tarantool-php --rm -v $PWD:/client -w /client client php vendor/bin/psalm - - name: Add code coverage report to workflow summary + - name: Upload code coverage report env: ${{ matrix.env }} if: ${{ env.COVERAGE_FILE }} + uses: actions/upload-artifact@v4 + with: + name: coverage-${{ strategy.job-index }} + path: ${{ env.COVERAGE_FILE }} + + coverage: + needs: tests + runs-on: ubuntu-24.04 + permissions: + actions: read + contents: read + statuses: write + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Download coverage reports + uses: actions/download-artifact@v4 + with: + pattern: coverage-* + path: coverage-reports + + - name: Add combined code coverage report to workflow summary uses: getsentry/coverage-action@0.3.8 with: token: ${{ secrets.GITHUB_TOKEN }} - files: ${{ env.COVERAGE_FILE }} + directory: coverage-reports coverage-format: cobertura - disable-search: true enable-tests: false - name: coverage-${{ strategy.job-index }} + name: full-test-matrix From ed49c97cbb474f32e8e8dee27287fbfd84c2bb2e Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Wed, 30 Sep 2026 01:12:10 +0200 Subject: [PATCH 26/34] ci: update artifact actions for Node 24 --- .github/workflows/qa.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index 46cfc6a1..31e36465 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -88,7 +88,7 @@ jobs: - name: Upload code coverage report env: ${{ matrix.env }} if: ${{ env.COVERAGE_FILE }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: coverage-${{ strategy.job-index }} path: ${{ env.COVERAGE_FILE }} @@ -105,7 +105,7 @@ jobs: uses: actions/checkout@v7 - name: Download coverage reports - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: pattern: coverage-* path: coverage-reports From 5961adadc4e65029727936f1d8f472bb100b1342 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Wed, 30 Sep 2026 01:24:29 +0200 Subject: [PATCH 27/34] test: cover firewall and logging middleware --- .../Middleware/FirewallMiddlewareTest.php | 53 +++++++++++++ .../Unit/Middleware/LoggingMiddlewareTest.php | 77 +++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 tests/Unit/Middleware/LoggingMiddlewareTest.php diff --git a/tests/Unit/Middleware/FirewallMiddlewareTest.php b/tests/Unit/Middleware/FirewallMiddlewareTest.php index 76a86a87..9221ef08 100644 --- a/tests/Unit/Middleware/FirewallMiddlewareTest.php +++ b/tests/Unit/Middleware/FirewallMiddlewareTest.php @@ -76,6 +76,18 @@ public function testAndAllow() : void $middleware->process(new PingRequest(), $this->handler); } + public function testAndAllowMultipleRequestTypes() : void + { + $this->handler->expects(self::exactly(2))->method('handle') + ->willReturn(TestDoubleFactory::createEmptyResponse()); + + $middleware = FirewallMiddleware::deny(RequestTypes::CALL) + ->andAllow(RequestTypes::PING, RequestTypes::SELECT); + + $middleware->process(new PingRequest(), $this->handler); + $middleware->process(new SelectRequest(1, 1, [], 0, 1, IteratorTypes::ALL), $this->handler); + } + public function testAndAllowForbids() : void { $middleware = FirewallMiddleware::deny(RequestTypes::CALL)->andAllow(RequestTypes::PING); @@ -96,6 +108,21 @@ public function testAndAllowOnly() : void $middleware->process(new PingRequest(), $this->handler); } + public function testAndAllowOnlyMultipleRequestTypes() : void + { + $this->handler->expects(self::exactly(2))->method('handle') + ->willReturn(TestDoubleFactory::createEmptyResponse()); + + $middleware = FirewallMiddleware::allow(RequestTypes::CALL) + ->andAllowOnly(RequestTypes::PING, RequestTypes::SELECT); + + $middleware->process(new PingRequest(), $this->handler); + $middleware->process(new SelectRequest(1, 1, [], 0, 1, IteratorTypes::ALL), $this->handler); + + $this->expectException(RequestDenied::class); + $middleware->process(new CallRequest('foo'), $this->handler); + } + public function testAndAllowOnlyForbids() : void { $middleware = FirewallMiddleware::allow(RequestTypes::CALL)->andAllowOnly(RequestTypes::PING); @@ -136,6 +163,18 @@ public function testAndDeny() : void $middleware->process(new PingRequest(), $this->handler); } + public function testAndDenyMultipleRequestTypes() : void + { + $this->handler->expects(self::once())->method('handle') + ->willReturn(TestDoubleFactory::createEmptyResponse()); + + $middleware = FirewallMiddleware::deny(RequestTypes::PING) + ->andDeny(RequestTypes::CALL, RequestTypes::EVALUATE); + + $this->expectException(RequestDenied::class); + $middleware->process(new EvaluateRequest('return 42'), $this->handler); + } + public function testAndDenyForbids() : void { $middleware = FirewallMiddleware::allow(RequestTypes::PING)->andDeny(RequestTypes::CALL); @@ -156,6 +195,20 @@ public function testAndDenyOnly() : void $middleware->process(new PingRequest(), $this->handler); } + public function testAndDenyOnlyMultipleRequestTypes() : void + { + $this->handler->expects(self::once())->method('handle') + ->willReturn(TestDoubleFactory::createEmptyResponse()); + + $middleware = FirewallMiddleware::deny(RequestTypes::PING) + ->andDenyOnly(RequestTypes::CALL, RequestTypes::EVALUATE); + + $middleware->process(new PingRequest(), $this->handler); + + $this->expectException(RequestDenied::class); + $middleware->process(new EvaluateRequest('return 42'), $this->handler); + } + public function testAndDenyOnlyForbids() : void { $middleware = FirewallMiddleware::deny(RequestTypes::PING)->andDenyOnly(RequestTypes::CALL); diff --git a/tests/Unit/Middleware/LoggingMiddlewareTest.php b/tests/Unit/Middleware/LoggingMiddlewareTest.php new file mode 100644 index 00000000..8d73754b --- /dev/null +++ b/tests/Unit/Middleware/LoggingMiddlewareTest.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Tarantool\Client\Tests\Unit\Middleware; + +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use RuntimeException; +use Tarantool\Client\Handler\Handler; +use Tarantool\Client\Middleware\LoggingMiddleware; +use Tarantool\Client\Request\PingRequest; +use Tarantool\PhpUnit\Client\TestDoubleFactory; + +final class LoggingMiddlewareTest extends TestCase +{ + public function testLogsRequestAndResponseWhenHandlingSucceeds() : void + { + $request = new PingRequest(); + $response = TestDoubleFactory::createEmptyResponse(); + $handler = $this->createMock(Handler::class); + $handler->expects(self::once())->method('handle')->with($request)->willReturn($response); + + $messages = []; + $logger = $this->createMock(LoggerInterface::class); + $logger->expects(self::exactly(2))->method('debug') + ->willReturnCallback(static function (string $message, array $context) use (&$messages) : void { + $messages[] = [$message, $context]; + }); + $logger->expects(self::never())->method('error'); + + $result = (new LoggingMiddleware($logger))->process($request, $handler); + + self::assertSame($response, $result); + self::assertSame('Starting handling request "ping"', $messages[0][0]); + self::assertSame(['request' => $request], $messages[0][1]); + self::assertSame('Finished handling request "ping"', $messages[1][0]); + self::assertSame($request, $messages[1][1]['request']); + self::assertSame($response, $messages[1][1]['response']); + self::assertIsNumeric($messages[1][1]['duration_ms']); + } + + public function testLogsAndRethrowsHandlerException() : void + { + $request = new PingRequest(); + $exception = new RuntimeException('handler failed'); + $handler = $this->createMock(Handler::class); + $handler->expects(self::once())->method('handle')->with($request)->willThrowException($exception); + + $logger = $this->createMock(LoggerInterface::class); + $logger->expects(self::once())->method('debug') + ->with('Starting handling request "ping"', ['request' => $request]); + $logger->expects(self::once())->method('error') + ->with('Request "ping" failed', self::callback(static function (array $context) use ($request, $exception) : bool { + return $request === ($context['request'] ?? null) + && $exception === ($context['exception'] ?? null) + && isset($context['duration_ms']) + && is_numeric($context['duration_ms']); + })); + + try { + (new LoggingMiddleware($logger))->process($request, $handler); + self::fail('Expected the handler exception to be rethrown'); + } catch (RuntimeException $actual) { + self::assertSame($exception, $actual); + } + } +} From 6ebdc80a8b64e17eed04fbd6f5df87e35a964e63 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Wed, 30 Sep 2026 01:29:08 +0200 Subject: [PATCH 28/34] test: fix firewall middleware test --- tests/Unit/Middleware/FirewallMiddlewareTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Unit/Middleware/FirewallMiddlewareTest.php b/tests/Unit/Middleware/FirewallMiddlewareTest.php index 9221ef08..886a9bc9 100644 --- a/tests/Unit/Middleware/FirewallMiddlewareTest.php +++ b/tests/Unit/Middleware/FirewallMiddlewareTest.php @@ -171,6 +171,8 @@ public function testAndDenyMultipleRequestTypes() : void $middleware = FirewallMiddleware::deny(RequestTypes::PING) ->andDeny(RequestTypes::CALL, RequestTypes::EVALUATE); + $middleware->process(new SelectRequest(1, 1, [], 0, 1, IteratorTypes::ALL), $this->handler); + $this->expectException(RequestDenied::class); $middleware->process(new EvaluateRequest('return 42'), $this->handler); } From 2de384ac0a5b396282f64531cbe4c85ce698b41a Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Wed, 30 Sep 2026 01:34:35 +0200 Subject: [PATCH 29/34] fix: code style --- tests/Unit/Middleware/LoggingMiddlewareTest.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/Unit/Middleware/LoggingMiddlewareTest.php b/tests/Unit/Middleware/LoggingMiddlewareTest.php index 8d73754b..64aa7e54 100644 --- a/tests/Unit/Middleware/LoggingMiddlewareTest.php +++ b/tests/Unit/Middleware/LoggingMiddlewareTest.php @@ -15,7 +15,6 @@ use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; -use RuntimeException; use Tarantool\Client\Handler\Handler; use Tarantool\Client\Middleware\LoggingMiddleware; use Tarantool\Client\Request\PingRequest; @@ -52,7 +51,7 @@ public function testLogsRequestAndResponseWhenHandlingSucceeds() : void public function testLogsAndRethrowsHandlerException() : void { $request = new PingRequest(); - $exception = new RuntimeException('handler failed'); + $exception = new \RuntimeException('handler failed'); $handler = $this->createMock(Handler::class); $handler->expects(self::once())->method('handle')->with($request)->willThrowException($exception); @@ -70,7 +69,7 @@ public function testLogsAndRethrowsHandlerException() : void try { (new LoggingMiddleware($logger))->process($request, $handler); self::fail('Expected the handler exception to be rethrown'); - } catch (RuntimeException $actual) { + } catch (\RuntimeException $actual) { self::assertSame($exception, $actual); } } From fe043f195978a03acecdf27d93261b191a4b17c6 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Wed, 30 Sep 2026 20:33:58 +0200 Subject: [PATCH 30/34] style: preserve fully qualified function calls --- .php-cs-fixer.dist.php | 26 +++++++++++---- src/Connection/Greeting.php | 8 ++--- src/Connection/StreamConnection.php | 20 ++++++------ src/Dsn.php | 32 +++++++++---------- src/Exception/CommunicationFailed.php | 2 +- src/Handler/DefaultHandler.php | 2 +- src/Handler/MiddlewareHandler.php | 4 +-- src/Middleware/CustomErrorMiddleware.php | 4 +-- src/Middleware/FirewallMiddleware.php | 12 +++---- src/Middleware/LoggingMiddleware.php | 6 ++-- src/Middleware/RetryMiddleware.php | 6 ++-- src/Packer/Extension/DecimalExtension.php | 18 +++++------ src/Packer/PacketLength.php | 2 +- src/Packer/PurePacker.php | 2 +- src/Request/AuthenticateRequest.php | 6 ++-- src/SqlQueryResult.php | 10 +++--- tests/Integration/BoxNullTest.php | 10 +++--- tests/Integration/ClientMiddlewareTest.php | 4 +-- tests/Integration/ClientSpaceCachingTest.php | 2 +- tests/Integration/CompositeKeyTest.php | 4 +-- .../Integration/Connection/ConnectionTest.php | 2 +- .../MessagePack/DecimalExtensionTest.php | 8 ++--- .../MessagePack/MessagePackTest.php | 4 +-- .../MessagePack/UuidExtensionTest.php | 8 ++--- .../Integration/Requests/AuthenticateTest.php | 10 +++--- tests/Integration/Requests/DeleteTest.php | 12 +++---- tests/Integration/Requests/InsertTest.php | 18 +++++------ tests/Integration/Requests/ReplaceTest.php | 8 ++--- tests/Integration/Requests/SelectTest.php | 14 ++++---- tests/Integration/Requests/UpdateTest.php | 10 +++--- tests/Integration/Requests/UpsertTest.php | 4 +-- 31 files changed, 145 insertions(+), 133 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index e349fe34..f535ca32 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -5,22 +5,34 @@ namespace Tarantool\Client; use PhpCsFixer\Config; +use PhpCsFixer\Fixer\ConfigurableFixerInterface; use PhpCsFixer\Fixer\ConstantNotation\NativeConstantInvocationFixer; -use PhpCsFixer\Fixer\FixerInterface; use PhpCsFixer\Fixer\FunctionNotation\NativeFunctionInvocationFixer; +use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface; +use PhpCsFixer\FixerDefinition\FixerDefinitionInterface; use PhpCsFixer\Tokenizer\Tokens; -final class FilterableFixer implements FixerInterface +final class FilterableFixer implements ConfigurableFixerInterface { - private $fixer; - private $pathRegex; + private ConfigurableFixerInterface $fixer; + private string $pathRegex; - public function __construct(FixerInterface $fixer, string $pathRegex) + public function __construct(ConfigurableFixerInterface $fixer, string $pathRegex) { $this->fixer = $fixer; $this->pathRegex = $pathRegex; } + public function configure(array $configuration) : void + { + $this->fixer->configure($configuration); + } + + public function getConfigurationDefinition() : FixerConfigurationResolverInterface + { + return $this->fixer->getConfigurationDefinition(); + } + public function isCandidate(Tokens $tokens) : bool { return $this->fixer->isCandidate($tokens); @@ -46,7 +58,7 @@ public function getPriority() : int return $this->fixer->getPriority(); } - public function getDefinition() : \PhpCsFixer\FixerDefinition\FixerDefinitionInterface + public function getDefinition() : FixerDefinitionInterface { return $this->fixer->getDefinition(); } @@ -86,7 +98,7 @@ public function supports(\SplFileInfo $file) : bool 'native_constant_invocation' => false, 'native_function_invocation' => false, 'FilterableFixer/native_constant_invocation' => true, - 'FilterableFixer/native_function_invocation' => true, + 'FilterableFixer/native_function_invocation' => ['include' => ['@all']], 'no_useless_else' => true, 'no_useless_return' => true, 'ordered_imports' => [ diff --git a/src/Connection/Greeting.php b/src/Connection/Greeting.php index 8e137a1b..09e48ef9 100644 --- a/src/Connection/Greeting.php +++ b/src/Connection/Greeting.php @@ -34,7 +34,7 @@ private function __construct(string $greeting) public static function parse(string $greeting) : self { - if (str_starts_with($greeting, 'Tarantool')) { + if (\str_starts_with($greeting, 'Tarantool')) { return new self($greeting); } @@ -59,11 +59,11 @@ public function getSalt() : string throw new \BadMethodCallException('Salt is unknown for persistent connections'); } - if (false === $salt = base64_decode(substr($this->greeting, 64, 44), true)) { + if (false === $salt = \base64_decode(\substr($this->greeting, 64, 44), true)) { throw new UnexpectedResponse('Unable to decode salt'); } - $salt = substr($salt, 0, 20); + $salt = \substr($salt, 0, 20); if (isset($salt[19])) { return $this->salt = $salt; @@ -82,7 +82,7 @@ public function getServerVersion() : string throw new \BadMethodCallException('Server version is unknown for persistent connections'); } - return $this->serverVersion = substr($this->greeting, 10, strspn($this->greeting, '0123456789.', 10)); + return $this->serverVersion = \substr($this->greeting, 10, \strspn($this->greeting, '0123456789.', 10)); } public function equals(?self $greeting) : bool diff --git a/src/Connection/StreamConnection.php b/src/Connection/StreamConnection.php index e7aeff53..edc5b49b 100644 --- a/src/Connection/StreamConnection.php +++ b/src/Connection/StreamConnection.php @@ -53,7 +53,7 @@ private function __construct($uri, float $connectTimeout, float $socketTimeout, $this->persistent = $persistent; if ($tcpNoDelay) { - $this->streamContext = stream_context_create(['socket' => ['tcp_nodelay' => true]]); + $this->streamContext = \stream_context_create(['socket' => ['tcp_nodelay' => true]]); } } @@ -79,7 +79,7 @@ public static function createUds(string $uri, array $options = []) : self public static function create(string $uri, array $options = []) : self { - return str_starts_with($uri, 'unix://') + return \str_starts_with($uri, 'unix://') ? self::createUds($uri, $options) : self::createTcp($uri, $options); } @@ -95,14 +95,14 @@ public function open() : Greeting ? \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_PERSISTENT : \STREAM_CLIENT_CONNECT; - $stream = $this->streamContext ? @stream_socket_client( + $stream = $this->streamContext ? @\stream_socket_client( $this->uri, $errorCode, $errorMessage, $this->connectTimeout, $flags, $this->streamContext - ) : @stream_socket_client( + ) : @\stream_socket_client( $this->uri, $errorCode, $errorMessage, @@ -116,11 +116,11 @@ public function open() : Greeting $socketTimeoutSeconds = (int) $this->socketTimeout; $socketTimeoutMicroSeconds = (int) (($this->socketTimeout - $socketTimeoutSeconds) * 1000000); - stream_set_timeout($stream, $socketTimeoutSeconds, $socketTimeoutMicroSeconds); + \stream_set_timeout($stream, $socketTimeoutSeconds, $socketTimeoutMicroSeconds); $this->stream = $stream; - if ($this->persistent && ftell($stream)) { + if ($this->persistent && \ftell($stream)) { return $this->greeting = Greeting::unknown(); } @@ -134,7 +134,7 @@ public function close() : void { if ($this->stream) { /** @psalm-suppress InvalidPropertyAssignmentValue */ - fclose($this->stream); + \fclose($this->stream); } $this->stream = null; @@ -154,7 +154,7 @@ public function send(string $data) : string throw new CommunicationFailed('Error writing request: connection closed'); } - if (!fwrite($this->stream, $data)) { + if (!\fwrite($this->stream, $data)) { throw CommunicationFailed::withLastPhpError('Error writing request'); } @@ -167,12 +167,12 @@ public function send(string $data) : string private function read(int $length, string $errorMessage) : string { /** @psalm-suppress PossiblyNullArgument */ - if ($data = stream_get_contents($this->stream, $length)) { + if ($data = \stream_get_contents($this->stream, $length)) { return $data; } /** @psalm-suppress PossiblyNullArgument */ - $meta = stream_get_meta_data($this->stream); + $meta = \stream_get_meta_data($this->stream); if ($meta['timed_out']) { throw new CommunicationFailed('Read timed out'); } diff --git a/src/Dsn.php b/src/Dsn.php index 7f8633a6..835af9f1 100644 --- a/src/Dsn.php +++ b/src/Dsn.php @@ -52,11 +52,11 @@ private function __construct($connectionUri) public static function parse(string $dsn) : self { - if (str_starts_with($dsn, 'unix://') && isset($dsn[7])) { + if (\str_starts_with($dsn, 'unix://') && isset($dsn[7])) { return self::parseUds($dsn); } - if (false === $parsed = parse_url($dsn)) { + if (false === $parsed = \parse_url($dsn)) { self::throwParseError($dsn); } if (!isset($parsed['scheme'], $parsed['host']) || 'tcp' !== $parsed['scheme']) { @@ -72,12 +72,12 @@ public static function parse(string $dsn) : self $self->isTcp = true; if (isset($parsed['user'])) { - $self->username = rawurldecode($parsed['user']); - $self->password = isset($parsed['pass']) ? rawurldecode($parsed['pass']) : ''; + $self->username = \rawurldecode($parsed['user']); + $self->password = isset($parsed['pass']) ? \rawurldecode($parsed['pass']) : ''; } if (isset($parsed['query'])) { - parse_str($parsed['query'], $self->options); + \parse_str($parsed['query'], $self->options); } return $self; @@ -85,12 +85,12 @@ public static function parse(string $dsn) : self private static function parseUds(string $dsn) : self { - $parts = explode('@', substr($dsn, 7), 2); + $parts = \explode('@', \substr($dsn, 7), 2); if (isset($parts[1])) { - $parsed = parse_url($parts[1]); - $authority = explode(':', $parts[0]); + $parsed = \parse_url($parts[1]); + $authority = \explode(':', $parts[0]); } else { - $parsed = parse_url($parts[0]); + $parsed = \parse_url($parts[0]); } if (false === $parsed) { @@ -101,15 +101,15 @@ private static function parseUds(string $dsn) : self } $self = new self('unix://'.$parsed['path']); - $self->path = rawurldecode($parsed['path']); + $self->path = \rawurldecode($parsed['path']); if (isset($authority)) { - $self->username = rawurldecode($authority[0]); - $self->password = isset($authority[1]) ? rawurldecode($authority[1]) : ''; + $self->username = \rawurldecode($authority[0]); + $self->password = isset($authority[1]) ? \rawurldecode($authority[1]) : ''; } if (isset($parsed['query'])) { - parse_str($parsed['query'], $self->options); + \parse_str($parsed['query'], $self->options); } return $self; @@ -161,7 +161,7 @@ public function getBool(string $name, ?bool $default = null) : ?bool return $default; } - if (null === $value = filter_var($this->options[$name], \FILTER_VALIDATE_BOOLEAN, \FILTER_NULL_ON_FAILURE)) { + if (null === $value = \filter_var($this->options[$name], \FILTER_VALIDATE_BOOLEAN, \FILTER_NULL_ON_FAILURE)) { throw new \TypeError(\sprintf('DSN option "%s" must be of type bool', $name)); } @@ -174,7 +174,7 @@ public function getInt(string $name, ?int $default = null) : ?int return $default; } - if (false === $value = filter_var($this->options[$name], \FILTER_VALIDATE_INT)) { + if (false === $value = \filter_var($this->options[$name], \FILTER_VALIDATE_INT)) { throw new \TypeError(\sprintf('DSN option "%s" must be of type int', $name)); } @@ -187,7 +187,7 @@ public function getFloat(string $name, ?float $default = null) : ?float return $default; } - if (false === $value = filter_var($this->options[$name], \FILTER_VALIDATE_FLOAT)) { + if (false === $value = \filter_var($this->options[$name], \FILTER_VALIDATE_FLOAT)) { throw new \TypeError(\sprintf('DSN option "%s" must be of type float', $name)); } diff --git a/src/Exception/CommunicationFailed.php b/src/Exception/CommunicationFailed.php index 6a221d01..bda6af40 100644 --- a/src/Exception/CommunicationFailed.php +++ b/src/Exception/CommunicationFailed.php @@ -17,7 +17,7 @@ final class CommunicationFailed extends \RuntimeException implements ClientExcep { public static function withLastPhpError(string $errorMessage) : self { - $error = error_get_last(); + $error = \error_get_last(); return new self($error ? \sprintf('%s: %s', $errorMessage, $error['message']) : $errorMessage); } diff --git a/src/Handler/DefaultHandler.php b/src/Handler/DefaultHandler.php index 2d5af603..0c3c56e7 100644 --- a/src/Handler/DefaultHandler.php +++ b/src/Handler/DefaultHandler.php @@ -34,7 +34,7 @@ public function __construct(Connection $connection, Packer $packer) #[\Override] public function handle(Request $request) : Response { - $packet = $this->packer->pack($request, $sync = mt_rand()); + $packet = $this->packer->pack($request, $sync = \mt_rand()); $this->connection->open(); $packet = $this->connection->send($packet); diff --git a/src/Handler/MiddlewareHandler.php b/src/Handler/MiddlewareHandler.php index c2e9bff7..d0d0acaa 100644 --- a/src/Handler/MiddlewareHandler.php +++ b/src/Handler/MiddlewareHandler.php @@ -45,7 +45,7 @@ public static function append(Handler $handler, array $middleware) : Handler } $handler = clone $handler; - $handler->middleware = array_merge($handler->middleware, $middleware); + $handler->middleware = \array_merge($handler->middleware, $middleware); return $handler; } @@ -60,7 +60,7 @@ public static function prepend(Handler $handler, array $middleware) : Handler } $handler = clone $handler; - $handler->middleware = array_merge($middleware, $handler->middleware); + $handler->middleware = \array_merge($middleware, $handler->middleware); return $handler; } diff --git a/src/Middleware/CustomErrorMiddleware.php b/src/Middleware/CustomErrorMiddleware.php index 14ec7e51..75a15304 100644 --- a/src/Middleware/CustomErrorMiddleware.php +++ b/src/Middleware/CustomErrorMiddleware.php @@ -104,7 +104,7 @@ static function (Error $err, RequestFailed $ex) use ($mapping) : \Exception { */ public static function fromNamespace(string $namespace) : self { - $namespace = rtrim($namespace, '\\').'\\'; + $namespace = \rtrim($namespace, '\\').'\\'; return new self( static function (Error $err, RequestFailed $ex) use ($namespace) : \Exception { @@ -116,7 +116,7 @@ static function (Error $err, RequestFailed $ex) use ($namespace) : \Exception { $className = $namespace.$customType; /** @psalm-suppress UnsafeInstantiation */ - return class_exists($className) + return \class_exists($className) ? new $className($err->getMessage(), $err->getCode()) : $ex; } diff --git a/src/Middleware/FirewallMiddleware.php b/src/Middleware/FirewallMiddleware.php index 9fc83595..c8a26f0b 100644 --- a/src/Middleware/FirewallMiddleware.php +++ b/src/Middleware/FirewallMiddleware.php @@ -33,8 +33,8 @@ final class FirewallMiddleware implements Middleware */ private function __construct($allowed, $denied) { - $this->allowed = $allowed ? array_fill_keys($allowed, true) : []; - $this->denied = $denied ? array_fill_keys($denied, true) : []; + $this->allowed = $allowed ? \array_fill_keys($allowed, true) : []; + $this->denied = $denied ? \array_fill_keys($denied, true) : []; } public static function allow(int $requestType, int ...$requestTypes) : self @@ -63,7 +63,7 @@ public function andAllow(int $requestType, int ...$requestTypes) : self { $new = clone $this; $new->allowed += $requestTypes - ? array_fill_keys([-1 => $requestType] + $requestTypes, true) + ? \array_fill_keys([-1 => $requestType] + $requestTypes, true) : [$requestType => true]; return $new; @@ -73,7 +73,7 @@ public function andAllowOnly(int $requestType, int ...$requestTypes) : self { $new = clone $this; $new->allowed = $requestTypes - ? array_fill_keys([-1 => $requestType] + $requestTypes, true) + ? \array_fill_keys([-1 => $requestType] + $requestTypes, true) : [$requestType => true]; return $new; @@ -83,7 +83,7 @@ public function andDeny(int $requestType, int ...$requestTypes) : self { $new = clone $this; $new->denied += $requestTypes - ? array_fill_keys([-1 => $requestType] + $requestTypes, true) + ? \array_fill_keys([-1 => $requestType] + $requestTypes, true) : [$requestType => true]; return $new; @@ -93,7 +93,7 @@ public function andDenyOnly(int $requestType, int ...$requestTypes) : self { $new = clone $this; $new->denied = $requestTypes - ? array_fill_keys([-1 => $requestType] + $requestTypes, true) + ? \array_fill_keys([-1 => $requestType] + $requestTypes, true) : [$requestType => true]; return $new; diff --git a/src/Middleware/LoggingMiddleware.php b/src/Middleware/LoggingMiddleware.php index ce8aadd0..c5e07020 100644 --- a/src/Middleware/LoggingMiddleware.php +++ b/src/Middleware/LoggingMiddleware.php @@ -37,14 +37,14 @@ public function process(Request $request, Handler $handler) : Response 'request' => $request, ]); - $start = microtime(true); + $start = \microtime(true); try { $response = $handler->handle($request); } catch (\Throwable $e) { $this->logger->error("Request \"$requestName\" failed", [ 'request' => $request, 'exception' => $e, - 'duration_ms' => round((microtime(true) - $start) * 1000), + 'duration_ms' => \round((\microtime(true) - $start) * 1000), ]); throw $e; @@ -53,7 +53,7 @@ public function process(Request $request, Handler $handler) : Response $this->logger->debug("Finished handling request \"$requestName\"", [ 'request' => $request, 'response' => $response, - 'duration_ms' => round((microtime(true) - $start) * 1000), + 'duration_ms' => \round((\microtime(true) - $start) * 1000), ]); return $response; diff --git a/src/Middleware/RetryMiddleware.php b/src/Middleware/RetryMiddleware.php index 23388f97..642162bf 100644 --- a/src/Middleware/RetryMiddleware.php +++ b/src/Middleware/RetryMiddleware.php @@ -88,9 +88,9 @@ public function process(Request $request, Handler $handler) : Response if (null === $delayMs = ($this->getDelayMs)(++$retries, $e)) { break; } - $delayMs = min($delayMs, self::MAX_DELAY_MS) / 2; - $delayMs += mt_rand(0, $delayMs); - usleep($delayMs * 1000); + $delayMs = \min($delayMs, self::MAX_DELAY_MS) / 2; + $delayMs += \mt_rand(0, $delayMs); + \usleep($delayMs * 1000); } } diff --git a/src/Packer/Extension/DecimalExtension.php b/src/Packer/Extension/DecimalExtension.php index 5a9aec55..1b20f156 100644 --- a/src/Packer/Extension/DecimalExtension.php +++ b/src/Packer/Extension/DecimalExtension.php @@ -41,13 +41,13 @@ public function pack(Packer $packer, $value) : ?string if ('-' === $data[0]) { $nibble = 'd'; - $data = substr($data, 1); + $data = \substr($data, 1); } else { $nibble = 'c'; } - $pieces = explode('.', $data, 2); - $pieces[1] = rtrim($pieces[1], '0'); + $pieces = \explode('.', $data, 2); + $pieces[1] = \rtrim($pieces[1], '0'); $data = "{$pieces[0]}{$pieces[1]}{$nibble}"; if (0 !== \strlen($data) % 2) { @@ -55,7 +55,7 @@ public function pack(Packer $packer, $value) : ?string } return $packer->packExt(self::TYPE, - $packer->packInt('' === $pieces[1] ? 0 : \strlen($pieces[1])).hex2bin($data) + $packer->packInt('' === $pieces[1] ? 0 : \strlen($pieces[1])).\hex2bin($data) ); } @@ -71,19 +71,19 @@ public function unpackExt(BufferUnpacker $unpacker, int $extLength) */ $scale = $unpacker->unpackInt(); $data = $unpacker->read($extLength - 1); - $data = bin2hex($data); + $data = \bin2hex($data); $sign = 'd' === $data[-1] ? '-' : ''; - $dec = substr($data, 0, -1); + $dec = \substr($data, 0, -1); if (\strlen($dec) > 1 && 1 === \strlen($dec) % 2 && '0' === $dec[0]) { - $dec = substr($dec, 1); + $dec = \substr($dec, 1); } if (0 !== $scale) { $length = \strlen($dec); $dec = ($length <= $scale) - ? substr_replace($dec, '0.'.str_repeat('0', $scale - $length), -$scale, 0) - : substr_replace($dec, '.', -$scale, 0); + ? \substr_replace($dec, '0.'.\str_repeat('0', $scale - $length), -$scale, 0) + : \substr_replace($dec, '.', -$scale, 0); } return Decimal::valueOf($sign.$dec, self::PRECISION); diff --git a/src/Packer/PacketLength.php b/src/Packer/PacketLength.php index e7cea7a4..ab73ed1a 100644 --- a/src/Packer/PacketLength.php +++ b/src/Packer/PacketLength.php @@ -23,7 +23,7 @@ private function __construct() public static function pack(int $length) : string { - return pack('CN', 0xCE, $length); + return \pack('CN', 0xCE, $length); } public static function unpack(string $data) : int diff --git a/src/Packer/PurePacker.php b/src/Packer/PurePacker.php index 01f0bbb5..10fb1d36 100644 --- a/src/Packer/PurePacker.php +++ b/src/Packer/PurePacker.php @@ -70,7 +70,7 @@ public static function fromAvailableExtensions() : self public function pack(Request $request, int $sync) : string { // Hot path optimization - $packet = pack('C*', 0x82, Keys::CODE, $request->getType(), Keys::SYNC). + $packet = \pack('C*', 0x82, Keys::CODE, $request->getType(), Keys::SYNC). $this->packer->packInt($sync). $this->packer->packMap($request->getBody()); diff --git a/src/Request/AuthenticateRequest.php b/src/Request/AuthenticateRequest.php index 1543c5e1..4afc7120 100644 --- a/src/Request/AuthenticateRequest.php +++ b/src/Request/AuthenticateRequest.php @@ -23,11 +23,11 @@ final class AuthenticateRequest implements Request public function __construct(string $salt, string $username, string $password = '') { - $hash1 = sha1($password, true); - $hash2 = sha1($hash1, true); + $hash1 = \sha1($password, true); + $hash2 = \sha1($hash1, true); $this->body = [ - Keys::TUPLE => ['chap-sha1', $hash1 ^ sha1($salt.$hash2, true)], + Keys::TUPLE => ['chap-sha1', $hash1 ^ \sha1($salt.$hash2, true)], Keys::USER_NAME => $username, ]; } diff --git a/src/SqlQueryResult.php b/src/SqlQueryResult.php index f2c1f8f3..7a7f8a31 100644 --- a/src/SqlQueryResult.php +++ b/src/SqlQueryResult.php @@ -28,7 +28,7 @@ public function __construct(array $data, array $metadata) { $this->data = $data; $this->metadata = $metadata; - $this->keys = $metadata ? array_column($metadata, 0) : []; + $this->keys = $metadata ? \array_column($metadata, 0) : []; } public function getData() : array @@ -48,19 +48,19 @@ public function isEmpty() : bool public function getFirst() : ?array { - return $this->data ? array_combine($this->keys, reset($this->data)) : null; + return $this->data ? \array_combine($this->keys, \reset($this->data)) : null; } public function getLast() : ?array { - return $this->data ? array_combine($this->keys, end($this->data)) : null; + return $this->data ? \array_combine($this->keys, \end($this->data)) : null; } #[\Override] public function getIterator() : \Generator { foreach ($this->data as $item) { - yield array_combine($this->keys, $item); + yield \array_combine($this->keys, $item); } } @@ -83,7 +83,7 @@ public function offsetGet($offset) : array throw new \OutOfBoundsException(\sprintf('The offset "%s" does not exist', $offset)); } - return array_combine($this->keys, $this->data[$offset]); + return \array_combine($this->keys, $this->data[$offset]); } #[\Override] diff --git a/tests/Integration/BoxNullTest.php b/tests/Integration/BoxNullTest.php index a76cfcc2..104bfd98 100644 --- a/tests/Integration/BoxNullTest.php +++ b/tests/Integration/BoxNullTest.php @@ -19,11 +19,11 @@ final class BoxNullTest extends TestCase { #[Lua('format = {}')] - #[Lua('format[1] = {name = \'foo\', type = \'unsigned\'}')] - #[Lua('format[2] = {name = \'bar\', type = \'map\', is_nullable = true}')] - #[Lua('format[3] = {name = \'baz\', type = \'unsigned\', is_nullable = true}')] - #[Lua('space = create_space(\'box_null\', {format = format})')] - #[Lua('space:create_index(\'pk\')')] + #[Lua('format[1] = {name = "foo", type = "unsigned"}')] + #[Lua('format[2] = {name = "bar", type = "map", is_nullable = true}')] + #[Lua('format[3] = {name = "baz", type = "unsigned", is_nullable = true}')] + #[Lua('space = create_space("box_null", {format = format})')] + #[Lua('space:create_index("pk")')] #[Lua('space:insert{1, {a = 1}}')] #[Lua('space:insert{2, {b = 2}, box.NULL}')] #[Lua('space:insert{3, box.NULL, 300}')] diff --git a/tests/Integration/ClientMiddlewareTest.php b/tests/Integration/ClientMiddlewareTest.php index 9738be08..b020b97c 100644 --- a/tests/Integration/ClientMiddlewareTest.php +++ b/tests/Integration/ClientMiddlewareTest.php @@ -53,8 +53,8 @@ public function testSpaceInheritsMiddleware() : void } #[DoesNotPerformAssertions] - #[Lua('fiber = require(\'fiber\')')] - #[Lua('function test() try_drop_user(\'foobar\') fiber.sleep(.5) create_user(\'foobar\', \'\') end')] + #[Lua('fiber = require("fiber")')] + #[Lua('function test() try_drop_user("foobar") fiber.sleep(.5) create_user("foobar", "") end')] #[Lua('fiber.create(test)')] public function testAuthenticationRetrySucceeds() : void { diff --git a/tests/Integration/ClientSpaceCachingTest.php b/tests/Integration/ClientSpaceCachingTest.php index 5dd6260a..86a6aa46 100644 --- a/tests/Integration/ClientSpaceCachingTest.php +++ b/tests/Integration/ClientSpaceCachingTest.php @@ -16,7 +16,7 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\PhpUnit\Attribute\Lua; -#[Lua('create_space(\'test_space_caching\'):create_index(\'primary\', {type = \'tree\', parts = {1, \'unsigned\'}})')] +#[Lua('create_space("test_space_caching"):create_index("primary", {type = "tree", parts = {1, "unsigned"}})')] final class ClientSpaceCachingTest extends TestCase { public function testCacheSpace() : void diff --git a/tests/Integration/CompositeKeyTest.php b/tests/Integration/CompositeKeyTest.php index 18d242ef..bb0ac522 100755 --- a/tests/Integration/CompositeKeyTest.php +++ b/tests/Integration/CompositeKeyTest.php @@ -17,8 +17,8 @@ use Tarantool\Client\Schema\Operations; use Tarantool\PhpUnit\Attribute\Lua; -#[Lua('space = create_space(\'composite_key\')')] -#[Lua('space:create_index(\'primary\', {type = \'tree\', unique = true, parts = {1, \'unsigned\', 2, \'unsigned\'}})')] +#[Lua('space = create_space("composite_key")')] +#[Lua('space:create_index("primary", {type = "tree", unique = true, parts = {1, "unsigned", 2, "unsigned"}})')] #[Lua('space:insert{2016, 10, 1}')] #[Lua('space:insert{2016, 11, 0}')] final class CompositeKeyTest extends TestCase diff --git a/tests/Integration/Connection/ConnectionTest.php b/tests/Integration/Connection/ConnectionTest.php index 626e72cd..f10c8c59 100644 --- a/tests/Integration/Connection/ConnectionTest.php +++ b/tests/Integration/Connection/ConnectionTest.php @@ -33,7 +33,7 @@ final class ConnectionTest extends TestCase { #[DataProvider('provideAutoConnectData')] #[DoesNotPerformAssertions] - #[Lua('create_space(\'test_auto_connect\'):create_index(\'primary\', {type = \'tree\', parts = {1, \'unsigned\'}})')] + #[Lua('create_space("test_auto_connect"):create_index("primary", {type = "tree", parts = {1, "unsigned"}})')] public function testAutoConnect(string $methodName, array $methodArgs, ?string $space = null) : void { $object = $space ? $this->client->getSpace($space) : $this->client; diff --git a/tests/Integration/MessagePack/DecimalExtensionTest.php b/tests/Integration/MessagePack/DecimalExtensionTest.php index 1ec9683b..fa9bec7e 100755 --- a/tests/Integration/MessagePack/DecimalExtensionTest.php +++ b/tests/Integration/MessagePack/DecimalExtensionTest.php @@ -29,10 +29,10 @@ #[RequiresTarantool('>=2.3')] #[RequiresPhpExtension('decimal')] -#[Lua('dec = require(\'decimal\').new(\'18446744073709551615\')')] -#[Lua('space = create_space(\'decimal_primary\')')] -#[Lua('space:format({{name = \'id\', type = \'decimal\'}})')] -#[Lua('space:create_index("primary", {parts = {1, \'decimal\'}})')] +#[Lua('dec = require("decimal").new("18446744073709551615")')] +#[Lua('space = create_space("decimal_primary")')] +#[Lua('space:format({{name = "id", type = "decimal"}})')] +#[Lua('space:create_index("primary", {parts = {1, "decimal"}})')] #[Lua('space:insert({dec})')] final class DecimalExtensionTest extends TestCase { diff --git a/tests/Integration/MessagePack/MessagePackTest.php b/tests/Integration/MessagePack/MessagePackTest.php index 04385fbd..d1c36a4d 100755 --- a/tests/Integration/MessagePack/MessagePackTest.php +++ b/tests/Integration/MessagePack/MessagePackTest.php @@ -68,8 +68,8 @@ public function testPackUnpackMultiDimensionalArray() : void self::assertEqualsCanonicalizing($array, $result); } - #[Lua('space = create_space(\'custom_type\')')] - #[Lua('space:create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] + #[Lua('space = create_space("custom_type")')] + #[Lua('space:create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] public function testCustomType() : void { $client = ClientBuilder::createFromEnv() diff --git a/tests/Integration/MessagePack/UuidExtensionTest.php b/tests/Integration/MessagePack/UuidExtensionTest.php index a64fe651..cd8a68c7 100755 --- a/tests/Integration/MessagePack/UuidExtensionTest.php +++ b/tests/Integration/MessagePack/UuidExtensionTest.php @@ -24,10 +24,10 @@ use Tarantool\PhpUnit\Attribute\RequiresTarantool; #[RequiresTarantool('>=2.4')] -#[Lua('uuid = require(\'uuid\').fromstr(\'64d22e4d-ac92-4a23-899a-e59f34af5479\')')] -#[Lua('space = create_space(\'uuid_primary\')')] -#[Lua('space:format({{name = \'id\', type = \'uuid\'}})')] -#[Lua('space:create_index("primary", {parts = {1, \'uuid\'}})')] +#[Lua('uuid = require("uuid").fromstr("64d22e4d-ac92-4a23-899a-e59f34af5479")')] +#[Lua('space = create_space("uuid_primary")')] +#[Lua('space:format({{name = "id", type = "uuid"}})')] +#[Lua('space:create_index("primary", {parts = {1, "uuid"}})')] #[Lua('space:insert({uuid})')] final class UuidExtensionTest extends TestCase { diff --git a/tests/Integration/Requests/AuthenticateTest.php b/tests/Integration/Requests/AuthenticateTest.php index fa9ec446..67b0d072 100644 --- a/tests/Integration/Requests/AuthenticateTest.php +++ b/tests/Integration/Requests/AuthenticateTest.php @@ -24,9 +24,9 @@ final class AuthenticateTest extends TestCase { #[DoesNotPerformAssertions] #[DataProvider('provideValidCredentials')] - #[Lua('create_user(\'user_foo\', \'foo\')')] - #[Lua('create_user(\'user_empty\', \'\')')] - #[Lua('create_user(\'user_big\', \'123456789012345678901234567890123456789012345678901234567890\')')] + #[Lua('create_user("user_foo", "foo")')] + #[Lua('create_user("user_empty", "")')] + #[Lua('create_user("user_big", "123456789012345678901234567890123456789012345678901234567890")')] public function testAuthenticateWithValidCredentials(string $username, string $password) : void { $client = ClientBuilder::createFromEnv()->setOptions([ @@ -71,8 +71,8 @@ public static function provideInvalidCredentials() : iterable ]; } - #[Lua('create_user(\'user_foo\', \'foo\')')] - #[Lua('create_space(\'test_auth_reconnect\'):create_index(\'primary\', {type = \'tree\', parts = {1, \'unsigned\'}})')] + #[Lua('create_user("user_foo", "foo")')] + #[Lua('create_space("test_auth_reconnect"):create_index("primary", {type = "tree", parts = {1, "unsigned"}})')] public function testUseCredentialsAfterReconnect() : void { $client = ClientBuilder::createFromEnv()->setOptions([ diff --git a/tests/Integration/Requests/DeleteTest.php b/tests/Integration/Requests/DeleteTest.php index 6f85d549..680b3df9 100755 --- a/tests/Integration/Requests/DeleteTest.php +++ b/tests/Integration/Requests/DeleteTest.php @@ -17,12 +17,12 @@ use Tarantool\Client\Tests\Integration\TestCase; use Tarantool\PhpUnit\Attribute\Lua; -#[Lua('space = create_space(\'request_delete\')')] -#[Lua('space:create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] -#[Lua('space:create_index(\'secondary\', {type = \'tree\', parts = {2, \'str\'}})')] -#[Lua('space:insert{3, \'delete_me_1\'}')] -#[Lua('space:insert{4, \'delete_me_2\'}')] -#[Lua('space:insert{5, \'delete_me_3\'}')] +#[Lua('space = create_space("request_delete")')] +#[Lua('space:create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] +#[Lua('space:create_index("secondary", {type = "tree", parts = {2, "str"}})')] +#[Lua('space:insert{3, "delete_me_1"}')] +#[Lua('space:insert{4, "delete_me_2"}')] +#[Lua('space:insert{5, "delete_me_3"}')] final class DeleteTest extends TestCase { public function testDelete() : void diff --git a/tests/Integration/Requests/InsertTest.php b/tests/Integration/Requests/InsertTest.php index 4cbc4c31..88c2d729 100755 --- a/tests/Integration/Requests/InsertTest.php +++ b/tests/Integration/Requests/InsertTest.php @@ -21,8 +21,8 @@ final class InsertTest extends TestCase { #[DataProvider('provideInsertData')] - #[Lua('create_space(\'request_insert_str\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'str\'}})')] - #[Lua('create_space(\'request_insert_num\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] + #[Lua('create_space("request_insert_str"):create_index("primary", {type = "hash", parts = {1, "str"}})')] + #[Lua('create_space("request_insert_num"):create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] public function testInsert(string $spaceName, array $values) : void { $space = $this->client->getSpace($spaceName); @@ -45,8 +45,8 @@ public static function provideInsertData() : iterable } #[DataProvider('provideInsertDataWithMismatchedTypes')] - #[Lua('create_space(\'request_insert_str\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'str\'}})')] - #[Lua('create_space(\'request_insert_num\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] + #[Lua('create_space("request_insert_str"):create_index("primary", {type = "hash", parts = {1, "str"}})')] + #[Lua('create_space("request_insert_num"):create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] public function testInsertTypeMismatchedValues(string $spaceName, array $values) : void { $space = $this->client->getSpace($spaceName); @@ -70,9 +70,9 @@ public static function provideInsertDataWithMismatchedTypes() : iterable ]; } - #[Lua('space = create_space(\'request_insert_dup_key\')')] - #[Lua('space:create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] - #[Lua('space:insert{1, \'foobar\'}')] + #[Lua('space = create_space("request_insert_dup_key")')] + #[Lua('space:create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] + #[Lua('space:insert{1, "foobar"}')] public function testInsertDuplicateKey() : void { $space = $this->client->getSpace('request_insert_dup_key'); @@ -83,8 +83,8 @@ public function testInsertDuplicateKey() : void $space->insert([1, 'bazqux']); } - #[Lua('space = create_space(\'request_insert_empty_tuple\')')] - #[Lua('space:create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] + #[Lua('space = create_space("request_insert_empty_tuple")')] + #[Lua('space:create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] public function testInsertEmptyTuple() : void { $space = $this->client->getSpace('request_insert_empty_tuple'); diff --git a/tests/Integration/Requests/ReplaceTest.php b/tests/Integration/Requests/ReplaceTest.php index b058aff7..e5232d9e 100755 --- a/tests/Integration/Requests/ReplaceTest.php +++ b/tests/Integration/Requests/ReplaceTest.php @@ -18,10 +18,10 @@ use Tarantool\Client\Tests\Integration\TestCase; use Tarantool\PhpUnit\Attribute\Lua; -#[Lua('space = create_space(\'request_replace\')')] -#[Lua('space:create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] -#[Lua('space:create_index(\'secondary\', {type = \'tree\', parts = {2, \'str\'}})')] -#[Lua('space:insert{2, \'replace_me\'}')] +#[Lua('space = create_space("request_replace")')] +#[Lua('space:create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] +#[Lua('space:create_index("secondary", {type = "tree", parts = {2, "str"}})')] +#[Lua('space:insert{2, "replace_me"}')] final class ReplaceTest extends TestCase { public function testReplace() : void diff --git a/tests/Integration/Requests/SelectTest.php b/tests/Integration/Requests/SelectTest.php index a320840a..d254379c 100755 --- a/tests/Integration/Requests/SelectTest.php +++ b/tests/Integration/Requests/SelectTest.php @@ -22,10 +22,10 @@ final class SelectTest extends TestCase { #[DataProvider('provideSelectData')] - #[Lua('space = create_space(\'request_select\')')] - #[Lua('space:create_index(\'primary\', {type = \'tree\', unique = true, parts = {1, \'unsigned\'}})')] - #[Lua('space:create_index(\'secondary\', {type = \'tree\', unique = false, parts = {2, \'unsigned\', 3, \'str\'}})')] - #[Lua('for i = 1, 100 do space:replace{i, i * 2 % 5, \'tuple_\' .. i} end')] + #[Lua('space = create_space("request_select")')] + #[Lua('space:create_index("primary", {type = "tree", unique = true, parts = {1, "unsigned"}})')] + #[Lua('space:create_index("secondary", {type = "tree", unique = false, parts = {2, "unsigned", 3, "str"}})')] + #[Lua('for i = 1, 100 do space:replace{i, i * 2 % 5, "tuple_" .. i} end')] public function testSelect(int $expectedCount, Criteria $criteria) : void { $space = $this->client->getSpace('request_select'); @@ -54,7 +54,7 @@ public static function provideSelectData() : iterable ]; } - #[Lua('create_space(\'request_select\'):create_index(\'primary\', {type = \'tree\', parts = {1, \'unsigned\'}})')] + #[Lua('create_space("request_select"):create_index("primary", {type = "tree", parts = {1, "unsigned"}})')] public function testSelectEmpty() : void { $space = $this->client->getSpace('request_select'); @@ -62,7 +62,7 @@ public function testSelectEmpty() : void self::assertEmpty($space->select(Criteria::key([]))); } - #[Lua('create_space(\'request_select\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] + #[Lua('create_space("request_select"):create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] public function testSelectWithNonExistingIndexName() : void { $space = $this->client->getSpace('request_select'); @@ -73,7 +73,7 @@ public function testSelectWithNonExistingIndexName() : void $space->select(Criteria::key([1])->andIndex('non_existing_index')); } - #[Lua('create_space(\'request_select\'):create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] + #[Lua('create_space("request_select"):create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] public function testSelectWithNonExistingIndexId() : void { $space = $this->client->getSpace('request_select'); diff --git a/tests/Integration/Requests/UpdateTest.php b/tests/Integration/Requests/UpdateTest.php index 9f69c681..417eb3b6 100755 --- a/tests/Integration/Requests/UpdateTest.php +++ b/tests/Integration/Requests/UpdateTest.php @@ -19,11 +19,11 @@ use Tarantool\Client\Tests\Integration\TestCase; use Tarantool\PhpUnit\Attribute\Lua; -#[Lua('space = create_space(\'request_update\')')] -#[Lua('space:create_index(\'primary\', {type = \'tree\', unique = true, parts = {1, \'unsigned\'}})')] -#[Lua('space:create_index(\'secondary\', {type = \'tree\', unique = false, parts = {2, \'unsigned\', 3, \'str\'}})')] -#[Lua('space:replace{1, 2, \'tuple_1\'}')] -#[Lua('space:replace{2, 4, \'tuple_2\'}')] +#[Lua('space = create_space("request_update")')] +#[Lua('space:create_index("primary", {type = "tree", unique = true, parts = {1, "unsigned"}})')] +#[Lua('space:create_index("secondary", {type = "tree", unique = false, parts = {2, "unsigned", 3, "str"}})')] +#[Lua('space:replace{1, 2, "tuple_1"}')] +#[Lua('space:replace{2, 4, "tuple_2"}')] final class UpdateTest extends TestCase { public function testUpdate() : void diff --git a/tests/Integration/Requests/UpsertTest.php b/tests/Integration/Requests/UpsertTest.php index 6d1c4fa7..7c1c3bf0 100755 --- a/tests/Integration/Requests/UpsertTest.php +++ b/tests/Integration/Requests/UpsertTest.php @@ -19,8 +19,8 @@ use Tarantool\Client\Tests\Integration\TestCase; use Tarantool\PhpUnit\Attribute\Lua; -#[Lua('space = create_space(\'request_upsert\')')] -#[Lua('space:create_index(\'primary\', {type = \'hash\', parts = {1, \'unsigned\'}})')] +#[Lua('space = create_space("request_upsert")')] +#[Lua('space:create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] final class UpsertTest extends TestCase { public function testUpsert() : void From f9acce0cefc0acf9bb69141473b19abba08b720b Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Wed, 30 Sep 2026 21:05:59 +0200 Subject: [PATCH 31/34] refactor: declare native property types --- .php-cs-fixer.dist.php | 1 + examples/logging/SlowRequestHandler.php | 6 +- src/Client.php | 2 +- src/Connection/StreamConnection.php | 20 ++--- src/Dsn.php | 28 ++---- src/Error.php | 16 ++-- src/Exception/RequestFailed.php | 3 +- src/Handler/DefaultHandler.php | 4 +- src/Middleware/AuthenticationMiddleware.php | 7 +- src/Middleware/CustomErrorMiddleware.php | 4 +- src/Middleware/FirewallMiddleware.php | 10 +-- src/Middleware/LoggingMiddleware.php | 2 +- src/Middleware/RetryMiddleware.php | 11 ++- src/Packer/Extension/DecimalExtension.php | 3 - src/Packer/PacketLength.php | 2 +- src/PreparedStatement.php | 10 +-- src/Request/AuthenticateRequest.php | 2 +- src/Request/CallRequest.php | 2 +- src/Request/DeleteRequest.php | 2 +- src/Request/EvaluateRequest.php | 2 +- src/Request/ExecuteRequest.php | 4 +- src/Request/InsertRequest.php | 2 +- src/Request/PrepareRequest.php | 4 +- src/Request/ReplaceRequest.php | 2 +- src/Request/SelectRequest.php | 2 +- src/Request/UpdateRequest.php | 2 +- src/Request/UpsertRequest.php | 2 +- src/Response.php | 4 +- src/Schema/Operations.php | 94 +++++---------------- src/Schema/Space.php | 12 ++- src/SqlQueryResult.php | 6 +- src/SqlUpdateResult.php | 2 +- 32 files changed, 96 insertions(+), 177 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index f535ca32..2d4168f9 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -95,6 +95,7 @@ public function supports(\SplFileInfo $file) : bool 'array_syntax' => ['syntax' => 'short'], 'binary_operator_spaces' => ['operators' => ['=' => null, '=>' => null]], 'declare_strict_types' => true, + 'integer_literal_case' => false, 'native_constant_invocation' => false, 'native_function_invocation' => false, 'FilterableFixer/native_constant_invocation' => true, diff --git a/examples/logging/SlowRequestHandler.php b/examples/logging/SlowRequestHandler.php index b1e103ba..8a813d82 100644 --- a/examples/logging/SlowRequestHandler.php +++ b/examples/logging/SlowRequestHandler.php @@ -53,12 +53,10 @@ public function handle(LogRecord $record) : bool $request = $record['context']['request']; - $newRecord = $record->with( + return $this->handler->handle($record->with( level: $this->level, message: sprintf('Slow %s request detected (%d ms)', RequestTypes::getName($request->getType()), $record['context']['duration_ms']), context: ['request_body' => $request->getBody()] + $record['context'] - ); - - return $this->handler->handle($newRecord); + )); } } diff --git a/src/Client.php b/src/Client.php index a7b63c55..966caaab 100644 --- a/src/Client.php +++ b/src/Client.php @@ -36,7 +36,7 @@ final class Client private Handler $handler; /** @var array */ - private $spaces = []; + private array $spaces = []; public function __construct(Handler $handler) { diff --git a/src/Connection/StreamConnection.php b/src/Connection/StreamConnection.php index edc5b49b..cd5f7587 100644 --- a/src/Connection/StreamConnection.php +++ b/src/Connection/StreamConnection.php @@ -21,17 +21,13 @@ final class StreamConnection implements Connection { public const DEFAULT_TCP_URI = 'tcp://127.0.0.1:3301'; - /** @var string */ - private $uri; + private string $uri; - /** @var float */ - private $connectTimeout; + private float $connectTimeout; - /** @var float */ - private $socketTimeout; + private float $socketTimeout; - /** @var bool */ - private $persistent; + private bool $persistent; /** @var resource|null */ private $streamContext; @@ -39,13 +35,9 @@ final class StreamConnection implements Connection /** @var resource|null */ private $stream; - /** @var Greeting|null */ - private $greeting; + private ?Greeting $greeting = null; - /** - * @param string $uri - */ - private function __construct($uri, float $connectTimeout, float $socketTimeout, bool $persistent, bool $tcpNoDelay) + private function __construct(string $uri, float $connectTimeout, float $socketTimeout, bool $persistent, bool $tcpNoDelay) { $this->uri = $uri; $this->connectTimeout = $connectTimeout; diff --git a/src/Dsn.php b/src/Dsn.php index 835af9f1..931d3ed8 100644 --- a/src/Dsn.php +++ b/src/Dsn.php @@ -15,37 +15,27 @@ final class Dsn { - /** @var string|null */ - private $host; + private ?string $host = null; - /** @var int|null */ - private $port; + private ?int $port = null; - /** @var string|null */ - private $path; + private ?string $path = null; - /** @var string */ - private $connectionUri; + private string $connectionUri; - /** @var string|null */ - private $username; + private ?string $username = null; - /** @var string|null */ - private $password; + private ?string $password = null; - /** @var bool */ - private $isTcp = false; + private bool $isTcp = false; /** * @var array * @psalm-suppress PropertyNotSetInConstructor */ - private $options; + private array $options = []; - /** - * @param string $connectionUri - */ - private function __construct($connectionUri) + private function __construct(string $connectionUri) { $this->connectionUri = $connectionUri; } diff --git a/src/Error.php b/src/Error.php index 485dbd0c..c53e7109 100644 --- a/src/Error.php +++ b/src/Error.php @@ -15,14 +15,14 @@ final class Error { - private $type; - private $file; - private $line; - private $message; - private $number; - private $code; - private $fields; - private $previous; + private string $type; + private string $file; + private int $line; + private string $message; + private int $number; + private int $code; + private array $fields; + private ?self $previous; public function __construct( string $type, diff --git a/src/Exception/RequestFailed.php b/src/Exception/RequestFailed.php index 704c388d..a1519624 100644 --- a/src/Exception/RequestFailed.php +++ b/src/Exception/RequestFailed.php @@ -19,8 +19,7 @@ final class RequestFailed extends \RuntimeException implements ClientException { - /** @var Error|null */ - private $error; + private ?Error $error = null; public function getError() : ?Error { diff --git a/src/Handler/DefaultHandler.php b/src/Handler/DefaultHandler.php index 0c3c56e7..3eba2ead 100644 --- a/src/Handler/DefaultHandler.php +++ b/src/Handler/DefaultHandler.php @@ -22,8 +22,8 @@ final class DefaultHandler implements Handler { - private $connection; - private $packer; + private Connection $connection; + private Packer $packer; public function __construct(Connection $connection, Packer $packer) { diff --git a/src/Middleware/AuthenticationMiddleware.php b/src/Middleware/AuthenticationMiddleware.php index 9e581b4f..ea9829b6 100644 --- a/src/Middleware/AuthenticationMiddleware.php +++ b/src/Middleware/AuthenticationMiddleware.php @@ -21,11 +21,10 @@ final class AuthenticationMiddleware implements Middleware { - private $username; - private $password; + private string $username; + private string $password; - /** @var Greeting|null */ - private $greeting; + private ?Greeting $greeting = null; public function __construct(string $username, string $password = '') { diff --git a/src/Middleware/CustomErrorMiddleware.php b/src/Middleware/CustomErrorMiddleware.php index 75a15304..8a7deb05 100644 --- a/src/Middleware/CustomErrorMiddleware.php +++ b/src/Middleware/CustomErrorMiddleware.php @@ -22,12 +22,12 @@ final class CustomErrorMiddleware implements Middleware { /** @var \Closure(Error, RequestFailed) : \Exception */ - private $factory; + private \Closure $factory; /** * @param \Closure(Error, RequestFailed) : \Exception $factory */ - private function __construct($factory) + private function __construct(\Closure $factory) { $this->factory = $factory; } diff --git a/src/Middleware/FirewallMiddleware.php b/src/Middleware/FirewallMiddleware.php index c8a26f0b..850b2992 100644 --- a/src/Middleware/FirewallMiddleware.php +++ b/src/Middleware/FirewallMiddleware.php @@ -22,16 +22,12 @@ final class FirewallMiddleware implements Middleware { /** @var array */ - private $allowed; + private array $allowed; /** @var array */ - private $denied; + private array $denied; - /** - * @param array $allowed - * @param array $denied - */ - private function __construct($allowed, $denied) + private function __construct(array $allowed, array $denied) { $this->allowed = $allowed ? \array_fill_keys($allowed, true) : []; $this->denied = $denied ? \array_fill_keys($denied, true) : []; diff --git a/src/Middleware/LoggingMiddleware.php b/src/Middleware/LoggingMiddleware.php index c5e07020..12e6a1b0 100644 --- a/src/Middleware/LoggingMiddleware.php +++ b/src/Middleware/LoggingMiddleware.php @@ -21,7 +21,7 @@ final class LoggingMiddleware implements Middleware { - private $logger; + private LoggerInterface $logger; public function __construct(LoggerInterface $logger) { diff --git a/src/Middleware/RetryMiddleware.php b/src/Middleware/RetryMiddleware.php index 642162bf..33bd3967 100644 --- a/src/Middleware/RetryMiddleware.php +++ b/src/Middleware/RetryMiddleware.php @@ -27,13 +27,13 @@ final class RetryMiddleware implements Middleware private const MAX_RETRIES_LIMIT = 10; private const MAX_DELAY_MS = 60000; - /** @var \Closure */ - private $getDelayMs; + /** @var \Closure(int, \Throwable) : ?int */ + private \Closure $getDelayMs; /** - * @param \Closure $getDelayMs + * @param \Closure(int, \Throwable) : ?int $getDelayMs */ - private function __construct($getDelayMs) + private function __construct(\Closure $getDelayMs) { $this->getDelayMs = $getDelayMs; } @@ -59,6 +59,9 @@ public static function linear(int $maxRetries = self::DEFAULT_MAX_RETRIES, int $ }); } + /** + * @param \Closure(int, \Throwable) : ?int $getDelayMs + */ public static function custom(\Closure $getDelayMs) : self { return new self(static function (int $retries, \Throwable $e) use ($getDelayMs) : ?int { diff --git a/src/Packer/Extension/DecimalExtension.php b/src/Packer/Extension/DecimalExtension.php index 1b20f156..268984e7 100644 --- a/src/Packer/Extension/DecimalExtension.php +++ b/src/Packer/Extension/DecimalExtension.php @@ -75,9 +75,6 @@ public function unpackExt(BufferUnpacker $unpacker, int $extLength) $sign = 'd' === $data[-1] ? '-' : ''; $dec = \substr($data, 0, -1); - if (\strlen($dec) > 1 && 1 === \strlen($dec) % 2 && '0' === $dec[0]) { - $dec = \substr($dec, 1); - } if (0 !== $scale) { $length = \strlen($dec); diff --git a/src/Packer/PacketLength.php b/src/Packer/PacketLength.php index ab73ed1a..c8572146 100644 --- a/src/Packer/PacketLength.php +++ b/src/Packer/PacketLength.php @@ -23,7 +23,7 @@ private function __construct() public static function pack(int $length) : string { - return \pack('CN', 0xCE, $length); + return \pack('CN', 0xce, $length); } public static function unpack(string $data) : int diff --git a/src/PreparedStatement.php b/src/PreparedStatement.php index 68cb3dc9..8249a51f 100644 --- a/src/PreparedStatement.php +++ b/src/PreparedStatement.php @@ -19,11 +19,11 @@ final class PreparedStatement { - private $handler; - private $id; - private $bindCount; - private $bindMetadata; - private $metadata; + private Handler $handler; + private int $id; + private int $bindCount; + private array $bindMetadata; + private array $metadata; public function __construct(Handler $handler, int $id, int $bindCount, array $bindMetadata, array $metadata) { diff --git a/src/Request/AuthenticateRequest.php b/src/Request/AuthenticateRequest.php index 4afc7120..3fa394d2 100644 --- a/src/Request/AuthenticateRequest.php +++ b/src/Request/AuthenticateRequest.php @@ -19,7 +19,7 @@ final class AuthenticateRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; public function __construct(string $salt, string $username, string $password = '') { diff --git a/src/Request/CallRequest.php b/src/Request/CallRequest.php index f45878fb..f832bf15 100644 --- a/src/Request/CallRequest.php +++ b/src/Request/CallRequest.php @@ -19,7 +19,7 @@ final class CallRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; public function __construct(string $funcName, array $args = []) { diff --git a/src/Request/DeleteRequest.php b/src/Request/DeleteRequest.php index a3a1371d..b4d3174e 100644 --- a/src/Request/DeleteRequest.php +++ b/src/Request/DeleteRequest.php @@ -19,7 +19,7 @@ final class DeleteRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; public function __construct(int $spaceId, int $indexId, array $key) { diff --git a/src/Request/EvaluateRequest.php b/src/Request/EvaluateRequest.php index 4a4f9b1e..1ac931c7 100644 --- a/src/Request/EvaluateRequest.php +++ b/src/Request/EvaluateRequest.php @@ -19,7 +19,7 @@ final class EvaluateRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; public function __construct(string $expr, array $args = []) { diff --git a/src/Request/ExecuteRequest.php b/src/Request/ExecuteRequest.php index c1819134..3c1e91f5 100644 --- a/src/Request/ExecuteRequest.php +++ b/src/Request/ExecuteRequest.php @@ -19,12 +19,12 @@ final class ExecuteRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; /** * @param non-empty-array $body */ - private function __construct($body) + private function __construct(array $body) { $this->body = $body; } diff --git a/src/Request/InsertRequest.php b/src/Request/InsertRequest.php index 75e64bc8..8a7baa9a 100644 --- a/src/Request/InsertRequest.php +++ b/src/Request/InsertRequest.php @@ -19,7 +19,7 @@ final class InsertRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; public function __construct(int $spaceId, array $tuple) { diff --git a/src/Request/PrepareRequest.php b/src/Request/PrepareRequest.php index c71128f6..d5540d17 100644 --- a/src/Request/PrepareRequest.php +++ b/src/Request/PrepareRequest.php @@ -19,12 +19,12 @@ final class PrepareRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; /** * @param non-empty-array $body */ - private function __construct($body) + private function __construct(array $body) { $this->body = $body; } diff --git a/src/Request/ReplaceRequest.php b/src/Request/ReplaceRequest.php index 5b613e99..c361c7eb 100644 --- a/src/Request/ReplaceRequest.php +++ b/src/Request/ReplaceRequest.php @@ -19,7 +19,7 @@ final class ReplaceRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; public function __construct(int $spaceId, array $tuple) { diff --git a/src/Request/SelectRequest.php b/src/Request/SelectRequest.php index edd32ef9..4069e7ab 100644 --- a/src/Request/SelectRequest.php +++ b/src/Request/SelectRequest.php @@ -19,7 +19,7 @@ final class SelectRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; public function __construct(int $spaceId, int $indexId, array $key, int $offset, int $limit, int $iteratorType) { diff --git a/src/Request/UpdateRequest.php b/src/Request/UpdateRequest.php index 4c16b0b1..89e8db50 100644 --- a/src/Request/UpdateRequest.php +++ b/src/Request/UpdateRequest.php @@ -19,7 +19,7 @@ final class UpdateRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; public function __construct(int $spaceId, int $indexId, array $key, array $operations) { diff --git a/src/Request/UpsertRequest.php b/src/Request/UpsertRequest.php index ee303e41..85b2eccb 100644 --- a/src/Request/UpsertRequest.php +++ b/src/Request/UpsertRequest.php @@ -19,7 +19,7 @@ final class UpsertRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; public function __construct(int $spaceId, array $tuple, array $operations) { diff --git a/src/Response.php b/src/Response.php index d5296cf9..d16a28d4 100644 --- a/src/Response.php +++ b/src/Response.php @@ -17,8 +17,8 @@ final class Response { public const TYPE_ERROR = 0x8000; - private $header; - private $body; + private array $header; + private array $body; public function __construct(array $header, array $body) { diff --git a/src/Schema/Operations.php b/src/Schema/Operations.php index 050c0176..9fd18e73 100644 --- a/src/Schema/Operations.php +++ b/src/Schema/Operations.php @@ -16,28 +16,22 @@ final class Operations { /** @var non-empty-array */ - private $operations; + private array $operations; /** * @param non-empty-array $operation */ - private function __construct($operation) + private function __construct(array $operation) { $this->operations = [$operation]; } - /** - * @param int|string $field - */ - public static function add($field, int $value) : self + public static function add(int|string $field, int $value) : self { return new self(['+', $field, $value]); } - /** - * @param int|string $field - */ - public function andAdd($field, int $value) : self + public function andAdd(int|string $field, int $value) : self { $new = clone $this; $new->operations[] = ['+', $field, $value]; @@ -45,18 +39,12 @@ public function andAdd($field, int $value) : self return $new; } - /** - * @param int|string $field - */ - public static function subtract($field, int $value) : self + public static function subtract(int|string $field, int $value) : self { return new self(['-', $field, $value]); } - /** - * @param int|string $field - */ - public function andSubtract($field, int $value) : self + public function andSubtract(int|string $field, int $value) : self { $new = clone $this; $new->operations[] = ['-', $field, $value]; @@ -64,18 +52,12 @@ public function andSubtract($field, int $value) : self return $new; } - /** - * @param int|string $field - */ - public static function bitwiseAnd($field, int $value) : self + public static function bitwiseAnd(int|string $field, int $value) : self { return new self(['&', $field, $value]); } - /** - * @param int|string $field - */ - public function andBitwiseAnd($field, int $value) : self + public function andBitwiseAnd(int|string $field, int $value) : self { $new = clone $this; $new->operations[] = ['&', $field, $value]; @@ -83,18 +65,12 @@ public function andBitwiseAnd($field, int $value) : self return $new; } - /** - * @param int|string $field - */ - public static function bitwiseOr($field, int $value) : self + public static function bitwiseOr(int|string $field, int $value) : self { return new self(['|', $field, $value]); } - /** - * @param int|string $field - */ - public function andBitwiseOr($field, int $value) : self + public function andBitwiseOr(int|string $field, int $value) : self { $new = clone $this; $new->operations[] = ['|', $field, $value]; @@ -102,18 +78,12 @@ public function andBitwiseOr($field, int $value) : self return $new; } - /** - * @param int|string $field - */ - public static function bitwiseXor($field, int $value) : self + public static function bitwiseXor(int|string $field, int $value) : self { return new self(['^', $field, $value]); } - /** - * @param int|string $field - */ - public function andBitwiseXor($field, int $value) : self + public function andBitwiseXor(int|string $field, int $value) : self { $new = clone $this; $new->operations[] = ['^', $field, $value]; @@ -121,18 +91,12 @@ public function andBitwiseXor($field, int $value) : self return $new; } - /** - * @param int|string $field - */ - public static function splice($field, int $offset, int $length, string $replacement) : self + public static function splice(int|string $field, int $offset, int $length, string $replacement) : self { return new self([':', $field, $offset, $length, $replacement]); } - /** - * @param int|string $field - */ - public function andSplice($field, int $offset, int $length, string $replacement) : self + public function andSplice(int|string $field, int $offset, int $length, string $replacement) : self { $new = clone $this; $new->operations[] = [':', $field, $offset, $length, $replacement]; @@ -140,18 +104,12 @@ public function andSplice($field, int $offset, int $length, string $replacement) return $new; } - /** - * @param int|string $field - */ - public static function insert($field, int $value) : self + public static function insert(int|string $field, int $value) : self { return new self(['!', $field, $value]); } - /** - * @param int|string $field - */ - public function andInsert($field, int $value) : self + public function andInsert(int|string $field, int $value) : self { $new = clone $this; $new->operations[] = ['!', $field, $value]; @@ -159,18 +117,12 @@ public function andInsert($field, int $value) : self return $new; } - /** - * @param int|string $field - */ - public static function delete($field, int $value) : self + public static function delete(int|string $field, int $value) : self { return new self(['#', $field, $value]); } - /** - * @param int|string $field - */ - public function andDelete($field, int $value) : self + public function andDelete(int|string $field, int $value) : self { $new = clone $this; $new->operations[] = ['#', $field, $value]; @@ -178,18 +130,12 @@ public function andDelete($field, int $value) : self return $new; } - /** - * @param int|string $field - */ - public static function set($field, $value) : self + public static function set(int|string $field, $value) : self { return new self(['=', $field, $value]); } - /** - * @param int|string $field - */ - public function andSet($field, $value) : self + public function andSet(int|string $field, $value) : self { $new = clone $this; $new->operations[] = ['=', $field, $value]; diff --git a/src/Schema/Space.php b/src/Schema/Space.php index 8faa7e84..7fc4ab20 100644 --- a/src/Schema/Space.php +++ b/src/Schema/Space.php @@ -30,11 +30,11 @@ final class Space public const VINDEX_ID = 289; public const VINDEX_NAME_INDEX = 2; - private $handler; - private $id; + private Handler $handler; + private int $id; /** @var array */ - private $indexes = []; + private array $indexes = []; public function __construct(Handler $handler, int $id) { @@ -88,10 +88,9 @@ public function replace(array $tuple) : array } /** - * @param int|string $index * @psalm-param non-empty-array $key */ - public function update(array $key, Operations $operations, $index = 0) : array + public function update(array $key, Operations $operations, int|string $index = 0) : array { if (\is_string($index)) { $index = $this->getIndexIdByName($index); @@ -113,10 +112,9 @@ public function upsert(array $tuple, Operations $operations) : void } /** - * @param int|string $index * @psalm-param non-empty-array $key */ - public function delete(array $key, $index = 0) : array + public function delete(array $key, int|string $index = 0) : array { if (\is_string($index)) { $index = $this->getIndexIdByName($index); diff --git a/src/SqlQueryResult.php b/src/SqlQueryResult.php index 7a7f8a31..eb97b518 100644 --- a/src/SqlQueryResult.php +++ b/src/SqlQueryResult.php @@ -16,13 +16,13 @@ final class SqlQueryResult implements \ArrayAccess, \Countable, \IteratorAggregate { /** @var array */ - private $data; + private array $data; /** @var array> */ - private $metadata; + private array $metadata; /** @var array */ - private $keys; + private array $keys; public function __construct(array $data, array $metadata) { diff --git a/src/SqlUpdateResult.php b/src/SqlUpdateResult.php index 9b901695..34aa3761 100644 --- a/src/SqlUpdateResult.php +++ b/src/SqlUpdateResult.php @@ -15,7 +15,7 @@ final class SqlUpdateResult implements \Countable { - private $info; + private array $info; public function __construct(array $info) { From d938604f450fba8a33eada9d4081fe53f257189a Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Wed, 30 Sep 2026 21:29:28 +0200 Subject: [PATCH 32/34] style: format Lua heredoc calls --- examples/protocol/delete.php | 3 +-- examples/protocol/insert.php | 3 +-- examples/protocol/replace.php | 3 +-- examples/protocol/select.php | 3 +-- examples/protocol/select_with_sorting.php | 3 +-- examples/protocol/update.php | 3 +-- examples/protocol/upsert.php | 3 +-- examples/user_defined_type/example_decimal.php | 3 +-- examples/user_defined_type/example_email.php | 3 +-- examples/user_defined_type/example_uuid.php | 3 +-- psalm.xml | 2 -- src/SqlQueryResult.php | 4 ++++ 12 files changed, 14 insertions(+), 22 deletions(-) diff --git a/examples/protocol/delete.php b/examples/protocol/delete.php index dc09dc75..4732aa78 100644 --- a/examples/protocol/delete.php +++ b/examples/protocol/delete.php @@ -16,8 +16,7 @@ $client = create_client(); $spaceName = 'example'; -$client->evaluate( - <<evaluate(<<evaluate( - <<evaluate(<<evaluate( - <<evaluate(<<evaluate( - <<evaluate(<<evaluate( - <<evaluate(<<evaluate( - <<evaluate(<<evaluate( - <<evaluate(<<evaluate( - <<evaluate(<<evaluate( - <<evaluate(<<evaluate( - <<evaluate(<< - - diff --git a/src/SqlQueryResult.php b/src/SqlQueryResult.php index eb97b518..609c3650 100644 --- a/src/SqlQueryResult.php +++ b/src/SqlQueryResult.php @@ -13,6 +13,10 @@ namespace Tarantool\Client; +/** + * @implements \ArrayAccess + * @implements \IteratorAggregate + */ final class SqlQueryResult implements \ArrayAccess, \Countable, \IteratorAggregate { /** @var array */ From dbbcf13d48a96dcb54c7abf08275a63164d9bb6d Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Wed, 30 Sep 2026 21:39:47 +0200 Subject: [PATCH 33/34] ci: simplify test matrix job names --- .github/workflows/qa.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index 31e36465..85341189 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -61,6 +61,7 @@ jobs: # some tests are skipped on Tarantool > 2.8 TNT_IMAGE: tarantool/tarantool:2.8 + name: ${{ matrix.env.PHP_IMAGE || 'php:8.3-cli' }}, ${{ matrix.env.TNT_IMAGE || 'tarantool/tarantool:3.1' }}${{ matrix.env.QA && ', qa' || '' }}${{ matrix.env.COVERAGE_FILE && ', coverage' || '' }}${{ matrix.env.EXT_DISABLE_DECIMAL && ', decimal disabled' || '' }}${{ matrix.env.TNT_LISTEN_URI && ', unix socket' || '' }} runs-on: ${{ matrix.operating-system }} steps: - name: Checkout From 6c4f47dae139694db85762fe5736ce45e51b2d8f Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Wed, 30 Sep 2026 21:59:39 +0200 Subject: [PATCH 34/34] style: group class properties without blank lines --- .php-cs-fixer.dist.php | 1 + src/Connection/Greeting.php | 3 --- src/Connection/StreamConnection.php | 3 --- src/Dsn.php | 6 ------ src/Middleware/AuthenticationMiddleware.php | 1 - src/Packer/PurePacker.php | 1 - src/Schema/Criteria.php | 1 - tests/Unit/Handler/MiddlewareHandlerTest.php | 1 - tests/Unit/Middleware/RetryMiddlewareTest.php | 1 - 9 files changed, 1 insertion(+), 17 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 2d4168f9..21f85273 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -94,6 +94,7 @@ public function supports(\SplFileInfo $file) : bool '@Symfony:risky' => true, 'array_syntax' => ['syntax' => 'short'], 'binary_operator_spaces' => ['operators' => ['=' => null, '=>' => null]], + 'class_attributes_separation' => ['elements' => ['method' => 'one', 'property' => 'none']], 'declare_strict_types' => true, 'integer_literal_case' => false, 'native_constant_invocation' => false, diff --git a/src/Connection/Greeting.php b/src/Connection/Greeting.php index 09e48ef9..f8aa3543 100644 --- a/src/Connection/Greeting.php +++ b/src/Connection/Greeting.php @@ -20,11 +20,8 @@ final class Greeting public const SIZE_BYTES = 128; private string $greeting; - private ?string $salt = null; - private ?string $serverVersion = null; - private bool $unknown = false; private function __construct(string $greeting) diff --git a/src/Connection/StreamConnection.php b/src/Connection/StreamConnection.php index cd5f7587..9cfd7e83 100644 --- a/src/Connection/StreamConnection.php +++ b/src/Connection/StreamConnection.php @@ -22,11 +22,8 @@ final class StreamConnection implements Connection public const DEFAULT_TCP_URI = 'tcp://127.0.0.1:3301'; private string $uri; - private float $connectTimeout; - private float $socketTimeout; - private bool $persistent; /** @var resource|null */ diff --git a/src/Dsn.php b/src/Dsn.php index 931d3ed8..57984a89 100644 --- a/src/Dsn.php +++ b/src/Dsn.php @@ -16,17 +16,11 @@ final class Dsn { private ?string $host = null; - private ?int $port = null; - private ?string $path = null; - private string $connectionUri; - private ?string $username = null; - private ?string $password = null; - private bool $isTcp = false; /** diff --git a/src/Middleware/AuthenticationMiddleware.php b/src/Middleware/AuthenticationMiddleware.php index ea9829b6..c7c34873 100644 --- a/src/Middleware/AuthenticationMiddleware.php +++ b/src/Middleware/AuthenticationMiddleware.php @@ -23,7 +23,6 @@ final class AuthenticationMiddleware implements Middleware { private string $username; private string $password; - private ?Greeting $greeting = null; public function __construct(string $username, string $password = '') diff --git a/src/Packer/PurePacker.php b/src/Packer/PurePacker.php index 10fb1d36..ba27cfb1 100644 --- a/src/Packer/PurePacker.php +++ b/src/Packer/PurePacker.php @@ -29,7 +29,6 @@ final class PurePacker implements ClientPacker { private Packer $packer; - private BufferUnpacker $unpacker; public function __construct(?Packer $packer = null, ?BufferUnpacker $unpacker = null) diff --git a/src/Schema/Criteria.php b/src/Schema/Criteria.php index 99c9a6ed..7756ebf7 100644 --- a/src/Schema/Criteria.php +++ b/src/Schema/Criteria.php @@ -21,7 +21,6 @@ final class Criteria private array $key = []; private int $limit = \PHP_INT_MAX & 0xFFFFFFFF; - private int $offset = 0; /** @psalm-var IteratorTypes::*|null */ diff --git a/tests/Unit/Handler/MiddlewareHandlerTest.php b/tests/Unit/Handler/MiddlewareHandlerTest.php index 8fa28e96..e65ed421 100644 --- a/tests/Unit/Handler/MiddlewareHandlerTest.php +++ b/tests/Unit/Handler/MiddlewareHandlerTest.php @@ -25,7 +25,6 @@ final class MiddlewareHandlerTest extends TestCase use TestDoubleClient; private Request $request; - private Handler $handler; protected function setUp() : void diff --git a/tests/Unit/Middleware/RetryMiddlewareTest.php b/tests/Unit/Middleware/RetryMiddlewareTest.php index 8579ac84..95d8e361 100644 --- a/tests/Unit/Middleware/RetryMiddlewareTest.php +++ b/tests/Unit/Middleware/RetryMiddlewareTest.php @@ -25,7 +25,6 @@ final class RetryMiddlewareTest extends TestCase { private Request&MockObject $request; - private Handler&MockObject $handler; protected function setUp() : void