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 App\Settings\GeneralSettings;
|
||||||
use Barryvdh\DomPDF\Facade\Pdf;
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
use Filament\Actions\Action;
|
use Filament\Actions\Action;
|
||||||
|
use Filament\Notifications\Notification;
|
||||||
use Filament\Tables\Table;
|
use Filament\Tables\Table;
|
||||||
use Illuminate\Support\Facades\Blade;
|
use Illuminate\Support\Facades\Blade;
|
||||||
|
|
||||||
class ExportAllReportsPdfAction extends Action
|
class ExportAllReportsPdfAction extends Action
|
||||||
{
|
{
|
||||||
|
private const int MAX_RECORDS = 500;
|
||||||
|
|
||||||
public static function getDefaultName(): ?string
|
public static function getDefaultName(): ?string
|
||||||
{
|
{
|
||||||
return 'export_all_pdf';
|
return 'export_all_pdf';
|
||||||
@ -25,21 +28,43 @@ protected function setUp(): void
|
|||||||
->color('info')
|
->color('info')
|
||||||
->icon('heroicon-o-arrow-down-tray')
|
->icon('heroicon-o-arrow-down-tray')
|
||||||
->action(function (Table $table) {
|
->action(function (Table $table) {
|
||||||
$settings = app(GeneralSettings::class);
|
$query = $table->getLivewire()->getFilteredTableQuery();
|
||||||
$records = $table->getLivewire()->getFilteredTableQuery()->get();
|
$count = (clone $query)->count();
|
||||||
|
|
||||||
$logoPath = $settings->site_icon ? storage_path('app/public/'.$settings->site_icon) : null;
|
if ($count > self::MAX_RECORDS) {
|
||||||
$logoBase64 = null;
|
Notification::make()
|
||||||
if ($logoPath && file_exists($logoPath)) {
|
->title('Data terlalu banyak')
|
||||||
$logoData = base64_encode(file_get_contents($logoPath));
|
->body('Maksimal '.self::MAX_RECORDS.' laporan per unduhan. Gunakan filter tabel untuk mempersempit data.')
|
||||||
$logoBase64 = 'data:image/'.pathinfo($logoPath, PATHINFO_EXTENSION).';base64,'.$logoData;
|
->warning()
|
||||||
|
->send();
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$records->each(function ($record) {
|
$settings = app(GeneralSettings::class);
|
||||||
$record->imageBase64 = MediaDataUri::fromMedia($record->getFirstMedia('reports'));
|
|
||||||
});
|
$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) {
|
return response()->streamDownload(function () use ($records, $settings, $logoBase64) {
|
||||||
|
@ini_set('memory_limit', '512M');
|
||||||
|
set_time_limit(120);
|
||||||
|
|
||||||
echo Pdf::loadHtml(
|
echo Pdf::loadHtml(
|
||||||
Blade::render('filament.manage.reports.print-all', [
|
Blade::render('filament.manage.reports.print-all', [
|
||||||
'records' => $records,
|
'records' => $records,
|
||||||
|
|||||||
@ -28,16 +28,17 @@ protected function setUp(): void
|
|||||||
$settings = app(GeneralSettings::class);
|
$settings = app(GeneralSettings::class);
|
||||||
|
|
||||||
$logoPath = $settings->site_icon ? storage_path('app/public/'.$settings->site_icon) : null;
|
$logoPath = $settings->site_icon ? storage_path('app/public/'.$settings->site_icon) : null;
|
||||||
|
$logoBase64 = MediaDataUri::fromPath($logoPath, maxWidth: 80, maxHeight: 100);
|
||||||
|
|
||||||
$logoBase64 = null;
|
$imageBase64 = MediaDataUri::thumbnailForPdf(
|
||||||
if ($logoPath && file_exists($logoPath)) {
|
$record->getFirstMedia('reports'),
|
||||||
$logoData = base64_encode(file_get_contents($logoPath));
|
maxWidth: 800,
|
||||||
$logoBase64 = 'data:image/'.pathinfo($logoPath, PATHINFO_EXTENSION).';base64,'.$logoData;
|
maxHeight: 400,
|
||||||
}
|
);
|
||||||
|
|
||||||
$imageBase64 = MediaDataUri::fromMedia($record->getFirstMedia('reports'));
|
|
||||||
|
|
||||||
return response()->streamDownload(function () use ($record, $settings, $logoBase64, $imageBase64) {
|
return response()->streamDownload(function () use ($record, $settings, $logoBase64, $imageBase64) {
|
||||||
|
set_time_limit(60);
|
||||||
|
|
||||||
echo Pdf::loadHtml(
|
echo Pdf::loadHtml(
|
||||||
Blade::render('filament.manage.reports.print', [
|
Blade::render('filament.manage.reports.print', [
|
||||||
'record' => $record,
|
'record' => $record,
|
||||||
|
|||||||
@ -24,4 +24,104 @@ public static function fromMedia(?Media $media): ?string
|
|||||||
|
|
||||||
return 'data:'.$mime.';base64,'.base64_encode($disk->get($path));
|
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