diff --git a/app/Filament/Resources/Manage/Cooperations/Actions/Report/ExportAllReportsPdfAction.php b/app/Filament/Resources/Manage/Cooperations/Actions/Report/ExportAllReportsPdfAction.php index ef11393..b13f526 100644 --- a/app/Filament/Resources/Manage/Cooperations/Actions/Report/ExportAllReportsPdfAction.php +++ b/app/Filament/Resources/Manage/Cooperations/Actions/Report/ExportAllReportsPdfAction.php @@ -7,11 +7,14 @@ use App\Settings\GeneralSettings; use Barryvdh\DomPDF\Facade\Pdf; use Filament\Actions\Action; +use Filament\Notifications\Notification; use Filament\Tables\Table; use Illuminate\Support\Facades\Blade; class ExportAllReportsPdfAction extends Action { + private const int MAX_RECORDS = 500; + public static function getDefaultName(): ?string { return 'export_all_pdf'; @@ -25,21 +28,43 @@ protected function setUp(): void ->color('info') ->icon('heroicon-o-arrow-down-tray') ->action(function (Table $table) { - $settings = app(GeneralSettings::class); - $records = $table->getLivewire()->getFilteredTableQuery()->get(); + $query = $table->getLivewire()->getFilteredTableQuery(); + $count = (clone $query)->count(); - $logoPath = $settings->site_icon ? storage_path('app/public/'.$settings->site_icon) : null; - $logoBase64 = null; - if ($logoPath && file_exists($logoPath)) { - $logoData = base64_encode(file_get_contents($logoPath)); - $logoBase64 = 'data:image/'.pathinfo($logoPath, PATHINFO_EXTENSION).';base64,'.$logoData; + if ($count > self::MAX_RECORDS) { + Notification::make() + ->title('Data terlalu banyak') + ->body('Maksimal '.self::MAX_RECORDS.' laporan per unduhan. Gunakan filter tabel untuk mempersempit data.') + ->warning() + ->send(); + + return; } - $records->each(function ($record) { - $record->imageBase64 = MediaDataUri::fromMedia($record->getFirstMedia('reports')); - }); + $settings = app(GeneralSettings::class); + + $records = $query + ->with([ + 'mediaTaskAssignment.partnerMedia', + 'media', + ]) + ->get(); + + $logoPath = $settings->site_icon ? storage_path('app/public/'.$settings->site_icon) : null; + $logoBase64 = MediaDataUri::fromPath($logoPath, maxWidth: 60, maxHeight: 60); + + foreach ($records as $record) { + $record->imageBase64 = MediaDataUri::thumbnailForPdf( + $record->getFirstMedia('reports'), + maxWidth: 150, + maxHeight: 80, + ); + } return response()->streamDownload(function () use ($records, $settings, $logoBase64) { + @ini_set('memory_limit', '512M'); + set_time_limit(120); + echo Pdf::loadHtml( Blade::render('filament.manage.reports.print-all', [ 'records' => $records, diff --git a/app/Filament/Resources/Manage/Cooperations/Actions/Report/ExportReportPdfAction.php b/app/Filament/Resources/Manage/Cooperations/Actions/Report/ExportReportPdfAction.php index 8d27e9d..2a7f889 100644 --- a/app/Filament/Resources/Manage/Cooperations/Actions/Report/ExportReportPdfAction.php +++ b/app/Filament/Resources/Manage/Cooperations/Actions/Report/ExportReportPdfAction.php @@ -28,16 +28,17 @@ protected function setUp(): void $settings = app(GeneralSettings::class); $logoPath = $settings->site_icon ? storage_path('app/public/'.$settings->site_icon) : null; + $logoBase64 = MediaDataUri::fromPath($logoPath, maxWidth: 80, maxHeight: 100); - $logoBase64 = null; - if ($logoPath && file_exists($logoPath)) { - $logoData = base64_encode(file_get_contents($logoPath)); - $logoBase64 = 'data:image/'.pathinfo($logoPath, PATHINFO_EXTENSION).';base64,'.$logoData; - } - - $imageBase64 = MediaDataUri::fromMedia($record->getFirstMedia('reports')); + $imageBase64 = MediaDataUri::thumbnailForPdf( + $record->getFirstMedia('reports'), + maxWidth: 800, + maxHeight: 400, + ); return response()->streamDownload(function () use ($record, $settings, $logoBase64, $imageBase64) { + set_time_limit(60); + echo Pdf::loadHtml( Blade::render('filament.manage.reports.print', [ 'record' => $record, diff --git a/app/Filament/Support/MediaDataUri.php b/app/Filament/Support/MediaDataUri.php index 7c02d0f..b0e3738 100644 --- a/app/Filament/Support/MediaDataUri.php +++ b/app/Filament/Support/MediaDataUri.php @@ -24,4 +24,104 @@ public static function fromMedia(?Media $media): ?string return 'data:'.$mime.';base64,'.base64_encode($disk->get($path)); } + + public static function fromPath(?string $absolutePath, int $maxWidth = 80, int $maxHeight = 80): ?string + { + if (! $absolutePath || ! file_exists($absolutePath)) { + return null; + } + + $contents = file_get_contents($absolutePath); + + if ($contents === false) { + return null; + } + + return self::encodeResizedImage($contents, $maxWidth, $maxHeight) + ?? self::encodeRawFile($absolutePath, $contents); + } + + public static function thumbnailForPdf(?Media $media, int $maxWidth = 150, int $maxHeight = 80): ?string + { + if (! $media) { + return null; + } + + $disk = Storage::disk($media->disk); + $path = $media->getPathRelativeToRoot(); + + if (! $disk->exists($path)) { + return null; + } + + $mime = $media->mime_type ?? ''; + + if (! str_starts_with($mime, 'image/')) { + return null; + } + + $contents = $disk->get($path); + + return self::encodeResizedImage($contents, $maxWidth, $maxHeight) + ?? self::fromMedia($media); + } + + private static function encodeResizedImage(string $contents, int $maxWidth, int $maxHeight): ?string + { + if (! extension_loaded('gd')) { + return null; + } + + $image = @imagecreatefromstring($contents); + + if ($image === false) { + return null; + } + + $width = imagesx($image); + $height = imagesy($image); + $ratio = min($maxWidth / $width, $maxHeight / $height, 1); + $newWidth = max(1, (int) round($width * $ratio)); + $newHeight = max(1, (int) round($height * $ratio)); + + $thumb = imagecreatetruecolor($newWidth, $newHeight); + + if ($thumb === false) { + imagedestroy($image); + + return null; + } + + imagecopyresampled($thumb, $image, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height); + imagedestroy($image); + + ob_start(); + imagejpeg($thumb, quality: 75); + imagedestroy($thumb); + $jpeg = ob_get_clean(); + + if ($jpeg === false || $jpeg === '') { + return null; + } + + return 'data:image/jpeg;base64,'.base64_encode($jpeg); + } + + private static function encodeRawFile(string $absolutePath, string $contents): ?string + { + $extension = strtolower(pathinfo($absolutePath, PATHINFO_EXTENSION)); + $mime = match ($extension) { + 'png' => 'image/png', + 'jpg', 'jpeg' => 'image/jpeg', + 'gif' => 'image/gif', + 'webp' => 'image/webp', + default => null, + }; + + if ($mime === null) { + return null; + } + + return 'data:'.$mime.';base64,'.base64_encode($contents); + } }