```
namespace app\models;

use app\components\traits\BitmaskTrait;

class Product extends ActiveRecord
{
	use BitmaskTrait;
	
	public const PURCHASE_OPTIONS_CART = 1;// 2^0
	public const PURCHASE_OPTIONS_INQUIRE = 2;// 2^1
	public const PURCHASE_OPTIONS_BUYNOW = 4;// 2^2
	
	/**
	* Virtual attribute to hold array for form checkbox binding.
	* @var int[]|null
	*/
	private ?array $_purchaseOptionsArray = null;
	
	public static function tableName(): string
	{
		return '{{%product}}';
	}
	
	public function rules(): array
	{
		return [
			['purchase_options', 'default', 'value' => self::PURCHASE_OPTIONS_CART | self::PURCHASE_OPTIONS_INQUIRE],
			['purchaseOptionsArray', 'safe'],// Also allow purchaseOptionsArray for form binding as safe
			['purchaseOptionsArray', 'validatePurchaseOptions'],
            	];
	}
	
	/**
	* Validates for $this->_purchaseOptionsArray into $product->purchase_options
	* @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 validatePurchaseOptions($attribute, $params = []): void
	{
		$values = $this->$attribute;
		
		if (!is_array($values))
		{
			$this->addError($attribute, 'Invalid purchase options.');
			
			return;
		}
		
		$bitmask = $this->arrayToBitmask($values);
		$flagsSum = array_sum(self::getPurchaseOptionFlags());
		
		if (($bitmask & ~$flagsSum) !== 0)
		{
			$this->addError($attribute, 'Product options contain invalid flags.');
			
			return;
		}
		
		if (($bitmask & self::PURCHASE_OPTIONS_CART) && ($bitmask & self::PURCHASE_OPTIONS_BUYNOW))
		{
			$this->addError($attribute, 'Product purchase options cannot include both Cart and Buy Now.');
		}
	}
	
	/**
	* Returns the map of purchase option keys to labels for UI.
	* @return array
	*/
	public function getPurchaseOptionsLabels(): array
	{
		return [
			self::PURCHASE_OPTIONS_CART => \Yii::t('app', 'Cart'),
			self::PURCHASE_OPTIONS_INQUIRE => \Yii::t('app', 'Inquire'),
			self::PURCHASE_OPTIONS_BUYNOW => \Yii::t('app', 'Buy Now'),
		];
	}
	
	/**
	* Before Validation
	* @url https://www.yiiframework.com/doc/api/2.0/yii-base-model#beforeValidate()-detail
	* return bool 	
	* Whether the validation should be executed. Defaults to true. If false is returned, the validation 
	* will stop and the model is considered invalid.
	* 
	* Automatically set the 'type' of the post based on its category's type before validation.
	*/
	public function beforeValidate(): bool
	{
		if (!parent::beforeValidate())
		{
			return false;
		}
		
		/**
		* Purchase Options Array to Bitmask
		* Convert purchaseOptionsArray from form into bitmask int before validation.
		*/
		if ($this->_purchaseOptionsArray !== null)
		{
			$this->purchase_options = $this->arrayToBitmask($this->_purchaseOptionsArray);
		}
		elseif (is_array($this->purchase_options))
		{
			// Defensive: convert in case purchase_options is array (usually from form POST)
			$this->purchase_options = $this->arrayToBitmask($this->purchase_options);
		}
		else
		{
			// Ensure integer type
			$this->purchase_options = (int) $this->purchase_options;
		}
		
		return true;
	}
	
	/**
	* Returns all possible purchase option flags.
	* Useful in forms and validation.
	*/
	public static function getPurchaseOptionFlags(): array
	{
		return [
			self::PURCHASE_OPTIONS_CART,
			self::PURCHASE_OPTIONS_INQUIRE,
			self::PURCHASE_OPTIONS_BUYNOW,
		];
	}
	
	/**
	* Defensive getter to return purchase_options with default if null.
	* @return int
	*/
	public function getPurchaseOptions(): int
	{
		if ($this->purchase_options !== null)
		{
			return $this->purchase_options;
		}
		
		if ($this->isNewRecord)
		{
			return self::PURCHASE_OPTIONS_CART | self::PURCHASE_OPTIONS_INQUIRE;
		}
		
		return 0;
		//return $this->purchase_options ?? 0;
	}
	
	/**
	* Get Purchase Options for Checkboxes
	* @return array
	*
	* Helper to get purchase options as array for checkbox input in forms.
	*/
	public function getPurchaseOptionsForCheckboxes(): array
	{
		return $this->bitmaskToArray($this->getPurchaseOptions(), self::getPurchaseOptionFlags());
	}
	
	/**
	* Returns the purchase options as an array of flags.
	* If the internal cache is null, it converts current bitmask.
	* Useful for checkboxes.
	*/
	public function getPurchaseOptionsArray(): array
	{
		if ($this->_purchaseOptionsArray === null)
		{
			$this->_purchaseOptionsArray = $this->getPurchaseOptionsForCheckboxes();
		}
		
		return $this->_purchaseOptionsArray;
	}
	
	/**
	* Accepts an array of flags and sets both virtual array and bitmask.
	*/
	public function setPurchaseOptionsArray(array $values): void
	{
		$this->_purchaseOptionsArray = $values;
		$this->purchase_options = $this->arrayToBitmask($values);
		
		//\Yii::error('setPurchaseOptionsArray called: ' . json_encode($values));
	}
	
	/**
	* Has Purchase Options
	* @param int $flag
	* @return bool
	*
	* Instead of calling hasStatus() twice in the if condition, you can directly 
	* check using a bitwise operation:
	*
	*	// Fetch the message with a specific ID.
	* 	$product = Product::findOne($id);
	*
	* 	if (($product->purchase_options & (Product::PURCHASE_OPTIONS_CART | Product::PURCHASE_OPTIONS_INQUIRE)) === 
	*		(Product::PURCHASE_OPTIONS_CART| Product::PURCHASE_OPTIONS_INQUIRE)
	*	)
	*	{
	*		echo "This product is inquire only.";
	*	}
	*
	* In this alternative approach:
	*
	* 	The expression Product::PURCHASE_OPTIONS_CART | Product::PURCHASE_OPTIONS_INQUIRE
	*	combines both statuses (using the bitwise OR).
	*
	* 	The condition checks if both statuses are set within the status field of 
	*	the message.
	*
	* 	if ($model->hasPurchaseOptions(Product::PURCHASE_OPTIONS_INQUIRE))
	*	{
	*		// do something
	*	}
	*/
	public function hasPurchaseOptions(int $flag): bool
	{
		return ($this->getPurchaseOptions() & $flag) === $flag;
	}
	
	/**
	* Add Purchase Options
	* @param int $flag
	*
	* Set Statuses (make sure to save):
	*
	*	$user->addPurchaseOptions(Product::PURCHASE_OPTIONS_CART);
	*	$user->save();// Save changes to the database.
	*/
	public function addPurchaseOptions(int $flag): void
	{
		$current = $this->purchase_options ?? 0;
		$this->purchase_options = $current | $flag;
	}
	
	/**
	* Remove Purchase Options
	* @param int $flag
	*
	* For example, if the current status is 5 (00101) and we want to remove 
	* the "Unread" status (1 or 00001), the resulting status will change to
	* 4 (00100).
	*
	* Removing Purchase Options:
	*	
	*	$user->removePurchaseOptions(Product::PURCHASE_OPTIONS_CART);
	*/
	public function removePurchaseOptions(int $flag): void
	{
		$current = $this->purchase_options ?? 0;
		$this->purchase_options = $current & (~$flag);
	}
	
	/**
	* Getter User Statuses
	* How to use:
	*
	*	$user->isActive();
	*/
	public function isCart(): bool
	{
		return $this->hasPurchaseOptions(self::PURCHASE_OPTIONS_CART);
	}
	
	public function isInquire(): bool
	{
		return $this->hasPurchaseOptions(self::PURCHASE_OPTIONS_INQUIRE);
	}
	
	public function isBuynow(): bool
	{
		return $this->hasPurchaseOptions(self::PURCHASE_OPTIONS_BUYNOW);
	}
	
	/**
	* Setters User Statuses
	* How to use:
	*
	*	$user->activateAccount();
	*
	* Note: Delete status is exclusive and clears all other flags.
	*/
	public function setCart(): void
	{
		$this->addPurchaseOptions(self::PURCHASE_OPTIONS_CART);
	}
	
	public function setInquire(): void
	{
		$this->addPurchaseOptions(self::PURCHASE_OPTIONS_INQUIRE);
	}
	
	public function setBuynow(): void
	{
		$this->addPurchaseOptions(self::PURCHASE_OPTIONS_BUYNOW);
	}
}
```

Bitmask Trait
```
namespace app\components\traits;

trait BitmaskTrait
{
	public function bitmaskToArray(int $bitmask, array $allFlags): array
	{
		$flags = [];
		
		foreach ($allFlags as $flag)
		{
			if (($bitmask & $flag) === $flag)
			{
				$flags[] = $flag;
			}
		}
		
		return $flags;
	}
	
	public function arrayToBitmask(array $flags): int
	{
		$bitmask = 0;
		
		foreach ($flags as $flag)
		{
			$bitmask |= (int) $flag;
		}
		
		return $bitmask;
	}
}
```

and how I use it in view
```
echo $form->field($model, 'purchaseOptionsArray')->checkboxList(
	$model->getPurchaseOptionsLabels(),
	[
		'encode' => false,
		'item' => function ($index, $label, $name, $checked, $value)
		{
			// Yii normally adds [] for multiple checkboxes automatically
			$id = $name . '_' . $index;
			
			$checkbox = Html::checkbox($name, $checked, [
				'value' => $value,
				'id' => $id,
				'class' => 'form-check-input',
			]);
			
			$labelTag = Html::label(Html::encode($label), $id, ['class' => 'form-check-label']);
			
			return Html::tag('div', $checkbox . $labelTag, [
				'class' => 'form-check form-check-inline',
				'style' => 'margin-right:15px;',
			]);
		},
	]
);
?>
```

Im showing you the product code and how purchase_options works because I need assistance in recoding my message status.
it also uses bitmasking.

```
namespace app\models;

class Message extends ActiveRecord
{
	const STATUS_UNREAD = 1;// 0b00001
	const STATUS_READ = 2;// 0b00010
	const STATUS_IMPORTANT = 4;// 0b00100
	const STATUS_RESOLVED = 8;// 0b01000
	const STATUS_SPAM = 16;// 0b10000
	const STATUS_ARCHIVED = 32;// 0b100000
	const STATUS_FLAGGED = 64;// 0b110000
	const STATUS_REPLIED = 128;// 0b10000000
	
	public static function tableName(): string
	{
		return '{{%message}}';
	}

	public function rules(): array
	{
		return [
			// Message Status
			['status', 'default', 'value' => self::STATUS_UNREAD],
			
			/**
			* Validate the order's status to ensure it does not contain any contradictory 
			* combinations before proceeding with the save operation. This method will add 
			* any validation errors to the model if invalid statuses are detected, preventing 
			* the order from being saved if the validation fails.
			*/
			['status', 'validateStatus'],
		];
	}
	
	public function validateStatus($attribute, $params = []): void
	{
		$validFlags = self::STATUS_UNREAD | self::STATUS_READ | self::STATUS_IMPORTANT | self::STATUS_RESOLVED | 
			self::STATUS_SPAM | self::STATUS_ARCHIVED | self::STATUS_FLAGGED | self::STATUS_REPLIED;
		
		// If any bit outside validFlags is set, invalid
		if (($this->$attribute & ~$validFlags) !== 0)
		{
			$this->addError($attribute, 'Status contains invalid flags.');
			
			return;
		}
		
		/**
		* Unread and Read conflict.
		*
		$unreadAndRead = self::STATUS_UNREAD | self::STATUS_READ;
		if (($this->status & $unreadAndRead) === ($unreadAndRead))
		{
			$this->addError($attribute, \Yii::t('app', 'Status cannot be both unread and read.'));
		}//*/
		
		// Important and Resolved conflict.
		$importantAndResolved = self::STATUS_IMPORTANT | self::STATUS_RESOLVED;
		if (($this->status & $importantAndResolved) === $importantAndResolved)
		{
			$this->addError($attribute, \Yii::t('app', 'Status cannot be both important and resolved.'));
		}
		
		// Important and Spam conflict.
		if (($this->status & self::STATUS_IMPORTANT) && ($this->status & self::STATUS_SPAM))
		{
			$this->addError($attribute, \Yii::t('app', 'Status cannot be both important and spam.'));
		}
		
		// Resolved and Spam conflict.
		if (($this->status & self::STATUS_RESOLVED) && ($this->status & self::STATUS_SPAM))
		{
			$this->addError($attribute, \Yii::t('app', 'Status cannot be both resolved and spam.'));
		}
		
		// Archived and Spam conflict.
		if (($this->status & self::STATUS_ARCHIVED) && ($this->status & self::STATUS_SPAM))
		{
			$this->addError($attribute, \Yii::t('app', 'Status cannot be both archived and spam.'));
		}
	}
	
	public function addError($attribute, $error = ''): void
	{
		// Example implementation, adapt as needed per your environment
		echo "Validation error on {$attribute}: {$error}\n";
	}
	
	public function getStatusLabels(): array
	{
		return [
			//self::STATUS_UNREAD => \Yii::t('app', 'Unread'),// Handled within.
			self::STATUS_READ => \Yii::t('app', 'Read'),
			self::STATUS_IMPORTANT => \Yii::t('app', 'Important'),
			self::STATUS_RESOLVED => \Yii::t('app', 'Resolved'),
			self::STATUS_SPAM => \Yii::t('app', 'Spam'),
			self::STATUS_ARCHIVED => \Yii::t('app', 'Archived'),
			self::STATUS_FLAGGED => \Yii::t('app', 'Flagged'),
			self::STATUS_REPLIED => \Yii::t('app', 'Replied'),
		];
	}
	
	public function getStatusLabel(): string
	{
		$labels = [];
		
		foreach (self::getStatusLabels() as $bit => $label)
		{
			if ($this->hasStatus($bit))
			{
				$labels[] = $label;
			}
		}
		
		return empty($labels) ? \Yii::t('app', 'Unknown') : implode(', ', $labels);
	}
	
	public function getStatusList(): string
	{
		$statuses = self::getStatusLabels();
		
		if (array_key_exists($this->status, $statuses))
		{
			return $statuses[$this->status];
		}
		
		return \Yii::t('app', 'Unknown');
	}
	
	/**
	* Types List
	*/
	public static function getTypeLabels(): array
	{
		return [
			self::TYPE_CONTACT => \Yii::t('app', 'Contact'),
			self::TYPE_INQUIRY => \Yii::t('app', 'Inquiry'),
			self::TYPE_ORDER => \Yii::t('app', 'Order'),
			self::TYPE_SUPPORT => \Yii::t('app', 'Assistance'),
		];
	}
	
	public function getTypeList(): string
	{
		$types = self::getTypeLabels();
		
		return $types[$this->type];
	}
	
	/**
	* Get Status for Checkboxes
	* @return array An array containing currently active statuses for the message.
	*
	* Returns array of active status flags for checkboxes.
	* No exclusivity enforced here; validation step forbids invalid combos.
	*/
	public function getStatusForCheckboxes(): array
	{
		$statuses = [];
		
		/**
		* Unread and Read conflict.
		*
		if ($this->hasStatus(self::STATUS_UNREAD) && !$this->hasStatus(self::STATUS_READ))
		{
			$statuses[] = self::STATUS_UNREAD;
		}
		elseif (!$this->hasStatus(self::STATUS_UNREAD) && $this->hasStatus(self::STATUS_READ)
		{
			$statuses[] = self::STATUS_READ;
		}//*/
		
		// Important and Resolved conflict.
		if ($this->hasStatus(self::STATUS_IMPORTANT) && !$this->hasStatus(self::STATUS_RESOLVED))
		{
			$statuses[] = self::STATUS_IMPORTANT;
		}
		elseif (!$this->hasStatus(self::STATUS_IMPORTANT) && $this->hasStatus(self::STATUS_RESOLVED))
		{
			$statuses[] = self::STATUS_RESOLVED;
		}
		
		// Only add Spam if it's not conflicting (important, resolved, archived)
		// Spam conflicts are handled at validation, so just add if set
		if ($this->hasStatus(self::STATUS_SPAM))
		{
			$statuses[] = self::STATUS_SPAM;
		}
		
		// Archived (not mutually exclusive with anything except spam, handled by validation)
		if ($this->hasStatus(self::STATUS_ARCHIVED))
		{
			$statuses[] = self::STATUS_ARCHIVED;
		}
		
		// Flagged and Replied just add if set
		if ($this->hasStatus(self::STATUS_FLAGGED))
		{
			$statuses[] = self::STATUS_FLAGGED;
		}
		
		if ($this->hasStatus(self::STATUS_REPLIED))
		{
			$statuses[] = self::STATUS_REPLIED;
		}
		
		return array_unique($statuses);
	}
	
	public function setStatusFromCheckboxes($checkboxes): void
	{
		$this->status = 0;
		foreach ($checkboxes as $value)
		{
			$this->addStatus((int) $value);
		}
	}
	
	/**
	* Has Status
	* @param int $flag
	* @return bool
	*
	* Instead of calling hasStatus() twice in the if condition, you can directly 
	* check using a bitwise operation:
	*
	* 	$user = User::findOne($id);// Fetch the message with a specific ID.
	* 	if (($user->status & (User::STATUS_ACTIVE | User::STATUS_LOCKED)) === 
	*		(User::STATUS_ACTIVE | User::STATUS_LOCKED))
	*	{
	*
	*		echo "This product is inquire only.";
	*	}
	*
	* In this alternative approach:
	*
	* 	The expression User::STATUS_ACTIVE  | User::STATUS_LOCKED
	*	combines both statuses (using the bitwise OR).
	*
	* 	The condition checks if both statuses are set within the status field of 
	*	the message.
	*/
	public function hasStatus(int $flag): bool
	{
		return ($this->status & $flag) === $flag;
	}
	
	/**
	* Add Status
	* @param int $flag
	*
	* Set Statuses (make sure to save):
	*
	*	$user->addStatus(User::STATUS_ACTIVE);
	*	$user->save();// Save changes to the database.
	*/
	public function addStatus(int $flag): void
	{
		$this->status |= $flag;
	}
	
	/**
	* Remove Status
	* @param int $flag
	*
	* Removing Statuses:
	*	
	*	$user->removeStatus(User::STATUS_ACTIVE);
	*/
	public function removeStatus(int $flag): void
	{
		$this->status &= ~$flag;
	}
	
	/**
	* Getter User Statuses
	* How to use:
	*
	*	$user->isActive();
	*/
	public function isUnread(): bool
	{
		return $this->hasStatus(self::STATUS_UNREAD);
	}
	
	public function isRead(): bool
	{
		return $this->hasStatus(self::STATUS_READ);
	}
	
	public function isImportant(): bool
	{
		return $this->hasStatus(self::STATUS_IMPORTANT);
	}
	
	public function isResolved(): bool
	{
		return $this->hasStatus(self::STATUS_RESOLVED);
	}
	
	public function isSpam(): bool
	{
		return $this->hasStatus(self::STATUS_SPAM);
	}
	
	public function isArchived(): bool
	{
		return $this->hasStatus(self::STATUS_ARCHIVED);
	}
	
	public function isFlagged(): bool
	{
		return $this->hasStatus(self::STATUS_FLAGGED);
	}
	
	public function isReplied(): bool
	{
		return $this->hasStatus(self::STATUS_REPLIED);
	}
	
	/**
	* Setters User Statuses
	* How to use:
	*
	*	$user->activateAccount();
	*/
	public function setUnread(): void
	{
		$this->addStatus(self::STATUS_UNREAD);
	}
	
	public function setRead(): void
	{
		$this->addStatus(self::STATUS_READ);
	}
	public function setImportant(): void
	{
		$this->addStatus(self::STATUS_IMPORTANT);
	}
	
	public function setResolved(): void
	{
		$this->addStatus(self::STATUS_RESOLVED);
	}
	
	public function setSpam(): void
	{
		$this->addStatus(self::STATUS_SPAM);
	}
	public function setArchived(): void
	{
		$this->addStatus(self::STATUS_ARCHIVED);
	}
	
	public function setFlagged(): void
	{
		$this->addStatus(self::STATUS_FLAGGED);
	}
	
	public function setReplied(): void
	{
		$this->addStatus(self::STATUS_REPLIED);
	}
}
```

message controller
```
namespace app\controllers;

class MessageController extends BaseController
{
	public function actionViewUpdate(int $id): Response|string
	{
		$model = $this->findModel($id);
		$replyForm = new ReplyForm($model->id);
		
		$request = \Yii::$app->request;
		if (($request->isPost) && ($replyForm->load($request->post())))
		{
			// Checks Message $model if $model->status has STATUS_REPLIED and if $model->replied been set.
			 if (!$model->hasStatus(Message::STATUS_REPLIED) && ValueHelper::isSetAndNull($model->replied))
			 {
			 	// Handle Replyform $replyForm->checkboxes as statuses bits (Message $model->status)
			 	$selectedStatus = 0;
			 	
			 	foreach ($replyForm->checkboxes as $status)
			 	{
			 		$selectedStatus |= (int) $status;
			 	}
			 	
			 	// Compare the Replyform $replyForm->status with the current Message $model->status
			 	$getStatus = $selectedStatus !== $model->status;
			 	
			 	// Determine if Replyform $replyForm->reply has been provided via the Replyform model
			 	$getReply = ValueHelper::isSetNotNull($replyForm->reply);
			 	
				if ($getReply && $getStatus)
				{
					$replyForm->scenario = 'both';
				}
				elseif ($getReply)
				{
					$replyForm->scenario = 'replyOnly';
				}
				elseif ($getStatus)
				{
					$replyForm->scenario = 'statusOnly';
				}
			}
			else
			{
				$replyForm->scenario = 'statusOnly';
			}
			
			// Use the selected scenario to validate ReplyForm $replyForm and run $replyForm->process() function
			if ($replyForm->validate())
			{
				// Update the Message model's status based on the checkboxes from the ReplyForm. This ensures 
				// the latest status is used for validation, allowing conflicts to be caught  e.g., conflicting 
				// statuses like important and resolved) during validation.
				$model->setStatusFromCheckboxes($replyForm->checkboxes);
				
				// Message $model custom status validation check. If error occurs, flash errors
				if (!$replyForm->validateAssociatedMessage($model))
				{
					$this->setErrorsFlash($model);
				}
				else
				{
					// if (!$model->hasStatus(Message::STATUS_REPLIED)) {
					if ($replyForm->process())
					{
						$this->setScenarioSuccessFlash($replyForm->scenario, $model);
						
						return $this->redirect(['index']);
					}
					else
					{
						$this->setErrorsFlash($replyForm);
					}
					//}// Else statement with error if trying to save Message $model->status as STATUS_REPLIED.
				}
			}
			// Replyform $replyForm validation failed. Check errors.
			else
			{
				$this->setErrorsFlash($replyForm);
			}
		}
		
		// First time viewing Message, mark Message $model->status to read and remove unread.
		if (($request->isGet) && ($model->hasStatus(Message::STATUS_UNREAD)))
		{
			try
			{
				$model->removeStatus(Message::STATUS_UNREAD);
				$model->addStatus(Message::STATUS_READ);
			
				if (!$model->save(false, ['status']))
				{
					throw new YiiDbException("Failed to save message status to the database.");
				}
			}
			catch (Throwable $e)
			{
				\Yii::$app->session->setFlash('error', 'Could not mark status as read.');
				
				// Use the ExceptionLogger to handle and log the exception.
				ExceptionLogger::log($e, 'reply_form_error_');
			}
		}
		
		// Fetching of replies for the message is only needed for Order and internal Inquries on product.
		$replies = $model->getReplies()->all();
		
		// Setup Formatter Helper for view
		$formatterHelper = FormatterHelper::create($this->_formatter);
		
		return $this->render('viewUpdate', [
			'model' => $model,
			'replyForm' => $replyForm,
			'replies' => $replies,
			'formatterHelper' => $formatterHelper,
		]);
	}
	
	private function setScenarioSuccessFlash(string $scenario, $model): void
	{
		switch ($scenario)
		{
			case 'statusOnly' :
				$msg = \Yii::t(
					'app',
					'The status for message #{id} has been updated.',
					['id' => $model->id]
				);
				
				break;
				
			case 'replyOnly' :
			case 'both' :
			default :
				$msg = \Yii::t(
					'app',
					'Your reply to {to} has been sent.',
					['to' => $model->email]
				);
				
				break;
		}
		
		\Yii::$app->session->setFlash('success', $msg);
	}
	
	private function setErrorsFlash($model): void
	{
		$modelErrors = $model->getErrors();
		
		if (!empty($modelErrors))
		{
			$errorMessages = [];
			foreach ($modelErrors as $errors)
			{
				$errorMessages = array_merge($errorMessages, $errors);
			}
			
			// Strip tags from each error message and prepare the final string.
			$strippedErrorMessages = implode(' ', array_map('strip_tags', $errorMessages));
			
			\Yii::$app->session->setFlash('error', \Yii::t('app', 'Error: {errors}', [
				'errors' => $strippedErrorMessages,
			]));
		}
		
		/**
		* Generic error response.
		*
		else
		{
			\Yii::$app->session->setFlash('error', ErrorMessageHelper::genericError());
		}//*/
	}
	
	protected function findModel(int $id): Message
	{
		if ($this->_isGuest)
		{
			return $this->goHome();
		}
		
		$model = Message::findOne(['id' => $id]);
		if ($model !== null)
		{
			return $model;
		}
		
		//throw new YiiWebNotFoundHttpException(ErrorMessageHelper::badRequest());
		$msg = \Yii::t('app', 'No Message found with `{value}`', ['value' => $id]);
		throw new YiiWebNotFoundHttpException($msg);
	}
}
```

replyform
```
declare(strict_types=1);

namespace app\models\forms;

class ReplyForm extends Model
{
	/**
	* Note: Public typed properties must be initialized with default 
	* values (e.g. empty string) to avoid "must not be accessed before 
	* initialization" PHP errors.
	**
	* Bootstrap 5 does not allow multi select. Changed from `$status` 
	* to `checkboxes`.
	*/
	public array $checkboxes = [];
	public string $reply = '';
	
	// @var app\models\Message
	private ?Message $_message = null;
	
	// @var ParamHelper to class property.
	private string $_appName;
	private string $_emailSupport;
	
	//public function __construct(Contact $contact, $config = [])// Dependency injection.
	public function __construct(int $id, array $config = [])
	{
		/**
		* Dependency injection Example
		* Passing Contact model into a class through its constructor.
		*
		* Note: At this time, we recatch the Message via find as a extra 
		* security messure.
		*
		$this->_message = $message;//*/
		
		// Assign user object class propert to a local variable
		$this->_message = Message::findOne($id);
		
		if (!$this->_message)
		{
			throw new YiiBaseInvalidArgumentException('Unable to find Message.');
		}
		
		// @var ParamHelper to class property
		$this->_appName = AppHelper::name();
		$this->_emailSupport = ParamHelper::get('email.support');
		
		/**
		* Call to parent constructor
		* The parent constructor should be called last to ensure proper object 
		* initialization and handling of configuration settings.
		*/
		parent::__construct($config);
	}
	
	public function rules(): array
	{
		return [
			// No fields are mandatory due to defaults; validate if they are set.
			[['checkboxes', 'reply'], 'safe'],
			[['reply'], 'required', 'on' => 'replyOnly'],// Making reply required only in the replyOnly scenario.
			
			/**
			* Example of syntax to require attributes per scenario, if needed:
			*/
			//[['status'], 'required', 'on' => 'statusOnly'],
			//[['reply'], 'required', 'on' => 'replyOnly'],
			//[['status', 'reply'], 'required', 'on' => 'both'],
		];
	}
	
	/**
	* Validates the associated message model
	* @param Message $messageModel
	* @return bool
	*/
	public function validateAssociatedMessage(Message $messageModel): bool
	{
		// Call the validateStatus method from the Message model.
		$messageModel->validateStatus('status', []);
		
		// Returns true if there are no errors.
		return !$messageModel->hasErrors();
	}
	
	public function scenarios()
	{
		$scenarios = parent::scenarios();
		$scenarios['replyOnly'] = ['reply'];// Only sends a reply.
		$scenarios['statusOnly'] = ['checkboxes'];// Using checkboxes to only update status.
		$scenarios['both'] = ['status', 'reply'];// Updates both status and reply.
		
		return $scenarios;
	}
	
	public function attributeLabels(): array
	{
		return ['replied' => \Yii::t('app', 'Reply')];
	}
	
	public function process(): bool
	{
		$transaction = \Yii::$app->db->beginTransaction();
		try
		{
			$scenario = $this->getScenario();
			$updatedFields = [];// Message model attubutes.
			
			// If Message Model status is not set to 'replied', and form Model 'reply' is not empty.
			if (($this->_message->status !== Message::STATUS_REPLIED) && (!empty($this->reply)))
			{
				if (in_array($scenario, ['both']))
				{
					$this->_message->setStatusFromCheckboxes($this->checkboxes);
					$this->_message->addStatus(Message::STATUS_REPLIED);
					$this->_message->replied = $this->reply;
					$this->_message->repliedTime = time();// Set it to the current Unix timestamp. 
					//$this->_message->repliedTime = date('Y-m-d H:i:s');// If defined as a timestamp '$this->timestamp()'.
					$updatedFields = ['status', 'replied', 'repliedTime'];
				}
				if (in_array($scenario, ['replyOnly']))
				{
					$this->_message->addStatus(Message::STATUS_REPLIED);
					$this->_message->replied = $this->reply;
					$this->_message->repliedTime = time();
					//$this->_message->repliedTime = date('Y-m-d H:i:s');
					$updatedFields = ['replied', 'repliedTime'];
				}
				if (in_array($scenario, ['statusOnly']))
				{
					$this->_message->setStatusFromCheckboxes($this->checkboxes);
					$this->_message->addStatus(Message::STATUS_READ);
					$updatedFields = ['status'];
				}
			}
			else
			{
				$this->_message->setStatusFromCheckboxes($this->checkboxes);
				$this->_message->addStatus(Message::STATUS_READ);
				$updatedFields = ['status'];
			}
			
			// Save Contact model depending on Scenario. $updatedFields['data'];
			if ($this->_message->save(false, $updatedFields))
			{
				if ((in_array($scenario, ['replyOnly', 'both'])) && (!empty($this->reply)))
				{
					if (!$this->sendEmail())
					{
						throw new YiiBaseException('Failed to send email.');
					}
				}
				
				// If all saves are successful, commit the transaction.
				$transaction->commit();
				
				return true;
			}
		}
		catch (Throwable $e)
		{
			// An error occurred; roll back the transaction.
			$transaction->rollBack();
			
			// Use the ExceptionLogger to handle and log the exception.
			ExceptionLogger::log($e, 'reply_form_error_');
		}
		
		return false;
	}
		
	protected function sendEmail(): bool
	{
		/**
		* Make Safe for User
		* Strip HTML and PHP tags from a string @url https://www.php.net/manual/en/function.strip-tags.php
		*/
		$stripReply = strip_tags($this->reply, '<p><a><i><b><u>');
		$sanitizedReply = preg_replace('/\bhttps?:\/\/\S+/i', '', $stripReply);// No links.
		
		try
		{
			$appName = AppHelper::name();
			
			$isSent = \Yii::$app->mailer->compose(
					['html' => 'emailReply-html', 'text' => 'emailReply-text'],
					[
						'emailAppName' => $this->_appName,
						'emailMessage' => $this->_message,
						'emailReply' => $sanitizedReply,
					],
				)
				->setFrom($this->_emailSupport)
				->setTo($this->_message->email)
				->setSubject('Re: ' . $this->_message->subject)//->setSubject(\Yii::t('appEmail', 'Welcome to...'))
				->setTextBody($sanitizedReply)
				->send();
			
			if (!$isSent)
			{
				throw new YiiBaseException("The email could not be sent to {$this->_message->email}.");
			}
			
			return true;
		}
		catch (Throwable $e)
		{
			// Use the ExceptionLogger to handle and log the exception.
			ExceptionLogger::log($e, 'reply_form_sendmail_error_');
		}
		
		return false;
	}
}
```

viewUpdate file and how checkboxes are being used
```
<fieldset>
<legend class="form-label fs-6"><?= \Yii::t('app', 'statuses:'); ?></legend>
<div class="d-flex flex-wrap justify-content-start">
<?php
$statusOptions = [
	//Message::STATUS_READ => \Yii::t('app', 'read'),
	//Message::STATUS_UNREAD => \Yii::t('app', 'unread'),
	//Message::STATUS_REPLIED => \Yii::t('app', 'replied'),
	Message::STATUS_IMPORTANT => \Yii::t('app', 'important'),
	Message::STATUS_RESOLVED => \Yii::t('app', 'resolved'),
	Message::STATUS_ARCHIVED => \Yii::t('app', 'archived'),
	Message::STATUS_SPAM => \Yii::t('app', 'spam'),
	Message::STATUS_FLAGGED => \Yii::t('app', 'flagged'),
];
$currentStatuses = $model->getStatusForCheckboxes();
$selectedCheckboxes = is_array($replyForm->checkboxes) ? $replyForm->checkboxes : [];

foreach ($statusOptions as $value => $label) :
?>
<div class="me-3">
<?= $form->field($replyForm, 'checkboxes[]')->checkbox([
	'value' => $value,
	'checked' => in_array($value, $currentStatuses) || in_array($value, $selectedCheckboxes),
	'class' => 'form-check-input form-control square',
])->label($label, ['class' => 'form-check-label'])->inline(); ?>
</div><!-- .me-3 -->

<?php endforeach; ?>
</div><!-- .d-flex .flex-wrap .justify-content-start -->
</fieldset>
```

so i want to refactor the message code to be more inline with how product uses bitmask, cleaner. But also my reply form is not work, no error logs.. just 
does nothing, which if i remember correct is usally a scenario issue. Lets make message code easier to understand and better. No snippets. full and complete
code only.