From 79cd9a8c391e5aac2778ee774b4451ba9910fb06 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Sat, 1 Aug 2026 13:36:32 +0700 Subject: [PATCH] feat: implement RegistersMedia trait for media handling across services --- .../Admin/Finance/CashAccountService.php | 35 ++------- app/Services/Admin/Finance/ExpenseService.php | 33 ++------- app/Services/Admin/HR/AttendanceService.php | 46 ++---------- .../Master/Product/ProductVariantService.php | 31 +++----- app/Services/Concerns/RegistersMedia.php | 73 +++++++++++++++++++ 5 files changed, 98 insertions(+), 120 deletions(-) create mode 100644 app/Services/Concerns/RegistersMedia.php diff --git a/app/Services/Admin/Finance/CashAccountService.php b/app/Services/Admin/Finance/CashAccountService.php index dc6a512..9ebcc47 100644 --- a/app/Services/Admin/Finance/CashAccountService.php +++ b/app/Services/Admin/Finance/CashAccountService.php @@ -5,18 +5,19 @@ use App\Enums\CashTransactionType; use App\Models\CashAccount; use App\Models\CashTransaction; +use App\Services\Concerns\RegistersMedia; use App\Services\NotificationService; use App\Services\S3PresignedService; use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator as PaginationLengthAwarePaginator; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; -use Illuminate\Support\Str; use Illuminate\Validation\ValidationException; -use Spatie\MediaLibrary\MediaCollections\Models\Media; class CashAccountService { + use RegistersMedia; + public function __construct( private S3PresignedService $s3Service = new S3PresignedService, ) {} @@ -109,7 +110,7 @@ public function deposit(array $data): CashTransaction ]); if (! empty($data['receipt_key'])) { - $this->registerMedia($transaction, $data['receipt_key'], $data['file_size'] ?? null, $data['file_mime_type'] ?? null); + $this->registerMedia($transaction, $data['receipt_key'], 'receipts', ['thumb' => true], $data['file_size'] ?? null, $data['file_mime_type'] ?? null); } return $transaction; @@ -149,7 +150,7 @@ public function withdrawal(array $data): CashTransaction ]); if (! empty($data['receipt_key'])) { - $this->registerMedia($transaction, $data['receipt_key'], $data['file_size'] ?? null, $data['file_mime_type'] ?? null); + $this->registerMedia($transaction, $data['receipt_key'], 'receipts', ['thumb' => true], $data['file_size'] ?? null, $data['file_mime_type'] ?? null); } return $transaction; @@ -208,7 +209,7 @@ public function updateTransaction(CashTransaction $transaction, array $data): Ca $transaction->clearMediaCollection('receipts'); if (! empty($data['receipt_key'])) { - $this->registerMedia($transaction, $data['receipt_key'], $data['file_size'] ?? null, $data['file_mime_type'] ?? null); + $this->registerMedia($transaction, $data['receipt_key'], 'receipts', ['thumb' => true], $data['file_size'] ?? null, $data['file_mime_type'] ?? null); } } } @@ -266,28 +267,4 @@ public function deleteTransaction(CashTransaction $transaction): bool return $deleted; }); } - - private function registerMedia(CashTransaction $transaction, string $s3Key, ?int $fileSize = null, ?string $mimeType = null): void - { - $fileName = pathinfo($s3Key, PATHINFO_BASENAME); - $name = pathinfo($s3Key, PATHINFO_FILENAME); - - Media::create([ - 'model_type' => CashTransaction::class, - 'model_id' => $transaction->id, - 'uuid' => Str::uuid(), - 'collection_name' => 'receipts', - 'name' => $name, - 'file_name' => $s3Key, - 'mime_type' => $mimeType ?? 'image/jpeg', - 'disk' => 's3', - 'conversions_disk' => 's3', - 'size' => $fileSize ?? 0, - 'manipulations' => [], - 'custom_properties' => [], - 'generated_conversions' => ['thumb' => true], - 'responsive_images' => [], - 'order_column' => 1, - ]); - } } diff --git a/app/Services/Admin/Finance/ExpenseService.php b/app/Services/Admin/Finance/ExpenseService.php index 0e2162f..898dc26 100644 --- a/app/Services/Admin/Finance/ExpenseService.php +++ b/app/Services/Admin/Finance/ExpenseService.php @@ -6,18 +6,19 @@ use App\Models\CashAccount; use App\Models\CashTransaction; use App\Models\Expense; +use App\Services\Concerns\RegistersMedia; use App\Services\NotificationService; use App\Services\S3PresignedService; use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\DB; -use Illuminate\Support\Str; use Illuminate\Validation\ValidationException; -use Spatie\MediaLibrary\MediaCollections\Models\Media; class ExpenseService { + use RegistersMedia; + public function __construct( private S3PresignedService $s3Service = new S3PresignedService, ) {} @@ -105,7 +106,7 @@ public function create(array $data): Expense ]); if (! empty($data['receipt_key'])) { - $this->registerMedia($expense, $data['receipt_key'], $data['file_size'] ?? null, $data['file_mime_type'] ?? null); + $this->registerMedia($expense, $data['receipt_key'], 'receipts', ['thumb' => true], $data['file_size'] ?? null, $data['file_mime_type'] ?? null); } return $expense; @@ -169,7 +170,7 @@ public function update(Expense $expense, array $data): Expense $expense->clearMediaCollection('receipts'); if (! empty($data['receipt_key'])) { - $this->registerMedia($expense, $data['receipt_key'], $data['file_size'] ?? null, $data['file_mime_type'] ?? null); + $this->registerMedia($expense, $data['receipt_key'], 'receipts', ['thumb' => true], $data['file_size'] ?? null, $data['file_mime_type'] ?? null); } } } @@ -217,28 +218,4 @@ public function delete(Expense $expense): bool return $deleted; }); } - - private function registerMedia(Expense $expense, string $s3Key, ?int $fileSize = null, ?string $mimeType = null): void - { - $fileName = pathinfo($s3Key, PATHINFO_BASENAME); - $name = pathinfo($s3Key, PATHINFO_FILENAME); - - Media::create([ - 'model_type' => Expense::class, - 'model_id' => $expense->id, - 'uuid' => Str::uuid(), - 'collection_name' => 'receipts', - 'name' => $name, - 'file_name' => $s3Key, - 'mime_type' => $mimeType ?? 'image/jpeg', - 'disk' => 's3', - 'conversions_disk' => 's3', - 'size' => $fileSize ?? 0, - 'manipulations' => [], - 'custom_properties' => [], - 'generated_conversions' => ['thumb' => true], - 'responsive_images' => [], - 'order_column' => 1, - ]); - } } diff --git a/app/Services/Admin/HR/AttendanceService.php b/app/Services/Admin/HR/AttendanceService.php index 64d5323..678268c 100644 --- a/app/Services/Admin/HR/AttendanceService.php +++ b/app/Services/Admin/HR/AttendanceService.php @@ -4,16 +4,17 @@ use App\Models\Attendance; use App\Models\LeaveRequest; +use App\Services\Concerns\RegistersMedia; use App\Services\NotificationService; use App\Services\S3PresignedService; use Carbon\Carbon; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Cache; -use Illuminate\Support\Str; -use Spatie\MediaLibrary\MediaCollections\Models\Media; class AttendanceService { + use RegistersMedia; + public function __construct( private S3PresignedService $s3Service = new S3PresignedService, ) {} @@ -115,7 +116,7 @@ public function checkIn(array $data): Attendance ]); if (! empty($data['photo'])) { - $this->registerMedia($attendance, $data['photo'], 'check-in'); + $this->registerMediaFromBase64($attendance, $data['photo'], 'check-in', 'attendances'); } NotificationService::notify( @@ -137,7 +138,7 @@ public function checkOut(Attendance $attendance, array $data): Attendance ]); if (! empty($data['photo'])) { - $this->registerMedia($attendance, $data['photo'], 'check-out'); + $this->registerMediaFromBase64($attendance, $data['photo'], 'check-out', 'attendances'); } NotificationService::notify( @@ -175,41 +176,4 @@ private function formatAttendance(Attendance $attendance): array return $toArray; } - - private function registerMedia(Attendance $attendance, string $photo, string $type): void - { - if (str_starts_with($photo, 'data:image')) { - $base64 = explode(',', $photo)[1]; - $imageData = base64_decode($base64); - $filename = $type.'_'.time().'_'.uniqid().'.jpg'; - $s3Key = 'attendances/'.$filename; - - app('filesystem')->disk('s3')->put($s3Key, $imageData); - $mimeType = 'image/jpeg'; - $fileSize = strlen($imageData); - } else { - $s3Key = $photo; - $filename = pathinfo($photo, PATHINFO_BASENAME); - $mimeType = 'image/jpeg'; - $fileSize = 0; - } - - Media::create([ - 'model_type' => Attendance::class, - 'model_id' => $attendance->id, - 'uuid' => Str::uuid(), - 'collection_name' => $type, - 'name' => $type, - 'file_name' => $s3Key, - 'mime_type' => $mimeType, - 'disk' => 's3', - 'conversions_disk' => 's3', - 'size' => $fileSize, - 'manipulations' => [], - 'custom_properties' => [], - 'generated_conversions' => [], - 'responsive_images' => [], - 'order_column' => 1, - ]); - } } diff --git a/app/Services/Admin/Master/Product/ProductVariantService.php b/app/Services/Admin/Master/Product/ProductVariantService.php index a2ea25e..5214258 100644 --- a/app/Services/Admin/Master/Product/ProductVariantService.php +++ b/app/Services/Admin/Master/Product/ProductVariantService.php @@ -5,14 +5,15 @@ use App\Models\Product; use App\Models\ProductPrice; use App\Models\ProductVariant; +use App\Services\Concerns\RegistersMedia; use App\Services\NotificationService; use App\Services\S3PresignedService; use Illuminate\Support\Facades\DB; -use Illuminate\Support\Str; -use Spatie\MediaLibrary\MediaCollections\Models\Media; class ProductVariantService { + use RegistersMedia; + public function __construct( private S3PresignedService $s3Service = new S3PresignedService, ) {} @@ -97,26 +98,12 @@ public function delete(Product $product, ProductVariant $variant): bool public function registerPhotos(ProductVariant $variant, array $photoKeys): void { foreach ($photoKeys as $order => $s3Key) { - $fileName = pathinfo($s3Key, PATHINFO_BASENAME); - $name = pathinfo($s3Key, PATHINFO_FILENAME); - - Media::create([ - 'model_type' => ProductVariant::class, - 'model_id' => $variant->id, - 'uuid' => Str::uuid(), - 'collection_name' => 'photos', - 'name' => $name, - 'file_name' => $s3Key, - 'mime_type' => 'image/jpeg', - 'disk' => 's3', - 'conversions_disk' => 's3', - 'size' => 0, - 'manipulations' => [], - 'custom_properties' => [], - 'generated_conversions' => [], - 'responsive_images' => [], - 'order_column' => $order + 1, - ]); + $this->registerMedia( + model: $variant, + s3Key: $s3Key, + collectionName: 'photos', + orderColumn: $order + 1, + ); } } diff --git a/app/Services/Concerns/RegistersMedia.php b/app/Services/Concerns/RegistersMedia.php new file mode 100644 index 0000000..007d4b9 --- /dev/null +++ b/app/Services/Concerns/RegistersMedia.php @@ -0,0 +1,73 @@ + $model->getMorphClass(), + 'model_id' => $model->id, + 'uuid' => Str::uuid(), + 'collection_name' => $collectionName, + 'name' => $name ?? $defaultName, + 'file_name' => $s3Key, + 'mime_type' => $mimeType ?? 'image/jpeg', + 'disk' => 's3', + 'conversions_disk' => 's3', + 'size' => $fileSize ?? 0, + 'manipulations' => [], + 'custom_properties' => [], + 'generated_conversions' => $generatedConversions, + 'responsive_images' => [], + 'order_column' => $orderColumn ?? 1, + ]); + } + + private function registerMediaFromBase64( + Model $model, + string $data, + string $collectionName, + string $subdirectory, + array $generatedConversions = [], + ): void { + if (str_starts_with($data, 'data:image')) { + $base64 = explode(',', $data)[1]; + $imageData = base64_decode($base64); + $filename = $collectionName.'_'.time().'_'.uniqid().'.jpg'; + $s3Key = $subdirectory.'/'.$filename; + + app('filesystem')->disk('s3')->put($s3Key, $imageData); + $mimeType = 'image/jpeg'; + $fileSize = strlen($imageData); + } else { + $s3Key = $data; + $mimeType = 'image/jpeg'; + $fileSize = 0; + } + + $this->registerMedia( + model: $model, + s3Key: $s3Key, + collectionName: $collectionName, + generatedConversions: $generatedConversions, + fileSize: $fileSize, + mimeType: $mimeType, + ); + } +}