adding a cart
linter / quality (push) Has been cancelled
tests / ci (8.3) (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled

This commit is contained in:
2026-04-10 08:54:20 -06:00
parent ebf30d4f5f
commit d9cb44e93c
16 changed files with 559 additions and 39 deletions
+78
View File
@@ -0,0 +1,78 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StoreCartRequest;
use App\Http\Requests\UpdateCartRequest;
use App\Models\Cart;
use App\Models\Product;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CartController extends Controller
{
public function store(StoreCartRequest $request): JsonResponse
{
$cart = $this->resolveCart();
$existing = $cart->products()->wherePivot('product_id', $request->product_id)->first();
if ($existing) {
$cart->products()->updateExistingPivot($request->product_id, [
'quantity' => $existing->pivot->quantity + 1,
]);
} else {
$cart->products()->attach($request->product_id, ['quantity' => 1]);
}
return response()->json($this->cartItems($cart));
}
public function update(UpdateCartRequest $request, Product $product): JsonResponse
{
$cart = $this->resolveCart();
$cart->products()->updateExistingPivot($product->id, [
'quantity' => $request->quantity,
]);
return response()->json($this->cartItems($cart));
}
public function destroy(Request $request, Product $product): JsonResponse
{
$cart = $this->resolveCart();
$cart->products()->detach($product->id);
return response()->json($this->cartItems($cart));
}
private function resolveCart(): Cart
{
$cartId = session('cart_id');
if ($cartId) {
$cart = Cart::find($cartId);
if ($cart) {
return $cart;
}
}
$cart = Cart::create(['user_id' => request()->user()?->id]);
session(['cart_id' => $cart->id]);
return $cart;
}
/**
* @return array<int, array{product_id: int, quantity: int}>
*/
private function cartItems(Cart $cart): array
{
return $cart->products()->get()->map(fn ($p) => [
'product_id' => $p->id,
'quantity' => $p->pivot->quantity,
])->all();
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
class StoreCartRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'product_id' => ['required', 'integer', 'exists:products,id'],
];
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
class UpdateCartRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'quantity' => ['required', 'integer', 'min:1'],
];
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace App\Models;
use Database\Factories\CartFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Cart extends Model
{
/** @use HasFactory<CartFactory> */
use HasFactory;
protected $fillable = ['user_id'];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function products(): BelongsToMany
{
return $this->belongsToMany(Product::class)->withPivot('quantity');
}
}
+6
View File
@@ -7,6 +7,7 @@ use Database\Factories\UserFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;
@@ -18,6 +19,11 @@ class User extends Authenticatable
/** @use HasFactory<UserFactory> */
use HasFactory, Notifiable, TwoFactorAuthenticatable;
public function cart(): HasOne
{
return $this->hasOne(Cart::class);
}
/**
* Get the attributes that should be cast.
*