```
namespace app\models;

class ContentCategory extends ActiveRecord
{
	const TYPE_POST = 1;
	const TYPE_PRODUCT = 2;
	
	// Declare the children property
	public array $children = [];
	
	/**
	* Holds the decoded array of allowed templates for the category.
	* @var array
	*
	* Used for binding to checkboxList in forms.
	*/
	public array $templatesArray = [];
	
	/**
	* Used to track category level for display/indentation purposes.
	* @return int
	*
	* Note: This is NOT a database attribute.
	*/
	public int $level;

	public static function tableName(): string
	{
		return '{{%content_category}}';
	}
	
	public function rules(): array
	{
		return [
			/**
			* Rules
			* Rules are handled by either app\models\forms\** for user access validation, or
			* handled directly within the model and than view file skipping form model validation
			* for administration only.
			*/
			[['title', 'type'], 'required'],
			
			// Integer
			[['parent_id', 'type', 'created_by', 'updated_by', 'created_at', 'updated_at'], 'integer'],
			
			// String
			[['title', 'slug'], 'string', 'max' => 255],
			['templates', 'string'],// JSON storage
			
			// Unique
			['slug', 'unique'],
			
			// Safe
			['templatesArray', 'safe'],
			
			// Defaults
			['type', 'default', 'value' => self::TYPE_POST],
			['type', 'in', 'range' => [
				self::TYPE_POST,
				self::TYPE_PRODUCT,
			]],
			
			// Ensures `parent_id` in this model refers to an existing `id` in the ContentCategory model.
			['parent_id', 'exist', 'skipOnError' => true, 'targetClass' => self::class, 'targetAttribute' => ['parent_id' => 'id']],
			
			/**
			* BlameableBehavior
			* @url https://www.yiiframework.com/doc/api/2.0/yii-behaviors-blameablebehavior
			*/
			['created_by', 'exist', 'skipOnError' => true, 'targetClass' => User::class, 'targetAttribute' => ['created_by' => 'id']],
			['updated_by', 'exist', 'skipOnError' => true, 'targetClass' => User::class, 'targetAttribute' => ['updated_by' => 'id']],
		];
	}
	
	public function attributeLabels(): array
	{
		return [
			'id' => \Yii::t('app', 'ID'),
			'type' => \Yii::t('app', 'Type'),
			'allowed_templates' => \Yii::t('app', 'Allowed Templates'),
			'title' => \Yii::t('app', 'Title'),
			'slug' => \Yii::t('app', 'Slug'),
			'parent_id' => \Yii::t('app', 'Parent ID'),
			'created_by' => \Yii::t('app', 'Created By'),
			'updated_by' => \Yii::t('app', 'Updated By'),
			'created_at' => \Yii::t('app', 'Created At'),
			'updated_at' => \Yii::t('app', 'Updated At'),
		];
	}
	
	/**
	* After Find
	* @url https://www.yiiframework.com/doc/api/2.0/yii-db-baseactiverecord#afterFind()-detail
	* @return void
	*
	* After the model is populated from the database, decode the JSON stored 
	* in 'allowed_templates' into an array and assign it to the public property 
	* for easy access/use in forms.
	*/
	public function afterFind()
	{
		parent::afterFind();
		
		// ...custom code here...
		
		$this->templatesArray = $this->getAllowedTemplates();
	}
	
	/**
	* Before Validation
	* @url https://www.yiiframework.com/doc/api/2.0/yii-base-model#beforeValidate()-detail
	* return bool
	* 
	* This keeps the JSON string in sync with the array used in the form.
	*/
	public function beforeValidate(): bool
	{
		if (!parent::beforeValidate())
		{
			return false;
		}
		
		// ...custom code here...
		
		$this->setAllowedTemplates($this->templatesArray);
		
		return true;
	}
	
	/**
        * Before Save
        * @url https://www.yiiframework.com/doc/api/2.0/yii-db-baseactiverecord#beforeSave()-detail
        * @url https://www.yiiframework.com/doc/guide/2.0/en/security-authentication#implementing-identity
        * @return boolean
        *
        * 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 beforeSave($insert): bool
	{
		if (!parent::beforeSave($insert))
		{
			return false;
		}
		
		// ...custom code here...
		
		// @url https://www.yiiframework.com/doc/api/2.0/yii-helpers-htmlpurifier
		$purifier = PurifierHelper::purifier();
		$this->title = $purifier->purify($this->title);
		$this->slug = $purifier->purify($this->slug);
		$this->parent_id = $purifier->purify($this->parent_id);
		
		return true;
	}
	
	/**
        * After Save
        * @url https://www.yiiframework.com/doc/api/2.0/yii-db-activerecord#afterSave()-detail
        * @return boolean
        *
        * 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 afterSave($insert, $changedAttributes)
	{
		parent::afterSave($insert, $changedAttributes);
		
		// If this is an update (not a new record insert) and the 'type' attribute has changed
		if (!$insert && isset($changedAttributes['type']))
		{
			\Yii::$app->db->createCommand()
				->update('{{%content}}', ['type' => $this->type], ['category_id' => $this->id])
				->execute();
		}
	}
	
	/**
	* Note: Using SluggleBehavior instead of using this.
	*
	* Before Save
	* @url https://www.yiiframework.com/doc/api/2.0/yii-db-baseactiverecord#beforeSave()-detail
	* @url https://www.yiiframework.com/doc/guide/2.0/en/security-authentication#implementing-identity
	* @return boolean
	*
        * 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 beforeSave($insert): bool
	{
		if (parent::beforeSave($insert))
		{
			if ($this->isNewRecord || $this->isAttributeChanged('name'))
			{
				$this->slug = $this->generateSlug($this->name);
			}
			
			return true;
		}
		
		return false;
	}
	
	// Note: Using SluggleBehavior instead of using this.
	protected function generateSlug($name): string
	{
		return Inflector::slug($name);
	}//*/
	
	/**
	* Get type labels to use in dropdowns
	* @return array
	*/
	public static function getTypeList(): array
	{
		return [
			self::TYPE_POST => \Yii::t('app', 'Post'),
			self::TYPE_PRODUCT => \Yii::t('app', 'Product'),
		];
	}
	
	/**
	* Get Types Labels
	* @return string
	*/
	public function getTypeLabels(): string
	{
		return self::getTypeList()[$this->type] ?? \Yii::t('app', 'Unknown');
	}
	
	/**
	* Get Allowed Templates
	* @return array
	*/
	public function getAllowedTemplates(): array
	{
		// Decode JSON templates stored in the category model e.g.
		if (empty($this->templates))
		{
			return [];
		}
		
		// Decode JSON from TEXT column
		return json_decode($this->templates, true) ?: [];
	}
	
	/**
	* Set Allowed Templates
	* @return void
	*/
	public function setAllowedTemplates(array $allowedTemplates): void
	{
		$this->templates = json_encode($allowedTemplates);
	}
	
	/**
	* Get Parent
	* Returns the parent of a category.
	*
	* The hierarchy implemented using the adjacency list model doesn't require separate 
	* storage for children or siblings, as they are derived through queries on the same 
	* data structure. 
	*
	* Parent-Child Relationship:
	* The relationship is made explicit by having a parent_id column in the category table, 
	* which stores the ID of a category's parent. If parent_id is null, the category is a 
	* root node or top-level category.
	*
	* Children and Siblings Retrieval:
	*
	* Children: Derived by querying all categories where parent_id equals the current 
	*           category's id.
	*
	* Siblings: Derived by querying categories where parent_id equals the current category's 
	*           parent_id, excluding the category itself.
        */
        //public function getParent(): ActiveQuery
        public function getParent()//: ActiveQuery | app\models\query\ContentCategoryQuery
	{
		return $this->hasOne(self::class, ['id' => 'parent_id']);
	}
	
	/**
	* TODO
	*
	* Get Siblings
	* Fetches other categories sharing the same parent.
	*
	* Similarly, retrieving siblings involves finding other categories with the same parent_id. 
	* This, again, utilizes the existing category data without needing explicit storage.
	*/
	//public function getChildren(): ActiveQuery
	public function getChildren()//: \yii\db\ActiveQuery|ProductCategoryQuery
	{
		return $this->hasMany(self::class, ['parent_id' => 'id']);
	}
		
	/**
	* TODO
	*
	* Get Siblings
	* Fetches other categories sharing the same parent.
	*
	* Similarly, retrieving siblings involves finding other categories with the same parent_id. This, 
	* again, utilizes the existing category data without needing explicit storage.
	*/
	//public function getSiblings(): ActiveQuery
	public function getSiblings()//: \yii\db\ActiveQuery|ProductCategoryQuery
	{
		return self::find()
			->where(['parent_id' => $this->parent_id])
			->andWhere(['!=', 'id', $this->id])
			->all();
	}
	
	/**
	* TODO
	*
	* Find Root
	* @return ActiveQuery|array
	*/
	//public static function findRoots()//: ActiveQuery|array
	public static function findRoots()//: \yii\db\ActiveQuery|ProductCategoryQuery
	{
		return self::find()->where(['parent_id' => null])->all();
	}
	
	/**
	* Find All Categories
	* @return ContentCategory[] all categories ordered by parent-child hierarchy
	*
	* This method retrieves all ContentCategory entries in the database,
	* ordered by parent_id to ensure that parent categories come before their children.
	*/
	public static function findAllCategories(): array
	{
		return self::find()->orderBy(['parent_id' => SORT_ASC, 'id' => SORT_ASC])->all();
	}
	
	/**
	* Structures Categories
	* @param array $categories List of categories to structure.
	* @return array Structured categories in a hierarchical format.
	*
	* This method groups and nests categories ensuring a hierarchical
	* relationship with parent categories containing their children.
	*/
	public static function structureCategories(array $categories): array
	{
		$grouped = [];
		foreach ($categories as $category)
		{
			$grouped[$category->parent_id][] = $category;
		}
		
		return self::buildCategoryTree($grouped, null);
	}
	
	/**
	* Build Category Tree
	* @param array $grouped Categories grouped by parent_id.
	* @param int|null $parentId The current parent id for building the tree.
	* @return array A nested array of categories forming the hierarchy.
	*
	* This recursive function builds a nested array of categories
	* representing the hierarchy using parent_id relationships.
	*/
	private static function buildCategoryTree(array &$grouped, int|null $parentId = null): array
	{
		$result = [];
		if (isset($grouped[$parentId]))
		{
			foreach ($grouped[$parentId] as $category)
			{
				$children = self::buildCategoryTree($grouped, $category->id);
				if ($children)
				{
					$category->children = $children;// Adding children to the category.
				}
				
				$result[] = $category;
			}
		}
		
		return $result;
	}
	
	/**
	* Flatten Categories GridView
	* @param array $categories Hierarchically structured categories.
	* @param int $level Current indentation level (used for recursion).
	* @return array Flattened categories with 'prefix' for visual indentation.
	*
	* Flattens hierarchical categories with indentation for display in GridView.
	*/
	public static function flattenCategoriesGridView(array $categories, int $level = 0): array
	{
		$result = [];
		foreach ($categories as $category)
		{
			// Create a copy to avoid modifying the original models.
			$categoryCopy = clone $category;
			
			// Store the current level for use in view indentation / icon rendering
			$categoryCopy->level = $level;
			
			$result[] = $categoryCopy;
			
			if (!empty($category->children))
			{
				$result = array_merge($result, self::flattenCategoriesGridView($category->children, $level + 1));
			}
		}
		
		return $result;
	}
	
	/**
	* Flatten Categories Dropdown
	* @param array $categories The hierarchical categories.
	* @param string $prefix HTML prefix using icons for indentation.
	* @return array An associative array for dropdown options with icons.
	*
	* Flattens a hierarchy of categories for a dropdown, using icons for indentation.
	*
	* If graphical representation, such as icons, is required, consider alternative
	* solutions such as:
	*   - Using libraries that enhance dropdown functionality (e.g., jQuery plugins like
	*     Select2 or Bootstrap Select) to allow richer content within dropdowns
	*   - Implementing custom dropdown menus using Bootstrap components to include HTML
	*     elements like icons, images, etc., as part of the dropdown items.
	*
	* Note: Due to limitations of standard HTML <select> elements, HTML content such as
	* icons cannot be rendered directly within <option> elements. HTML dropdowns do not
	* support rich content and will typically display such elements as raw text.
	*/
	public static function flattenCategoriesDropdown(array $categories, string $prefix = ''): array
	{
		$list = [];
		foreach ($categories as $category)
		{
			$list[$category->id] = $prefix . $category->title;
			
			if (isset($category->children))
			{
				$list += self::flattenCategoriesDropdown($category->children, $prefix . '= ');
			}
		}
		
		return $list;
	}
	
	public function getContentCategories(): ActiveQuery
	{
		return $this->hasMany(self::class, ['parent_id' => 'id']);
	}
	
	public function getContent(): ActiveQuery
	{
		return $this->hasMany(Content::class, ['category_id' => 'id']);
	}
	
	public function getCreatedBy(): ActiveQuery
	{
		return $this->hasOne(User::class, ['id' => 'created_by']);
	}
	
	public function getUpdatedBy(): ActiveQuery
	{
		return $this->hasOne(User::class, ['id' => 'updated_by']);
	}
	
	/**
	* {@inheritdoc}
	* @url https://www.yiiframework.com/doc/api/2.0/yii-db-activerecord#find()-detail
	* @return ContentQuery the active query used by this AR class.
	*/
	public static function find(): ContentCategoryQuery
	{
		return new ContentCategoryQuery(get_called_class());
	}
}
```

I want the childen to inhirient the parent templates