feat: implement record limit check and enhance image handling in PDF export actions
This commit is contained in:
parent
23f32b3cf1
commit
beae82a898
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user