feat: implement product variant CRUD operations and tenant configuration seeding
This commit is contained in:
@@ -2,14 +2,17 @@
|
||||
|
||||
namespace App\Domains\Catalog\Services;
|
||||
|
||||
use App\Domains\Attachable\Services\AttachmentService;
|
||||
use App\Domains\Catalog\Models\Attribute;
|
||||
use App\Domains\Catalog\Models\Product;
|
||||
use App\Domains\Catalog\Models\ProductVariant;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ProductService
|
||||
{
|
||||
public function __construct(protected AttachmentService $attachmentService) {}
|
||||
/**
|
||||
* Create a product.
|
||||
*
|
||||
@@ -80,9 +83,16 @@ class ProductService
|
||||
public function createVariant(Product $product, array $data): ProductVariant
|
||||
{
|
||||
return DB::transaction(function () use ($product, $data) {
|
||||
$images = $data['images'] ?? [];
|
||||
unset($data['images']);
|
||||
|
||||
$variant = $product->createVariant($data);
|
||||
|
||||
return $variant->load(['product', 'definitions.attribute']);
|
||||
if (! empty($images)) {
|
||||
$this->syncImages($variant, $images);
|
||||
}
|
||||
|
||||
return $variant->load(['product', 'definitions.attribute', 'attachments']);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -94,11 +104,19 @@ class ProductService
|
||||
public function updateVariant(ProductVariant $variant, array $data): ProductVariant
|
||||
{
|
||||
return DB::transaction(function () use ($variant, $data) {
|
||||
$hasImages = array_key_exists('images', $data);
|
||||
$images = $data['images'] ?? [];
|
||||
unset($data['images']);
|
||||
|
||||
/** @var Product $product */
|
||||
$product = $variant->product;
|
||||
$updatedVariant = $product->updateVariant($variant, $data);
|
||||
|
||||
return $updatedVariant->load(['product', 'definitions.attribute']);
|
||||
if ($hasImages) {
|
||||
$this->syncImages($updatedVariant, $images);
|
||||
}
|
||||
|
||||
return $updatedVariant->load(['product', 'definitions.attribute', 'attachments']);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -138,6 +156,29 @@ class ProductService
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a list of image files/base64 strings and sync them to a variant.
|
||||
*
|
||||
* When called on update, the existing attachments are detached first so the
|
||||
* final set always matches exactly what was sent in the request.
|
||||
*
|
||||
* @param array<int, UploadedFile|string> $images
|
||||
*/
|
||||
protected function syncImages(ProductVariant $variant, array $images): void
|
||||
{
|
||||
// Detach any existing attachments before replacing them
|
||||
$variant->attachments()->detach();
|
||||
|
||||
$attachmentIds = [];
|
||||
|
||||
foreach ($images as $image) {
|
||||
$attachment = $this->attachmentService->store($image, 'variants');
|
||||
$attachmentIds[] = $attachment->id;
|
||||
}
|
||||
|
||||
$variant->attachments()->sync($attachmentIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an attribute.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user