- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
188 lines
6.2 KiB
PHP
188 lines
6.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Application\Admin;
|
|
|
|
use App\Application\Admin\Service\AdminLayoutProcessor;
|
|
use App\Domain\Media\Image;
|
|
use App\Domain\Media\ImageRepository;
|
|
use App\Domain\Media\ImageResizer;
|
|
use App\Domain\Media\ImageVariantRepository;
|
|
use App\Framework\Attributes\Route;
|
|
use App\Framework\Auth\Auth;
|
|
use App\Framework\Core\PathProvider;
|
|
use App\Framework\Http\Method;
|
|
use App\Framework\Http\Request;
|
|
use App\Framework\Http\Session\FormIdGenerator;
|
|
use App\Framework\Http\UploadedFile;
|
|
use App\Framework\Meta\MetaData;
|
|
use App\Framework\Router\Result\ViewResult;
|
|
use App\Framework\Ulid\StringConverter;
|
|
use App\Framework\Ulid\Ulid;
|
|
use App\Framework\View\FormBuilder;
|
|
use App\Framework\View\RawHtml;
|
|
|
|
final readonly class ShowImageUpload
|
|
{
|
|
public function __construct(
|
|
private PathProvider $pathProvider,
|
|
private StringConverter $stringConverter,
|
|
private FormIdGenerator $formIdGenerator,
|
|
private AdminLayoutProcessor $layoutProcessor,
|
|
) {
|
|
}
|
|
|
|
#[Auth]
|
|
#[Route('/upload')]
|
|
public function __invoke(): ViewResult
|
|
{
|
|
$form = FormBuilder::create('/upload', 'post', $this->formIdGenerator)
|
|
->withClass('upload-form')
|
|
->addFileInput('image', 'Bild hochladen:', true)
|
|
->addSubmitButton('Upload');
|
|
|
|
// Set enctype for file upload
|
|
$formHtml = str_replace('<form', '<form enctype="multipart/form-data"', (string) $form);
|
|
|
|
$data = [
|
|
'title' => 'Bild-Upload',
|
|
'description' => 'Laden Sie neue Bilder in das System hoch.',
|
|
'formHtml' => RawHtml::from($formHtml),
|
|
];
|
|
|
|
$finalData = $this->layoutProcessor->processLayoutFromArray($data);
|
|
|
|
$metaData = MetaData::create(
|
|
title: 'Bild-Upload | Admin Panel',
|
|
description: 'Upload new images to the system'
|
|
);
|
|
|
|
return new ViewResult('upload-form', $metaData, $finalData);
|
|
}
|
|
|
|
#[Auth]
|
|
#[Route('/upload', Method::POST)]
|
|
public function upload(Request $request, Ulid $ulid, ImageRepository $imageRepository, ImageVariantRepository $imageVariantRepository): ViewResult
|
|
{
|
|
try {
|
|
/** @var UploadedFile $file */
|
|
$file = $request->files->get('image');
|
|
|
|
if (! $file || $file->error !== UPLOAD_ERR_OK) {
|
|
return $this->renderUploadError('Keine gültige Datei hochgeladen.');
|
|
}
|
|
|
|
$storageFolder = $this->pathProvider->resolvePath('/storage');
|
|
$uploadDirectory = sprintf('uploads/%s/%s/%s', date('Y'), date('m'), date('d'));
|
|
|
|
$ulid = (string)$ulid;
|
|
$id = substr($ulid, 10); // Remove Timestamp
|
|
|
|
$hash = hash_file('sha256', $file->tmpName);
|
|
|
|
// Prüfen, ob ein Bild mit diesem Hash bereits existiert
|
|
$existingImage = $imageRepository->findByHash($hash);
|
|
if ($existingImage !== null) {
|
|
return $this->renderUploadSuccess(
|
|
'Bild bereits vorhanden',
|
|
"Dieses Bild wurde bereits hochgeladen. Bild-ID: {$existingImage->ulid}"
|
|
);
|
|
}
|
|
|
|
$idStr = str_pad((string)$id, 9, '0', STR_PAD_LEFT);
|
|
$filePathPattern = sprintf(
|
|
'%s/%s/%s',
|
|
substr($idStr, 0, 3),
|
|
substr($idStr, 3, 3),
|
|
substr($idStr, 6, 3),
|
|
);
|
|
|
|
$path = $storageFolder . '/' . $uploadDirectory . '/' . $filePathPattern . "/";
|
|
$filename = $idStr . '_' . $hash . "_";
|
|
|
|
[$width, $height] = getimagesize($file->tmpName);
|
|
|
|
$image = new Image(
|
|
ulid : $ulid,
|
|
filename : $filename . 'original.jpg',
|
|
originalFilename: $file->name,
|
|
mimeType : $file->getMimeType(),
|
|
fileSize : $file->size,
|
|
width : $width,
|
|
height : $height,
|
|
hash : $hash,
|
|
path : $path,
|
|
altText : 'Uploaded image',
|
|
);
|
|
|
|
$imageRepository->save($image, $file->tmpName);
|
|
|
|
// Create thumbnail variant
|
|
$variant = new ImageResizer()($image, 150, 150);
|
|
$imageVariantRepository->save($variant);
|
|
|
|
return $this->renderUploadSuccess(
|
|
'Upload erfolgreich!',
|
|
"Bild wurde erfolgreich hochgeladen.<br>" .
|
|
"Original: {$image->filename}<br>" .
|
|
"Thumbnail: {$variant->filename}<br>" .
|
|
"ULID: {$image->ulid}"
|
|
);
|
|
|
|
} catch (\Exception $e) {
|
|
return $this->renderUploadError(
|
|
"Fehler beim Upload: " . $e->getMessage()
|
|
);
|
|
}
|
|
}
|
|
|
|
private function renderUploadError(string $message): ViewResult
|
|
{
|
|
$data = [
|
|
'title' => 'Upload Fehler',
|
|
'description' => $message,
|
|
'error' => true,
|
|
'formHtml' => $this->buildUploadForm(),
|
|
];
|
|
|
|
$finalData = $this->layoutProcessor->processLayoutFromArray($data);
|
|
|
|
return new ViewResult(
|
|
'upload-form',
|
|
MetaData::create('Upload Fehler | Admin Panel', $message),
|
|
$finalData
|
|
);
|
|
}
|
|
|
|
private function renderUploadSuccess(string $title, string $message): ViewResult
|
|
{
|
|
$data = [
|
|
'title' => $title,
|
|
'description' => $message,
|
|
'success' => true,
|
|
'formHtml' => $this->buildUploadForm(),
|
|
];
|
|
|
|
$finalData = $this->layoutProcessor->processLayoutFromArray($data);
|
|
|
|
return new ViewResult(
|
|
'upload-form',
|
|
MetaData::create($title . ' | Admin Panel', $message),
|
|
$finalData
|
|
);
|
|
}
|
|
|
|
private function buildUploadForm(): RawHtml
|
|
{
|
|
$form = FormBuilder::create('/upload', 'post', $this->formIdGenerator)
|
|
->withClass('upload-form')
|
|
->addFileInput('image', 'Bild hochladen:', true)
|
|
->addSubmitButton('Upload');
|
|
|
|
$formHtml = str_replace('<form', '<form enctype="multipart/form-data"', (string) $form);
|
|
|
|
return RawHtml::from($formHtml);
|
|
}
|
|
}
|