2025-07-17 02:04:44 [::1][-][-][error][debug mode] ActionAdd - Added to cart; Context: {
    "product id": 6,
    "quantity": 1,
    "method": "app\\controllers\\CartController::actionAdd",
    "category": "debug mode"
}
2025-07-17 02:04:46 [::1][-][-][error][debug mode] ActionIndex $cartItems data; Context: {
    "cart items": [
        {
            "id": 6,
            "quantity": 1,
            "available_quantity": 4,
            "total_price": 400024
        }
    ],
    "method": "app\\controllers\\CartController::actionIndex",
    "category": "debug mode"
}
2025-07-17 02:04:46 [::1][-][-][error][debug mode] ActionIndex $model->items data; Context: {
    "model items": [
        {
            "productId": 6,
            "quantity": 1,
            "availableQuantity": 4,
            "totalPrice": 400024
        }
    ],
    "method": "app\\controllers\\CartController::actionIndex",
    "category": "debug mode"
}
2025-07-17 02:04:49 [::1][-][-][error][debug mode] ActionIndex $cartItems data; Context: {
    "cart items": [
        {
            "id": 6,
            "quantity": 1,
            "available_quantity": 4,
            "total_price": 400024
        }
    ],
    "method": "app\\controllers\\CartController::actionIndex",
    "category": "debug mode"
}
2025-07-17 02:04:49 [::1][-][-][error][debug mode] ActionIndex $model->items data; Context: {
    "model items": [
        {
            "productId": 6,
            "quantity": 1,
            "availableQuantity": 4,
            "totalPrice": 400024
        }
    ],
    "method": "app\\controllers\\CartController::actionIndex",
    "category": "debug mode"
}
2025-07-17 02:04:49 [::1][-][-][error][debug mode] ActionIndex - isPost; Context: {
    "post data": {
        "_csrf": "nFLHGvCOe2-rhaeokd855dF5T9V9fD5IEflXf4wwtRD4JpdXucUoBIay9szkigiOqzsngCwXSgtkgy5OtUnSdg==",
        "CartUpdateForm": {
            "items": [
                {
                    "quantity": "2",
                    "productId": "1"
                }
            ]
        }
    },
    "model loaded data": true,
    "method": "app\\controllers\\CartController::actionIndex",
    "category": "debug mode"
}
2025-07-17 02:04:49 [::1][-][-][error][debug mode] CartUpdateForm - ValidateItem attributes; Context: {
    "$attributes": "items",
    "method": "app\\models\\forms\\CartUpdateForm::validateItem",
    "category": "debug mode"
}
2025-07-17 02:04:49 [::1][-][-][error][debug mode] CartUpdateForm - ValidateItem foreach attribute as item; Context: {
    "item": {
        "quantity": "2",
        "productId": "1"
    },
    "method": "app\\models\\forms\\CartUpdateForm::validateItem",
    "category": "debug mode"
}
2025-07-17 02:04:49 [::1][-][-][error][application] Cart update validation failed: {"items":["Item #0: Product not found"]}; Context: {
    "errors": {
        "items": [
            "Item #0: Product not found"
        ]
    },
    "method": "app\\controllers\\CartController::actionIndex"
}
2025-07-17 02:04:49 [::1][-][-][error][application] Missing product for ID 1 rendering fallback input; Context: {
    "item id": "1",
    "method": ""
}


view
```
<?php
$form = ActiveForm::begin([
	'id' => 'cart-update-form',
	'action' => ['cart/index'],
	'method' => 'post',
	'options' => ['class' => 'form-inline'],
]);

if (ValueHelper::isSetNotNull($model->items)) :
	foreach ($model->items as $index => $item) :

/**
* Content `product` are fetched as ActiveRecord and indexed by ID for quick access.
* @see app\models\Content.php
*
* Using the model's items array (which contains ['productId' => int, 'quantity' => int] entries),
* extract all product IDs to query the database and retrieve the corresponding active product records.
*
* Then, when rendering the view, iterate over each item from the model:
* - Retrieve the product ID from the item.
* - Use the product ID to fetch the full product ActiveRecord from the loaded $products array.
* - If a matching product is found, we can safely use all its attributes and relations (e.g., price, 
*   title, quantity).
* - If not found (e.g., product removed or inactive), skip that item.
*
* Note: Keep in mind $products is coming from the CartController call to Content model...
*
* 	// Fetch all active product records for items in $model->items
* 	$productIds = array_column($model->items, 'productId');
* 	$products = Content::find()
* 		->id($productIds)
* 		->ofType('product')
* 		->indexBy('id')
* 		->all();
* 	
* 	return $this->render('index', [
* 		'model' => $model,
* 		'products' => $products,
* 	]);
*
* Handling of ActiveRecord via CartController - $products is from the Content model...
*/
$itemId = $item['productId'];
$product = $products[$itemId] ?? null;

if (!$product)
{
	LogHelper::error("Missing product for ID {$item['productId']} rendering fallback input", [
		'item id' => $item['productId'],
		'method' => __METHOD__
	]);
	
	continue;
}

$requestedQty = $item['quantity'];
$availableQty = $item['availableQuantity'];
$productStock = $product->quantity;
$cartTotalPrice = $item['totalPrice'];


$itemAvailQuantity = $model->items[$index]['availableQuantity'] ?? $availableQty;
$itemTemplate = $product->template;
$itemTitle = $product->title;
$itemCategorySlug = $product->category->slug ?? null;
$itemSlug = $product->slug;
$itemPrice = $product->price;
$itemImage = $product->product_image_one;
?>

<?= $form->field($model, "items[$index][quantity]")->input('number', [
	'min' => 0,
	'max' => $productStock,
	'class' => 'cart-quantity form-control',
	'data-product-id' => $itemId,
	'style' => 'width:80px;',
]); ?>

<?= Html::activeHiddenInput($model, "items[$index][productId]"); ?>

<?php endforeach; ?>


<div class="text-center" style="margin:1em 1em">
<small class="text-muted">All payments and transactions are powered by <a href="https://stripe.com/">stripe</a></small>
</div>


<?php else : ?>
<p class="text-muted text-center p-5"><?= \Yii::t('app', 'You have no items in your cart.'); ?></p>


<?php
endif;
ActiveForm::end();
?>
```

controller
```
public function actionIndex(): string|Response
	{
		/** 
		* Sets the metadata for the current webpage.
		* @see app/controllers/SeoController.php
		*
		* This function configures the HTML meta tags for the page's title, keywords, and description. 
		* These tags are important for search engine optimization and enhancement of page display properties.
		*
		* @param string|null $title The title of the page. 
		* 	- If provided, the title will be formatted as "AppName / Title".
		* 	- If not provided, it defaults to "AppName".
		* 
		* @param string|null $keywords A comma-separated list of keywords for the page.
		* 	- These keywords are used by search engines to understand the page content.
		*
		* @param string|null $description A brief description of the page content.
		*	 - This description is used by search engines for the page summary.
		*
		* Example Usage:
		* $this->setMeta('Contact Us', 'contact, help, support', 'Get in touch with us for support.');
		*/
		$pageTitle = \Yii::t('app', 'cart');
		// Set Meta Data for website title, keywords and description.
		$this->setMeta($pageTitle, 'cart, shopping cart', null);
		// Set page breadcrumbs. (optional)
		\Yii::$app->layoutManager->addBreadcrumb($pageTitle);// page now.
		
		
		// Setup model
		$model = new CartUpdateForm();
		
		// @return array
		$cartItems = $this->_isGuest
			? $this->_sessionCart->getCartItems()
			: $this->_userCart->getCartItems();
		
		if ($this->_debugMode)
		{
			//print_r($cartItems);die;
			LogHelper::debug('ActionIndex $cartItems data',[
				'cart items' => $cartItems,
				'method' => __METHOD__
			]);
		}
			
		$model->items = [];
		foreach ($cartItems as $itemData)
		{
			/**
			* Content `product` are fetched as ActiveRecord and indexed by ID for quick access.
			*
			* Using the model's items array (which contains ['productId' => int, 'quantity' => int] entries),
			* extract all product IDs to query the database and retrieve the corresponding active product records.
			*
			* Then, when rendering the view, iterate over each item from the model:
			* - Retrieve the product ID from the item.
			* - Use the product ID to fetch the full product ActiveRecord from the loaded $products array.
			* - If a matching product is found, we can safely use all its attributes and relations (e.g., price, 
			*   title, quantity).
			* - If not found (e.g., product removed or inactive), skip that item.
			*/
			$model->items[] = [
				'productId' => (int) $itemData['id'],
				'quantity' => (int) $itemData['quantity'],
				'availableQuantity' => (int) $itemData['available_quantity'],
				'totalPrice' => (int) $itemData['total_price']
			];
		}
		
		if ($this->_debugMode)
		{
			//print_r($model->items);die;
			LogHelper::debug('ActionIndex $model->items data',[
				'model items' => $model->items,
				'method' => __METHOD__
			]);
		}
		
		$session = \Yii::$app->session;
		$request = \Yii::$app->request;
		//if (($request->isPost) && ($model->load($request->post()) && $model->validate()))
		if (($request->isPost) && ($model->load($request->post())))
		//if ($request->isPost)
		{
			//$model->load($request->post());
		
			if ($this->_debugMode)
			{
				LogHelper::debug('ActionIndex - isPost',[
					'post data' => $request->post(),
					// Load posted data into model (overwrites $model->items)
					'model loaded data' => $model->load($request->post()),
					'method' => __METHOD__
				]);
			}
			
			if ($model->validate())
			{
				$cartService = $this->_isGuest ? $this->_sessionCart : $this->_userCart;
				
				foreach ($model->items as $item)
				{
					$pid = (int) $item['productId'];
					$qty = (int) $item['quantity'];
					
					if ($qty > 0)
					{
						$additive = !$cartService->hasItem($pid);
						
						if ($this->_isGuest)
						{
							$cartService->addItem($pid, $qty, $additive);
						}
						else
						{
							// For user cart addItem signature expects four arguments
							$cartService->addItem($pid, $qty, false, $additive);
						}
					}
					else
					{
						$cartService->removeItem($pid);
					}
				}
				
				\Yii::$app->session->setFlash('success', \Yii::t('app', 'Purchase list updated successfully.'));
				
				return $this->refresh();
			}
			else
			{
				LogHelper::error('Cart update validation failed: ' . json_encode($model->errors), [
					'errors' => $model->errors,
					'method' => __METHOD__,
				]);
			}
		}
		
		// Fetch all active product records for items in $model->items
		$productIds = array_column($model->items, 'productId');
		$products = Content::find()
			->id($productIds)
			->ofType('product')
			->indexBy('id')
			->all();
		
		return $this->render('index', [
			'model' => $model,
			'products' => $products,
		]);
	}
```

form
```
declare(strict_types=1);

namespace app\models\forms;

use yii\base\Model;

use app\models\Content;
use app\helpers\LogHelper;

class CartUpdateForm extends Model
{
	private bool $_debugMode = true;

	/**
	* Items to update: array of ['productId' => int, 'quantity' => int]
	* @var array
	*
	* Example:
	*	[
	* 		['productId' => 123, 'quantity' => 2],
	* 		['productId' => 456, 'quantity' => 0]
	* 	]
	*/
	public array $items = [];
	
	public function rules()
	{
		return [
			['items', 'validateItem']
		];
	}
	
	public function attributeLabels(): array
	{
		return [
			'items' => 'Cart Items',
		];
	}
	
	/**
	* Validate Item
	* @param string $attribute
	* @param array $params
	*
	* Note: Do NOT add parameter(s) type hints. This method overrides an interface 
        * without type hints on parameters, adding types will cause PHP compatibility errors. 
        * Only docblock types to indicate expected input types.
	*/
	public function validateItem($attribute, $params = [])
	{
		if ($this->_debugMode)
		{
			//print_r($cartItems);die;
			LogHelper::debug('CartUpdateForm - ValidateItem attributes',[
				'$attributes' => $attribute,
				'method' => __METHOD__
			]);
		}
	
		foreach ($this->$attribute as $index => $item)
		{
			if ($this->_debugMode)
			{
				//print_r($cartItems);die;
				LogHelper::debug('CartUpdateForm - ValidateItem foreach attribute as item',[
					'item' => $item,
					'method' => __METHOD__
				]);
			}
		
			if (!isset($item['productId']) || !is_numeric($item['productId']))
			{
				$this->addError($attribute, "Item #$index: Invalid Product ID");
			}
			
			// Prevents ContentQuery::id(): Argument #1 ($id) must be of type array|int, string given error...
			$productId = (int) $item['productId'];
			
			// Check if product exists
			$exists = Content::find()
				->id($productId)
				->ofType('product')
				->exists();
			
			if (!$exists)
			{
				$this->addError($attribute, "Item #$index: Product not found");
			}
			
			if (!isset($item['quantity']) || !is_numeric($item['quantity']) || $item['quantity'] < 0)
			{
				$this->addError($attribute, "Item #$index: Quantity must be integer and >= 0");
			}
		}
	}
}
```

Do you see the issue? can you help, yes or no.. and please keep on topic. 




























2025-07-17 01:38:00 [::1][-][-][error][debug mode] ActionIndex $model->items data; Context: {
    "model items": [],
    "method": "app\\controllers\\CartController::actionIndex",
    "category": "debug mode"
}
2025-07-17 01:38:00 [::1][-][-][error][debug mode] ActionIndex - isPost; Context: {
    "post data": {
        "_csrf": "VxhA1DJDmTof158Xc1E4gVuwyK6vkYn6jLHYfcmwGTIuci--XiarTii_wGYFYHbQK_b4lsHB7JTq9qIthuBRYQ==",
        "CartUpdateForm": {
            "items": [
                {
                    "quantity": "2",
                    "productId": "1"
                }
            ]
        }
    },
    "model loaded data": true,
    "method": "app\\controllers\\CartController::actionIndex",
    "category": "debug mode"
}
2025-07-17 01:38:00 [::1][-][-][error][application] Cart update validation failed: {"items":["Item #0: Product not found"]}; Context: {
    "errors": {
        "items": [
            "Item #0: Product not found"
        ]
    },
    "method": "app\\controllers\\CartController::actionIndex"
}
2025-07-17 01:38:00 [::1][-][-][error][application] Missing product for ID 1 rendering fallback input; Context: {
    "item id": "1",
    "method": ""
}

CartController
```
public function actionIndex(): string|Response
	{
		/** 
		* Sets the metadata for the current webpage.
		* @see app/controllers/SeoController.php
		*
		* This function configures the HTML meta tags for the page's title, keywords, and description. 
		* These tags are important for search engine optimization and enhancement of page display properties.
		*
		* @param string|null $title The title of the page. 
		* 	- If provided, the title will be formatted as "AppName / Title".
		* 	- If not provided, it defaults to "AppName".
		* 
		* @param string|null $keywords A comma-separated list of keywords for the page.
		* 	- These keywords are used by search engines to understand the page content.
		*
		* @param string|null $description A brief description of the page content.
		*	 - This description is used by search engines for the page summary.
		*
		* Example Usage:
		* $this->setMeta('Contact Us', 'contact, help, support', 'Get in touch with us for support.');
		*/
		$pageTitle = \Yii::t('app', 'cart');
		// Set Meta Data for website title, keywords and description.
		$this->setMeta($pageTitle, 'cart, shopping cart', null);
		// Set page breadcrumbs. (optional)
		\Yii::$app->layoutManager->addBreadcrumb($pageTitle);// page now.
		
		
		// Setup model
		$model = new CartUpdateForm();
		
		$session = \Yii::$app->session;
		$request = \Yii::$app->request;
		if ($request->isGet)
		{
			// @return array
			$cartItems = $this->_isGuest
				? $this->_sessionCart->getCartItems()
				: $this->_userCart->getCartItems();
			
			/**
			* SessionCartService and CartService
			* @see app\components\services\SessionCartService.php
			* @see app\components\services\CartService.php
			*
			* Both classes handle data within the same construct when returning
			* the array[] of information regarding what is in the guest/user
			* cart.
			*
			* 	array (size=1)
			*		0 => 
			*		array (size=2)
			*			'id' => int 6
			*			'quantity' => int 1
			*
			var_dump($cartItems);die;//*/
			
			$model->items = [];
			foreach ($cartItems as $itemData)
			{
				/**
				* Content `product` are fetched as ActiveRecord and indexed by ID for quick access.
				*
				* Using the model's items array (which contains ['productId' => int, 'quantity' => int] entries),
				* extract all product IDs to query the database and retrieve the corresponding active product records.
				*
				* Then, when rendering the view, iterate over each item from the model:
				* - Retrieve the product ID from the item.
				* - Use the product ID to fetch the full product ActiveRecord from the loaded $products array.
				* - If a matching product is found, we can safely use all its attributes and relations (e.g., price, 
				*   title, quantity).
				* - If not found (e.g., product removed or inactive), skip that item.
				*/
				$model->items[] = [
					'productId' => (int) ($itemData['id'] ?? 0),
					'quantity' => (int) ($itemData['quantity'] ?? 0),
					'availableQuantity' => (int) ($itemData['available_quantity'] ?? 0),
					'totalPrice' => (int) ($itemData['total_price'] ?? 0)
				];
			}
		}
		
		if ($this->_debugMode)
		{
			//print_r($model->items);die;
			LogHelper::debug('ActionIndex $model->items data',[
				'model items' => $model->items,
				'method' => __METHOD__
			]);
		}
		
		//if (($request->isPost) && ($model->load($request->post()) && $model->validate()))
		if (($request->isPost) && ($model->load($request->post())))
		if ($request->isPost)
		{
			//$model->load($request->post());
		
			if ($this->_debugMode)
			{
				LogHelper::debug('ActionIndex - isPost',[
					'post data' => $request->post(),
					// Load posted data into model (overwrites $model->items)
					'model loaded data' => $model->load($request->post()),
					'method' => __METHOD__
				]);
			}
			
			if ($model->validate())
			{
				$cartService = $this->_isGuest ? $this->_sessionCart : $this->_userCart;
				
				foreach ($model->items as $item)
				{
					$pid = (int) $item['productId'];
					$qty = (int) $item['quantity'];
					
					if ($qty > 0)
					{
						$additive = !$cartService->hasItem($pid);
						
						if ($this->_isGuest)
						{
							$cartService->addItem($pid, $qty, $additive);
						}
						else
						{
							// For user cart addItem signature expects four arguments
							$cartService->addItem($pid, $qty, false, $additive);
						}
					}
					else
					{
						$cartService->removeItem($pid);
					}
				}
				
				\Yii::$app->session->setFlash('success', \Yii::t('app', 'Purchase list updated successfully.'));
				
				return $this->refresh();
			}
			else
			{
				LogHelper::error('Cart update validation failed: ' . json_encode($model->errors), [
					'errors' => $model->errors,
					'method' => __METHOD__,
				]);
			}
		}
		
		// Fetch all active product records for items in $model->items
		$productIds = array_column($model->items, 'productId');
		$products = Content::find()
			->id($productIds)
			->ofType('product')
			->indexBy('id')
			->all();
		
		return $this->render('index', [
			'model' => $model,
			'products' => $products,
		]);
	}
```

Cart view
```
<?php
declare(strict_types=1);

use yii\bootstrap5\Html;
use yii\bootstrap5\ActiveForm;
use yii\helpers\Url;

use app\helpers\LogHelper;
use app\helpers\MoneyHelper;
use app\helpers\ValueHelper;
?>

$form = ActiveForm::begin([
	'id' => 'cart-update-form',
	'action' => ['cart/index'],
	'method' => 'post',
	'options' => ['class' => 'form-inline'],
]);

if (ValueHelper::isSetNotNull($model->items)) :
	foreach ($model->items as $index => $item) :

/**
* Content `product` are fetched as ActiveRecord and indexed by ID for quick access.
* @see app\models\Content.php
*
* Using the model's items array (which contains ['productId' => int, 'quantity' => int] entries),
* extract all product IDs to query the database and retrieve the corresponding active product records.
*
* Then, when rendering the view, iterate over each item from the model:
* - Retrieve the product ID from the item.
* - Use the product ID to fetch the full product ActiveRecord from the loaded $products array.
* - If a matching product is found, we can safely use all its attributes and relations (e.g., price, 
*   title, quantity).
* - If not found (e.g., product removed or inactive), skip that item.
*
* Note: Keep in mind $products is coming from the CartController call to Content model...
*
* 	// Fetch all active product records for items in $model->items
* 	$productIds = array_column($model->items, 'productId');
* 	$products = Content::find()
* 		->id($productIds)
* 		->ofType('product')
* 		->indexBy('id')
* 		->all();
* 	
* 	return $this->render('index', [
* 		'model' => $model,
* 		'products' => $products,
* 	]);
*
* Handling of ActiveRecord via CartController - $products is from the Content model...
*/
$itemId = $item['productId'];
$product = $products[$itemId] ?? null;

if (!$product)
{
	LogHelper::error("Missing product for ID {$item['productId']} rendering fallback input", [
		'item id' => $item['productId'],
		'method' => __METHOD__
	]);
	
	continue;
}

$requestedQty = $item['quantity'];
$availableQty = $item['availableQuantity'];
$productStock = $product->quantity;
$cartTotalPrice = $item['totalPrice'];


$itemAvailQuantity = $model->items[$index]['availableQuantity'] ?? $availableQty;
$itemTemplate = $product->template;
$itemTitle = $product->title;
$itemCategorySlug = $product->category->slug ?? null;
$itemSlug = $product->slug;
$itemPrice = $product->price;
$itemImage = $product->product_image_one;
?>

<?= $form->field($model, "items[$index][quantity]")->input('number', [
	'min' => 0,
	'max' => $productStock,
	'class' => 'cart-quantity form-control',
	'data-product-id' => $itemId,
	'style' => 'width:80px;',
]); ?>

<?= Html::activeHiddenInput($model, "items[$index][productId]"); ?>

<?php endforeach; ?>


<div class="text-center" style="margin:1em 1em">
<small class="text-muted">All payments and transactions are powered by <a href="https://stripe.com/">stripe</a></small>
</div>


<?php else : ?>
<p class="text-muted text-center p-5"><?= \Yii::t('app', 'You have no items in your cart.'); ?></p>


<?php
endif;
ActiveForm::end();
?>
```

FormCartUpdate
```
declare(strict_types=1);

namespace app\models\forms;

use yii\base\Model;

use app\models\Content;

class CartUpdateForm extends Model
{
	/**
	* Items to update: array of ['productId' => int, 'quantity' => int]
	* @var array
	*
	* Example:
	*	[
	* 		['productId' => 123, 'quantity' => 2],
	* 		['productId' => 456, 'quantity' => 0]
	* 	]
	*/
	public array $items = [];
	
	public function rules()
	{
		return [
			['items', 'validateItem']
		];
	}
	
	public function attributeLabels(): array
	{
		return [
			'items' => 'Cart Items',
		];
	}
	
	/**
	* Validate Item
	* @param string $attribute
	* @param array $params
	*
	* Note: Do NOT add parameter(s) type hints. This method overrides an interface 
        * without type hints on parameters, adding types will cause PHP compatibility errors. 
        * Only docblock types to indicate expected input types.
	*/
	public function validateItem($attribute, $params = [])
	{
		foreach ($this->$attribute as $index => $item)
		{
			if (!isset($item['productId']) || !is_numeric($item['productId']))
			{
				$this->addError($attribute, "Item #$index: Invalid Product ID");
			}
			
			// Prevents ContentQuery::id(): Argument #1 ($id) must be of type array|int, string given error...
			$productId = (int) $item['productId'];
			
			// Check if product exists
			$exists = Content::find()
				->id($productId)
				->ofType('product')
				->exists();
			
			if (!$exists)
			{
				$this->addError($attribute, "Item #$index: Product not found");
			}
			
			if (!isset($item['quantity']) || !is_numeric($item['quantity']) || $item['quantity'] < 0)
			{
				$this->addError($attribute, "Item #$index: Quantity must be integer and >= 0");
			}
		}
	}
}

```