Merge branch 'backend'
This commit is contained in:
commit
068975d3b0
16
backend/app/Actions/CreateProductAction.php
Normal file
16
backend/app/Actions/CreateProductAction.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions;
|
||||
|
||||
use App\Data\UploadImageDTO;
|
||||
|
||||
final readonly class CreateProductAction
|
||||
{
|
||||
public function execute(UploadImageDTO $uploadImageDTO): void
|
||||
{
|
||||
$path = $uploadImageDTO->image->store('public/images');
|
||||
$uploadImageDTO->product->images()->create([
|
||||
'path' => $path,
|
||||
]);
|
||||
}
|
||||
}
|
||||
19
backend/app/Actions/GetAllProductCategory.php
Normal file
19
backend/app/Actions/GetAllProductCategory.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions;
|
||||
|
||||
use App\Data\ProductCategoryDTO;
|
||||
use App\Models\ProductCategory;
|
||||
|
||||
final readonly class GetAllProductCategory
|
||||
{
|
||||
/**
|
||||
* Execute the action.
|
||||
*/
|
||||
public function execute(): array
|
||||
{
|
||||
return ProductCategory::all(columns: ['id', 'name', 'slug'])
|
||||
->map(fn ($category) => ProductCategoryDTO::fromModel($category))
|
||||
->toArray();
|
||||
}
|
||||
}
|
||||
16
backend/app/Actions/UploadImageAction.php
Normal file
16
backend/app/Actions/UploadImageAction.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions;
|
||||
|
||||
use App\Data\UploadImageDTO;
|
||||
|
||||
final readonly class UploadImageAction
|
||||
{
|
||||
public function execute(UploadImageDTO $uploadImageDTO): void
|
||||
{
|
||||
$path = $uploadImageDTO->image->store('public/images');
|
||||
$uploadImageDTO->product->images()->create([
|
||||
'path' => $path,
|
||||
]);
|
||||
}
|
||||
}
|
||||
32
backend/app/Console/Commands/MakeActionCommand.php
Normal file
32
backend/app/Console/Commands/MakeActionCommand.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\GeneratorCommand;
|
||||
|
||||
class MakeActionCommand extends GeneratorCommand
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'make:action {name}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Create a new action class';
|
||||
|
||||
protected function getStub(): string
|
||||
{
|
||||
return base_path('stubs/action.stub');
|
||||
}
|
||||
|
||||
protected function getDefaultNamespace($rootNamespace): string
|
||||
{
|
||||
return $rootNamespace.'\Actions';
|
||||
}
|
||||
}
|
||||
36
backend/app/Data/ProductCategoryDTO.php
Normal file
36
backend/app/Data/ProductCategoryDTO.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Data;
|
||||
|
||||
use App\Contracts\OutputDataTransferObject;
|
||||
use App\Models\ProductCategory;
|
||||
|
||||
final readonly class ProductCategoryDTO implements OutputDataTransferObject
|
||||
{
|
||||
public function __construct(
|
||||
public int $id,
|
||||
public string $name,
|
||||
public string $slug,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'name' => $this->name,
|
||||
'slug' => $this->slug,
|
||||
];
|
||||
}
|
||||
|
||||
public static function fromModel(ProductCategory $category): self
|
||||
{
|
||||
return new self(
|
||||
id: $category->id,
|
||||
name: $category->name,
|
||||
slug: $category->slug,
|
||||
);
|
||||
}
|
||||
}
|
||||
53
backend/app/Data/ProductDTO.php
Normal file
53
backend/app/Data/ProductDTO.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Data;
|
||||
|
||||
use App\Contracts\OutputDataTransferObject;
|
||||
use App\Models\Product;
|
||||
use App\Models\ProductImage;
|
||||
|
||||
final readonly class ProductDTO implements OutputDataTransferObject
|
||||
{
|
||||
/**
|
||||
* @param ProductImageDTO[] $productImages
|
||||
*/
|
||||
public function __construct(
|
||||
public int $id,
|
||||
public string $title,
|
||||
public string $description,
|
||||
public int $actualPrice,
|
||||
public int $listPrice,
|
||||
public ProductCategoryDTO $category,
|
||||
public array $productImages,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'title' => $this->title,
|
||||
'description' => $this->description,
|
||||
'actualPrice' => $this->actualPrice,
|
||||
'listPrice' => $this->listPrice,
|
||||
'category' => $this->category->toArray(),
|
||||
'productImage' => array_map(fn (ProductImageDTO $productImage) => $productImage->toArray(),
|
||||
$this->productImages),
|
||||
];
|
||||
}
|
||||
|
||||
public static function fromModel(Product $product): self
|
||||
{
|
||||
return new self(
|
||||
id: $product->id,
|
||||
title: $product->title,
|
||||
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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
36
backend/app/Data/ProductImageDTO.php
Normal file
36
backend/app/Data/ProductImageDTO.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Data;
|
||||
|
||||
use App\Contracts\OutputDataTransferObject;
|
||||
use App\Models\ProductImage;
|
||||
|
||||
final readonly class ProductImageDTO implements OutputDataTransferObject
|
||||
{
|
||||
public function __construct(
|
||||
public ?int $id = null,
|
||||
public ?string $path = null,
|
||||
public ?int $productId = null,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'path' => $this->path,
|
||||
'productId' => $this->productId,
|
||||
];
|
||||
}
|
||||
|
||||
public static function fromModel(ProductImage $productImage): self
|
||||
{
|
||||
return new self(
|
||||
$productImage->id,
|
||||
$productImage->path,
|
||||
$productImage->product_id
|
||||
);
|
||||
}
|
||||
}
|
||||
22
backend/app/Data/UploadImageDTO.php
Normal file
22
backend/app/Data/UploadImageDTO.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Data;
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
|
||||
readonly class UploadImageDTO
|
||||
{
|
||||
public function __construct(
|
||||
public UploadedFile $image,
|
||||
public Product $product,
|
||||
) {}
|
||||
|
||||
public static function fromRequest(array $data): self
|
||||
{
|
||||
return new self(
|
||||
image: $data['image'],
|
||||
product: Product::find($data['product_id']),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -12,6 +12,7 @@ public function __construct(
|
||||
public string $email,
|
||||
public string $mobileNumber,
|
||||
public string $city,
|
||||
public string $role
|
||||
) {}
|
||||
|
||||
/**
|
||||
@ -25,6 +26,7 @@ public function toArray(): array
|
||||
'email' => $this->email,
|
||||
'mobileNumber' => $this->mobileNumber,
|
||||
'city' => $this->city,
|
||||
'role' => $this->role,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
10
backend/app/Enums/UserRoles.php
Normal file
10
backend/app/Enums/UserRoles.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum UserRoles: string
|
||||
{
|
||||
case Admin = 'admin';
|
||||
case Customer = 'customer';
|
||||
case Broker = 'broker';
|
||||
}
|
||||
@ -40,7 +40,8 @@ public function show()
|
||||
name: $user->name,
|
||||
email: $user->email,
|
||||
mobileNumber: $user->mobile_number,
|
||||
city: $user->city
|
||||
city: $user->city,
|
||||
role: $user->role->value
|
||||
);
|
||||
|
||||
return response()->json($userDto->toArray());
|
||||
|
||||
13
backend/app/Http/Controllers/ProductCategoryController.php
Normal file
13
backend/app/Http/Controllers/ProductCategoryController.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Actions\GetAllProductCategory;
|
||||
|
||||
class ProductCategoryController extends Controller
|
||||
{
|
||||
public function index(GetAllProductCategory $action)
|
||||
{
|
||||
return $action->execute();
|
||||
}
|
||||
}
|
||||
31
backend/app/Http/Controllers/ProductController.php
Normal file
31
backend/app/Http/Controllers/ProductController.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Data\ProductDTO;
|
||||
use App\Http\Requests\CreateProductRequest;
|
||||
use App\Http\Resources\ProductResource;
|
||||
use App\Models\Product;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ProductController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$paginator = Product::query()->with(['category:id,name,slug', 'images:id,path,product_id'])->paginate();
|
||||
$paginatedDtos = $paginator->through(fn ($product) => ProductDTO::fromModel($product));
|
||||
|
||||
return ProductResource::collection($paginatedDtos);
|
||||
}
|
||||
|
||||
public function store(CreateProductRequest $request)
|
||||
{
|
||||
return Product::create($request->validated());
|
||||
}
|
||||
|
||||
public function show(Product $product) {}
|
||||
|
||||
public function update(Request $request, Product $product) {}
|
||||
|
||||
public function destroy(Product $product) {}
|
||||
}
|
||||
30
backend/app/Http/Controllers/ProductImagesController.php
Normal file
30
backend/app/Http/Controllers/ProductImagesController.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Actions\UploadImageAction;
|
||||
use App\Data\UploadImageDTO;
|
||||
use App\Http\Requests\UploadImageRequest;
|
||||
use App\Models\ProductImages;
|
||||
|
||||
class ProductImagesController extends Controller
|
||||
{
|
||||
public function store(UploadImageRequest $request, UploadImageAction $action)
|
||||
{
|
||||
$action->execute(UploadImageDTO::fromRequest($request->validated()));
|
||||
|
||||
return response()->json(['message' => 'Image uploaded successfully']);
|
||||
}
|
||||
|
||||
public function show(ProductImages $productImages)
|
||||
{
|
||||
return $productImages;
|
||||
}
|
||||
|
||||
public function destroy(ProductImages $productImages)
|
||||
{
|
||||
$productImages->delete();
|
||||
|
||||
return response()->json();
|
||||
}
|
||||
}
|
||||
24
backend/app/Http/Requests/CreateProductRequest.php
Normal file
24
backend/app/Http/Requests/CreateProductRequest.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class CreateProductRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'title' => 'required|string|max:255',
|
||||
'description' => 'required|string',
|
||||
'product_category_id' => 'required|exists:product_categories,id',
|
||||
'actual_price' => 'required|numeric|min:0',
|
||||
'list_price' => 'required|numeric|min:0',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
29
backend/app/Http/Requests/UploadImageRequest.php
Normal file
29
backend/app/Http/Requests/UploadImageRequest.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UploadImageRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
|
||||
'product_id' => 'required|exists:products,id',
|
||||
];
|
||||
}
|
||||
}
|
||||
16
backend/app/Http/Resources/ProductCollection.php
Normal file
16
backend/app/Http/Resources/ProductCollection.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||
|
||||
class ProductCollection extends ResourceCollection
|
||||
{
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'data' => $this->collection,
|
||||
];
|
||||
}
|
||||
}
|
||||
18
backend/app/Http/Resources/ProductResource.php
Normal file
18
backend/app/Http/Resources/ProductResource.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use App\Data\ProductDTO;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
/**
|
||||
* @property ProductDTO $resource
|
||||
*/
|
||||
class ProductResource extends JsonResource
|
||||
{
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return $this->resource->toArray();
|
||||
}
|
||||
}
|
||||
28
backend/app/Models/Product.php
Normal file
28
backend/app/Models/Product.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class Product extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'actual_price',
|
||||
'list_price',
|
||||
'description',
|
||||
'product_category_id',
|
||||
];
|
||||
|
||||
public function category(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(ProductCategory::class, 'product_category_id');
|
||||
}
|
||||
|
||||
public function images(): HasMany
|
||||
{
|
||||
return $this->hasMany(ProductImage::class, 'product_id', 'id');
|
||||
}
|
||||
}
|
||||
10
backend/app/Models/ProductCategory.php
Normal file
10
backend/app/Models/ProductCategory.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ProductCategory extends Model
|
||||
{
|
||||
//
|
||||
}
|
||||
19
backend/app/Models/ProductImage.php
Normal file
19
backend/app/Models/ProductImage.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class ProductImage extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'path',
|
||||
'product_id',
|
||||
];
|
||||
|
||||
public function product(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Product::class);
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,7 @@
|
||||
namespace App\Models;
|
||||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use App\Enums\UserRoles;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
@ -23,6 +24,7 @@ class User extends Authenticatable
|
||||
'password',
|
||||
'city',
|
||||
'mobile_number',
|
||||
'role',
|
||||
];
|
||||
|
||||
/**
|
||||
@ -45,6 +47,7 @@ protected function casts(): array
|
||||
return [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
'role' => UserRoles::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('product_categories', function (Blueprint $table) {
|
||||
$table->id()->index();
|
||||
$table->string('name')->unique();
|
||||
$table->string('slug')->unique();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('product_categories');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use App\Models\ProductCategory;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('products', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('title');
|
||||
$table->text('description');
|
||||
$table->decimal('actual_price', 10, 2);
|
||||
$table->decimal('list_price', 10, 2);
|
||||
$table->foreignIdFor(ProductCategory::class)->index();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('products');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('product_images', function (Blueprint $table) {
|
||||
$table->id()->index();
|
||||
$table->string('path');
|
||||
$table->foreignIdFor(Product::class)->index();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('product_images');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\UserRoles;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->enum('role', array_column(UserRoles::cases(), 'value'))->default(UserRoles::Customer->value);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('role');
|
||||
});
|
||||
}
|
||||
};
|
||||
28
backend/database/seeders/ProductCategorySeeder.php
Normal file
28
backend/database/seeders/ProductCategorySeeder.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\ProductCategory;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ProductCategorySeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$names = [
|
||||
'Electronics', 'Clothing', 'Home', 'Books',
|
||||
'Sports', 'Toys', 'Health', 'Beauty', 'Automotive',
|
||||
];
|
||||
|
||||
// Transform the flat names into an array of associative arrays
|
||||
$categories = collect($names)->map(function ($name) {
|
||||
return [
|
||||
'name' => $name,
|
||||
'slug' => Str::slug($name),
|
||||
];
|
||||
})->toArray();
|
||||
|
||||
ProductCategory::upsert($categories, ['name'], ['slug']);
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,9 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\AuthenticatedUserController;
|
||||
use App\Http\Controllers\ProductCategoryController;
|
||||
use App\Http\Controllers\ProductController;
|
||||
use App\Http\Controllers\ProductImagesController;
|
||||
use App\Http\Controllers\RegisteredUserController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
@ -11,4 +14,7 @@
|
||||
Route::middleware('auth:sanctum')->group(function () {
|
||||
Route::get('/user', [AuthenticatedUserController::class, 'show']);
|
||||
Route::post('/logout', [AuthenticatedUserController::class, 'destroy']);
|
||||
Route::post('/upload/images', action: [ProductImagesController::class, 'store']);
|
||||
});
|
||||
Route::get('/categories', [ProductCategoryController::class, 'index']);
|
||||
Route::apiResource('products', ProductController::class);
|
||||
|
||||
14
backend/stubs/action.stub
Normal file
14
backend/stubs/action.stub
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace {{ namespace }};
|
||||
|
||||
final readonly class {{ class }}
|
||||
{
|
||||
/**
|
||||
* Execute the action.
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
// Your logic here
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user