feat: implement RegistersMedia trait for media handling across services

This commit is contained in:
Yoga Pangestu 2026-08-01 13:36:32 +07:00
parent e3c0f14c43
commit 79cd9a8c39
5 changed files with 98 additions and 120 deletions

View File

@ -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,
]);
}
}

View File

@ -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,
]);
}
}

View File

@ -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,
]);
}
}

View File

@ -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,
);
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace App\Services\Concerns;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
trait RegistersMedia
{
private function registerMedia(
Model $model,
string $s3Key,
string $collectionName,
array $generatedConversions = [],
?int $fileSize = null,
?string $mimeType = null,
?int $orderColumn = null,
?string $name = null,
): void {
$defaultName = pathinfo($s3Key, PATHINFO_FILENAME);
Media::create([
'model_type' => $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,
);
}
}