Files
wordpress-theme-aksrt/src/AKSRT/Shop/CartService.php
T
kate522 68d2e78d77 fix(ns): class_exists() must use FQCN after PSR-4
Bare class_exists('Balance') looks up global Balance, always false
under AKSRT\* namespaces → REST 403 on balance exchange and friends.
Rewrite string checks to AKSRT\{Domain}\{Class}.
2026-07-17 15:40:20 +08:00

174 lines
5.8 KiB
PHP

<?php
/**
* @package AKSRT
*/
namespace AKSRT\Shop;
defined('ABSPATH') || exit;
class CartService {
private Shop $shop;
public function __construct(Shop $shop) {
$this->shop = $shop;
}
public function get_cart(int $user_id): array {
if ($user_id <= 0) {
return [];
}
$cart = get_user_meta($user_id, 'shop_cart', true);
return is_array($cart) ? $cart : [];
}
public function get_cart_count(int $user_id): int {
$cart = $this->get_cart($user_id);
$count = 0;
foreach ($cart as $opts) {
if (is_array($opts)) {
foreach ($opts as $qty) {
$count += (int) $qty;
}
}
}
return $count;
}
public function add_to_cart(int $user_id, int $product_id, string $options_string = '', int $count = 1): array {
if ($user_id <= 0 || $product_id <= 0 || $count <= 0) {
return ['error' => 'invalid_params'];
}
$validation = $this->validate_cart_item($product_id, $options_string);
if ($validation !== true) {
return ['error' => $validation];
}
$cart = $this->get_cart($user_id);
$pid_key = (string) $product_id;
$opt_key = $options_string !== '' ? $options_string : '_default';
if (!isset($cart[$pid_key]) || !is_array($cart[$pid_key])) {
$cart[$pid_key] = [];
}
$cart[$pid_key][$opt_key] = ((int) ($cart[$pid_key][$opt_key] ?? 0)) + $count;
// Enforce limit_buy if set
$limit = (int) get_post_meta($product_id, '_aksrt_limit_buy', true);
if ($limit > 0 && $cart[$pid_key][$opt_key] > $limit) {
$cart[$pid_key][$opt_key] = $limit;
}
update_user_meta($user_id, 'shop_cart', $cart);
return ['success' => true, 'cart_count' => $this->get_cart_count($user_id)];
}
public function reduce_from_cart(int $user_id, int $product_id, string $options_string = '', int $count = 1): array {
if ($user_id <= 0 || $product_id <= 0 || $count <= 0) {
return ['error' => 'invalid_params'];
}
$cart = $this->get_cart($user_id);
$pid_key = (string) $product_id;
$opt_key = $options_string !== '' ? $options_string : '_default';
if (isset($cart[$pid_key][$opt_key])) {
$cart[$pid_key][$opt_key] -= $count;
if ($cart[$pid_key][$opt_key] <= 0) {
unset($cart[$pid_key][$opt_key]);
}
}
if (empty($cart[$pid_key])) {
unset($cart[$pid_key]);
}
update_user_meta($user_id, 'shop_cart', $cart);
return ['success' => true, 'cart_count' => $this->get_cart_count($user_id)];
}
public function remove_from_cart(int $user_id, int $product_id, string $options_string = ''): array {
if ($user_id <= 0) {
return ['error' => 'invalid_params'];
}
$cart = $this->get_cart($user_id);
$pid_key = (string) $product_id;
$opt_key = $options_string !== '' ? $options_string : '_default';
if ($options_string === '' && isset($cart[$pid_key])) {
// Remove all options for this product
unset($cart[$pid_key]);
} elseif (isset($cart[$pid_key][$opt_key])) {
unset($cart[$pid_key][$opt_key]);
if (empty($cart[$pid_key])) {
unset($cart[$pid_key]);
}
}
update_user_meta($user_id, 'shop_cart', $cart);
return ['success' => true, 'cart_count' => $this->get_cart_count($user_id)];
}
public function remove_multi_from_cart(int $user_id, array $items): array {
if ($user_id <= 0) {
return ['error' => 'invalid_params'];
}
$cart = $this->get_cart($user_id);
foreach ($items as $item) {
$pid_key = (string) ($item['product_id'] ?? 0);
$opt_key = !empty($item['options_string']) ? $item['options_string'] : '_default';
if (isset($cart[$pid_key][$opt_key])) {
unset($cart[$pid_key][$opt_key]);
if (empty($cart[$pid_key])) {
unset($cart[$pid_key]);
}
}
}
update_user_meta($user_id, 'shop_cart', $cart);
return ['success' => true, 'cart_count' => $this->get_cart_count($user_id)];
}
public function empty_cart(int $user_id): array {
if ($user_id <= 0) {
return ['error' => 'invalid_params'];
}
delete_user_meta($user_id, 'shop_cart');
return ['success' => true, 'cart_count' => 0];
}
/**
* Validate a product for cart addition.
* Returns true if valid, or a string error code.
*/
public function validate_cart_item(int $product_id, string $options_string = '') {
$post = get_post($product_id);
if (!$post || $post->post_type !== 'aksrt_product') {
return 'invalid_product';
}
if ($post->post_status !== 'publish') {
return 'product_not_published';
}
// Check stock (unless unlimited)
$stock = (int) get_post_meta($product_id, '_aksrt_stock', true);
if ($stock > -1 && $stock <= 0) {
return 'out_of_stock';
}
// Check guest_buy — if disabled and user not logged in
if (!is_user_logged_in()) {
$guest = get_post_meta($product_id, '_aksrt_guest_buy', true);
if ($guest === '0' || $guest === '') {
// Fall back to inheritance chain via TermMeta
if (class_exists('AKSRT\Shop\TermMeta')) {
$resolved = TermMeta::resolve_inheritance($product_id, 'guest_buy');
if (empty($resolved)) {
return 'login_required';
}
}
}
}
return true;
}
}