CartManager
in package
Holds the cart content and the in-progress checkout.
The only class components (Cart, CartWidget, Checkout) and presenters may inject: the
manager is the only model layer visible outside; the lower layers (CartService, mappers,
repositories) are used only by it.
It carries all business logic (quantity cap, case-insensitive voucher dedup, checkout merge,
token, order ownership) and is the only one allowed to touch other managers/framework
services directly: User (who is logged in) and Session (token
and order ownership). Items, vouchers and checkout are delegated to CartService, which
only decides the storage (session or DB).
IMPORTANT: the one-time step-3 token and the order ownership (confirmation page of a guest) always stay in the session, in both storage variants. They are bound to the browser and one form submit, not to the cart content, so a service/mapper/repository abstraction makes no sense for them.
Invariant: the storage holds no price, rate or discount, only identifiers and customer texts. Prices are always computed by the server (OrderCheckoutManager).
Table of Contents
Constants
- MAX_QUANTITY : int = 999
- Quantity cap of one item; guards against typos and nonsensical requests.
- KEY_ORDER_BY_TOKEN : string = 'orderByToken'
- KEY_ORDERS : string = 'orders'
- KEY_TOKEN : string = 'token'
- SECTION : string = 'eshop.cart'
- TOKEN_ORDER_HISTORY : int = 5
- How many token to order pairs the session remembers ({@see rememberOrderForToken()}).
Properties
- $service : CartService
- $session : Session
- $snapshot : CartSnapshot|null
- $snapshotUserId : int|null
- User active at the last snapshot load; detects a login in the middle of a request (see {@see snapshot()}).
- $user : User
Methods
- __construct() : mixed
- add() : void
- Adds the quantity to an existing row (repeated "add to cart" sums instead of overwriting).
- addVoucherCode() : bool
- Returns false when the code is already in the cart (case-insensitive; the `code` collation is case-insensitive).
- clearAfterOrder() : void
- Empties the cart, codes and in-progress checkout after a successful submit.
- consumeToken() : bool
- Returns true when the token was valid and has just been burned; false when it does not match or was already used.
- getCheckout() : array<string, mixed>
- getCheckoutValue() : mixed
- getItems() : array<int, int>
- getLines() : array<int, array{setId: int, quantity: int}>
- getOwnedOrderIds() : array<int, int>
- getTotalQuantity() : int
- Returns the number of pieces in the cart (for the header badge), not the number of rows.
- getVoucherCodes() : array<int, string>
- isEmpty() : bool
- issueToken() : string
- Issues the one-time token when step 3 is displayed.
- mergeCheckout() : void
- orderForToken() : int|null
- Returns the order created by the submit with this token, or `null` (the token created nothing).
- ownsOrder() : bool
- registerOrder() : void
- Remembers an order created by this session.
- rememberOrderForToken() : void
- Remembers which order the submit with this (already burned) token created.
- remove() : void
- removeMany() : void
- removeVoucherCode() : void
- setQuantity() : void
- Sets the absolute quantity; `<= 0` removes the row.
- clampQuantity() : int
- currentUserId() : int|null
- orderTokenMap() : array<string, int>
- persist() : void
- section() : SessionSection
- snapshot() : CartSnapshot
- Reads the logged-in state live and reloads the snapshot when it differs from the last load.
- writeItems() : void
- writeVouchers() : void
Constants
MAX_QUANTITY
Quantity cap of one item; guards against typos and nonsensical requests.
public
int
MAX_QUANTITY
= 999
KEY_ORDER_BY_TOKEN
private
string
KEY_ORDER_BY_TOKEN
= 'orderByToken'
KEY_ORDERS
private
string
KEY_ORDERS
= 'orders'
KEY_TOKEN
private
string
KEY_TOKEN
= 'token'
SECTION
private
string
SECTION
= 'eshop.cart'
TOKEN_ORDER_HISTORY
How many token to order pairs the session remembers ({@see rememberOrderForToken()}).
private
int
TOKEN_ORDER_HISTORY
= 5
Properties
$service read-only
private
CartService
$service
$session read-only
private
Session
$session
$snapshot
private
CartSnapshot|null
$snapshot
= null
$snapshotUserId
User active at the last snapshot load; detects a login in the middle of a request (see {@see snapshot()}).
private
int|null
$snapshotUserId
= null
$user read-only
private
User
$user
Methods
__construct()
public
__construct(CartService $service, Session $session, User $user) : mixed
Parameters
- $service : CartService
- $session : Session
- $user : User
add()
Adds the quantity to an existing row (repeated "add to cart" sums instead of overwriting).
public
add(int $setId[, int $quantity = 1 ]) : void
Parameters
- $setId : int
- $quantity : int = 1
addVoucherCode()
Returns false when the code is already in the cart (case-insensitive; the `code` collation is case-insensitive).
public
addVoucherCode(string $code) : bool
Parameters
- $code : string
Return values
boolclearAfterOrder()
Empties the cart, codes and in-progress checkout after a successful submit.
public
clearAfterOrder() : void
The list of owned orders is deliberately kept so that the customer can reach the confirmation page even after a refresh.
consumeToken()
Returns true when the token was valid and has just been burned; false when it does not match or was already used.
public
consumeToken(string|null $token) : bool
Parameters
- $token : string|null
Return values
boolgetCheckout()
public
getCheckout() : array<string, mixed>
Return values
array<string, mixed>getCheckoutValue()
public
getCheckoutValue(string $key[, mixed $default = null ]) : mixed
Parameters
- $key : string
- $default : mixed = null
getItems()
public
getItems() : array<int, int>
Return values
array<int, int> —setId => quantity (in insertion order)
getLines()
public
getLines() : array<int, array{setId: int, quantity: int}>
Return values
array<int, array{setId: int, quantity: int}> —shape expected by api/eshop/order/checkout
getOwnedOrderIds()
public
getOwnedOrderIds() : array<int, int>
Return values
array<int, int>getTotalQuantity()
Returns the number of pieces in the cart (for the header badge), not the number of rows.
public
getTotalQuantity() : int
Return values
intgetVoucherCodes()
public
getVoucherCodes() : array<int, string>
Return values
array<int, string>isEmpty()
public
isEmpty() : bool
Return values
boolissueToken()
Issues the one-time token when step 3 is displayed.
public
issueToken() : string
The form carries it in a hidden field; consumeToken() burns it on submit, so a second submit (double click, reload, back button) does not create another order. The PHP session lock serializes concurrent requests of the same session, so a double click cannot pass both branches at once.
Return values
stringmergeCheckout()
public
mergeCheckout(array<string, mixed> $values) : void
Parameters
- $values : array<string, mixed>
-
merged with the stored ones (a step overwrites only its own fields)
orderForToken()
Returns the order created by the submit with this token, or `null` (the token created nothing).
public
orderForToken(string|null $token) : int|null
Parameters
- $token : string|null
Return values
int|nullownsOrder()
public
ownsOrder(int $orderId) : bool
Parameters
- $orderId : int
Return values
boolregisterOrder()
Remembers an order created by this session.
public
registerOrder(int $orderId) : void
A guest has no account, so this is the only way to show them the confirmation page and not to show it to anyone who types a foreign id into the URL.
Parameters
- $orderId : int
rememberOrderForToken()
Remembers which order the submit with this (already burned) token created.
public
rememberOrderForToken(string $token, int $orderId) : void
A double click or reload then leads exactly to it, not to "the last order the session owns". The difference shows after a failed submit: the token is burned, no order was created, and without this link the customer would see an old unrelated order of the same session as the confirmation.
The map is kept short (self::TOKEN_ORDER_HISTORY); only the window between submit and leaving step 3 matters.
Parameters
- $token : string
- $orderId : int
remove()
public
remove(int $setId) : void
Parameters
- $setId : int
removeMany()
public
removeMany(array<int, int> $setIds) : void
Parameters
- $setIds : array<int, int>
-
bulk removal ("remove selected" in the cart)
removeVoucherCode()
public
removeVoucherCode(string $code) : void
Parameters
- $code : string
setQuantity()
Sets the absolute quantity; `<= 0` removes the row.
public
setQuantity(int $setId, int $quantity) : void
Parameters
- $setId : int
- $quantity : int
clampQuantity()
private
clampQuantity(int $quantity) : int
Parameters
- $quantity : int
Return values
intcurrentUserId()
private
currentUserId() : int|null
Return values
int|nullorderTokenMap()
private
orderTokenMap() : array<string, int>
Return values
array<string, int>persist()
private
persist() : void
section()
private
section() : SessionSection
Return values
SessionSectionsnapshot()
Reads the logged-in state live and reloads the snapshot when it differs from the last load.
private
snapshot() : CartSnapshot
A login changes which cart is the right one (merge), so the state is never cached; the
reload also merges through CartService. A normal request logs in through a different
action (PRG redirect), so in practice this branch runs once; it also protects future code
that would use CartManager both before and after User::login() in one request.
Return values
CartSnapshotwriteItems()
private
writeItems(array<int, int> $items) : void
Parameters
- $items : array<int, int>
writeVouchers()
private
writeVouchers(array<int, string> $vouchers) : void
Parameters
- $vouchers : array<int, string>