- Create ProBundleExportService with generateBundle() method - Generate flat ZIP with .pro file + image files at root level - Add downloadBundle() method to ServiceController - Add services.download-bundle route - Add .probundle download buttons to Information, Moderation, Sermon blocks - Add 3 tests verifying ZIP structure and validation - All tests pass (206/206, 1129 assertions)
118 lines
3.2 KiB
PHP
118 lines
3.2 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Service;
|
|
use InvalidArgumentException;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use ProPresenter\Parser\ProFileGenerator;
|
|
use ZipArchive;
|
|
|
|
class ProBundleExportService
|
|
{
|
|
private const ALLOWED_BLOCK_TYPES = ['information', 'moderation', 'sermon'];
|
|
|
|
public function generateBundle(Service $service, string $blockType): string
|
|
{
|
|
if (! in_array($blockType, self::ALLOWED_BLOCK_TYPES, true)) {
|
|
throw new InvalidArgumentException('Ungültiger Blocktyp für .probundle Export.');
|
|
}
|
|
|
|
$slides = $service->slides()
|
|
->where('type', $blockType)
|
|
->orderBy('sort_order')
|
|
->get();
|
|
|
|
$tempDir = sys_get_temp_dir().'/probundle-export-'.uniqid();
|
|
mkdir($tempDir, 0755, true);
|
|
|
|
$groupName = ucfirst($blockType);
|
|
$slideData = [];
|
|
$copiedImagePaths = [];
|
|
|
|
foreach ($slides as $slide) {
|
|
$sourcePath = Storage::disk('public')->path('slides/'.$slide->stored_filename);
|
|
if (! file_exists($sourcePath)) {
|
|
continue;
|
|
}
|
|
|
|
$imageFilename = basename($slide->stored_filename);
|
|
$tempImagePath = $tempDir.'/'.$imageFilename;
|
|
copy($sourcePath, $tempImagePath);
|
|
$copiedImagePaths[] = $tempImagePath;
|
|
|
|
$slideData[] = [
|
|
'text' => $slide->original_filename ?? '',
|
|
'media' => $imageFilename,
|
|
'format' => 'JPG',
|
|
];
|
|
}
|
|
|
|
$groups = [
|
|
[
|
|
'name' => $groupName,
|
|
'color' => [0, 0, 0, 1],
|
|
'slides' => $slideData,
|
|
],
|
|
];
|
|
|
|
$arrangements = [
|
|
[
|
|
'name' => 'normal',
|
|
'groupNames' => [$groupName],
|
|
],
|
|
];
|
|
|
|
$proFilePath = $tempDir.'/'.$blockType.'.pro';
|
|
ProFileGenerator::generateAndWrite($proFilePath, $groupName, $groups, $arrangements);
|
|
|
|
$bundlePath = sys_get_temp_dir().'/'.uniqid($blockType.'-').'.probundle';
|
|
|
|
$zip = new ZipArchive();
|
|
$openResult = $zip->open($bundlePath, ZipArchive::CREATE | ZipArchive::OVERWRITE);
|
|
if ($openResult !== true) {
|
|
$this->deleteDirectory($tempDir);
|
|
throw new InvalidArgumentException('Konnte .probundle nicht erstellen.');
|
|
}
|
|
|
|
$zip->addFile($proFilePath, basename($proFilePath));
|
|
|
|
foreach ($copiedImagePaths as $imagePath) {
|
|
$zip->addFile($imagePath, basename($imagePath));
|
|
}
|
|
|
|
$zip->close();
|
|
|
|
$this->deleteDirectory($tempDir);
|
|
|
|
return $bundlePath;
|
|
}
|
|
|
|
private function deleteDirectory(string $dir): void
|
|
{
|
|
if (! is_dir($dir)) {
|
|
return;
|
|
}
|
|
|
|
$entries = scandir($dir);
|
|
if ($entries === false) {
|
|
return;
|
|
}
|
|
|
|
foreach ($entries as $entry) {
|
|
if ($entry === '.' || $entry === '..') {
|
|
continue;
|
|
}
|
|
|
|
$path = $dir.'/'.$entry;
|
|
if (is_dir($path)) {
|
|
$this->deleteDirectory($path);
|
|
} else {
|
|
@unlink($path);
|
|
}
|
|
}
|
|
|
|
@rmdir($dir);
|
|
}
|
|
}
|