From c7ac0e6dbe30008fc2e52de41b2cde9a88e0fb99 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 24 Feb 2026 09:27:04 +0300 Subject: [PATCH] Update `yiisoft/data-response` and refactor --- CHANGELOG.md | 3 +- composer.json | 16 +++++----- config/web/di/application.php | 19 ++++++------ src/Api/Shared/Presenter/AsIsPresenter.php | 6 ++-- .../Shared/Presenter/CollectionPresenter.php | 9 ++---- src/Api/Shared/Presenter/FailPresenter.php | 11 ++----- .../Presenter/OffsetPaginatorPresenter.php | 10 +++---- .../Shared/Presenter/PresenterInterface.php | 4 +-- src/Api/Shared/Presenter/SuccessPresenter.php | 16 ++++------ .../Presenter/ValidationResultPresenter.php | 7 ++--- src/Api/Shared/ResponseFactory.php | 14 +++++---- .../Shared/ExceptionResponderFactoryTest.php | 16 +++++----- .../OffsetPaginatorPresenterTest.php | 27 ++++------------- tests/Unit/Api/Shared/ResponseFactoryTest.php | 30 +++++++++++-------- 14 files changed, 81 insertions(+), 107 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ef5721..e87e9cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ - Bug #256: Fix incorrect .env files used in Docker Compose for production (@aa-chernyh) - Enh #258: Set locale `C.UTF-8` in `Dockerfile` (@vjik) - Bug #260: Fix psalm cache directory in configuration file (@vjik) -- Enh #260: Update composer dependencies (@vjik) +- Enh #260, #265: Update composer dependencies and refactor to replace use of deprecated classes (@vjik) +- Chg #265: Refactor `PresenterInterface` and implementations for preparing data only (@vjik) ## 1.1.0 December 22, 2025 diff --git a/composer.json b/composer.json index 060ba60..1c323b4 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,7 @@ "yiisoft/aliases": "^3.1.1", "yiisoft/config": "^1.6.2", "yiisoft/data": "^1.0.1", - "yiisoft/data-response": "^2.1.2", + "yiisoft/data-response": "^2.2", "yiisoft/definitions": "^3.4.1", "yiisoft/di": "^1.4.1", "yiisoft/error-handler": "^4.3.2", @@ -54,7 +54,7 @@ "yiisoft/log-target-file": "^3.1", "yiisoft/middleware-dispatcher": "^5.4", "yiisoft/request-body-parser": "^1.2.1", - "yiisoft/request-provider": "^1.2", + "yiisoft/request-provider": "^1.3", "yiisoft/router": "^4.0.2", "yiisoft/router-fastroute": "^4.0.3", "yiisoft/validator": "^2.5.1", @@ -65,19 +65,19 @@ }, "require-dev": { "codeception/c3": "^2.9", - "codeception/codeception": "^5.3.4", - "codeception/lib-innerbrowser": "^4.0.8", + "codeception/codeception": "^5.3.5", + "codeception/lib-innerbrowser": "^4.1.0", "codeception/module-asserts": "^3.3.0", "codeception/module-cli": "^2.0.1", "codeception/module-db": "^3.2.2", "codeception/module-phpbrowser": "^3.0.2", "codeception/module-rest": "^3.4.3", - "friendsofphp/php-cs-fixer": "^3.93.0", - "phpunit/phpunit": "^11.5.49", - "rector/rector": "^2.3.4", + "friendsofphp/php-cs-fixer": "^3.94.2", + "phpunit/phpunit": "^11.5.55", + "rector/rector": "^2.3.8", "roave/infection-static-analysis-plugin": "^1.40", "shipmonk/composer-dependency-analyser": "^1.8.4", - "vimeo/psalm": "^6.14.3" + "vimeo/psalm": "^6.15.1" }, "autoload": { "psr-4": { diff --git a/config/web/di/application.php b/config/web/di/application.php index cf3d4e9..23cfffe 100644 --- a/config/web/di/application.php +++ b/config/web/di/application.php @@ -4,10 +4,9 @@ use App\Api\Shared\ExceptionResponderFactory; use App\Api\Shared\NotFoundMiddleware; -use Yiisoft\DataResponse\Formatter\JsonDataResponseFormatter; -use Yiisoft\DataResponse\Formatter\XmlDataResponseFormatter; -use Yiisoft\DataResponse\Middleware\ContentNegotiator; -use Yiisoft\DataResponse\Middleware\FormatDataResponseAsJson; +use Yiisoft\DataResponse\Formatter\JsonFormatter; +use Yiisoft\DataResponse\Formatter\XmlFormatter; +use Yiisoft\DataResponse\Middleware\ContentNegotiatorDataResponseMiddleware; use Yiisoft\Definitions\DynamicReference; use Yiisoft\Definitions\Reference; use Yiisoft\ErrorHandler\Middleware\ErrorCatcher; @@ -29,11 +28,13 @@ 'class' => MiddlewareDispatcher::class, 'withMiddlewares()' => [ [ - FormatDataResponseAsJson::class, - static fn() => new ContentNegotiator([ - 'application/xml' => new XmlDataResponseFormatter(), - 'application/json' => new JsonDataResponseFormatter(), - ]), + static fn() => new ContentNegotiatorDataResponseMiddleware( + formatters: [ + 'application/xml' => new XmlFormatter(), + 'application/json' => new JsonFormatter(), + ], + fallback: new JsonFormatter(), + ), ErrorCatcher::class, static fn(ExceptionResponderFactory $factory) => $factory->create(), RequestBodyParser::class, diff --git a/src/Api/Shared/Presenter/AsIsPresenter.php b/src/Api/Shared/Presenter/AsIsPresenter.php index 04e5c60..d2b29f4 100644 --- a/src/Api/Shared/Presenter/AsIsPresenter.php +++ b/src/Api/Shared/Presenter/AsIsPresenter.php @@ -4,15 +4,13 @@ namespace App\Api\Shared\Presenter; -use Yiisoft\DataResponse\DataResponse; - /** * @implements PresenterInterface */ final readonly class AsIsPresenter implements PresenterInterface { - public function present(mixed $value, DataResponse $response): DataResponse + public function present(mixed $value): mixed { - return $response->withData($value); + return $value; } } diff --git a/src/Api/Shared/Presenter/CollectionPresenter.php b/src/Api/Shared/Presenter/CollectionPresenter.php index 03ad5b0..0e50b74 100644 --- a/src/Api/Shared/Presenter/CollectionPresenter.php +++ b/src/Api/Shared/Presenter/CollectionPresenter.php @@ -4,8 +4,6 @@ namespace App\Api\Shared\Presenter; -use Yiisoft\DataResponse\DataResponse; - /** * @implements PresenterInterface */ @@ -15,13 +13,12 @@ public function __construct( private PresenterInterface $itemPresenter = new AsIsPresenter(), ) {} - public function present(mixed $value, DataResponse $response): DataResponse + public function present(mixed $value): array { $result = []; foreach ($value as $item) { - $response = $this->itemPresenter->present($item, $response); - $result[] = $response->getData(); + $result[] = $this->itemPresenter->present($item); } - return $response->withData($result); + return $result; } } diff --git a/src/Api/Shared/Presenter/FailPresenter.php b/src/Api/Shared/Presenter/FailPresenter.php index 6674e2f..9e326ad 100644 --- a/src/Api/Shared/Presenter/FailPresenter.php +++ b/src/Api/Shared/Presenter/FailPresenter.php @@ -4,9 +4,6 @@ namespace App\Api\Shared\Presenter; -use Yiisoft\DataResponse\DataResponse; -use Yiisoft\Http\Status; - /** * @implements PresenterInterface */ @@ -15,13 +12,11 @@ public function __construct( private string $message = 'Unknown error.', private int|null $code = null, - private int $httpCode = Status::BAD_REQUEST, private PresenterInterface $presenter = new AsIsPresenter(), ) {} - public function present(mixed $value, DataResponse $response): DataResponse + public function present(mixed $value): mixed { - $response = $this->presenter->present($value, $response); $result = [ 'status' => 'failed', 'error_message' => $this->message, @@ -30,8 +25,8 @@ public function present(mixed $value, DataResponse $response): DataResponse $result['error_code'] = $this->code; } if ($value !== null) { - $result['error_data'] = $response->getData(); + $result['error_data'] = $this->presenter->present($value); } - return $response->withData($result)->withStatus($this->httpCode); + return $result; } } diff --git a/src/Api/Shared/Presenter/OffsetPaginatorPresenter.php b/src/Api/Shared/Presenter/OffsetPaginatorPresenter.php index 29b10f9..c9ed424 100644 --- a/src/Api/Shared/Presenter/OffsetPaginatorPresenter.php +++ b/src/Api/Shared/Presenter/OffsetPaginatorPresenter.php @@ -5,7 +5,6 @@ namespace App\Api\Shared\Presenter; use Yiisoft\Data\Paginator\OffsetPaginator; -use Yiisoft\DataResponse\DataResponse; /** * @implements PresenterInterface @@ -20,14 +19,13 @@ public function __construct( $this->collectionPresenter = new CollectionPresenter($itemPresenter); } - public function present(mixed $value, DataResponse $response): DataResponse + public function present(mixed $value): array { - $collectionResponse = $this->collectionPresenter->present($value->read(), $response); - return $collectionResponse->withData([ - 'items' => $collectionResponse->getData(), + return [ + 'items' => $this->collectionPresenter->present($value->read()), 'pageSize' => $value->getPageSize(), 'currentPage' => $value->getCurrentPage(), 'totalPages' => $value->getTotalPages(), - ]); + ]; } } diff --git a/src/Api/Shared/Presenter/PresenterInterface.php b/src/Api/Shared/Presenter/PresenterInterface.php index 0f5f3b0..0d5d1fa 100644 --- a/src/Api/Shared/Presenter/PresenterInterface.php +++ b/src/Api/Shared/Presenter/PresenterInterface.php @@ -4,8 +4,6 @@ namespace App\Api\Shared\Presenter; -use Yiisoft\DataResponse\DataResponse; - /** * @template T */ @@ -14,5 +12,5 @@ interface PresenterInterface /** * @param T $value */ - public function present(mixed $value, DataResponse $response): DataResponse; + public function present(mixed $value): mixed; } diff --git a/src/Api/Shared/Presenter/SuccessPresenter.php b/src/Api/Shared/Presenter/SuccessPresenter.php index 6f2b5c5..963ff03 100644 --- a/src/Api/Shared/Presenter/SuccessPresenter.php +++ b/src/Api/Shared/Presenter/SuccessPresenter.php @@ -4,9 +4,6 @@ namespace App\Api\Shared\Presenter; -use Yiisoft\DataResponse\DataResponse; -use Yiisoft\Http\Status; - /** * @implements PresenterInterface */ @@ -16,14 +13,11 @@ public function __construct( private PresenterInterface $presenter = new AsIsPresenter(), ) {} - public function present(mixed $value, DataResponse $response): DataResponse + public function present(mixed $value): array { - $response = $this->presenter->present($value, $response); - return $response - ->withData([ - 'status' => 'success', - 'data' => $response->getData(), - ]) - ->withStatus(Status::OK); + return [ + 'status' => 'success', + 'data' => $this->presenter->present($value), + ]; } } diff --git a/src/Api/Shared/Presenter/ValidationResultPresenter.php b/src/Api/Shared/Presenter/ValidationResultPresenter.php index ffc449b..fd44b02 100644 --- a/src/Api/Shared/Presenter/ValidationResultPresenter.php +++ b/src/Api/Shared/Presenter/ValidationResultPresenter.php @@ -4,7 +4,6 @@ namespace App\Api\Shared\Presenter; -use Yiisoft\DataResponse\DataResponse; use Yiisoft\Validator\Result; /** @@ -12,10 +11,8 @@ */ final readonly class ValidationResultPresenter implements PresenterInterface { - public function present(mixed $value, DataResponse $response): DataResponse + public function present(mixed $value): array { - return $response->withData( - $value->getErrorMessagesIndexedByPath(), - ); + return $value->getErrorMessagesIndexedByPath(); } } diff --git a/src/Api/Shared/ResponseFactory.php b/src/Api/Shared/ResponseFactory.php index ccf5706..2fc6d6a 100644 --- a/src/Api/Shared/ResponseFactory.php +++ b/src/Api/Shared/ResponseFactory.php @@ -10,7 +10,7 @@ use App\Api\Shared\Presenter\SuccessPresenter; use App\Api\Shared\Presenter\ValidationResultPresenter; use Psr\Http\Message\ResponseInterface; -use Yiisoft\DataResponse\DataResponseFactoryInterface; +use Yiisoft\DataResponse\ResponseFactory\DataResponseFactoryInterface; use Yiisoft\Http\Status; use Yiisoft\Validator\Result; @@ -24,8 +24,9 @@ public function success( array|object|null $data = null, PresenterInterface $presenter = new AsIsPresenter(), ): ResponseInterface { - return (new SuccessPresenter($presenter)) - ->present($data, $this->dataResponseFactory->createResponse()); + return $this->dataResponseFactory->createResponse( + (new SuccessPresenter($presenter))->present($data), + ); } public function fail( @@ -35,8 +36,11 @@ public function fail( int $httpCode = Status::BAD_REQUEST, PresenterInterface $presenter = new AsIsPresenter(), ): ResponseInterface { - return (new FailPresenter($message, $code, $httpCode, $presenter)) - ->present($data, $this->dataResponseFactory->createResponse()); + return $this->dataResponseFactory + ->createResponse( + (new FailPresenter($message, $code, $presenter))->present($data), + ) + ->withStatus($httpCode); } public function notFound(string $message = 'Not found.'): ResponseInterface diff --git a/tests/Unit/Api/Shared/ExceptionResponderFactoryTest.php b/tests/Unit/Api/Shared/ExceptionResponderFactoryTest.php index 5c03f64..cae5ddc 100644 --- a/tests/Unit/Api/Shared/ExceptionResponderFactoryTest.php +++ b/tests/Unit/Api/Shared/ExceptionResponderFactoryTest.php @@ -9,13 +9,12 @@ use Codeception\Test\Unit; use HttpSoft\Message\ResponseFactory as PsrResponseFactory; use HttpSoft\Message\ServerRequest; -use HttpSoft\Message\StreamFactory; use LogicException; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; -use Yiisoft\DataResponse\DataResponse; -use Yiisoft\DataResponse\DataResponseFactory; +use Yiisoft\DataResponse\DataStream\DataStream; +use Yiisoft\DataResponse\ResponseFactory\DataResponseFactory; use Yiisoft\Di\Container; use Yiisoft\ErrorHandler\Exception\UserException; use Yiisoft\ErrorHandler\Middleware\ExceptionResponder; @@ -38,8 +37,9 @@ public function handle(ServerRequestInterface $request): ResponseInterface }; $response = $this->createExceptionResponder()->process($request, $handler); + $body = $response->getBody(); - $this->assertInstanceOf(DataResponse::class, $response); + $this->assertInstanceOf(DataStream::class, $body); $this->assertSame( [ 'status' => 'failed', @@ -48,7 +48,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface 'name' => ['error1'], ], ], - $response->getData(), + $body->getData(), ); } @@ -63,15 +63,16 @@ public function handle(ServerRequestInterface $request): ResponseInterface }; $response = $this->createExceptionResponder()->process($request, $handler); + $body = $response->getBody(); - $this->assertInstanceOf(DataResponse::class, $response); + $this->assertInstanceOf(DataStream::class, $body); $this->assertSame( [ 'status' => 'failed', 'error_message' => 'Hello, Exception!', 'error_code' => 0, ], - $response->getData(), + $body->getData(), ); } @@ -97,7 +98,6 @@ private function createExceptionResponder(): ExceptionResponder new ResponseFactory( new DataResponseFactory( new PsrResponseFactory(), - new StreamFactory(), ), ), new Injector(new Container()), diff --git a/tests/Unit/Api/Shared/Presenter/OffsetPaginatorPresenterTest.php b/tests/Unit/Api/Shared/Presenter/OffsetPaginatorPresenterTest.php index 09a8102..18bf0c2 100644 --- a/tests/Unit/Api/Shared/Presenter/OffsetPaginatorPresenterTest.php +++ b/tests/Unit/Api/Shared/Presenter/OffsetPaginatorPresenterTest.php @@ -7,12 +7,8 @@ use App\Api\Shared\Presenter\OffsetPaginatorPresenter; use App\Api\Shared\Presenter\PresenterInterface; use Codeception\Test\Unit; -use HttpSoft\Message\ResponseFactory; -use HttpSoft\Message\StreamFactory; use Yiisoft\Data\Paginator\OffsetPaginator; use Yiisoft\Data\Reader\Iterable\IterableDataReader; -use Yiisoft\DataResponse\DataResponse; -use Yiisoft\Http\Status; final class OffsetPaginatorPresenterTest extends Unit { @@ -31,7 +27,7 @@ public function testBase(): void ->withCurrentPage(2); $presenter = new OffsetPaginatorPresenter(); - $result = $presenter->present($paginator, $this->createDataResponse()); + $result = $presenter->present($paginator); $this->assertSame( [ @@ -43,7 +39,7 @@ public function testBase(): void 'currentPage' => 2, 'totalPages' => 3, ], - $result->getData(), + $result, ); } @@ -57,14 +53,14 @@ public function testItemPresenter(): void ); $presenter = new OffsetPaginatorPresenter( new class implements PresenterInterface { - public function present(mixed $value, DataResponse $response): DataResponse + public function present(mixed $value): mixed { - return $response->withData($value['name']); + return $value['name']; } }, ); - $result = $presenter->present($paginator, $this->createDataResponse()); + $result = $presenter->present($paginator); $this->assertSame( [ @@ -73,18 +69,7 @@ public function present(mixed $value, DataResponse $response): DataResponse 'currentPage' => 1, 'totalPages' => 1, ], - $result->getData(), - ); - } - - private function createDataResponse(): DataResponse - { - return new DataResponse( - '', - Status::OK, - '', - new ResponseFactory(), - new StreamFactory(), + $result, ); } } diff --git a/tests/Unit/Api/Shared/ResponseFactoryTest.php b/tests/Unit/Api/Shared/ResponseFactoryTest.php index 897c507..e11d6c1 100644 --- a/tests/Unit/Api/Shared/ResponseFactoryTest.php +++ b/tests/Unit/Api/Shared/ResponseFactoryTest.php @@ -7,9 +7,8 @@ use App\Api\Shared\ResponseFactory; use Codeception\Test\Unit; use HttpSoft\Message\ResponseFactory as PsrResponseFactory; -use HttpSoft\Message\StreamFactory; -use Yiisoft\DataResponse\DataResponse; -use Yiisoft\DataResponse\DataResponseFactory; +use Yiisoft\DataResponse\DataStream\DataStream; +use Yiisoft\DataResponse\ResponseFactory\DataResponseFactory; use Yiisoft\Validator\Result; final class ResponseFactoryTest extends Unit @@ -20,13 +19,15 @@ public function testSuccess(): void ->createResponseFactory() ->success(['name' => 'test']); - $this->assertInstanceOf(DataResponse::class, $response); + $body = $response->getBody(); + + $this->assertInstanceOf(DataStream::class, $body); $this->assertSame( [ 'status' => 'success', 'data' => ['name' => 'test'], ], - $response->getData(), + $body->getData(), ); } @@ -36,13 +37,15 @@ public function testFail(): void ->createResponseFactory() ->fail('error text'); - $this->assertInstanceOf(DataResponse::class, $response); + $body = $response->getBody(); + + $this->assertInstanceOf(DataStream::class, $body); $this->assertSame( [ 'status' => 'failed', 'error_message' => 'error text', ], - $response->getData(), + $body->getData(), ); } @@ -52,13 +55,15 @@ public function testNotFound(): void ->createResponseFactory() ->notFound(); - $this->assertInstanceOf(DataResponse::class, $response); + $body = $response->getBody(); + + $this->assertInstanceOf(DataStream::class, $body); $this->assertSame( [ 'status' => 'failed', 'error_message' => 'Not found.', ], - $response->getData(), + $body->getData(), ); } @@ -72,7 +77,9 @@ public function testFailValidation(): void ->createResponseFactory() ->failValidation($result); - $this->assertInstanceOf(DataResponse::class, $response); + $body = $response->getBody(); + + $this->assertInstanceOf(DataStream::class, $body); $this->assertSame( [ 'status' => 'failed', @@ -82,7 +89,7 @@ public function testFailValidation(): void 'age' => ['error3'], ], ], - $response->getData(), + $body->getData(), ); } @@ -91,7 +98,6 @@ private function createResponseFactory(): ResponseFactory return new ResponseFactory( new DataResponseFactory( new PsrResponseFactory(), - new StreamFactory(), ), ); }