Add Brand and Category management features with controllers, requests, resources, and API routes
This commit is contained in:
55
app/Domains/Catalog/Controllers/BrandController.php
Normal file
55
app/Domains/Catalog/Controllers/BrandController.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Catalog\Controllers;
|
||||
|
||||
use App\Domains\Catalog\Models\Brand;
|
||||
use App\Domains\Catalog\Requests\StoreBrandRequest;
|
||||
use App\Domains\Catalog\Requests\UpdateBrandRequest;
|
||||
use App\Domains\Catalog\Resources\BrandResource;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class BrandController extends Controller
|
||||
{
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
return BrandResource::collection(Brand::query()->orderByDesc('id')->get())->response();
|
||||
}
|
||||
|
||||
public function store(StoreBrandRequest $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validated();
|
||||
$props = $validated['props'] ?? [];
|
||||
unset($validated['props']);
|
||||
|
||||
$brand = Brand::create($validated);
|
||||
$brand->syncPropValues($props);
|
||||
|
||||
return BrandResource::make($brand)->response()->setStatusCode(201);
|
||||
}
|
||||
|
||||
public function show(Brand $marca): BrandResource
|
||||
{
|
||||
return BrandResource::make($marca);
|
||||
}
|
||||
|
||||
public function update(UpdateBrandRequest $request, Brand $marca): BrandResource
|
||||
{
|
||||
$validated = $request->validated();
|
||||
$props = $validated['props'] ?? [];
|
||||
unset($validated['props']);
|
||||
|
||||
$marca->update($validated);
|
||||
$marca->syncPropValues($props);
|
||||
|
||||
return BrandResource::make($marca);
|
||||
}
|
||||
|
||||
public function destroy(Brand $marca): Response
|
||||
{
|
||||
$marca->delete();
|
||||
|
||||
return response()->noContent();
|
||||
}
|
||||
}
|
||||
59
app/Domains/Catalog/Controllers/CategoryController.php
Normal file
59
app/Domains/Catalog/Controllers/CategoryController.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Catalog\Controllers;
|
||||
|
||||
use App\Domains\Catalog\Models\Category;
|
||||
use App\Domains\Catalog\Requests\StoreCategoryRequest;
|
||||
use App\Domains\Catalog\Requests\UpdateCategoryRequest;
|
||||
use App\Domains\Catalog\Resources\CategoryResource;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class CategoryController extends Controller
|
||||
{
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
return CategoryResource::collection(
|
||||
Category::query()->with(['parent', 'subCategories','tenant'])->orderByDesc('id')->get()
|
||||
)->response();
|
||||
}
|
||||
|
||||
public function store(StoreCategoryRequest $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validated();
|
||||
$props = $validated['props'] ?? [];
|
||||
unset($validated['props']);
|
||||
|
||||
$category = Category::create($validated);
|
||||
$category->syncPropValues($props);
|
||||
|
||||
return CategoryResource::make($category->load(['parent', 'subCategories', 'tenant']))
|
||||
->response()
|
||||
->setStatusCode(201);
|
||||
}
|
||||
|
||||
public function show(Category $categoria): CategoryResource
|
||||
{
|
||||
return CategoryResource::make($categoria->load(['parent', 'subCategories', 'tenant']));
|
||||
}
|
||||
|
||||
public function update(UpdateCategoryRequest $request, Category $categoria): CategoryResource
|
||||
{
|
||||
$validated = $request->validated();
|
||||
$props = $validated['props'] ?? [];
|
||||
unset($validated['props']);
|
||||
|
||||
$categoria->update($validated);
|
||||
$categoria->syncPropValues($props);
|
||||
|
||||
return CategoryResource::make($categoria->load(['parent', 'subCategories', 'tenant']));
|
||||
}
|
||||
|
||||
public function destroy(Category $categoria): Response
|
||||
{
|
||||
$categoria->delete();
|
||||
|
||||
return response()->noContent();
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,29 @@
|
||||
namespace App\Domains\Catalog\Models;
|
||||
|
||||
use App\Domains\Prop\Concerns\Propable;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
#[Fillable([
|
||||
'tenant_codigo',
|
||||
'nombre',
|
||||
'descripcion',
|
||||
])]
|
||||
class Brand extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Propable;
|
||||
|
||||
protected $table = 'brands';
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Tenant, $this>
|
||||
*/
|
||||
public function tenant(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Tenant::class, 'tenant_codigo', 'codigo');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,58 @@
|
||||
namespace App\Domains\Catalog\Models;
|
||||
|
||||
use App\Domains\Prop\Concerns\Propable;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
#[Fillable([
|
||||
'tenant_code',
|
||||
'categoria_id',
|
||||
'nombre',
|
||||
])]
|
||||
class Category extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Propable;
|
||||
|
||||
protected $table = 'categorias';
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'categoria_id' => 'integer',
|
||||
];
|
||||
}
|
||||
|
||||
public function isGlobal(): bool
|
||||
{
|
||||
return $this->tenant_code === null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Tenant, $this>
|
||||
*/
|
||||
public function tenant(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Tenant::class, 'tenant_code', 'codigo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Category, $this>
|
||||
*/
|
||||
public function parent(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(self::class, 'categoria_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HasMany<Category, $this>
|
||||
*/
|
||||
public function subCategories(): HasMany
|
||||
{
|
||||
return $this->hasMany(self::class, 'categoria_id');
|
||||
}
|
||||
}
|
||||
|
||||
27
app/Domains/Catalog/Requests/StoreBrandRequest.php
Normal file
27
app/Domains/Catalog/Requests/StoreBrandRequest.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Catalog\Requests;
|
||||
|
||||
use App\Domains\Prop\Support\PropRules;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreBrandRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'tenant_codigo' => ['required', 'string', 'exists:tenants,codigo'],
|
||||
'nombre' => ['required', 'string', 'max:255'],
|
||||
'descripcion' => ['nullable', 'string'],
|
||||
...PropRules::sync(),
|
||||
];
|
||||
}
|
||||
}
|
||||
27
app/Domains/Catalog/Requests/StoreCategoryRequest.php
Normal file
27
app/Domains/Catalog/Requests/StoreCategoryRequest.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Catalog\Requests;
|
||||
|
||||
use App\Domains\Prop\Support\PropRules;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreCategoryRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'tenant_code' => ['required', 'string', 'exists:tenants,codigo'],
|
||||
'categoria_id' => ['nullable', 'integer', 'exists:categorias,id'],
|
||||
'nombre' => ['required', 'string', 'max:255'],
|
||||
...PropRules::sync(),
|
||||
];
|
||||
}
|
||||
}
|
||||
27
app/Domains/Catalog/Requests/UpdateBrandRequest.php
Normal file
27
app/Domains/Catalog/Requests/UpdateBrandRequest.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Catalog\Requests;
|
||||
|
||||
use App\Domains\Prop\Support\PropRules;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UpdateBrandRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'tenant_codigo' => ['required', 'string', 'exists:tenants,codigo'],
|
||||
'nombre' => ['required', 'string', 'max:255'],
|
||||
'descripcion' => ['nullable', 'string'],
|
||||
...PropRules::sync(),
|
||||
];
|
||||
}
|
||||
}
|
||||
37
app/Domains/Catalog/Requests/UpdateCategoryRequest.php
Normal file
37
app/Domains/Catalog/Requests/UpdateCategoryRequest.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Catalog\Requests;
|
||||
|
||||
use App\Domains\Catalog\Models\Category;
|
||||
use App\Domains\Prop\Support\PropRules;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class UpdateCategoryRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
/** @var Category|null $category */
|
||||
$category = $this->route('categoria');
|
||||
|
||||
return [
|
||||
'tenant_code' => ['required', 'string', 'exists:tenants,codigo'],
|
||||
'categoria_id' => [
|
||||
'nullable',
|
||||
'integer',
|
||||
'exists:categorias,id',
|
||||
Rule::notIn([$category?->id]),
|
||||
],
|
||||
'nombre' => ['required', 'string', 'max:255'],
|
||||
...PropRules::sync(),
|
||||
];
|
||||
}
|
||||
}
|
||||
25
app/Domains/Catalog/Resources/BrandResource.php
Normal file
25
app/Domains/Catalog/Resources/BrandResource.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Catalog\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
/**
|
||||
* @mixin \App\Domains\Catalog\Models\Brand
|
||||
*/
|
||||
class BrandResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'tenant_codigo' => $this->tenant_codigo,
|
||||
'nombre' => $this->nombre,
|
||||
'descripcion' => $this->descripcion,
|
||||
];
|
||||
}
|
||||
}
|
||||
32
app/Domains/Catalog/Resources/CategoryResource.php
Normal file
32
app/Domains/Catalog/Resources/CategoryResource.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Catalog\Resources;
|
||||
|
||||
use App\Domains\Tenant\Resources\TenantResource;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
/**
|
||||
* @mixin \App\Domains\Catalog\Models\Category
|
||||
*/
|
||||
class CategoryResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'tenant_code' => $this->tenant_code,
|
||||
'is_global' => $this->resource->isGlobal(),
|
||||
'tenant' => $this->resource->isGlobal()
|
||||
? null
|
||||
: TenantResource::make($this->whenLoaded('tenant')),
|
||||
'categoria_id' => $this->categoria_id,
|
||||
'nombre' => $this->nombre,
|
||||
'parent' => self::make($this->whenLoaded('parent')),
|
||||
'sub_categories' => self::collection($this->whenLoaded('subCategories')),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
<?php
|
||||
|
||||
use App\Domains\Catalog\Controllers\BrandController;
|
||||
use App\Domains\Catalog\Controllers\CategoryController;
|
||||
use App\Domains\Catalog\Controllers\ProductController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::apiResource('marcas', BrandController::class)->parameters(['marcas' => 'marca']);
|
||||
Route::apiResource('categorias', CategoryController::class)->parameters(['categorias' => 'categoria']);
|
||||
Route::apiResource('productos', ProductController::class);
|
||||
|
||||
Reference in New Issue
Block a user