From 0201c5c55989c5b4d68412ed27e4702183896b8f Mon Sep 17 00:00:00 2001 From: Flo Date: Sat, 24 Feb 2024 20:16:24 +0100 Subject: [PATCH] paginated list --- bin/createApi.php | 14 ++++-- config/pipeline.php | 2 + docker/php/config/uploads.ini | 1 + .../VideoList/src/Handler/ReadListHandler.php | 10 ++--- .../ReadListResponseFormatter.php | 15 +++++-- .../src/Repository/VideoRepository.php | 29 +++++++------ .../Handler/Query/ReadList/ReadListQuery.php | 21 +++++++-- .../Query/ReadList/ReadListQueryBuilder.php | 8 +++- .../Query/ReadList/ReadListQueryHandler.php | 10 ++++- .../Query/ReadList/ReadListQueryResult.php | 20 +++++++++ .../src/Middleware/AnalyzeBodyMiddleware.php | 43 +++++++++++++++++++ 11 files changed, 141 insertions(+), 32 deletions(-) create mode 100644 src/HandlingDomain/VideoList/src/Handler/Query/ReadList/ReadListQueryResult.php create mode 100644 src/Infrastructure/Request/src/Middleware/AnalyzeBodyMiddleware.php diff --git a/bin/createApi.php b/bin/createApi.php index cd8d703..6e9efa8 100644 --- a/bin/createApi.php +++ b/bin/createApi.php @@ -15,19 +15,22 @@ $apiName = $argv[3]; $cqrsType = strtolower($argv[4]) === 'true' ? 'Command' : 'Query'; $cqrsNamespace = $argv[5]; +$apiDirectoryPath = $projectSourceDirectory . 'ApiDomain/' . $apiType . '/' . $apiNamespace . '/'; +$cqrsDirectoryPath = $projectSourceDirectory . 'HandlingDomain/' . $cqrsNamespace . '/'; + # API Handler $apiHandlerName = $apiName . 'Handler'; $apiHandlerNamespace = $projectNamespace . '\\API\\' . $apiType . '\\' . $apiNamespace . '\\Handler'; -$apiHandlerFilePath = $projectSourceDirectory . 'ApiDomain/' . $apiType . '/' . $apiNamespace . '/src/Handler/' . $apiHandlerName . '.php'; +$apiHandlerFilePath = $apiDirectoryPath . 'src/Handler/' . $apiHandlerName . '.php'; # Response Formatter $apiResponseFormatterName = $apiName . 'ResponseFormatter'; $apiResponseFormatterNamespace = $projectNamespace . '\\API\\' . $apiType . '\\' . $apiNamespace . '\\ResponseFormatter'; $apiResponseFormatterUsingNamespace = $apiResponseFormatterNamespace . '\\' . $apiResponseFormatterName; -$apiResponseFormatterFilePath = $projectSourceDirectory . 'ApiDomain/' . $apiType . '/' . $apiNamespace . '/src/ResponseFormatter/' . $apiResponseFormatterName . '.php'; +$apiResponseFormatterFilePath = $apiDirectoryPath . 'src/ResponseFormatter/' . $apiResponseFormatterName . '.php'; # CQRS -$cqrsFilePath = $projectSourceDirectory . 'HandlingDomain/' . $cqrsNamespace . '/src/Handler/' . $cqrsType . '/' . $apiName . '/'; +$cqrsFilePath = $cqrsDirectoryPath . 'src/Handler/' . $cqrsType . '/' . $apiName . '/'; $cqrsName = $apiName . $cqrsType; $cqrsVariableName = lcfirst($cqrsName); $cqrsNamespace = $projectNamespace . '\\Handling\\' . $cqrsNamespace . '\\Handler\\' . $cqrsType . '\\' . $apiName; @@ -70,6 +73,11 @@ function writeToFile($path, $content) { file_put_contents($path, $content); } +if (!file_exists($apiDirectoryPath)) { + $routesFilePath = $apiDirectoryPath . 'config/routes.php'; + $serviceManagerFilePath = $apiDirectoryPath . 'config/service_manager.php'; +} + $apiHandlerFileContent = "pipe(MyTubeExceptionHandlerMiddleware::class); $app->pipe(AnalyzeHeaderMiddleware::class); + $app->pipe(AnalyzeBodyMiddleware::class); //// MyTube Space $app->pipe(SessionMiddleware::class); diff --git a/docker/php/config/uploads.ini b/docker/php/config/uploads.ini index 0ded08e..db9e741 100644 --- a/docker/php/config/uploads.ini +++ b/docker/php/config/uploads.ini @@ -1,4 +1,5 @@ file_uploads = On +max_file_uploads = 1000 memory_limit = 10000M upload_max_filesize = 10000M post_max_size = 10000M diff --git a/src/ApiDomain/External/VideoList/src/Handler/ReadListHandler.php b/src/ApiDomain/External/VideoList/src/Handler/ReadListHandler.php index 16eef1a..278a1cc 100644 --- a/src/ApiDomain/External/VideoList/src/Handler/ReadListHandler.php +++ b/src/ApiDomain/External/VideoList/src/Handler/ReadListHandler.php @@ -7,6 +7,7 @@ namespace MyTube\API\External\VideoList\Handler; use MyTube\API\External\VideoList\ResponseFormatter\ReadListResponseFormatter; use MyTube\Handling\VideoList\Handler\Query\ReadList\ReadListQueryHandler; use MyTube\Handling\VideoList\Handler\Query\ReadList\ReadListQueryBuilder; +use MyTube\Infrastructure\Request\Middleware\AnalyzeBodyMiddleware; use MyTube\Infrastructure\Response\SuccessResponse; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -23,13 +24,12 @@ class ReadListHandler implements RequestHandlerInterface public function handle(ServerRequestInterface $request): ResponseInterface { - $data = json_decode( - $request->getBody()->getContents(), - true - ); + $data = $request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA); $readListQuery = $this->readListQueryBuilder->build( - $data + $data['query'] ?? null, + $data['page'], + $data['perPage'], ); $result = $this->readListQueryHandler->execute($readListQuery); diff --git a/src/ApiDomain/External/VideoList/src/ResponseFormatter/ReadListResponseFormatter.php b/src/ApiDomain/External/VideoList/src/ResponseFormatter/ReadListResponseFormatter.php index ce67090..d31ef84 100644 --- a/src/ApiDomain/External/VideoList/src/ResponseFormatter/ReadListResponseFormatter.php +++ b/src/ApiDomain/External/VideoList/src/ResponseFormatter/ReadListResponseFormatter.php @@ -6,12 +6,16 @@ namespace MyTube\API\External\VideoList\ResponseFormatter; use MyTube\Data\Business\Entity\Tag; use MyTube\Data\Business\Entity\Video; +use MyTube\Handling\VideoList\Handler\Query\ReadList\ReadListQueryResult; class ReadListResponseFormatter { - public function format(array $videos): array + public function format(ReadListQueryResult $queryResult): array { - $result = []; + $paginator = $queryResult->getPaginator(); + $videos = $paginator->getIterator(); + + $items = []; /** @var Video $video */ foreach ($videos as $video) { @@ -22,13 +26,16 @@ class ReadListResponseFormatter $tags[] = $tag->getDescription(); } - $result[] = [ + $items[] = [ 'title' => $video->getTitle(), 'id' => $video->getId()->toString(), 'tags' => $tags ]; } - return $result; + return [ + 'total' => $paginator->count(), + 'items' => $items, + ]; } } diff --git a/src/DataDomain/Business/src/Repository/VideoRepository.php b/src/DataDomain/Business/src/Repository/VideoRepository.php index bcf5a77..09b73b1 100644 --- a/src/DataDomain/Business/src/Repository/VideoRepository.php +++ b/src/DataDomain/Business/src/Repository/VideoRepository.php @@ -8,21 +8,24 @@ use Doctrine\ORM\EntityRepository; class VideoRepository extends EntityRepository { public function findByFilter( - string $identifier + ?string $query, + int $page, + int $perPage, ): Paginator { - $queryBuilder = $this->createQueryBuilder('r'); - $queryBuilder->where( - $queryBuilder->expr()->orX( - $queryBuilder->expr()->eq('r.username', ':identifier'), - $queryBuilder->expr()->eq('r.mail', ':identifier') - ) - ) - ->setParameter('identifier', $identifier); - $query = $queryBuilder->getQuery(); + $queryBuilder = $this->createQueryBuilder('v'); - /** @var ?Registration $registration */ - $registration = $query->execute()[0] ?? null; - return $registration; + if ($query !== null) { + $query = '%'.$query.'%'; + + $queryBuilder + ->where('v.title like :query') + ->setParameter('query', $query); + } + + $queryBuilder->setFirstResult($perPage * ($page - 1)); + $queryBuilder->setMaxResults($perPage); + + return new Paginator($queryBuilder->getQuery()); } } \ No newline at end of file diff --git a/src/HandlingDomain/VideoList/src/Handler/Query/ReadList/ReadListQuery.php b/src/HandlingDomain/VideoList/src/Handler/Query/ReadList/ReadListQuery.php index cd2a14d..db4db43 100644 --- a/src/HandlingDomain/VideoList/src/Handler/Query/ReadList/ReadListQuery.php +++ b/src/HandlingDomain/VideoList/src/Handler/Query/ReadList/ReadListQuery.php @@ -7,9 +7,24 @@ namespace MyTube\Handling\VideoList\Handler\Query\ReadList; class ReadListQuery { public function __construct( - #TODO + private readonly ?string $query, + private readonly int $page, + private readonly int $perPage, ) { } - - #TODO + + public function getQuery(): ?string + { + return $this->query; + } + + public function getPage(): int + { + return $this->page; + } + + public function getPerPage(): int + { + return $this->perPage; + } } diff --git a/src/HandlingDomain/VideoList/src/Handler/Query/ReadList/ReadListQueryBuilder.php b/src/HandlingDomain/VideoList/src/Handler/Query/ReadList/ReadListQueryBuilder.php index 8e67e01..fb7571a 100644 --- a/src/HandlingDomain/VideoList/src/Handler/Query/ReadList/ReadListQueryBuilder.php +++ b/src/HandlingDomain/VideoList/src/Handler/Query/ReadList/ReadListQueryBuilder.php @@ -7,10 +7,14 @@ namespace MyTube\Handling\VideoList\Handler\Query\ReadList; class ReadListQueryBuilder { public function build( - #TODO + ?string $query, + int $page, + int $perPage, ): ReadListQuery { return new ReadListQuery( - #TODO + $query, + $page, + $perPage, ); } } diff --git a/src/HandlingDomain/VideoList/src/Handler/Query/ReadList/ReadListQueryHandler.php b/src/HandlingDomain/VideoList/src/Handler/Query/ReadList/ReadListQueryHandler.php index c3be531..423d051 100644 --- a/src/HandlingDomain/VideoList/src/Handler/Query/ReadList/ReadListQueryHandler.php +++ b/src/HandlingDomain/VideoList/src/Handler/Query/ReadList/ReadListQueryHandler.php @@ -20,8 +20,14 @@ class ReadListQueryHandler ) { } - public function execute(ReadListQuery $readListQuery): array + public function execute(ReadListQuery $readListQuery): ReadListQueryResult { - return $this->videoRepository->findAll(); + return new ReadListQueryResult( + $this->videoRepository->findByFilter( + $readListQuery->getQuery(), + $readListQuery->getPage(), + $readListQuery->getPerPage() + ) + ); } } diff --git a/src/HandlingDomain/VideoList/src/Handler/Query/ReadList/ReadListQueryResult.php b/src/HandlingDomain/VideoList/src/Handler/Query/ReadList/ReadListQueryResult.php new file mode 100644 index 0000000..cb88e9e --- /dev/null +++ b/src/HandlingDomain/VideoList/src/Handler/Query/ReadList/ReadListQueryResult.php @@ -0,0 +1,20 @@ +paginator; + } +} diff --git a/src/Infrastructure/Request/src/Middleware/AnalyzeBodyMiddleware.php b/src/Infrastructure/Request/src/Middleware/AnalyzeBodyMiddleware.php new file mode 100644 index 0000000..31d22cc --- /dev/null +++ b/src/Infrastructure/Request/src/Middleware/AnalyzeBodyMiddleware.php @@ -0,0 +1,43 @@ +getHeaderLine(self::CONTENT_TYPE_HEADER); + + if (str_contains($contentType, self::CONTENT_TYPE_APPLICATION_JSON)) { + $jsonData = json_decode( + $request->getBody()->getContents(), + true + ); + } + + return $handler->handle($request->withAttribute( + self::JSON_DATA, + $jsonData + )); + } +} \ No newline at end of file