Compare commits

...

10 Commits

Author SHA1 Message Date
Flo
1df97ff326 tags 2024-02-25 16:02:24 +01:00
Flo
544a9480ae improved create scripte 2024-02-24 21:10:40 +01:00
Flo
fe366cbe86 improved create pipeline 2024-02-24 21:06:41 +01:00
Flo
c8a2513b87 tagList first version 2024-02-24 21:03:10 +01:00
Flo
24192495cf restored content 2024-02-24 20:35:39 +01:00
Flo
27be2c79dd createApi improvements 2024-02-24 20:31:55 +01:00
Flo
3cb5eaa4d9 createApi improvements 2024-02-24 20:30:36 +01:00
Flo
2b210fd8bc createApi improvements 2024-02-24 20:25:42 +01:00
Flo
0201c5c559 paginated list 2024-02-24 20:16:24 +01:00
Flo
3f97413c4e bulk upload 2024-02-23 19:12:22 +01:00
109 changed files with 2853 additions and 149 deletions

View File

@ -14,20 +14,25 @@ $apiNamespace = $argv[2];
$apiName = $argv[3];
$cqrsType = strtolower($argv[4]) === 'true' ? 'Command' : 'Query';
$cqrsNamespace = $argv[5];
$originalCqrsNamespace = $cqrsNamespace;
$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';
$apiHandlerUsingNamespace = $apiHandlerNamespace . '\\' . $apiHandlerName;
$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 +75,113 @@ function writeToFile($path, $content) {
file_put_contents($path, $content);
}
if (!file_exists($apiDirectoryPath)) {
$routesFileContent = "<?php
declare(strict_types=1);
use {$apiHandlerUsingNamespace};
return [
[
'name' => 'TODO.TODO',
'path' => '/api/TODO/TODO[/]',
'allowed_methods' => ['POST'],
'middleware' => [
{$apiHandlerName}::class,
],
],
];
";
$routesFilePath = $apiDirectoryPath . 'config/routes.php';
writeToFile($routesFilePath, $routesFileContent);
$serviceManagerFileContent = "<?php
declare(strict_types=1);
use {$apiHandlerUsingNamespace};
use {$apiResponseFormatterUsingNamespace};
use Reinfi\\DependencyInjection\\Factory\\AutoWiringFactory;
return [
'factories' => [
// Handler
{$apiHandlerName}::class => AutoWiringFactory::class,
// Response Formatter
{$apiResponseFormatterName}::class => AutoWiringFactory::class,
],
];
";
$serviceManagerFilePath = $apiDirectoryPath . 'config/service_manager.php';
writeToFile($serviceManagerFilePath, $serviceManagerFileContent);
$configProviderFileContent = "<?php
declare(strict_types=1);
namespace MyTube\\API\\{$apiType}\\{$apiNamespace};
class ConfigProvider
{
public function __invoke(): array
{
return [
'dependencies' => require __DIR__ . './../config/service_manager.php',
'routes' => require __DIR__ . '/./../config/routes.php',
];
}
}
";
$configProviderFilePath = $apiDirectoryPath . 'src/ConfigProvider.php';
writeToFile($configProviderFilePath, $configProviderFileContent);
}
if (!file_exists($cqrsDirectoryPath)) {
$serviceManagerFileContent = "<?php
declare(strict_types=1);
use {$cqrsHandlerUsingNamespace};
use {$cqrsBuilderUsingNamespace};
use Reinfi\\DependencyInjection\\Factory\\AutoWiringFactory;
use Reinfi\\DependencyInjection\\Factory\\InjectionFactory;
return [
'factories' => [
/// CQRS
// {$apiName}
{$cqrsBuilderName}::class => AutoWiringFactory::class,
{$cqrsHandlerName}::class => AutoWiringFactory::class,
],
];
";
$serviceManagerFilePath = $cqrsDirectoryPath . 'config/service_manager.php';
writeToFile($serviceManagerFilePath, $serviceManagerFileContent);
$configProviderFileContent = "<?php
declare(strict_types=1);
namespace MyTube\\Handling\\{$originalCqrsNamespace};
class ConfigProvider
{
public function __invoke(): array
{
return [
'dependencies' => require __DIR__ . './../config/service_manager.php',
];
}
}
";
$configProviderFilePath = $cqrsDirectoryPath . 'src/ConfigProvider.php';
writeToFile($configProviderFilePath, $configProviderFileContent);
}
$apiHandlerFileContent = "<?php
declare(strict_types=1);
@ -79,10 +191,11 @@ namespace {$apiHandlerNamespace};
use {$cqrsHandlerUsingNamespace};
use {$cqrsBuilderUsingNamespace};
use {$apiResponseFormatterUsingNamespace};
use {$projectNamespace}\\Infrastructure\\Request\\Middleware\\AnalyzeBodyMiddleware;
use {$projectNamespace}\\Infrastructure\\Response\\SuccessResponse;
use Psr\\Http\\Message\\ResponseInterface;
use Psr\\Http\\Message\\ServerRequestInterface;
use Psr\\Http\\Server\\RequestHandlerInterface;
use {$projectNamespace}\\Infrastructure\\Response\\SuccessResponse;
class {$apiHandlerName} implements RequestHandlerInterface
{
@ -95,10 +208,7 @@ class {$apiHandlerName} implements RequestHandlerInterface
public function handle(ServerRequestInterface \$request): ResponseInterface
{
\$data = json_decode(
\$request->getBody()->getContents(),
true
);
\$data = \$request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
\${$cqrsVariableName} = \$this->{$cqrsBuilderVariableName}->build(
\$data
@ -138,7 +248,7 @@ namespace {$cqrsNamespace};
class {$cqrsName}
{
public function __construct(
#TODO
#TODO
) {
}
}
@ -154,7 +264,7 @@ namespace {$cqrsNamespace};
class {$cqrsResultName}
{
public function __construct(
#TODO
#TODO
) {
}
}

View File

@ -16,7 +16,8 @@ $stepNames = array_slice($argv, 3);
# Pipeline
$pipelineClassName = $pipelineName . 'Pipeline';
$pipelineVariableName = lcfirst($pipelineClassName);
$pipelineFilePath = $projectSourceDirectory . 'HandlingDomain/' . $pipelineNamespace . '/src/Pipeline/' . $pipelineName . '/' . $pipelineClassName . '.php';
$pipelineDirectoryPath = $projectSourceDirectory . 'HandlingDomain/' . $pipelineNamespace . '/';
$pipelineFilePath = $pipelineDirectoryPath . 'src/Pipeline/' . $pipelineName . '/' . $pipelineClassName . '.php';
$pipelineFullNamespace = $projectNamespace . '\\Handling\\' . $pipelineNamespace . '\\Pipeline\\' . $pipelineName;
$pipelineUsingNamespace = $pipelineFullNamespace . '\\' . $pipelineClassName;
@ -57,8 +58,11 @@ function writeToFile($path, $content) {
file_put_contents($path, $content);
}
$createNamespaceFiles = !file_exists($pipelineDirectoryPath);
$stepsUsingNamespaces = [];
$stepsDeclarations = [];
$stepsAutoWirings = [];
$stepsReferences = [];
foreach ($steps as $step) {
@ -69,6 +73,7 @@ foreach ($steps as $step) {
$stepsUsingNamespaces[] = $stepUsingNamespace . ';';
$stepsDeclarations[] = 'private readonly ' . $stepClassName . ' $' . $stepVariableName . ',';
$stepsAutoWirings[] = $stepClassName . '::class => AutoWiringFactory::class,';
$stepsReferences[] = '$this->' . $stepVariableName . ',';
$stepFileContent = "<?php
@ -89,10 +94,7 @@ class {$stepClassName} implements TaskInterface
) {
}
public function __invoke(
\$payload,
PipelineInterface \$pipeline
): void
public function __invoke(\$payload, PipelineInterface \$pipeline): void
{
/** @var {$payloadClassName} \${$payloadVariableName} */
\${$payloadVariableName} = \$payload;
@ -106,6 +108,7 @@ class {$stepClassName} implements TaskInterface
$stepsUsingNamespace = implode(PHP_EOL, $stepsUsingNamespaces);
$stepsDeclaration = implode(PHP_EOL . ' ', $stepsDeclarations);
$stepsAutoWiring = implode(PHP_EOL . ' ', $stepsAutoWirings);
$stepsReference = implode(PHP_EOL . ' ', $stepsReferences);
@ -140,10 +143,52 @@ namespace {$payloadFullNamespace};
class {$payloadClassName}
{
public function __construct(
#TODO
) {
}
#TODO
}
";
writeToFile($payloadFilePath, $payloadFileContent);
if ($createNamespaceFiles) {
$serviceManagerFileContent = "<?php
declare(strict_types=1);
use {$pipelineUsingNamespace};
{$stepsUsingNamespace}
use Reinfi\\DependencyInjection\\Factory\\AutoWiringFactory;
use Reinfi\\DependencyInjection\\Factory\\InjectionFactory;
return [
'factories' => [
/// Pipeline
// {$pipelineName}
{$pipelineClassName}::class => AutoWiringFactory::class,
{$stepsAutoWiring}
],
];
";
$serviceManagerFilePath = $pipelineDirectoryPath . 'config/service_manager.php';
writeToFile($serviceManagerFilePath, $serviceManagerFileContent);
$configProviderFileContent = "<?php
declare(strict_types=1);
namespace MyTube\\Handling\\{$pipelineNamespace};
class ConfigProvider
{
public function __invoke(): array
{
return [
'dependencies' => require __DIR__ . './../config/service_manager.php',
];
}
}
";
$configProviderFilePath = $pipelineDirectoryPath . 'src/ConfigProvider.php';
writeToFile($configProviderFilePath, $configProviderFileContent);
}

View File

@ -27,6 +27,8 @@
"MyTube\\API\\Console\\": "src\/ApiDomain\/Console\/src",
"MyTube\\API\\External\\Authentication\\": "src\/ApiDomain\/External\/Authentication\/src",
"MyTube\\API\\External\\Health\\": "src\/ApiDomain\/External\/Health\/src",
"MyTube\\API\\External\\Tag\\": "src\/ApiDomain\/External\/Tag\/src",
"MyTube\\API\\External\\TagList\\": "src\/ApiDomain\/External\/TagList\/src",
"MyTube\\API\\External\\User\\": "src\/ApiDomain\/External\/User\/src",
"MyTube\\API\\External\\Video\\": "src\/ApiDomain\/External\/Video\/src",
"MyTube\\API\\External\\VideoList\\": "src\/ApiDomain\/External\/VideoList\/src",
@ -34,6 +36,8 @@
"MyTube\\Data\\Log\\": "src\/DataDomain\/Log\/src",
"MyTube\\Handling\\Registration\\": "src\/HandlingDomain\/Registration\/src",
"MyTube\\Handling\\Role\\": "src\/HandlingDomain\/Role\/src",
"MyTube\\Handling\\Tag\\": "src\/HandlingDomain\/Tag\/src",
"MyTube\\Handling\\TagList\\": "src\/HandlingDomain\/TagList\/src",
"MyTube\\Handling\\User\\": "src\/HandlingDomain\/User\/src",
"MyTube\\Handling\\UserSession\\": "src\/HandlingDomain\/UserSession\/src",
"MyTube\\Handling\\Video\\": "src\/HandlingDomain\/Video\/src",
@ -95,6 +99,8 @@
"psr-4": {
"MyTube\\API\\External\\Authentication\\": "src\/ApiDomain\/External\/Authentication\/src",
"MyTube\\API\\External\\Health\\": "src\/ApiDomain\/External\/Health\/src",
"MyTube\\API\\External\\Tag\\": "src\/ApiDomain\/External\/Tag\/src",
"MyTube\\API\\External\\TagList\\": "src\/ApiDomain\/External\/TagList\/src",
"MyTube\\API\\External\\User\\": "src\/ApiDomain\/External\/User\/src",
"MyTube\\API\\External\\Video\\": "src\/ApiDomain\/External\/Video\/src",
"MyTube\\API\\External\\VideoList\\": "src\/ApiDomain\/External\/VideoList\/src",
@ -102,6 +108,8 @@
"MyTube\\Data\\Log\\": "src\/DataDomain\/Log\/src",
"MyTube\\Handling\\Registration\\": "src\/HandlingDomain\/Registration\/src",
"MyTube\\Handling\\Role\\": "src\/HandlingDomain\/Role\/src",
"MyTube\\Handling\\Tag\\": "src\/HandlingDomain\/Tag\/src",
"MyTube\\Handling\\TagList\\": "src\/HandlingDomain\/TagList\/src",
"MyTube\\Handling\\User\\": "src\/HandlingDomain\/User\/src",
"MyTube\\Handling\\UserSession\\": "src\/HandlingDomain\/UserSession\/src",
"MyTube\\Handling\\Video\\": "src\/HandlingDomain\/Video\/src",

View File

@ -59,6 +59,8 @@ $aggregator = new ConfigAggregator([
\MyTube\Handling\Registration\ConfigProvider::class,
\MyTube\Handling\Video\ConfigProvider::class,
\MyTube\Handling\VideoList\ConfigProvider::class,
\MyTube\Handling\Tag\ConfigProvider::class,
\MyTube\Handling\TagList\ConfigProvider::class,
// API
/// Command
@ -70,6 +72,8 @@ $aggregator = new ConfigAggregator([
\MyTube\API\External\Authentication\ConfigProvider::class,
\MyTube\API\External\Video\ConfigProvider::class,
\MyTube\API\External\VideoList\ConfigProvider::class,
\MyTube\API\External\Tag\ConfigProvider::class,
\MyTube\API\External\TagList\ConfigProvider::class,
/// Internal

View File

@ -3,6 +3,7 @@
declare(strict_types=1);
use MyTube\Infrastructure\Exception\Middleware\MyTubeExceptionHandlerMiddleware;
use MyTube\Infrastructure\Request\Middleware\AnalyzeBodyMiddleware;
use MyTube\Infrastructure\Request\Middleware\AnalyzeHeaderMiddleware;
use MyTube\Infrastructure\Session\Middleware\SessionMiddleware;
use Laminas\Stratigility\Middleware\ErrorHandler;
@ -69,6 +70,7 @@ return function (Application $app, MiddlewareFactory $factory, ContainerInterfac
//// Pre MyTube Space
$app->pipe(MyTubeExceptionHandlerMiddleware::class);
$app->pipe(AnalyzeHeaderMiddleware::class);
$app->pipe(AnalyzeBodyMiddleware::class);
//// MyTube Space
$app->pipe(SessionMiddleware::class);

View File

@ -14,18 +14,24 @@ final class Version20240223130626 extends AbstractMigration
{
public function getDescription(): string
{
return '';
return "Create Table 'tag'";
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$sql = "CREATE TABLE tag (
id binary(16) NOT NULL,
description varchar(255) NOT NULL,
created_at datetime NOT NULL,
updated_at datetime NOT NULL,
PRIMARY KEY (id)
);";
$this->addSql($sql);
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql("DROP TABLE tag;");
}
}

View File

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace MyTube\Migrations\MyTube;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240223130835 extends AbstractMigration
{
public function getDescription(): string
{
return "Create Table 'tag_alias'";
}
public function up(Schema $schema): void
{
$sql = "CREATE TABLE tag_alias (
id binary(16) NOT NULL,
tag_id binary(16) NOT NULL,
description varchar(255) NOT NULL,
created_at datetime NOT NULL,
updated_at datetime NOT NULL,
PRIMARY KEY (id)
);";
$this->addSql($sql);
}
public function down(Schema $schema): void
{
$this->addSql("DROP TABLE tag_alias;");
}
}

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace MyTube\Migrations\MyTube;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240223142111 extends AbstractMigration
{
public function getDescription(): string
{
return "Create Table 'video_tag'";
}
public function up(Schema $schema): void
{
$sql = "CREATE TABLE video_tag (
video_id binary(16) NOT NULL,
tag_id binary(16) NOT NULL,
PRIMARY KEY (video_id, tag_id)
);";
$this->addSql($sql);
}
public function down(Schema $schema): void
{
$this->addSql("DROP TABLE video_tag;");
}
}

View File

@ -5,7 +5,7 @@ upstream host-backend-app {
server {
listen 80 default_server;
client_max_body_size 1000M;
client_max_body_size 10000M;
location / {
fastcgi_pass host-backend-app;

View File

@ -1,5 +1,6 @@
file_uploads = On
memory_limit = 1000M
upload_max_filesize = 1000M
post_max_size = 1000M
max_execution_time = 600
max_file_uploads = 1000
memory_limit = 10000M
upload_max_filesize = 10000M
post_max_size = 10000M
max_execution_time = 1000

View File

@ -1,11 +1,15 @@
<?php
use MyTube\API\Console\Command\AnalyzeVideoTitlesCommand;
use MyTube\API\Console\Command\InitializeDataCommand;
use MyTube\API\Console\Command\RbacUpdateCommand;
use MyTube\API\Console\Command\ReadUntaggedVideosCommand;
return [
'commands' => [
InitializeDataCommand::class,
RbacUpdateCommand::class,
AnalyzeVideoTitlesCommand::class,
ReadUntaggedVideosCommand::class,
]
];

View File

@ -1,12 +1,16 @@
<?php
use MyTube\API\Console\Command\AnalyzeVideoTitlesCommand;
use MyTube\API\Console\Command\InitializeDataCommand;
use MyTube\API\Console\Command\RbacUpdateCommand;
use MyTube\API\Console\Command\ReadUntaggedVideosCommand;
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
return [
'factories' => [
InitializeDataCommand::class => AutoWiringFactory::class,
RbacUpdateCommand::class => AutoWiringFactory::class,
AnalyzeVideoTitlesCommand::class => AutoWiringFactory::class,
ReadUntaggedVideosCommand::class => AutoWiringFactory::class,
],
];

View File

@ -0,0 +1,66 @@
<?php
namespace MyTube\API\Console\Command;
use MyTube\Data\Business\Entity\Tag;
use MyTube\Data\Business\Entity\Video;
use MyTube\Data\Business\Manager\MyTubeEntityManager;
use MyTube\Data\Business\Repository\VideoRepository;
use MyTube\Handling\Video\Analyzer\VideoTitleAnalyzer;
use MyTube\Infrastructure\Logging\Logger\Logger;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(name: 'analyze:video-title', description: 'Analyzes video titles and add tags')]
class AnalyzeVideoTitlesCommand extends Command
{
private readonly VideoRepository $videoRepository;
public function __construct(
private readonly MyTubeEntityManager $entityManager,
private readonly VideoTitleAnalyzer $analyzer,
private readonly Logger $logger,
) {
parent::__construct($this->getName());
$this->videoRepository = $this->entityManager->getRepository(Video::class);
}
protected function execute(
InputInterface $input,
OutputInterface $output
): int {
$io = new SymfonyStyle($input, $output);
try {
$videos = $this->videoRepository->findAll();
/** @var Video $video */
foreach ($videos as $video) {
$io->info($video->getTitle());
$matches = $this->analyzer->analyze($video);
/** @var Tag $match */
foreach ($matches as $match) {
echo sprintf("Added Tag '%s'", $match->getDescription());
}
$this->entityManager->persist($video);
$this->entityManager->flush();
}
$io->success('OK!');
} catch (\Throwable $e) {
$io->error($e->getMessage());
$io->error($e->getTraceAsString());
$this->logger->error($e->getMessage(), ['exception' => $e]);
return Command::FAILURE;
}
return Command::SUCCESS;
}
}

View File

@ -0,0 +1,64 @@
<?php
namespace MyTube\API\Console\Command;
use MyTube\Data\Business\Entity\Tag;
use MyTube\Data\Business\Entity\Video;
use MyTube\Data\Business\Manager\MyTubeEntityManager;
use MyTube\Data\Business\Repository\VideoRepository;
use MyTube\Handling\Video\Analyzer\VideoTitleAnalyzer;
use MyTube\Infrastructure\Logging\Logger\Logger;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(name: 'analyze:untagged', description: 'Returns the names of all untagged videos')]
class ReadUntaggedVideosCommand extends Command
{
private readonly VideoRepository $videoRepository;
public function __construct(
private readonly MyTubeEntityManager $entityManager,
private readonly Logger $logger,
) {
parent::__construct($this->getName());
$this->videoRepository = $this->entityManager->getRepository(Video::class);
}
protected function execute(
InputInterface $input,
OutputInterface $output
): int {
$io = new SymfonyStyle($input, $output);
try {
$qb = $this->videoRepository
->createQueryBuilder('v')
->leftJoin('v.tags', 't')
->groupBy('v.id')
->having('COUNT(t.id) = 0')
->orderBy('v.title');
$videos = $qb->getQuery()->execute();
/** @var Video $video */
foreach ($videos as $video) {
echo $video->getTitle() . PHP_EOL;
}
$io->info('total: ' . count($videos));
$io->success('OK!');
} catch (\Throwable $e) {
$io->error($e->getMessage());
$io->error($e->getTraceAsString());
$this->logger->error($e->getMessage(), ['exception' => $e]);
return Command::FAILURE;
}
return Command::SUCCESS;
}
}

View File

@ -7,6 +7,7 @@ namespace MyTube\API\External\Authentication\Handler;
use MyTube\API\External\User\Formatter\UserFormatter;
use MyTube\Handling\Registration\Handler\Command\ConfirmRegistration\ConfirmRegistrationCommandBuilder;
use MyTube\Handling\Registration\Handler\Command\ConfirmRegistration\ConfirmRegistrationCommandHandler;
use MyTube\Infrastructure\Request\Middleware\AnalyzeBodyMiddleware;
use MyTube\Infrastructure\Session\Middleware\SessionMiddleware;
use Laminas\Diactoros\Response\JsonResponse;
use Psr\Http\Message\ResponseInterface;
@ -25,10 +26,7 @@ class ConfirmRegistrationHandler implements RequestHandlerInterface
public function handle(ServerRequestInterface $request): ResponseInterface
{
$data = json_decode(
$request->getBody()->getContents(),
true
);
$data = $request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
$query = $this->builder->build(
Uuid::fromString($data['id']),

View File

@ -6,6 +6,7 @@ namespace MyTube\API\External\Authentication\Handler;
use MyTube\Handling\UserSession\Handler\Command\LoginUser\LoginUserCommandBuilder;
use MyTube\Handling\UserSession\Handler\Command\LoginUser\LoginUserCommandHandler;
use MyTube\Infrastructure\Request\Middleware\AnalyzeBodyMiddleware;
use MyTube\Infrastructure\Session\Middleware\SessionMiddleware;
use Laminas\Diactoros\Response\JsonResponse;
use Psr\Http\Message\ResponseInterface;
@ -23,10 +24,7 @@ class LoginUserHandler implements RequestHandlerInterface
public function handle(ServerRequestInterface $request): ResponseInterface
{
$session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
$data = json_decode(
$request->getBody()->getContents(),
true
);
$data = $request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
$query = $this->builder->build(
$session,

View File

@ -8,6 +8,7 @@ use MyTube\Handling\Registration\Handler\Command\RegisterUser\RegisterUserComman
use MyTube\Handling\Registration\Handler\Command\RegisterUser\RegisterUserCommandHandler;
use MyTube\Infrastructure\Exception\Middleware\MyTubeExceptionHandlerMiddleware;
use MyTube\Infrastructure\Logging\Logger\Logger;
use MyTube\Infrastructure\Request\Middleware\AnalyzeBodyMiddleware;
use MyTube\Infrastructure\Request\Middleware\AnalyzeHeaderMiddleware;
use MyTube\Infrastructure\Response\SuccessResponse;
use MyTube\Infrastructure\Session\Middleware\SessionMiddleware;
@ -28,10 +29,7 @@ class RegisterUserHandler implements RequestHandlerInterface
public function handle(ServerRequestInterface $request): ResponseInterface
{
$host = $request->getAttribute(AnalyzeHeaderMiddleware::HOST_ATTRIBUTE);
$data = json_decode(
$request->getBody()->getContents(),
true
);
$data = $request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
$query = $this->builder->build(
$data['username'],

View File

@ -0,0 +1,41 @@
<?php
use MyTube\API\External\Tag\Handler\AddAliasHandler;
use MyTube\API\External\Tag\Handler\CreateHandler;
use MyTube\API\External\Tag\Handler\ReadDetailsHandler;
use MyTube\API\External\Tag\Handler\ReadVideoListHandler;
return [
[
'name' => 'tag.create',
'path' => '/api/tag/create[/]',
'allowed_methods' => ['POST'],
'middleware' => [
CreateHandler::class,
],
],
[
'name' => 'tag.add-alias',
'path' => '/api/tag/add-alias[/]',
'allowed_methods' => ['POST'],
'middleware' => [
AddAliasHandler::class,
],
],
[
'name' => 'tag.read-details',
'path' => '/api/tag/read-details[/]',
'allowed_methods' => ['POST'],
'middleware' => [
ReadDetailsHandler::class,
],
],
[
'name' => 'tag.read-video-list',
'path' => '/api/tag/read-video-list[/]',
'allowed_methods' => ['POST'],
'middleware' => [
ReadVideoListHandler::class,
],
],
];

View File

@ -0,0 +1,27 @@
<?php
use MyTube\API\External\Tag\Handler\AddAliasHandler;
use MyTube\API\External\Tag\Handler\CreateHandler;
use MyTube\API\External\Tag\Handler\ReadDetailsHandler;
use MyTube\API\External\Tag\Handler\ReadVideoListHandler;
use MyTube\API\External\Tag\ResponseFormatter\AddAliasResponseFormatter;
use MyTube\API\External\Tag\ResponseFormatter\CreateResponseFormatter;
use MyTube\API\External\Tag\ResponseFormatter\ReadDetailsResponseFormatter;
use MyTube\API\External\Tag\ResponseFormatter\ReadVideoListResponseFormatter;
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
return [
'factories' => [
// Handler
AddAliasHandler::class => AutoWiringFactory::class,
CreateHandler::class => AutoWiringFactory::class,
ReadDetailsHandler::class => AutoWiringFactory::class,
ReadVideoListHandler::class => AutoWiringFactory::class,
// Response Formatter
AddAliasResponseFormatter::class => AutoWiringFactory::class,
CreateResponseFormatter::class => AutoWiringFactory::class,
ReadDetailsResponseFormatter::class => AutoWiringFactory::class,
ReadVideoListResponseFormatter::class => AutoWiringFactory::class,
],
];

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\Tag;
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,44 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\Tag\Handler;
use MyTube\Handling\Tag\Exception\TagAliasAlreadyExistsException;
use MyTube\Handling\Tag\Exception\TagNotFoundByIdException;
use MyTube\Handling\Tag\Handler\Command\AddAlias\AddAliasCommandHandler;
use MyTube\Handling\Tag\Handler\Command\AddAlias\AddAliasCommandBuilder;
use MyTube\API\External\Tag\ResponseFormatter\AddAliasResponseFormatter;
use MyTube\Infrastructure\Request\Middleware\AnalyzeBodyMiddleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use MyTube\Infrastructure\Response\SuccessResponse;
use Ramsey\Uuid\Uuid;
class AddAliasHandler implements RequestHandlerInterface
{
public function __construct(
private readonly AddAliasCommandHandler $addAliasCommandHandler,
private readonly AddAliasCommandBuilder $addAliasCommandBuilder,
private readonly AddAliasResponseFormatter $responseFormatter,
) {
}
/**
* @throws TagNotFoundByIdException
* @throws TagAliasAlreadyExistsException
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
$data = $request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
$addAliasCommand = $this->addAliasCommandBuilder->build(
Uuid::fromString($data['tagId']),
$data['description']
);
$result = $this->addAliasCommandHandler->execute($addAliasCommand);
return new SuccessResponse($this->responseFormatter->format($result));
}
}

View File

@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\Tag\Handler;
use MyTube\Handling\Tag\Exception\TagAlreadyExistsException;
use MyTube\Handling\Tag\Handler\Command\Create\CreateCommandHandler;
use MyTube\Handling\Tag\Handler\Command\Create\CreateCommandBuilder;
use MyTube\API\External\Tag\ResponseFormatter\CreateResponseFormatter;
use MyTube\Infrastructure\Request\Middleware\AnalyzeBodyMiddleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use MyTube\Infrastructure\Response\SuccessResponse;
class CreateHandler implements RequestHandlerInterface
{
public function __construct(
private readonly CreateCommandHandler $createCommandHandler,
private readonly CreateCommandBuilder $createCommandBuilder,
private readonly CreateResponseFormatter $responseFormatter,
) {
}
/**
* @throws TagAlreadyExistsException
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
$data = $request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
$createCommand = $this->createCommandBuilder->build(
$data['description']
);
$result = $this->createCommandHandler->execute($createCommand);
return new SuccessResponse($this->responseFormatter->format($result));
}
}

View File

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\Tag\Handler;
use MyTube\Handling\Tag\Exception\TagNotFoundByIdException;
use MyTube\Handling\Tag\Handler\Query\ReadDetails\ReadDetailsQueryHandler;
use MyTube\Handling\Tag\Handler\Query\ReadDetails\ReadDetailsQueryBuilder;
use MyTube\API\External\Tag\ResponseFormatter\ReadDetailsResponseFormatter;
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;
use Ramsey\Uuid\Uuid;
class ReadDetailsHandler implements RequestHandlerInterface
{
public function __construct(
private readonly ReadDetailsQueryHandler $readDetailsQueryHandler,
private readonly ReadDetailsQueryBuilder $readDetailsQueryBuilder,
private readonly ReadDetailsResponseFormatter $responseFormatter,
) {
}
/**
* @throws TagNotFoundByIdException
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
$data = $request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
$readDetailsQuery = $this->readDetailsQueryBuilder->build(
Uuid::fromString($data['tagId']),
);
$result = $this->readDetailsQueryHandler->execute($readDetailsQuery);
return new SuccessResponse($this->responseFormatter->format($result));
}
}

View File

@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\Tag\Handler;
use MyTube\Handling\Tag\Handler\Query\ReadVideoList\ReadVideoListQueryHandler;
use MyTube\Handling\Tag\Handler\Query\ReadVideoList\ReadVideoListQueryBuilder;
use MyTube\API\External\Tag\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;
use Ramsey\Uuid\Uuid;
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(
Uuid::fromString($data['tagId']),
$data['query'] ?? null,
$data['page'],
$data['perPage'],
);
$result = $this->readVideoListQueryHandler->execute($readVideoListQuery);
return new SuccessResponse($this->responseFormatter->format($result));
}
}

View File

@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\Tag\ResponseFormatter;
use MyTube\Handling\Tag\Handler\Command\AddAlias\AddAliasCommandResult;
class AddAliasResponseFormatter
{
public function format(AddAliasCommandResult $addAliasCommandResult): array
{
$alias = $addAliasCommandResult->getAlias();
$tag = $alias->getTag();
return [
'id' => $alias->getId()->toString(),
'description' => $alias->getDescription(),
'tag' => [
'id' => $tag->getId()->toString(),
'description' => $tag->getDescription()
],
];
}
}

View File

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\Tag\ResponseFormatter;
use MyTube\Handling\Tag\Handler\Command\Create\CreateCommandResult;
class CreateResponseFormatter
{
public function format(CreateCommandResult $createCommandResult): array
{
$tag = $createCommandResult->getTag();
return [
'id' => $tag->getId()->toString(),
'description' => $tag->getDescription(),
];
}
}

View File

@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\Tag\ResponseFormatter;
use MyTube\Data\Business\Entity\TagAlias;
use MyTube\Handling\Tag\Handler\Query\ReadDetails\ReadDetailsQueryResult;
class ReadDetailsResponseFormatter
{
public function format(ReadDetailsQueryResult $readDetailsQueryResult): array
{
$tag = $readDetailsQueryResult->getTag();
$aliases = [];
/** @var TagAlias $alias */
foreach ($tag->getAliases() as $alias) {
$aliases[] = $alias->getDescription();
}
return [
'id' => $tag->getId()->toString(),
'description' => $tag->getDescription(),
'aliases' => $aliases
];
}
}

View File

@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\Tag\ResponseFormatter;
use MyTube\Data\Business\Entity\Tag;
use MyTube\Data\Business\Entity\Video;
use MyTube\Handling\Tag\Handler\Query\ReadVideoList\ReadVideoListQueryResult;
class ReadVideoListResponseFormatter
{
public function format(ReadVideoListQueryResult $readVideoListQueryResult): array
{
$paginator = $readVideoListQueryResult->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(),
'tags' => $tags
];
}
return [
'total' => $paginator->count(),
'items' => $items,
];
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
use MyTube\API\External\TagList\Handler\ReadListHandler;
return [
[
'name' => 'tag-list.read-list',
'path' => '/api/tag-list/read-list[/]',
'allowed_methods' => ['POST'],
'middleware' => [
ReadListHandler::class,
],
],
];

View File

@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
use MyTube\API\External\TagList\Handler\ReadListHandler;
use MyTube\API\External\TagList\ResponseFormatter\ReadListResponseFormatter;
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
return [
'factories' => [
// Handler
ReadListHandler::class => AutoWiringFactory::class,
// Response Formatter
ReadListResponseFormatter::class => AutoWiringFactory::class,
],
];

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\TagList;
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,36 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\TagList\Handler;
use MyTube\Handling\TagList\Handler\Query\ReadList\ReadListQueryHandler;
use MyTube\Handling\TagList\Handler\Query\ReadList\ReadListQueryBuilder;
use MyTube\API\External\TagList\ResponseFormatter\ReadListResponseFormatter;
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 ReadListHandler implements RequestHandlerInterface
{
public function __construct(
private readonly ReadListQueryHandler $readListQueryHandler,
private readonly ReadListQueryBuilder $readListQueryBuilder,
private readonly ReadListResponseFormatter $responseFormatter,
) {
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
$data = $request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
$readListQuery = $this->readListQueryBuilder->build(
$data['query'] ?? null,
);
$result = $this->readListQueryHandler->execute($readListQuery);
return new SuccessResponse($this->responseFormatter->format($result));
}
}

View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\TagList\ResponseFormatter;
use MyTube\Data\Business\Entity\Tag;
use MyTube\Handling\TagList\Handler\Query\ReadList\ReadListQueryResult;
class ReadListResponseFormatter
{
public function format(ReadListQueryResult $readListQueryResult): array
{
$tags = $readListQueryResult->getItems();
$items = [];
/** @var Tag $tag */
foreach ($tags as $tag) {
$items[] = [
'id' => $tag->getId()->toString(),
'description' => $tag->getDescription(),
];
}
return [
'total' => count($items),
'items' => $items,
];
}
}

View File

@ -26,10 +26,7 @@ class ChangePasswordHandler implements RequestHandlerInterface
/** @var User $user */
$user = $request->getAttribute(LoggedInUserMiddleware::USER_KEY);
$data = json_decode(
$request->getBody()->getContents(),
true
);
$data = $request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
$query = $this->builder->build(
$user,

View File

@ -7,6 +7,7 @@ namespace MyTube\API\External\User\Handler;
use MyTube\Data\Business\Entity\User;
use MyTube\Handling\User\Handler\Command\ChangeUsername\ChangeUsernameCommandBuilder;
use MyTube\Handling\User\Handler\Command\ChangeUsername\ChangeUsernameCommandHandler;
use MyTube\Infrastructure\Request\Middleware\AnalyzeBodyMiddleware;
use MyTube\Infrastructure\Response\SuccessResponse;
use MyTube\Infrastructure\Session\Middleware\LoggedInUserMiddleware;
use Psr\Http\Message\ResponseInterface;
@ -25,11 +26,7 @@ class ChangeUsernameHandler implements RequestHandlerInterface
{
/** @var User $user */
$user = $request->getAttribute(LoggedInUserMiddleware::USER_KEY);
$data = json_decode(
$request->getBody()->getContents(),
true
);
$data = $request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
$query = $this->builder->build(
$user,

View File

@ -8,6 +8,7 @@ use MyTube\API\External\User\Formatter\UserFormatter;
use MyTube\Handling\User\Handler\Command\CreateUser\CreateUserCommandBuilder;
use MyTube\Handling\User\Handler\Command\CreateUser\CreateUserCommandHandler;
use Laminas\Diactoros\Response\JsonResponse;
use MyTube\Infrastructure\Request\Middleware\AnalyzeBodyMiddleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
@ -23,10 +24,7 @@ class CreateUserHandler implements RequestHandlerInterface
public function handle(ServerRequestInterface $request): ResponseInterface
{
$data = json_decode(
$request->getBody()->getContents(),
true
);
$data = $request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
$query = $this->builder->build(
$data['username'],

View File

@ -8,6 +8,7 @@ use MyTube\Handling\Video\Exception\VideoNotFoundByIdException;
use MyTube\Handling\Video\Handler\Query\ReadDetails\ReadDetailsQueryHandler;
use MyTube\Handling\Video\Handler\Query\ReadDetails\ReadDetailsQueryBuilder;
use MyTube\API\External\Video\ResponseFormatter\ReadDetailsResponseFormatter;
use MyTube\Infrastructure\Request\Middleware\AnalyzeBodyMiddleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
@ -28,10 +29,7 @@ class ReadDetailsHandler implements RequestHandlerInterface
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
$data = json_decode(
$request->getBody()->getContents(),
true
);
$data = $request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
$readDetailsQuery = $this->readDetailsQueryBuilder->build(
Uuid::fromString($data['videoId'])

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace MyTube\API\External\Video\ResponseFormatter;
use MyTube\Data\Business\Entity\Tag;
use MyTube\Handling\Video\Handler\Query\ReadDetails\ReadDetailsQueryResult;
class ReadDetailsResponseFormatter
@ -12,9 +13,20 @@ class ReadDetailsResponseFormatter
{
$video = $readDetailsQueryResult->getVideo();
$tags = [];
/** @var Tag $tag */
foreach ($video->getTags() as $tag) {
$tags = [
'id' => $tag->getId(),
'description' => $tag->getDescription(),
];
}
return [
'id' => $video->getId(),
'title' => $video->getTitle()
'title' => $video->getTitle(),
'tags' => $tags,
];
}
}

View File

@ -1,6 +1,7 @@
<?php
use MyTube\API\External\VideoList\Handler\ReadListHandler;
use MyTube\API\External\VideoList\Handler\UploadHandler;
return [
[
@ -11,4 +12,12 @@ return [
ReadListHandler::class
],
],
[
'name' => 'video-list.upload',
'path' => '/api/video-list/upload[/]',
'allowed_methods' => ['POST'],
'middleware' => [
UploadHandler::class
],
],
];

View File

@ -1,15 +1,17 @@
<?php
use MyTube\API\External\Video\Handler\StreamHandler;
use MyTube\API\External\Video\Handler\UploadHandler;
use MyTube\API\External\VideoList\Handler\UploadHandler;
use MyTube\API\External\VideoList\Handler\ReadListHandler;
use MyTube\API\External\VideoList\ResponseFormatter\ReadListResponseFormatter;
use MyTube\API\External\VideoList\ResponseFormatter\UploadResponseFormatter;
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
return [
'factories' => [
ReadListHandler::class => AutoWiringFactory::class,
UploadHandler::class => AutoWiringFactory::class,
ReadListResponseFormatter::class => AutoWiringFactory::class,
UploadResponseFormatter::class => AutoWiringFactory::class,
],
];

View File

@ -5,8 +5,9 @@ declare(strict_types=1);
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\Handling\VideoList\Handler\Query\ReadList\ReadListQueryHandler;
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);

View File

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\VideoList\Handler;
use Laminas\Diactoros\Response\JsonResponse;
use Laminas\Http\Response;
use MyTube\Handling\VideoList\Handler\Command\Upload\UploadCommandHandler;
use MyTube\Handling\VideoList\Handler\Command\Upload\UploadCommandBuilder;
use MyTube\API\External\VideoList\ResponseFormatter\UploadResponseFormatter;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use MyTube\Infrastructure\Response\SuccessResponse;
class UploadHandler implements RequestHandlerInterface
{
public function __construct(
private readonly UploadCommandHandler $uploadCommandHandler,
private readonly UploadCommandBuilder $uploadCommandBuilder,
private readonly UploadResponseFormatter $responseFormatter,
) {
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
$uploadedFiles = $request->getUploadedFiles();
if (count($uploadedFiles) < 1) {
return new JsonResponse('Upload at least one File', Response::STATUS_CODE_400);
}
$uploadCommand = $this->uploadCommandBuilder->build(
$request->getUploadedFiles()
);
$result = $this->uploadCommandHandler->execute($uploadCommand);
return new SuccessResponse($this->responseFormatter->format($result));
}
}

View File

@ -4,22 +4,41 @@ declare(strict_types=1);
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) {
$result[] = [
$tags = [];
/** @var Tag $tag */
foreach ($video->getTags() as $tag) {
$tags[] = [
'id' => $tag->getId(),
'description' => $tag->getDescription()
];
}
$items[] = [
'title' => $video->getTitle(),
'id' => $video->getId()->toString(),
'id' => $video->getId(),
'tags' => $tags
];
}
return $result;
return [
'total' => $paginator->count(),
'items' => $items,
];
}
}

View File

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace MyTube\API\External\VideoList\ResponseFormatter;
use MyTube\Handling\VideoList\Handler\Command\Upload\UploadCommandResult;
use MyTube\Handling\VideoList\Model\UploadedFileResult;
class UploadResponseFormatter
{
public function format(UploadCommandResult $uploadCommandResult): array
{
$uploadedFileResults = $uploadCommandResult->getUploadedFileResults();
$details = [];
$successCount = 0;
$failCount = 0;
/** @var UploadedFileResult $uploadedFileResult */
foreach ($uploadedFileResults as $uploadedFileResult) {
$detail = [
'file' => $uploadedFileResult->getUploadedFile()->getClientFilename(),
'success' => $uploadedFileResult->getSuccess(),
];
if ($uploadedFileResult->getSuccess()) {
$detail['id'] = $uploadedFileResult->getVideo()->getId()->toString();
$successCount++;
} else {
$detail['error'] = $uploadedFileResult->getException()->getMessage();
$failCount++;
}
$details[] = $detail;
}
return [
'total' => count($uploadedFileResults),
'failed' => $failCount,
'succeeded' => $successCount,
'details' => $details
];
}
}

View File

@ -0,0 +1,119 @@
<?php
namespace MyTube\Data\Business\Entity;
use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use MyTube\Infrastructure\UuidGenerator\UuidGenerator;
use Ramsey\Uuid\UuidInterface;
/**
* @ORM\Entity(repositoryClass="MyTube\Data\Business\Repository\TagRepository")
* @ORM\Table(name="tag")
*/
class Tag {
/**
* @ORM\Id
* @ORM\Column(name="id", type="uuid_binary_ordered_time")
*/
private UuidInterface $id;
/** @ORM\Column(name="description", type="string") */
private string $description;
/**
* @ORM\ManyToMany(targetEntity="Video", mappedBy="tags")
* @ORM\JoinTable(name="video_tag")
*/
private Collection $videos;
/** @ORM\OneToMany(targetEntity="TagAlias", mappedBy="tag") */
private Collection $aliases;
/** @ORM\Column(name="created_at", type="datetime") */
private DateTime $createdAt;
/** @ORM\Column(name="updated_at", type="datetime") */
private DateTime $updatedAt;
public function __construct() {
$this->id = UuidGenerator::generate();
$this->aliases = new ArrayCollection();
$this->videos = new ArrayCollection();
$now = new DateTime();
$this->setCreatedAt($now);
$this->setUpdatedAt($now);
}
public function getId(): UuidInterface {
return $this->id;
}
public function getDescription(): string {
return $this->description;
}
public function setDescription(string $description): void {
$this->description = $description;
}
public function getVideos(): Collection
{
return $this->videos;
}
public function setVideos(Collection $videos): void
{
$this->videos = $videos;
}
public function addVideo(Video $video): void
{
if (!$this->videos->contains($video)) {
$this->videos->add($video);
}
}
public function removeVideo(Video $video): void
{
if ($this->videos->contains($video)) {
$this->videos->removeElement($video);
}
}
public function getAliases(): Collection
{
return $this->aliases;
}
public function setAliases(Collection $aliases): void
{
$this->aliases = $aliases;
}
public function addAlias(TagAlias $alias): void
{
if (!$this->aliases->contains($alias)) {
$this->aliases->add($alias);
}
}
public function removeAlias(TagAlias $alias): void
{
if ($this->aliases->contains($alias)) {
$this->aliases->removeElement($alias);
}
}
public function getCreatedAt(): DateTime {
return $this->createdAt;
}
public function setCreatedAt(DateTime $createdAt): void {
$this->createdAt = $createdAt;
}
public function getUpdatedAt(): DateTime {
return $this->updatedAt;
}
public function setUpdatedAt(DateTime $updatedAt): void {
$this->updatedAt = $updatedAt;
}
}

View File

@ -0,0 +1,90 @@
<?php
namespace MyTube\Data\Business\Entity;
use DateTime;
use Doctrine\ORM\Mapping as ORM;
use MyTube\Infrastructure\UuidGenerator\UuidGenerator;
use Ramsey\Uuid\UuidInterface;
/**
* @ORM\Entity(repositoryClass="MyTube\Data\Business\Repository\TagAliasRepository")
* @ORM\Table(name="tag_alias")
*/
class TagAlias {
/**
* @ORM\Id
* @ORM\Column(name="id", type="uuid_binary_ordered_time")
*/
private UuidInterface $id;
/** @ORM\Column(name="tag_id", type="uuid_binary_ordered_time") */
private UuidInterface $tagId;
/**
* @ORM\ManyToOne(targetEntity="Tag", inversedBy="aliases")
* @ORM\JoinColumn(name="tag_id", referencedColumnName="id")
*/
private Tag $tag;
/** @ORM\Column(name="description", type="string") */
private string $description;
/** @ORM\Column(name="created_at", type="datetime") */
private DateTime $createdAt;
/** @ORM\Column(name="updated_at", type="datetime") */
private DateTime $updatedAt;
public function __construct() {
$this->id = UuidGenerator::generate();
$now = new DateTime();
$this->setCreatedAt($now);
$this->setUpdatedAt($now);
}
public function getId(): UuidInterface {
return $this->id;
}
public function getTagId(): UuidInterface
{
return $this->tagId;
}
public function setTagId(UuidInterface $tagId): void
{
$this->tagId = $tagId;
}
public function getTag(): Tag
{
return $this->tag;
}
public function setTag(Tag $tag): void
{
$this->tag = $tag;
}
public function getDescription(): string {
return $this->description;
}
public function setDescription(string $description): void {
$this->description = $description;
}
public function getCreatedAt(): DateTime {
return $this->createdAt;
}
public function setCreatedAt(DateTime $createdAt): void {
$this->createdAt = $createdAt;
}
public function getUpdatedAt(): DateTime {
return $this->updatedAt;
}
public function setUpdatedAt(DateTime $updatedAt): void {
$this->updatedAt = $updatedAt;
}
}

View File

@ -3,6 +3,8 @@
namespace MyTube\Data\Business\Entity;
use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use MyTube\Infrastructure\UuidGenerator\UuidGenerator;
use Ramsey\Uuid\UuidInterface;
@ -24,6 +26,12 @@ class Video {
/** @ORM\Column(name="directory_path", type="string") */
private ?string $directoryPath;
/**
* @ORM\ManyToMany(targetEntity="Tag", inversedBy="videos")
* @ORM\JoinTable(name="video_tag")
*/
private Collection $tags;
/** @ORM\Column(name="created_at", type="datetime") */
private DateTime $createdAt;
@ -33,7 +41,9 @@ class Video {
public function __construct() {
$this->id = UuidGenerator::generate();
$this->tags = new ArrayCollection();
$now = new DateTime();
$this->setCreatedAt($now);
$this->setUpdatedAt($now);
@ -47,7 +57,6 @@ class Video {
public function getTitle(): string {
return $this->title;
}
public function setTitle(string $title): void {
$this->title = $title;
}
@ -55,15 +64,34 @@ class Video {
public function getDirectoryPath(): ?string {
return $this->directoryPath;
}
public function setDirectoryPath(?string $directoryPath): void {
$this->directoryPath = $directoryPath;
}
public function getTags(): Collection
{
return $this->tags;
}
public function setTags(Collection $tags): void
{
$this->tags = $tags;
}
public function addTag(Tag $tag): void
{
if (!$this->tags->contains($tag)) {
$this->tags->add($tag);
}
}
public function removeTag(Tag $tag): void
{
if ($this->tags->contains($tag)) {
$this->tags->removeElement($tag);
}
}
public function getCreatedAt(): DateTime {
return $this->createdAt;
}
public function setCreatedAt(DateTime $createdAt): void {
$this->createdAt = $createdAt;
}
@ -71,7 +99,6 @@ class Video {
public function getUpdatedAt(): DateTime {
return $this->updatedAt;
}
public function setUpdatedAt(DateTime $updatedAt): void {
$this->updatedAt = $updatedAt;
}

View File

@ -0,0 +1,8 @@
<?php
namespace MyTube\Data\Business\Repository;
use Doctrine\ORM\EntityRepository;
class TagAliasRepository extends EntityRepository {
}

View File

@ -0,0 +1,24 @@
<?php
namespace MyTube\Data\Business\Repository;
use Doctrine\ORM\EntityRepository;
class TagRepository extends EntityRepository {
public function findByFilter(
?string $query,
): array
{
$queryBuilder = $this->createQueryBuilder('t');
if ($query !== null) {
$query = '%'.$query.'%';
$queryBuilder
->where('t.description like :query')
->setParameter('query', $query);
}
return $queryBuilder->getQuery()->execute();
}
}

View File

@ -5,24 +5,37 @@ namespace MyTube\Data\Business\Repository;
use Doctrine\ORM\Tools\Pagination\Paginator;
use MyTube\Data\Business\Entity\Registration;
use Doctrine\ORM\EntityRepository;
use MyTube\Data\Business\Entity\Tag;
use Ramsey\Uuid\Doctrine\UuidBinaryOrderedTimeType;
class VideoRepository extends EntityRepository {
public function findByFilter(
string $identifier
?string $query,
int $page,
int $perPage,
?Tag $tag = null,
): 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);
}
if ($tag !== null) {
$queryBuilder
->join('v.tags', 't')
->andWhere('t.id = :tagId')
->setParameter('tagId', $tag->getId(), UuidBinaryOrderedTimeType::NAME);
}
$queryBuilder->setFirstResult($perPage * ($page - 1));
$queryBuilder->setMaxResults($perPage);
return new Paginator($queryBuilder->getQuery());
}
}

View File

@ -0,0 +1,44 @@
<?php
use MyTube\Handling\Tag\Builder\TagAliasBuilder;
use MyTube\Handling\Tag\Builder\TagBuilder;
use MyTube\Handling\Tag\Handler\Command\AddAlias\AddAliasCommandBuilder;
use MyTube\Handling\Tag\Handler\Command\AddAlias\AddAliasCommandHandler;
use MyTube\Handling\Tag\Handler\Command\Create\CreateCommandBuilder;
use MyTube\Handling\Tag\Handler\Command\Create\CreateCommandHandler;
use MyTube\Handling\Tag\Handler\Query\ReadDetails\ReadDetailsQueryBuilder;
use MyTube\Handling\Tag\Handler\Query\ReadDetails\ReadDetailsQueryHandler;
use MyTube\Handling\Tag\Handler\Query\ReadVideoList\ReadVideoListQueryBuilder;
use MyTube\Handling\Tag\Handler\Query\ReadVideoList\ReadVideoListQueryHandler;
use MyTube\Handling\Tag\Rule\TagAliasExistsRule;
use MyTube\Handling\Tag\Rule\TagExistsRule;
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
use Reinfi\DependencyInjection\Factory\InjectionFactory;
return [
'factories' => [
/// Rule
TagExistsRule::class => InjectionFactory::class,
TagAliasExistsRule::class => InjectionFactory::class,
/// Builder
TagBuilder::class => AutoWiringFactory::class,
TagAliasBuilder::class => AutoWiringFactory::class,
/// CQRS
// Add Alias
AddAliasCommandBuilder::class => AutoWiringFactory::class,
AddAliasCommandHandler::class => InjectionFactory::class,
// Create
CreateCommandBuilder::class => AutoWiringFactory::class,
CreateCommandHandler::class => AutoWiringFactory::class,
// Read Details
ReadDetailsQueryBuilder::class => AutoWiringFactory::class,
ReadDetailsQueryHandler::class => InjectionFactory::class,
// Read Video List
ReadVideoListQueryBuilder::class => AutoWiringFactory::class,
ReadVideoListQueryHandler::class => InjectionFactory::class,
],
];

View File

@ -0,0 +1,21 @@
<?php
namespace MyTube\Handling\Tag\Builder;
use MyTube\Data\Business\Entity\Tag;
use MyTube\Data\Business\Entity\TagAlias;
class TagAliasBuilder
{
public function build(
Tag $tag,
string $description,
): TagAlias
{
$tagAlias = new TagAlias();
$tagAlias->setTag($tag);
$tagAlias->setDescription($description);
return $tagAlias;
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace MyTube\Handling\Tag\Builder;
use MyTube\Data\Business\Entity\Tag;
class TagBuilder
{
public function build(
string $description,
): Tag
{
$tag = new Tag();
$tag->setDescription($description);
return $tag;
}
}

View File

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

View File

@ -0,0 +1,25 @@
<?php
namespace MyTube\Handling\Tag\Exception;
use MyTube\Infrastructure\Exception\ErrorCode;
use MyTube\Infrastructure\Exception\ErrorDomain;
use MyTube\Infrastructure\Exception\Exception\MyTubeException;
use Ramsey\Uuid\UuidInterface;
class TagAliasAlreadyExistsException extends MyTubeException {
private const MESSAGE = "The TagAlias '%s' already exists!";
public function __construct(string $description)
{
parent::__construct(
sprintf(
self::MESSAGE,
$description
),
ErrorDomain::TagAlias,
ErrorCode::AlreadyExists
);
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace MyTube\Handling\Tag\Exception;
use MyTube\Infrastructure\Exception\ErrorCode;
use MyTube\Infrastructure\Exception\ErrorDomain;
use MyTube\Infrastructure\Exception\Exception\MyTubeException;
use Ramsey\Uuid\UuidInterface;
class TagAlreadyExistsException extends MyTubeException {
private const MESSAGE = "The Tag '%s' already exists!";
public function __construct(string $description)
{
parent::__construct(
sprintf(
self::MESSAGE,
$description
),
ErrorDomain::Tag,
ErrorCode::AlreadyExists
);
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace MyTube\Handling\Tag\Exception;
use MyTube\Infrastructure\Exception\ErrorCode;
use MyTube\Infrastructure\Exception\ErrorDomain;
use MyTube\Infrastructure\Exception\Exception\MyTubeException;
use Ramsey\Uuid\UuidInterface;
class TagNotFoundByIdException extends MyTubeException {
private const MESSAGE = 'The Tag with the Id %s was not found!';
public function __construct(UuidInterface $id)
{
parent::__construct(
sprintf(
self::MESSAGE,
$id->toString()
),
ErrorDomain::Tag,
ErrorCode::NotFound
);
}
}

View File

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Tag\Handler\Command\AddAlias;
use Ramsey\Uuid\UuidInterface;
class AddAliasCommand
{
public function __construct(
private readonly UuidInterface $tagId,
private readonly string $description,
) {
}
public function getTagId(): UuidInterface
{
return $this->tagId;
}
public function getDescription(): string
{
return $this->description;
}
}

View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Tag\Handler\Command\AddAlias;
use Ramsey\Uuid\UuidInterface;
class AddAliasCommandBuilder
{
public function build(
UuidInterface $tagId,
string $description,
): AddAliasCommand {
return new AddAliasCommand(
$tagId,
$description
);
}
}

View File

@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Tag\Handler\Command\AddAlias;
use MyTube\Data\Business\Manager\MyTubeEntityManager;
use MyTube\Data\Business\Repository\TagRepository;
use MyTube\Handling\Tag\Builder\TagAliasBuilder;
use MyTube\Handling\Tag\Exception\TagAliasAlreadyExistsException;
use MyTube\Handling\Tag\Exception\TagNotFoundByIdException;
use MyTube\Handling\Tag\Rule\TagAliasExistsRule;
use Reinfi\DependencyInjection\Annotation\Inject;
use Reinfi\DependencyInjection\Annotation\InjectDoctrineRepository;
class AddAliasCommandHandler
{
/**
* @Inject("MyTube\Handling\Tag\Rule\TagAliasExistsRule")
* @InjectDoctrineRepository(
* entityManager="MyTube\Data\Business\Manager\MyTubeEntityManager",
* entity="MyTube\Data\Business\Entity\Tag"
* )
* @Inject("MyTube\Handling\Tag\Builder\TagAliasBuilder")
* @Inject("MyTube\Data\Business\Manager\MyTubeEntityManager")
*/
public function __construct(
private readonly TagAliasExistsRule $existsRule,
private readonly TagRepository $tagRepository,
private readonly TagAliasBuilder $aliasBuilder,
private readonly MyTubeEntityManager $entityManager,
) {
}
/**
* @throws TagAliasAlreadyExistsException
* @throws TagNotFoundByIdException
*/
public function execute(AddAliasCommand $addAliasCommand): AddAliasCommandResult
{
$tagId = $addAliasCommand->getTagId();
$description = $addAliasCommand->getDescription();
if ($this->existsRule->appliesTo($description)) {
throw new TagAliasAlreadyExistsException($description);
}
$tag = $this->tagRepository->findOneBy(['id' => $tagId]);
if ($tag === null) {
throw new TagNotFoundByIdException($tagId);
}
$tagAlias = $this->aliasBuilder->build(
$tag,
$description
);
$this->entityManager->persist($tagAlias);
$this->entityManager->flush();
return new AddAliasCommandResult($tagAlias);
}
}

View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Tag\Handler\Command\AddAlias;
use MyTube\Data\Business\Entity\TagAlias;
class AddAliasCommandResult
{
public function __construct(
private readonly TagAlias $alias,
) {
}
public function getAlias(): TagAlias
{
return $this->alias;
}
}

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Tag\Handler\Command\Create;
class CreateCommand
{
public function __construct(
private readonly string $description
) {
}
public function getDescription(): string
{
return $this->description;
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Tag\Handler\Command\Create;
class CreateCommandBuilder
{
public function build(
string $description
): CreateCommand {
return new CreateCommand(
$description
);
}
}

View File

@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Tag\Handler\Command\Create;
use MyTube\Data\Business\Manager\MyTubeEntityManager;
use MyTube\Handling\Tag\Builder\TagBuilder;
use MyTube\Handling\Tag\Exception\TagAlreadyExistsException;
use MyTube\Handling\Tag\Rule\TagExistsRule;
class CreateCommandHandler
{
public function __construct(
private readonly TagExistsRule $existsRule,
private readonly TagBuilder $tagBuilder,
private readonly MyTubeEntityManager $entityManager
) {
}
/**
* @throws TagAlreadyExistsException
*/
public function execute(CreateCommand $createCommand): CreateCommandResult
{
$description = $createCommand->getDescription();
if ($this->existsRule->appliesTo($description)) {
throw new TagAlreadyExistsException($description);
}
$tag = $this->tagBuilder->build($description);
$this->entityManager->persist($tag);
$this->entityManager->flush();
return new CreateCommandResult($tag);
}
}

View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Tag\Handler\Command\Create;
use MyTube\Data\Business\Entity\Tag;
class CreateCommandResult
{
public function __construct(
private readonly Tag $tag,
) {
}
public function getTag(): Tag
{
return $this->tag;
}
}

View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Tag\Handler\Query\ReadDetails;
use Ramsey\Uuid\UuidInterface;
class ReadDetailsQuery
{
public function __construct(
private readonly UuidInterface $tagId,
) {
}
public function getTagId(): UuidInterface
{
return $this->tagId;
}
}

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Tag\Handler\Query\ReadDetails;
use Ramsey\Uuid\UuidInterface;
class ReadDetailsQueryBuilder
{
public function build(
UuidInterface $tagId,
): ReadDetailsQuery {
return new ReadDetailsQuery(
$tagId
);
}
}

View File

@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Tag\Handler\Query\ReadDetails;
use MyTube\Data\Business\Repository\TagRepository;
use MyTube\Handling\Tag\Exception\TagNotFoundByIdException;
use Reinfi\DependencyInjection\Annotation\InjectDoctrineRepository;
class ReadDetailsQueryHandler
{
/**
* @InjectDoctrineRepository(
* entityManager="MyTube\Data\Business\Manager\MyTubeEntityManager",
* entity="MyTube\Data\Business\Entity\Tag"
* )
*/
public function __construct(
private readonly TagRepository $tagRepository,
) {
}
/**
* @throws TagNotFoundByIdException
*/
public function execute(ReadDetailsQuery $readDetailsQuery): ReadDetailsQueryResult
{
$tagId = $readDetailsQuery->getTagId();
$tag = $this->tagRepository->findOneBy(['id' => $tagId]);
if ($tag === null) {
throw new TagNotFoundByIdException($tagId);
}
return new ReadDetailsQueryResult($tag);
}
}

View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Tag\Handler\Query\ReadDetails;
use MyTube\Data\Business\Entity\Tag;
class ReadDetailsQueryResult
{
public function __construct(
private readonly Tag $tag,
) {
}
public function getTag(): Tag
{
return $this->tag;
}
}

View File

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Tag\Handler\Query\ReadVideoList;
use Ramsey\Uuid\UuidInterface;
class ReadVideoListQuery
{
public function __construct(
private readonly UuidInterface $tagId,
private readonly ?string $query,
private readonly int $page,
private readonly int $perPage,
) {
}
public function getTagId(): UuidInterface
{
return $this->tagId;
}
public function getQuery(): ?string
{
return $this->query;
}
public function getPage(): int
{
return $this->page;
}
public function getPerPage(): int
{
return $this->perPage;
}
}

View File

@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Tag\Handler\Query\ReadVideoList;
use Ramsey\Uuid\UuidInterface;
class ReadVideoListQueryBuilder
{
public function build(
UuidInterface $tagId,
?string $query,
int $page,
int $perPage,
): ReadVideoListQuery {
return new ReadVideoListQuery(
$tagId,
$query,
$page,
$perPage,
);
}
}

View File

@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Tag\Handler\Query\ReadVideoList;
use MyTube\Data\Business\Repository\TagRepository;
use MyTube\Data\Business\Repository\VideoRepository;
use MyTube\Handling\Tag\Exception\TagNotFoundByIdException;
use Reinfi\DependencyInjection\Annotation\InjectDoctrineRepository;
class ReadVideoListQueryHandler
{
/**
* @InjectDoctrineRepository(
* entityManager="MyTube\Data\Business\Manager\MyTubeEntityManager",
* entity="MyTube\Data\Business\Entity\Tag"
* )
* @InjectDoctrineRepository(
* entityManager="MyTube\Data\Business\Manager\MyTubeEntityManager",
* entity="MyTube\Data\Business\Entity\Video"
* )
*/
public function __construct(
private readonly TagRepository $tagRepository,
private readonly VideoRepository $videoRepository,
) {
}
/**
* @throws TagNotFoundByIdException
*/
public function execute(ReadVideoListQuery $readVideoListQuery): ReadVideoListQueryResult
{
$tagId = $readVideoListQuery->getTagId();
$tag = $this->tagRepository->findOneBy(['id' => $tagId]);
if ($tag === null) {
throw new TagNotFoundByIdException($tagId);
}
return new ReadVideoListQueryResult(
$this->videoRepository->findByFilter(
query: $readVideoListQuery->getQuery(),
page: $readVideoListQuery->getPage(),
perPage: $readVideoListQuery->getPerPage(),
tag: $tag
)
);
}
}

View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Tag\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,27 @@
<?php
namespace MyTube\Handling\Tag\Rule;
use MyTube\Data\Business\Repository\TagAliasRepository;
use Reinfi\DependencyInjection\Annotation\InjectDoctrineRepository;
class TagAliasExistsRule
{
/**
* @InjectDoctrineRepository(
* entityManager="MyTube\Data\Business\Manager\MyTubeEntityManager",
* entity="MyTube\Data\Business\Entity\TagAlias"
* )
*/
public function __construct(
private readonly TagAliasRepository $tagAliasRepository,
) {
}
public function appliesTo(
string $description,
): bool
{
return $this->tagAliasRepository->findOneBy(['description' => $description]) !== null;
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace MyTube\Handling\Tag\Rule;
use MyTube\Data\Business\Entity\Tag;
use MyTube\Data\Business\Repository\TagRepository;
use Reinfi\DependencyInjection\Annotation\InjectDoctrineRepository;
class TagExistsRule
{
/**
* @InjectDoctrineRepository(
* entityManager="MyTube\Data\Business\Manager\MyTubeEntityManager",
* entity="MyTube\Data\Business\Entity\Tag"
* )
*/
public function __construct(
private readonly TagRepository $tagRepository,
) {
}
public function appliesTo(
string $description,
): bool
{
return $this->tagRepository->findOneBy(['description' => $description]) !== null;
}
}

View File

@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
use MyTube\Handling\TagList\Handler\Query\ReadList\ReadListQueryHandler;
use MyTube\Handling\TagList\Handler\Query\ReadList\ReadListQueryBuilder;
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
use Reinfi\DependencyInjection\Factory\InjectionFactory;
return [
'factories' => [
/// CQRS
// ReadList
ReadListQueryBuilder::class => AutoWiringFactory::class,
ReadListQueryHandler::class => InjectionFactory::class,
],
];

View File

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

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\TagList\Handler\Query\ReadList;
class ReadListQuery
{
public function __construct(
private readonly ?string $query,
) {
}
public function getQuery(): ?string
{
return $this->query;
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\TagList\Handler\Query\ReadList;
class ReadListQueryBuilder
{
public function build(
?string $query,
): ReadListQuery {
return new ReadListQuery(
$query,
);
}
}

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\TagList\Handler\Query\ReadList;
use MyTube\Data\Business\Repository\TagRepository;
use Reinfi\DependencyInjection\Annotation\InjectDoctrineRepository;
class ReadListQueryHandler
{
/**
* @InjectDoctrineRepository(
* entityManager="MyTube\Data\Business\Manager\MyTubeEntityManager",
* entity="MyTube\Data\Business\Entity\Tag"
* )
*/
public function __construct(
private readonly TagRepository $tagRepository
) {
}
public function execute(ReadListQuery $readListQuery): ReadListQueryResult
{
return new ReadListQueryResult(
$this->tagRepository->findByFilter(
$readListQuery->getQuery(),
)
);
}
}

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\TagList\Handler\Query\ReadList;
class ReadListQueryResult
{
public function __construct(
private readonly array $items
) {
}
public function getItems(): array
{
return $this->items;
}
}

View File

@ -10,6 +10,14 @@ use MyTube\Handling\Video\Handler\Query\Stream\StreamQueryBuilder;
use MyTube\Handling\Video\Handler\Query\Stream\StreamQueryHandler;
use MyTube\Handling\Video\Handler\Query\Thumbnail\ThumbnailQueryBuilder;
use MyTube\Handling\Video\Handler\Query\Thumbnail\ThumbnailQueryHandler;
use MyTube\Handling\Video\Analyzer\VideoTitleAnalyzer;
use MyTube\Handling\Video\Pipeline\Upload\Step\AnalyzeTitleStep;
use MyTube\Handling\Video\Pipeline\Upload\Step\BuildVideoStep;
use MyTube\Handling\Video\Pipeline\Upload\Step\CheckVideoStep;
use MyTube\Handling\Video\Pipeline\Upload\Step\SaveEntityStep;
use MyTube\Handling\Video\Pipeline\Upload\Step\UploadFileStep;
use MyTube\Handling\Video\Pipeline\Upload\UploadPipeline;
use MyTube\Handling\Video\Rule\VideoExistsRule;
use MyTube\Handling\Video\Uploader\VideoUploader;
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
use Reinfi\DependencyInjection\Factory\InjectionFactory;
@ -17,6 +25,9 @@ use Reinfi\DependencyInjection\Factory\InjectionFactory;
return [
'factories' => [
/// Analyzer
VideoTitleAnalyzer::class => InjectionFactory::class,
/// Uploader
VideoUploader::class => AutoWiringFactory::class,
@ -24,6 +35,9 @@ return [
VideoBuilder::class => AutoWiringFactory::class,
VideoImageBuilder::class => AutoWiringFactory::class,
/// Rule
VideoExistsRule::class => InjectionFactory::class,
/// CQRS
// Stream Query
StreamQueryHandler::class => InjectionFactory::class,
@ -37,5 +51,14 @@ return [
// Read Details
ReadDetailsQueryHandler::class => InjectionFactory::class,
ReadDetailsQueryBuilder::class => AutoWiringFactory::class,
/// Pipeline
// Upload
UploadPipeline::class => AutoWiringFactory::class,
CheckVideoStep::class => AutoWiringFactory::class,
BuildVideoStep::class => AutoWiringFactory::class,
AnalyzeTitleStep::class => AutoWiringFactory::class,
UploadFileStep::class => AutoWiringFactory::class,
SaveEntityStep::class => AutoWiringFactory::class,
],
];

View File

@ -0,0 +1,66 @@
<?php
namespace MyTube\Handling\Video\Analyzer;
use Exception;
use MyTube\Data\Business\Entity\Tag;
use MyTube\Data\Business\Entity\TagAlias;
use MyTube\Data\Business\Entity\Video;
use MyTube\Data\Business\Repository\TagRepository;
use Psr\Http\Message\UploadedFileInterface;
use Ramsey\Uuid\UuidInterface;
use Reinfi\DependencyInjection\Annotation\InjectDoctrineRepository;
class VideoTitleAnalyzer
{
/**
* @InjectDoctrineRepository(
* entityManager="MyTube\Data\Business\Manager\MyTubeEntityManager",
* entity="MyTube\Data\Business\Entity\Tag"
* )
*/
public function __construct(
private readonly TagRepository $tagRepository,
) {
}
public function analyze(
Video $video
): array {
$title = $this->normalizeString($video->getTitle());
$tags = $this->tagRepository->findAll();
$matches = [];
/** @var Tag $tag */
foreach ($tags as $tag) {
if (str_contains($title, $this->normalizeString($tag->getDescription()))) {
$matches[] = $tag;
continue;
}
/** @var TagAlias $alias */
foreach ($tag->getAliases() as $alias) {
if (str_contains($title, $this->normalizeString($alias->getDescription()))) {
$matches[] = $tag;
break;
}
}
}
/** @var Tag $match */
foreach ($matches as $match) {
$video->addTag($match);
}
return $matches;
}
private function normalizeString(string $string): string {
return preg_replace(
'/[^a-zA-Z0-9]+/',
'',
strtolower($string)
);
}
}

View File

@ -2,24 +2,27 @@
namespace MyTube\Handling\Video\Builder;
use MyTube\Data\Business\Entity\Video;
use Ramsey\Uuid\UuidInterface;
class VideoImageBuilder
{
private const FILE_NAME = 'thumbnail.png';
public function build(
Video $video,
UuidInterface $directoryId,
string $timestamp = '00:00:10'
): string|null
{
$videoId = $video->getId()->toString();
$targetPath = sprintf(
'%s/%s/%s/%s',
$directoryPath = sprintf(
'%s/%s/%s',
APP_ROOT,
'var/filestore',
$videoId,
$directoryId->toString()
);
$targetPath = sprintf(
'%s/%s',
$directoryPath,
self::FILE_NAME
);
@ -27,11 +30,14 @@ class VideoImageBuilder
return null;
}
$command = "cd /var/www/html/var/filestore/" . $videoId . "/" .
" && " .
"ffmpeg -i video.mp4 -ss " . $timestamp . " -vframes 1 " . self::FILE_NAME;
$command = sprintf(
"cd %s && ffmpeg -i video.mp4 -ss %s -vframes 1 %s",
$directoryPath,
$timestamp,
self::FILE_NAME
);
$output = shell_exec($command);
shell_exec($command);
return $targetPath;
}

View File

@ -0,0 +1,25 @@
<?php
namespace MyTube\Handling\Video\Exception;
use MyTube\Infrastructure\Exception\ErrorCode;
use MyTube\Infrastructure\Exception\ErrorDomain;
use MyTube\Infrastructure\Exception\Exception\MyTubeException;
use Psr\Http\Message\UploadedFileInterface;
class VideoAlreadyExistsException extends MyTubeException {
private const MESSAGE = 'A Video with the Title %s does already exist!';
public function __construct(UploadedFileInterface $uploadedFile)
{
parent::__construct(
sprintf(
self::MESSAGE,
$uploadedFile->getClientFilename()
),
ErrorDomain::Video,
ErrorCode::AlreadyExists
);
}
}

View File

@ -9,7 +9,7 @@ use Ramsey\Uuid\UuidInterface;
class VideoNotFoundByIdException extends MyTubeException {
private const MESSAGE = 'The user with the Id %s was not found!';
private const MESSAGE = 'The Video with the Id %s was not found!';
public function __construct(UuidInterface $id)
{

View File

@ -8,38 +8,26 @@ use MyTube\Data\Business\Entity\Video;
use MyTube\Data\Business\Manager\MyTubeEntityManager;
use MyTube\Handling\Video\Builder\VideoBuilder;
use MyTube\Handling\Video\Builder\VideoImageBuilder;
use MyTube\Handling\Video\Uploader\VideoUploader;
use MyTube\Handling\Video\Pipeline\Upload\UploadPayload;
use MyTube\Handling\Video\Pipeline\Upload\UploadPipeline;
use MyTube\Handling\Video\Uploader\VideoTitleAnalyzer;
use Psr\Http\Message\UploadedFileInterface;
use Exception;
class UploadCommandHandler
{
public function __construct(
private readonly VideoBuilder $videoBuilder,
private readonly MyTubeEntityManager $entityManager,
private readonly VideoUploader $uploader,
private readonly UploadPipeline $pipeline,
) {
}
/**
* @throws Exception
*/
public function execute(UploadCommand $uploadCommand): Video
{
$uploadedFile = $uploadCommand->getUploadedFile();
$payload = new UploadPayload();
$payload->setUploadedFile($uploadCommand->getUploadedFile());
$video = $this->videoBuilder->build(
$uploadedFile->getClientFilename()
);
$this->pipeline->handle($payload);
$this->uploader->upload(
$uploadedFile,
$video
);
$this->entityManager->persist($video);
$this->entityManager->flush();
return $video;
return $payload->getVideo();
}
}

View File

@ -18,9 +18,11 @@ class ReadDetailsQueryHandler
* entityManager="MyTube\Data\Business\Manager\MyTubeEntityManager",
* entity="MyTube\Data\Business\Entity\Video"
* )
* @Inject("MyTube\Handling\Video\Builder\VideoImageBuilder")
*/
public function __construct(
private readonly VideoRepository $videoRepository,
private readonly VideoImageBuilder $videoImageBuilder,
) {
}
@ -38,6 +40,8 @@ class ReadDetailsQueryHandler
throw new VideoNotFoundByIdException($videoId);
}
$this->videoImageBuilder->build($video->getId());
return new ReadDetailsQueryResult($video);
}
}

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Video\Pipeline\Upload\Step;
use MyTube\Handling\Video\Analyzer\VideoTitleAnalyzer;
use MyTube\Handling\Video\Pipeline\Upload\UploadPayload;
use teewurst\Pipeline\PipelineInterface;
use teewurst\Pipeline\TaskInterface;
class AnalyzeTitleStep implements TaskInterface
{
public function __construct(
private readonly VideoTitleAnalyzer $analyzer,
) {
}
public function __invoke(
$payload,
PipelineInterface $pipeline
): void
{
/** @var UploadPayload $uploadPayload */
$uploadPayload = $payload;
$video = $uploadPayload->getVideo();
$this->analyzer->analyze($video);
$pipeline->next()($payload, $pipeline);
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Video\Pipeline\Upload\Step;
use MyTube\Handling\Video\Builder\VideoBuilder;
use MyTube\Handling\Video\Pipeline\Upload\UploadPayload;
use teewurst\Pipeline\PipelineInterface;
use teewurst\Pipeline\TaskInterface;
class BuildVideoStep implements TaskInterface
{
public function __construct(
private readonly VideoBuilder $videoBuilder,
) {
}
public function __invoke(
$payload,
PipelineInterface $pipeline
): void
{
/** @var UploadPayload $uploadPayload */
$uploadPayload = $payload;
$uploadedFile = $uploadPayload->getUploadedFile();
$video = $this->videoBuilder->build(
$uploadedFile->getClientFilename()
);
$uploadPayload->setVideo($video);
$pipeline->next()($payload, $pipeline);
}
}

View File

@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Video\Pipeline\Upload\Step;
use MyTube\Handling\Video\Builder\VideoBuilder;
use MyTube\Handling\Video\Exception\VideoAlreadyExistsException;
use MyTube\Handling\Video\Pipeline\Upload\UploadPayload;
use MyTube\Handling\Video\Rule\VideoExistsRule;
use teewurst\Pipeline\PipelineInterface;
use teewurst\Pipeline\TaskInterface;
class CheckVideoStep implements TaskInterface
{
public function __construct(
private readonly VideoExistsRule $existsRule,
) {
}
/**
* @throws VideoAlreadyExistsException
*/
public function __invoke(
$payload,
PipelineInterface $pipeline
): void
{
/** @var UploadPayload $uploadPayload */
$uploadPayload = $payload;
$uploadedFile = $uploadPayload->getUploadedFile();
if ($this->existsRule->appliesTo($uploadedFile)) {
throw new VideoAlreadyExistsException($uploadedFile);
}
$pipeline->next()($payload, $pipeline);
}
}

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Video\Pipeline\Upload\Step;
use MyTube\Data\Business\Manager\MyTubeEntityManager;
use MyTube\Handling\Video\Pipeline\Upload\UploadPayload;
use teewurst\Pipeline\PipelineInterface;
use teewurst\Pipeline\TaskInterface;
class SaveEntityStep implements TaskInterface
{
public function __construct(
private readonly MyTubeEntityManager $entityManager,
) {
}
public function __invoke(
$payload,
PipelineInterface $pipeline
): void
{
/** @var UploadPayload $uploadPayload */
$uploadPayload = $payload;
$video = $uploadPayload->getVideo();
$this->entityManager->persist($video);
$this->entityManager->flush();
}
}

View File

@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Video\Pipeline\Upload\Step;
use MyTube\Handling\Video\Builder\VideoImageBuilder;
use MyTube\Handling\Video\Pipeline\Upload\UploadPayload;
use MyTube\Handling\Video\Uploader\VideoUploader;
use teewurst\Pipeline\PipelineInterface;
use teewurst\Pipeline\TaskInterface;
class UploadFileStep implements TaskInterface
{
public function __construct(
private readonly VideoUploader $uploader,
private readonly VideoImageBuilder $imageBuilder,
) {
}
/**
* @throws \Exception
*/
public function __invoke(
$payload,
PipelineInterface $pipeline
): void
{
/** @var UploadPayload $uploadPayload */
$uploadPayload = $payload;
$video = $uploadPayload->getVideo();
$uploadedFile = $uploadPayload->getUploadedFile();
$directoryPath = $this->uploader->upload($uploadedFile, $video->getId());
$video->setDirectoryPath($directoryPath);
$this->imageBuilder->build($video->getId());
$pipeline->next()($payload, $pipeline);
}
}

View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Video\Pipeline\Upload;
use MyTube\Data\Business\Entity\Video;
use Psr\Http\Message\UploadedFileInterface;
class UploadPayload
{
private UploadedFileInterface $uploadedFile;
private Video $video;
public function getUploadedFile(): UploadedFileInterface
{
return $this->uploadedFile;
}
public function setUploadedFile(UploadedFileInterface $uploadedFile): void
{
$this->uploadedFile = $uploadedFile;
}
public function getVideo(): Video
{
return $this->video;
}
public function setVideo(Video $video): void
{
$this->video = $video;
}
}

View File

@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\Video\Pipeline\Upload;
use MyTube\Handling\Video\Pipeline\Upload\Step\BuildVideoStep;
use MyTube\Handling\Video\Pipeline\Upload\Step\AnalyzeTitleStep;
use MyTube\Handling\Video\Pipeline\Upload\Step\CheckVideoStep;
use MyTube\Handling\Video\Pipeline\Upload\Step\UploadFileStep;
use MyTube\Handling\Video\Pipeline\Upload\Step\SaveEntityStep;
use teewurst\Pipeline\Pipeline;
class UploadPipeline extends Pipeline
{
public function __construct(
private readonly CheckVideoStep $checkVideoStep,
private readonly BuildVideoStep $buildVideoStep,
private readonly AnalyzeTitleStep $analyzeTitleStep,
private readonly UploadFileStep $uploadFileStep,
private readonly SaveEntityStep $saveEntityStep,
) {
parent::__construct([
$this->checkVideoStep,
$this->buildVideoStep,
$this->analyzeTitleStep,
$this->uploadFileStep,
$this->saveEntityStep,
]);
}
public function reset(): void
{
$this->tasks = [
$this->checkVideoStep,
$this->buildVideoStep,
$this->analyzeTitleStep,
$this->uploadFileStep,
$this->saveEntityStep,
];
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace MyTube\Handling\Video\Rule;
use MyTube\Data\Business\Entity\Video;
use MyTube\Data\Business\Repository\VideoRepository;
use Psr\Http\Message\UploadedFileInterface;
use Reinfi\DependencyInjection\Annotation\InjectDoctrineRepository;
class VideoExistsRule
{
/**
* @InjectDoctrineRepository(
* entityManager="MyTube\Data\Business\Manager\MyTubeEntityManager",
* entity="MyTube\Data\Business\Entity\Video"
* )
*/
public function __construct(
private readonly VideoRepository $tagRepository,
) {
}
public function appliesTo(
UploadedFileInterface $uploadedFile,
): bool
{
return $this->tagRepository->findOneBy(['title' => $uploadedFile->getClientFilename()]) !== null;
}
}

View File

@ -4,37 +4,31 @@ namespace MyTube\Handling\Video\Uploader;
use Exception;
use MyTube\Data\Business\Entity\Video;
use MyTube\Handling\Video\Builder\VideoImageBuilder;
use Psr\Http\Message\UploadedFileInterface;
use Ramsey\Uuid\UuidInterface;
class VideoUploader
{
public function __construct(
private readonly VideoImageBuilder $imageBuilder,
) {
}
public function upload(
UploadedFileInterface $file,
Video $video,
): void {
$targetPath = sprintf(
UuidInterface $directoryId,
): string {
$directoryPath = sprintf(
'%s/%s/%s/',
APP_ROOT,
'var/filestore',
$video->getId()->toString(),
$directoryId->toString(),
);
if (file_exists($targetPath)) {
if (file_exists($directoryPath)) {
throw new Exception('File already exists');
}
mkdir($targetPath, 0777, true);
$video->setDirectoryPath($targetPath);
mkdir($directoryPath, 0777, true);
$targetPath = $targetPath . 'video.' . substr(strrchr($file->getClientFilename(),'.'),1);
$targetPath = $directoryPath . 'video.' . substr(strrchr($file->getClientFilename(),'.'),1);
$file->moveTo($targetPath);
$this->imageBuilder->build($video);
return $directoryPath;
}
}

View File

@ -1,10 +1,7 @@
<?php
use MyTube\Handling\Video\Builder\VideoBuilder;
use MyTube\Handling\Video\Handler\Command\Upload\UploadCommandBuilder;
use MyTube\Handling\Video\Handler\Command\Upload\UploadCommandHandler;
use MyTube\Handling\Video\Handler\Query\Stream\StreamQueryBuilder;
use MyTube\Handling\Video\Handler\Query\Stream\StreamQueryHandler;
use MyTube\Handling\VideoList\Handler\Command\Upload\UploadCommandBuilder;
use MyTube\Handling\VideoList\Handler\Command\Upload\UploadCommandHandler;
use MyTube\Handling\VideoList\Handler\Query\ReadList\ReadListQueryBuilder;
use MyTube\Handling\VideoList\Handler\Query\ReadList\ReadListQueryHandler;
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
@ -15,7 +12,10 @@ return [
'factories' => [
/// CQRS
// Read List
ReadListQueryHandler::class => InjectionFactory::class,
ReadListQueryBuilder::class => AutoWiringFactory::class,
ReadListQueryHandler::class => InjectionFactory::class,
// Upload
UploadCommandBuilder::class => AutoWiringFactory::class,
UploadCommandHandler::class => AutoWiringFactory::class,
],
];

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\VideoList\Handler\Command\Upload;
class UploadCommand
{
public function __construct(
private array $uploadedFiles
) {
}
public function getUploadedFiles(): array
{
return $this->uploadedFiles;
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace MyTube\Handling\VideoList\Handler\Command\Upload;
class UploadCommandBuilder
{
public function build(
array $uploadedFiles
): UploadCommand {
return new UploadCommand(
$uploadedFiles
);
}
}

Some files were not shown because too many files have changed in this diff Show More