This commit is contained in:
Flo 2024-08-05 10:27:38 +00:00
parent cb8ac3a08e
commit caff0ec71f
29 changed files with 579 additions and 18 deletions

View File

@ -26,6 +26,7 @@
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"MyTube\\API\\Console\\": "src\/ApiDomain\/Console\/src", "MyTube\\API\\Console\\": "src\/ApiDomain\/Console\/src",
"MyTube\\API\\External\\Analyze\\": "src\/ApiDomain\/External\/Analyze\/src",
"MyTube\\API\\External\\Authentication\\": "src\/ApiDomain\/External\/Authentication\/src", "MyTube\\API\\External\\Authentication\\": "src\/ApiDomain\/External\/Authentication\/src",
"MyTube\\API\\External\\Health\\": "src\/ApiDomain\/External\/Health\/src", "MyTube\\API\\External\\Health\\": "src\/ApiDomain\/External\/Health\/src",
"MyTube\\API\\External\\Tag\\": "src\/ApiDomain\/External\/Tag\/src", "MyTube\\API\\External\\Tag\\": "src\/ApiDomain\/External\/Tag\/src",
@ -35,6 +36,7 @@
"MyTube\\API\\External\\VideoList\\": "src\/ApiDomain\/External\/VideoList\/src", "MyTube\\API\\External\\VideoList\\": "src\/ApiDomain\/External\/VideoList\/src",
"MyTube\\Data\\Business\\": "src\/DataDomain\/Business\/src", "MyTube\\Data\\Business\\": "src\/DataDomain\/Business\/src",
"MyTube\\Data\\Log\\": "src\/DataDomain\/Log\/src", "MyTube\\Data\\Log\\": "src\/DataDomain\/Log\/src",
"MyTube\\Handling\\Analyze\\": "src\/HandlingDomain\/Analyze\/src",
"MyTube\\Handling\\Registration\\": "src\/HandlingDomain\/Registration\/src", "MyTube\\Handling\\Registration\\": "src\/HandlingDomain\/Registration\/src",
"MyTube\\Handling\\Role\\": "src\/HandlingDomain\/Role\/src", "MyTube\\Handling\\Role\\": "src\/HandlingDomain\/Role\/src",
"MyTube\\Handling\\Tag\\": "src\/HandlingDomain\/Tag\/src", "MyTube\\Handling\\Tag\\": "src\/HandlingDomain\/Tag\/src",
@ -98,6 +100,7 @@
}, },
"autoload-dev": { "autoload-dev": {
"psr-4": { "psr-4": {
"MyTube\\API\\External\\Analyze\\": "src\/ApiDomain\/External\/Analyze\/src",
"MyTube\\API\\External\\Authentication\\": "src\/ApiDomain\/External\/Authentication\/src", "MyTube\\API\\External\\Authentication\\": "src\/ApiDomain\/External\/Authentication\/src",
"MyTube\\API\\External\\Health\\": "src\/ApiDomain\/External\/Health\/src", "MyTube\\API\\External\\Health\\": "src\/ApiDomain\/External\/Health\/src",
"MyTube\\API\\External\\Tag\\": "src\/ApiDomain\/External\/Tag\/src", "MyTube\\API\\External\\Tag\\": "src\/ApiDomain\/External\/Tag\/src",
@ -107,6 +110,7 @@
"MyTube\\API\\External\\VideoList\\": "src\/ApiDomain\/External\/VideoList\/src", "MyTube\\API\\External\\VideoList\\": "src\/ApiDomain\/External\/VideoList\/src",
"MyTube\\Data\\Business\\": "src\/DataDomain\/Business\/src", "MyTube\\Data\\Business\\": "src\/DataDomain\/Business\/src",
"MyTube\\Data\\Log\\": "src\/DataDomain\/Log\/src", "MyTube\\Data\\Log\\": "src\/DataDomain\/Log\/src",
"MyTube\\Handling\\Analyze\\": "src\/HandlingDomain\/Analyze\/src",
"MyTube\\Handling\\Registration\\": "src\/HandlingDomain\/Registration\/src", "MyTube\\Handling\\Registration\\": "src\/HandlingDomain\/Registration\/src",
"MyTube\\Handling\\Role\\": "src\/HandlingDomain\/Role\/src", "MyTube\\Handling\\Role\\": "src\/HandlingDomain\/Role\/src",
"MyTube\\Handling\\Tag\\": "src\/HandlingDomain\/Tag\/src", "MyTube\\Handling\\Tag\\": "src\/HandlingDomain\/Tag\/src",

View File

@ -54,6 +54,7 @@ $aggregator = new ConfigAggregator([
\MyTube\Infrastructure\Session\ConfigProvider::class, \MyTube\Infrastructure\Session\ConfigProvider::class,
// HandlingDomain // HandlingDomain
\MyTube\Handling\Analyze\ConfigProvider::class,
\MyTube\Handling\User\ConfigProvider::class, \MyTube\Handling\User\ConfigProvider::class,
\MyTube\Handling\UserSession\ConfigProvider::class, \MyTube\Handling\UserSession\ConfigProvider::class,
\MyTube\Handling\Registration\ConfigProvider::class, \MyTube\Handling\Registration\ConfigProvider::class,
@ -70,6 +71,7 @@ $aggregator = new ConfigAggregator([
\MyTube\API\External\Health\ConfigProvider::class, \MyTube\API\External\Health\ConfigProvider::class,
\MyTube\API\External\User\ConfigProvider::class, \MyTube\API\External\User\ConfigProvider::class,
\MyTube\API\External\Authentication\ConfigProvider::class, \MyTube\API\External\Authentication\ConfigProvider::class,
\MyTube\API\External\Analyze\ConfigProvider::class,
\MyTube\API\External\Video\ConfigProvider::class, \MyTube\API\External\Video\ConfigProvider::class,
\MyTube\API\External\VideoList\ConfigProvider::class, \MyTube\API\External\VideoList\ConfigProvider::class,
\MyTube\API\External\Tag\ConfigProvider::class, \MyTube\API\External\Tag\ConfigProvider::class,

View File

@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
use MyTube\API\External\Analyze\Handler\AnalyzeVideosHandler;
use MyTube\API\External\Analyze\Handler\ReadVideoListHandler;
return [
[
'name' => 'analyze.analyze-videos',
'path' => '/api/analyze/analyze-videos[/]',
'allowed_methods' => ['POST'],
'middleware' => [
AnalyzeVideosHandler::class,
],
],
[
'name' => 'analyze.read-video-list',
'path' => '/api/analyze/read-video-list[/]',
'allowed_methods' => ['POST'],
'middleware' => [
ReadVideoListHandler::class,
],
],
];

View File

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
use MyTube\API\External\Analyze\Handler\AnalyzeVideosHandler;
use MyTube\API\External\Analyze\Handler\ReadVideoListHandler;
use MyTube\API\External\Analyze\ResponseFormatter\AnalyzeVideosResponseFormatter;
use MyTube\API\External\Analyze\ResponseFormatter\ReadVideoListResponseFormatter;
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
return [
'factories' => [
// Handler
AnalyzeVideosHandler::class => AutoWiringFactory::class,
ReadVideoListHandler::class => AutoWiringFactory::class,
// Response Formatter
AnalyzeVideosResponseFormatter::class => AutoWiringFactory::class,
ReadVideoListResponseFormatter::class => AutoWiringFactory::class,
],
];

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\Analyze;
class ConfigProvider
{
public function __invoke(): array
{
return [
'dependencies' => require __DIR__ . './../config/service_manager.php',
'routes' => require __DIR__ . '/./../config/routes.php',
];
}
}

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\Analyze\Handler;
use MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos\AnalyzeVideosCommandHandler;
use MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos\AnalyzeVideosCommandBuilder;
use MyTube\API\External\Analyze\ResponseFormatter\AnalyzeVideosResponseFormatter;
use MyTube\Infrastructure\Request\Middleware\AnalyzeBodyMiddleware;
use MyTube\Infrastructure\Response\SuccessResponse;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
class AnalyzeVideosHandler implements RequestHandlerInterface
{
public function __construct(
private readonly AnalyzeVideosCommandHandler $analyzeVideosCommandHandler,
private readonly AnalyzeVideosCommandBuilder $analyzeVideosCommandBuilder,
private readonly AnalyzeVideosResponseFormatter $responseFormatter,
) {
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
$data = $request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
$analyzeVideosCommand = $this->analyzeVideosCommandBuilder->build();
$result = $this->analyzeVideosCommandHandler->execute($analyzeVideosCommand);
return new SuccessResponse($this->responseFormatter->format($result));
}
}

View File

@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\Analyze\Handler;
use MyTube\Handling\Analyze\Handler\Query\ReadVideoList\ReadVideoListQueryHandler;
use MyTube\Handling\Analyze\Handler\Query\ReadVideoList\ReadVideoListQueryBuilder;
use MyTube\API\External\Analyze\ResponseFormatter\ReadVideoListResponseFormatter;
use MyTube\Infrastructure\Request\Middleware\AnalyzeBodyMiddleware;
use MyTube\Infrastructure\Response\SuccessResponse;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
class ReadVideoListHandler implements RequestHandlerInterface
{
public function __construct(
private readonly ReadVideoListQueryHandler $readVideoListQueryHandler,
private readonly ReadVideoListQueryBuilder $readVideoListQueryBuilder,
private readonly ReadVideoListResponseFormatter $responseFormatter,
) {
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
$data = $request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
$readVideoListQuery = $this->readVideoListQueryBuilder->build(
$data['query'] ?? null,
$data['page'],
$data['perPage'],
$data['onlyTagless'] ?? false,
);
$result = $this->readVideoListQueryHandler->execute($readVideoListQuery);
return new SuccessResponse($this->responseFormatter->format($result));
}
}

View File

@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\Analyze\ResponseFormatter;
use MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos\AnalyzeVideosCommandResult;
use MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos\Model\VideoChangedModel;
class AnalyzeVideosResponseFormatter
{
public function format(AnalyzeVideosCommandResult $analyzeVideosCommandResult): array
{
$result = [];
/** @var VideoChangedModel $changedVideo */
foreach ($analyzeVideosCommandResult->getChangedVideos() as $changedVideo) {
$tags = [];
$newTags = [];
$video = $changedVideo->getVideo();
foreach ($changedVideo->getNewTags() as $tag) {
$newTags[] = [
'id' => $tag->getId(),
'description' => $tag->getDescription(),
];
}
foreach ($video->getTags() as $tag) {
$tags[] = [
'id' => $tag->getId(),
'description' => $tag->getDescription(),
];
}
$result[] = [
'video' => [
'id' => $video->getId(),
'title' => $video->getTitle(),
'duration' => gmdate("H:i:s", $video->getDuration()),
'tags' => $tags,
],
'newTags' => $newTags,
'newDuration' => $changedVideo->isNewDuration()
];
}
return $result;
}
}

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\Analyze\ResponseFormatter;
use MyTube\Data\Business\Entity\Tag;
use MyTube\Data\Business\Entity\Video;
use MyTube\Handling\Analyze\Handler\Query\ReadVideoList\ReadVideoListQueryResult;
class ReadVideoListResponseFormatter
{
public function format(ReadVideoListQueryResult $queryResult): array
{
$paginator = $queryResult->getPaginator();
$videos = $paginator->getIterator();
$items = [];
/** @var Video $video */
foreach ($videos as $video) {
$tags = [];
/** @var Tag $tag */
foreach ($video->getTags() as $tag) {
$tags[] = [
'id' => $tag->getId(),
'description' => $tag->getDescription()
];
}
$items[] = [
'title' => $video->getTitle(),
'id' => $video->getId(),
'duration' => $video->getDuration() === null ? 'n. def' : gmdate("H:i:s", $video->getDuration()),
'tags' => $tags
];
}
return [
'total' => $paginator->count(),
'items' => $items,
];
}
}

View File

@ -30,7 +30,6 @@ class ReadListHandler implements RequestHandlerInterface
$data['query'] ?? null, $data['query'] ?? null,
$data['page'], $data['page'],
$data['perPage'], $data['perPage'],
$data['onlyTagless'] ?? false,
); );
$result = $this->readListQueryHandler->execute($readListQuery); $result = $this->readListQueryHandler->execute($readListQuery);

View File

@ -18,7 +18,6 @@ class VideoRepository extends EntityRepository {
?string $query, ?string $query,
int $page, int $page,
int $perPage, int $perPage,
bool $onlyTagless,
?Tag $tag = null, ?Tag $tag = null,
?string $orderBy = null, ?string $orderBy = null,
string $orderDirection = 'desc' string $orderDirection = 'desc'
@ -43,7 +42,7 @@ class VideoRepository extends EntityRepository {
->setParameter('tagId', $tag->getId(), UuidBinaryOrderedTimeType::NAME); ->setParameter('tagId', $tag->getId(), UuidBinaryOrderedTimeType::NAME);
} }
if ($onlyTagless) { if (false) { //only tagless
$queryBuilder = $queryBuilder $queryBuilder = $queryBuilder
->andWhere( $queryBuilder->expr()->isNull('t.id') ); ->andWhere( $queryBuilder->expr()->isNull('t.id') );
} }

View File

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
use MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos\AnalyzeVideosCommandHandler;
use MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos\AnalyzeVideosCommandBuilder;
use MyTube\Handling\Analyze\Handler\Query\ReadVideoList\ReadVideoListQueryBuilder;
use MyTube\Handling\Analyze\Handler\Query\ReadVideoList\ReadVideoListQueryHandler;
use MyTube\Handling\Analyze\Repository\AnalyzeVideoRepository;
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
use Reinfi\DependencyInjection\Factory\InjectionFactory;
return [
'factories' => [
/// Repository
AnalyzeVideoRepository::class => AutoWiringFactory::class,
/// CQRS
// AnalyzeVideos
AnalyzeVideosCommandBuilder::class => AutoWiringFactory::class,
AnalyzeVideosCommandHandler::class => AutoWiringFactory::class,
// Read Video List
ReadVideoListQueryBuilder::class => AutoWiringFactory::class,
ReadVideoListQueryHandler::class => AutoWiringFactory::class,
],
];

View File

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Analyze;
class ConfigProvider
{
public function __invoke(): array
{
return [
'dependencies' => require __DIR__ . './../config/service_manager.php',
];
}
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos;
class AnalyzeVideosCommand
{
public function __construct(
#TODO
) {
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos;
class AnalyzeVideosCommandBuilder
{
public function build(
#TODO
): AnalyzeVideosCommand {
return new AnalyzeVideosCommand(
#TODO
);
}
}

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos;
use MyTube\Data\Business\Entity\Video;
use MyTube\Data\Business\Manager\MyTubeEntityManager;
use MyTube\Data\Business\Repository\VideoRepository;
use MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos\Model\VideoChangedModel;
use MyTube\Handling\Video\Analyzer\VideoDurationAnalyzer;
use MyTube\Handling\Video\Analyzer\VideoTitleAnalyzer;
class AnalyzeVideosCommandHandler
{
private readonly VideoRepository $videoRepository;
public function __construct(
private readonly MyTubeEntityManager $entityManager,
private readonly VideoTitleAnalyzer $titleAnalyzer,
private readonly VideoDurationAnalyzer $durationAnalyzer,
) {
$this->videoRepository = $this->entityManager->getRepository(Video::class);
}
public function execute(AnalyzeVideosCommand $analyzeVideosCommand): AnalyzeVideosCommandResult
{
$videos = $this->videoRepository->findAll();
$changedVideos = [];
/** @var Video $video */
foreach ($videos as $video) {
$newTags = $this->titleAnalyzer->analyze($video);
$newDuration = $this->durationAnalyzer->analyze($video);
if (count($newTags) > 0 || $newDuration) {
$changedVideos[] = new VideoChangedModel($video, $newTags, $newDuration);
$this->entityManager->persist($video);
$this->entityManager->flush();
}
}
return new AnalyzeVideosCommandResult($changedVideos);
}
}

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos;
class AnalyzeVideosCommandResult
{
public function __construct(
private array $changedVideos
) {
}
public function getChangedVideos(): array
{
return $this->changedVideos;
}
}

View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos\Model;
use MyTube\Data\Business\Entity\Video;
class VideoChangedModel
{
public function __construct(
private readonly Video $video,
private readonly ?array $newTags = null,
private readonly bool $newDuration = false
) {
}
public function getVideo(): Video
{
return $this->video;
}
public function getNewTags(): ?array
{
return $this->newTags;
}
public function isNewDuration(): bool
{
return $this->newDuration;
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Analyze\Handler\Query\ReadVideoList;
class ReadVideoListQuery
{
public function __construct(
private readonly ?string $query,
private readonly int $page,
private readonly int $perPage,
private readonly bool $onlyTagless,
) {
}
public function getQuery(): ?string
{
return $this->query;
}
public function getPage(): int
{
return $this->page;
}
public function getPerPage(): int
{
return $this->perPage;
}
public function getOnlyTagless(): bool
{
return $this->onlyTagless;
}
}

View File

@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Analyze\Handler\Query\ReadVideoList;
class ReadVideoListQueryBuilder
{
public function build(
?string $query,
int $page,
int $perPage,
bool $onlyTagless,
): ReadVideoListQuery {
return new ReadVideoListQuery(
$query,
$page,
$perPage,
$onlyTagless,
);
}
}

View File

@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Analyze\Handler\Query\ReadVideoList;
use MyTube\Handling\Analyze\Repository\AnalyzeVideoRepository;
class ReadVideoListQueryHandler
{
public function __construct(
private readonly AnalyzeVideoRepository $analyzeVideoRepository
) {
}
public function execute(ReadVideoListQuery $readVideoListQuery): ReadVideoListQueryResult
{
return new ReadVideoListQueryResult(
$this->analyzeVideoRepository->findByFilter(
query: $readVideoListQuery->getQuery(),
page: $readVideoListQuery->getPage(),
perPage: $readVideoListQuery->getPerPage(),
onlyTagless: $readVideoListQuery->getOnlyTagless()
)
);
}
}

View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Analyze\Handler\Query\ReadVideoList;
use Doctrine\ORM\Tools\Pagination\Paginator;
class ReadVideoListQueryResult
{
public function __construct(
private readonly Paginator $paginator
) {
}
public function getPaginator(): Paginator
{
return $this->paginator;
}
}

View File

@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Analyze\Repository;
use Doctrine\ORM\Tools\Pagination\Paginator;
use MyTube\Data\Business\Entity\Video;
use MyTube\Data\Business\Manager\MyTubeEntityManager;
class AnalyzeVideoRepository
{
public function __construct(
private readonly MyTubeEntityManager $entityManager
) {
}
private const FIELD_MAP = [
'duration' => 'v.duration',
'title' => 'v.title',
'createdAt' => 'v.createdAt'
];
public function findByFilter(
?string $query,
int $page,
int $perPage,
bool $onlyTagless,
?string $orderBy = null,
string $orderDirection = 'asc'
): Paginator
{
$orderBy = self::FIELD_MAP[$orderBy] ?? self::FIELD_MAP['title'];
$queryBuilder = $this->entityManager->createQueryBuilder()
->select('v')
->from(Video::class, 'v')
->leftJoin('v.tags', 't');
if ($query !== null) {
$query = '%'.$query.'%';
$queryBuilder = $queryBuilder
->where('v.title like :query')
->orWhere('t.description like :query')
->setParameter('query', $query);
}
if ($onlyTagless) {
$queryBuilder = $queryBuilder
->andWhere( $queryBuilder->expr()->isNull('t.id') );
}
$queryBuilder->orderBy($orderBy,$orderDirection);
$queryBuilder->setFirstResult($perPage * ($page - 1));
$queryBuilder->setMaxResults($perPage);
return new Paginator($queryBuilder->getQuery());
}
}

View File

@ -44,7 +44,6 @@ class ReadVideoListQueryHandler
query: $readVideoListQuery->getQuery(), query: $readVideoListQuery->getQuery(),
page: $readVideoListQuery->getPage(), page: $readVideoListQuery->getPage(),
perPage: $readVideoListQuery->getPerPage(), perPage: $readVideoListQuery->getPerPage(),
onlyTagless: false,
tag: $tag tag: $tag
) )
); );

View File

@ -15,7 +15,7 @@ class VideoDurationAnalyzer
{ {
public function analyze( public function analyze(
Video $video Video $video
): void { ): bool {
if ($video->getDuration() === null) { if ($video->getDuration() === null) {
$command = sprintf( $command = sprintf(
"ffprobe -i %s%s -show_entries format=duration -v quiet -of csv='p=0'", "ffprobe -i %s%s -show_entries format=duration -v quiet -of csv='p=0'",
@ -26,7 +26,9 @@ class VideoDurationAnalyzer
$duration = shell_exec($command); $duration = shell_exec($command);
if ($duration !== null) { if ($duration !== null) {
$video->setDuration(intval($duration)); $video->setDuration(intval($duration));
return true;
} }
} }
return false;
} }
} }

View File

@ -31,6 +31,7 @@ class VideoTitleAnalyzer
$tags = $this->tagRepository->findAll(); $tags = $this->tagRepository->findAll();
$matches = []; $matches = [];
$appliedMatches = [];
/** @var Tag $tag */ /** @var Tag $tag */
foreach ($tags as $tag) { foreach ($tags as $tag) {
@ -50,10 +51,13 @@ class VideoTitleAnalyzer
/** @var Tag $match */ /** @var Tag $match */
foreach ($matches as $match) { foreach ($matches as $match) {
if(!$video->getTags()->contains($match)) {
$appliedMatches[] = $match;
$video->addTag($match); $video->addTag($match);
} }
}
return $matches; return $appliedMatches;
} }
private function normalizeString(string $string): string { private function normalizeString(string $string): string {

View File

@ -9,8 +9,7 @@ class ReadListQuery
public function __construct( public function __construct(
private readonly ?string $query, private readonly ?string $query,
private readonly int $page, private readonly int $page,
private readonly int $perPage, private readonly int $perPage
private readonly bool $onlyTagless,
) { ) {
} }
@ -28,9 +27,4 @@ class ReadListQuery
{ {
return $this->perPage; return $this->perPage;
} }
public function getOnlyTagless(): bool
{
return $this->onlyTagless;
}
} }

View File

@ -10,13 +10,11 @@ class ReadListQueryBuilder
?string $query, ?string $query,
int $page, int $page,
int $perPage, int $perPage,
bool $onlyTagless,
): ReadListQuery { ): ReadListQuery {
return new ReadListQuery( return new ReadListQuery(
$query, $query,
$page, $page,
$perPage, $perPage,
$onlyTagless,
); );
} }
} }

View File

@ -26,8 +26,7 @@ class ReadListQueryHandler
$this->videoRepository->findByFilter( $this->videoRepository->findByFilter(
query: $readListQuery->getQuery(), query: $readListQuery->getQuery(),
page: $readListQuery->getPage(), page: $readListQuery->getPage(),
perPage: $readListQuery->getPerPage(), perPage: $readListQuery->getPerPage()
onlyTagless: $readListQuery->getOnlyTagless()
) )
); );
} }