feature: update quantity and remove product from cart

add endpoint for update quantity of products (min:1, max:10)
add endpoint for removing product from cart
This commit is contained in:
kusowl 2026-03-10 19:01:52 +05:30
parent 1656739ecd
commit 5bbec0ee2b
6 changed files with 152 additions and 7 deletions

View File

@ -0,0 +1,21 @@
<?php
namespace App\Actions;
use App\Models\User;
final readonly class RemoveProductFromCartAction
{
public function __construct(private GetActiveUserCartAction $activeCartAction) {}
/**
* Execute the action.
*/
public function execute(int $productId, User $user)
{
$cart = $user->carts()->active()->sole();
$cart->products()->detach($productId);
return $this->activeCartAction->execute($user);
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace App\Actions;
use App\Data\AddToCartDTO;
use App\Data\CartDTO;
use App\Models\User;
use InvalidArgumentException;
final readonly class UpdateProductInCartAction
{
/**
* Execute the action.
*
* @throws InvalidArgumentException
*/
public function execute(AddToCartDTO $cartData, User $user)
{
$cart = $user->carts()->active()->sole();
$productInCart = $cart->products()->find($cartData->productId);
throw_if($productInCart === null, new InvalidArgumentException('Product not found'));
$cart->products()->updateExistingPivot($cartData->productId, [
'quantity' => $cartData->quantity,
]);
return CartDTO::fromModel($cart->load(['products' => function ($query) {
$query->withPivot('quantity', 'price');
}]));
}
}

View File

@ -4,10 +4,13 @@
use App\Actions\AddProductToCartAction; use App\Actions\AddProductToCartAction;
use App\Actions\GetActiveUserCartAction; use App\Actions\GetActiveUserCartAction;
use App\Actions\RemoveProductFromCartAction;
use App\Actions\UpdateProductInCartAction;
use App\Data\AddToCartDTO; use App\Data\AddToCartDTO;
use App\Http\Requests\AddProductToCartRequest; use App\Http\Requests\AddProductToCartRequest;
use App\Http\Requests\RemoveProductFromCartRequest;
use App\Http\Requests\UpdateProductInCartRequest;
use App\Http\Resources\CartResource; use App\Http\Resources\CartResource;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
class CartController extends Controller class CartController extends Controller
@ -36,16 +39,45 @@ public function show(GetActiveUserCartAction $action)
/** /**
* Update the specified resource in storage. * Update the specified resource in storage.
*/ */
public function update(Request $request, string $id) public function update(UpdateProductInCartRequest $request, UpdateProductInCartAction $action)
{ {
// $updateCartData = AddToCartDTO::fromRequest($request);
$cart = $action->execute($updateCartData, $request->user());
return new CartResource($cart);
} }
/** /**
* Remove the specified resource from storage. * Remove the specified resource from storage.
*/ */
public function destroy(string $id) public function destroy(RemoveProductFromCartRequest $request, RemoveProductFromCartAction $action)
{ {
// $user = $request->user();
try {
$cart = $action->execute($request->productId, $user);
return new CartResource($cart);
} catch (ModelNotFoundException $e) {
Log::error('No active cart found when removing a product from cart.', [
'user' => $user->id,
'error' => $e->getMessage(),
]);
return response()->json([
'message' => 'No active cart found.',
], 404);
} catch (MultipleRecordsFoundException $e) {
Log::error('Multiple active carts found for the user', [
'user' => $user->id,
'error' => $e->getMessage(),
]);
return response()->json([
'message' => 'Multiple Active carts found.',
], 409);
}
} }
} }

View File

@ -0,0 +1,28 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class RemoveProductFromCartRequest 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 [
'productId' => ['required', 'exists:products,id'],
];
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UpdateProductInCartRequest 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 [
'productId' => ['required', 'exists:products,id'],
'quantity' => ['required', 'min:0', 'max:10'],
];
}
}

View File

@ -21,8 +21,9 @@
// Favorites // Favorites
Route::post('/products/{product}/favorite', [FavouriteProductController::class, 'toggle']); Route::post('/products/{product}/favorite', [FavouriteProductController::class, 'toggle']);
Route::post('/cart', [CartController::class, 'store']); Route::apiSingleton('/cart', CartController::class)
Route::get('/cart', [CartController::class, 'show']); ->creatable()
->destroyable();
}); });
Route::get('/categories', [ProductCategoryController::class, 'index']); Route::get('/categories', [ProductCategoryController::class, 'index']);
Route::apiResource('products', ProductController::class); Route::apiResource('products', ProductController::class);