resolveIdentity($request); if ($resolvedIdentity === null) { return $this->makeEmptyCart($tenant); } $cart = $this->findCart($tenant, $resolvedIdentity['identity']); if ($cart === null) { return $this->makeEmptyCart($tenant); } return $this->loadCart($cart); } /** * @return array{cart: Cart, guest_token: ?string} */ public function addItem(Tenant $tenant, Request $request, string $buyableType, int $buyableId, int $quantity): array { $resolvedIdentity = $this->resolveIdentity($request, true); $identity = $resolvedIdentity['identity']; $cart = $this->findOrCreateCart($tenant, $identity); $cart->addItem($buyableType, $buyableId, $quantity); return [ 'cart' => $this->loadCart($cart), 'guest_token' => $resolvedIdentity['generated_guest_token'], ]; } public function updateItemQuantity(Tenant $tenant, Request $request, int $cartItemId, int $quantity): Cart { $identity = $this->requireIdentity($request); $cart = $this->findCartOrFail($tenant, $identity); $cart->updateItem($cartItemId, $quantity); return $this->loadCart($cart); } public function removeItem(Tenant $tenant, Request $request, int $cartItemId): Cart { $identity = $this->requireIdentity($request); $cart = $this->findCartOrFail($tenant, $identity); $cart->removeItem($cartItemId); return $this->loadCart($cart); } public function makeGuestTokenCookie(string $guestToken): Cookie { return cookie( 'guest_token', $guestToken, 60 * 24 * 180, '/', null, false, true, false, 'lax', ); } protected function makeEmptyCart(Tenant $tenant): Cart { $cart = new Cart([ 'tenant_codigo' => $tenant->codigo, 'status' => 'active', ]); $cart->setRelation('items', collect()); return $cart; } protected function loadCart(Cart $cart): Cart { return $cart->fresh()->load([ 'items.buyable' => function (MorphTo $morphTo): void { $morphTo->morphWith([ ProductVariant::class => [ 'product', 'definitions.productAttribute.attribute', 'attachments', ], Bundle::class => ['items.variant'], ]); }, ]); } /** * @return array{identity: array{user_id: ?int, guest_token: ?string}, generated_guest_token: ?string}|null */ protected function resolveIdentity(Request $request, bool $generateGuestToken = false): ?array { $user = $request->user() ?? Auth::guard('sanctum')->user(); if ($user instanceof User) { return [ 'identity' => [ 'user_id' => $user->getKey(), 'guest_token' => null, ], 'generated_guest_token' => null, ]; } $guestToken = $request->cookie('guest_token'); if (is_string($guestToken) && $guestToken !== '') { return [ 'identity' => [ 'user_id' => null, 'guest_token' => $guestToken, ], 'generated_guest_token' => null, ]; } if (! $generateGuestToken) { return null; } $generatedGuestToken = (string) Str::uuid(); return [ 'identity' => [ 'user_id' => null, 'guest_token' => $generatedGuestToken, ], 'generated_guest_token' => $generatedGuestToken, ]; } /** * @return array{user_id: ?int, guest_token: ?string} */ protected function requireIdentity(Request $request): array { $resolvedIdentity = $this->resolveIdentity($request); if ($resolvedIdentity === null) { throw new NotFoundHttpException('Cart not found.'); } return $resolvedIdentity['identity']; } /** * @param array{user_id: ?int, guest_token: ?string} $identity */ protected function findCart(Tenant $tenant, array $identity): ?Cart { return Cart::query() ->where('tenant_codigo', $tenant->codigo) ->when( $identity['user_id'] !== null, fn ($query) => $query->where('user_id', $identity['user_id']), fn ($query) => $query->where('guest_token', $identity['guest_token']), ) ->first(); } /** * @param array{user_id: ?int, guest_token: ?string} $identity */ protected function findCartOrFail(Tenant $tenant, array $identity): Cart { $cart = $this->findCart($tenant, $identity); if ($cart === null) { throw new NotFoundHttpException('Cart not found.'); } return $cart; } /** * @param array{user_id: ?int, guest_token: ?string} $identity */ protected function findOrCreateCart(Tenant $tenant, array $identity): Cart { $attributes = ['tenant_codigo' => $tenant->codigo]; if ($identity['user_id'] !== null) { $attributes['user_id'] = $identity['user_id']; } else { $attributes['guest_token'] = $identity['guest_token']; } return Cart::query()->firstOrCreate($attributes, ['status' => 'active']); } }