diff --git a/backend/app/Data/ProductDTO.php b/backend/app/Data/ProductDTO.php index ea34b90..64bc2da 100644 --- a/backend/app/Data/ProductDTO.php +++ b/backend/app/Data/ProductDTO.php @@ -14,11 +14,14 @@ public function __construct( public int $id, public string $title, + public string $slug, public string $description, public int $actualPrice, public int $listPrice, public ProductCategoryDTO $category, public array $productImages, + public ?string $updatedAt = null, + public ?string $createdAt = null, ) {} /** @@ -29,12 +32,15 @@ public function toArray(): array return [ 'id' => $this->id, 'title' => $this->title, + 'slug' => $this->slug, 'description' => $this->description, 'actualPrice' => $this->actualPrice, 'listPrice' => $this->listPrice, 'category' => $this->category->toArray(), 'productImage' => array_map(fn (ProductImageDTO $productImage) => $productImage->toArray(), $this->productImages), + 'updatedAt' => $this->updatedAt, + 'createdAt' => $this->createdAt, ]; } @@ -43,11 +49,14 @@ public static function fromModel(Product $product): self return new self( id: $product->id, title: $product->title, + slug: $product->slug, description: $product->description, actualPrice: $product->actual_price, listPrice: $product->list_price, category: ProductCategoryDTO::fromModel($product->category), productImages: $product->images->map(fn (ProductImage $productImage) => ProductImageDTO::fromModel($productImage))->all(), + updatedAt: $product->updated_at, + createdAt: $product->created_at, ); } } diff --git a/backend/app/Http/Controllers/ProductController.php b/backend/app/Http/Controllers/ProductController.php index 9081473..f58296a 100644 --- a/backend/app/Http/Controllers/ProductController.php +++ b/backend/app/Http/Controllers/ProductController.php @@ -23,7 +23,12 @@ public function store(CreateProductRequest $request) return Product::create($request->validated()); } - public function show(Product $product) {} + public function show(string $slug) + { + $product = Product::where('slug', $slug)->with(['category:id,name,slug', 'images:id,path,product_id'])->firstOrFail(); + + return new ProductResource(ProductDTO::fromModel($product)); + } public function update(Request $request, Product $product) {} diff --git a/backend/app/Http/Requests/UploadImageRequest.php b/backend/app/Http/Requests/UploadImageRequest.php index c5b523a..c214fa9 100644 --- a/backend/app/Http/Requests/UploadImageRequest.php +++ b/backend/app/Http/Requests/UploadImageRequest.php @@ -22,7 +22,7 @@ public function authorize(): bool public function rules(): array { return [ - 'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048', + 'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:10240', 'product_id' => 'required|exists:products,id', ]; } diff --git a/backend/app/Http/Resources/ProductResource.php b/backend/app/Http/Resources/ProductResource.php index ea6b9f8..e650cc7 100644 --- a/backend/app/Http/Resources/ProductResource.php +++ b/backend/app/Http/Resources/ProductResource.php @@ -3,8 +3,10 @@ namespace App\Http\Resources; use App\Data\ProductDTO; +use App\Data\ProductImageDTO; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; +use Illuminate\Support\Facades\Storage; /** * @property ProductDTO $resource @@ -13,6 +15,21 @@ class ProductResource extends JsonResource { public function toArray(Request $request): array { - return $this->resource->toArray(); + return [ + 'id' => $this->resource->id, + 'title' => $this->resource->title, + 'slug' => $this->resource->slug, + 'description' => $this->resource->description, + 'actualPrice' => $this->resource->actualPrice, + 'listPrice' => $this->resource->listPrice, + 'category' => [ + 'name' => $this->resource->category->name, + 'slug' => $this->resource->category->slug, + ], + 'productImages' => array_map(function (ProductImageDTO $productImage) { + return Storage::disk('public')->url($productImage->path); + }, $this->resource->productImages), + 'updatedAt' => $this->resource->updatedAt, + ]; } } diff --git a/backend/app/Models/Product.php b/backend/app/Models/Product.php index c0725a3..82c3200 100644 --- a/backend/app/Models/Product.php +++ b/backend/app/Models/Product.php @@ -5,11 +5,13 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Support\Str; class Product extends Model { protected $fillable = [ 'title', + 'slug', 'actual_price', 'list_price', 'description', @@ -25,4 +27,13 @@ public function images(): HasMany { return $this->hasMany(ProductImage::class, 'product_id', 'id'); } + + protected static function booted(): void + { + static::saving(function ($product) { + if (empty($product->slug) || $product->isDirty('title')) { + $product->slug = Str::slug($product->title); + } + }); + } } diff --git a/backend/database/migrations/2026_02_26_073626_create_products_table.php b/backend/database/migrations/2026_02_26_073626_create_products_table.php index 6dc7a2f..4692626 100644 --- a/backend/database/migrations/2026_02_26_073626_create_products_table.php +++ b/backend/database/migrations/2026_02_26_073626_create_products_table.php @@ -1,6 +1,6 @@ -string('slug')->unique()->after('title')->nullable(); + }); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('products', function (Blueprint $table) { + $table->dropColumn('slug'); + }); + } +};