|null ids for this request, including a toggle just made */ private ?array $guestIds = null; /** @return array newest first */ public function ids(): array { if ($user = Auth::user()) { return WishlistItem::where('user_id', $user->id) ->latest('id') ->pluck('product_id') ->all(); } return $this->guestIds(); } public function has(int $productId): bool { return in_array($productId, $this->ids(), true); } /** * @return bool whether the product is on the wishlist afterwards */ public function toggle(int $productId): bool { if ($user = Auth::user()) { $deleted = WishlistItem::where('user_id', $user->id)->where('product_id', $productId)->delete(); if ($deleted) { return false; } WishlistItem::create(['user_id' => $user->id, 'product_id' => $productId]); return true; } $ids = $this->guestIds(); if (in_array($productId, $ids, true)) { $this->storeGuestIds(array_values(array_diff($ids, [$productId]))); return false; } $this->storeGuestIds(array_slice([$productId, ...$ids], 0, self::GUEST_MAX)); return true; } public function remove(int $productId): void { if ($this->has($productId)) { $this->toggle($productId); } } /** * Moves the guest cookie's products onto $user's wishlist and clears it. */ public function mergeGuestInto(Authenticatable $user): void { $ids = $this->guestIds(); if ($ids === []) { return; } // Oldest first, so the newest cookie item also ends up newest here. foreach (array_reverse($ids) as $productId) { WishlistItem::firstOrCreate(['user_id' => $user->id, 'product_id' => $productId]); } $this->guestIds = []; Cookie::queue(Cookie::forget(self::COOKIE)); } /** @return array */ private function guestIds(): array { if ($this->guestIds !== null) { return $this->guestIds; } $decoded = json_decode((string) request()->cookie(self::COOKIE), true); return $this->guestIds = is_array($decoded) ? array_values(array_unique(array_filter(array_map('intval', $decoded)))) : []; } /** @param array $ids */ private function storeGuestIds(array $ids): void { $this->guestIds = $ids; Cookie::queue(self::COOKIE, json_encode($ids), self::COOKIE_MINUTES); } }