Search code examples
phprecursionyiitreecatalog

Yii 1. Get products from categories AND their subcategories [Unlimited nesting]


I'm working on some catalog based project, which contains unlimited nesting (in reality, the maximum level would be 3, I guess, but it have to be dynamic anyways).

Let me show what is done:

OrganizationCategory model:

public function relations()
{
    return array(
        'organizations' => array(self::HAS_MANY, 'Organization', 'organization_category_id'),
        'parent' => array(self::BELONGS_TO, 'OrganizationCategory', 'category_parent_id'),
        'children' => array(self::HAS_MANY, 'OrganizationCategory', 'category_parent_id'),
    );
}

public static function getParentCategories()
{
    if (is_null(self::$categories))
    {
        self::$categories = array();
        $criteria = new CDbCriteria();
        $criteria->order = 't.category_title';
        $criteria->condition = "t.category_parent_id IS NULL";
        $arr = self::model()->with('children')->findAll($criteria);
        foreach ($arr as $item)
            self::$categories[$item->primaryKey] = $item;
    }

    return self::$categories;
}

public static function createTree($children, $counter)
{
    $tree = '';

    if(count($children)){

        $tree .= CHtml::tag('ul', array('class'=>'menu_open_'.$counter));

        foreach($children as $child):

            $childrenSub = self::createTree($child->children, $counter+1);

            $tree .= CHtml::tag('li',  (empty($childrenSub) ? array('class'=>'no_child_li') : array()));

            $organizations = Organization::model()->findByAttributes(array('organization_category_id'=>$child->category_id));

            $tree .= CHtml::link($child->category_title, array('organizationCategory/view', 'slug'=>$child->category_slug));

            $tree .= $childrenSub;
            $tree .=CHtml::closeTag('li');

        endforeach;

        $tree .= CHtml::closeTag('ul');

    }

    return $tree;
}

CategoryController:

public function actionView($slug = '')
{
    $model = $this->loadModelSlug($slug);

    $organizationsList = Organization::getOrganizations($model->category_id);

    $this->pageTitle=$model->category_title;
    Yii::app()->clientScript->registerMetaTag($model->meta_description, 'description');
    Yii::app()->clientScript->registerMetaTag($model->meta_keywords, 'keywords');

    $this->render('view',array(
        'model'=>$model,
        'organizationsList'=>$organizationsList,
    ));
}

Organization model getOrganizations():

public static function getOrganizations($category_id) {

    $criteria = new CDbCriteria;
    $criteria->condition = 'organization_category_id = :cat_id';
    $criteria->params = array(':cat_id'=>$category_id);
    $result = self::model()->findAll($criteria);

    return $result;
}

Category view.php

<?php if(!empty($model->children)) {
echo OrganizationCategory::model()->createTree($model->children, 1); 
} ?>

<?php $i=1; foreach($model->organizations as $organization): ?>
    blah blah blah
<?php $i++; endforeach; ?>

As you can guess, now I can get only those products, which are associated only with the currently displayed category.

And my aim is to get products from categories and all its subcategories->subcategories->subcategories.

I was trying to find solution almost everywhere, but still can't implement this trivial task in my project.

I would appreciate any help provided, thanks


Solution

  • For other folks who could be interested in this issue, I've solved it in a such way:

    In category controller view action I call:

    $model = $this->loadModelSlug($slug);
    $organizationsList = Organization::getOrganizationsFromSubcategories($model);
    

    In Organization model:

    public static function getOrganizationsFromSubcategories($category) {
    
        $childCategoriesIds = OrganizationCategory::getChildCategoriesIds($category);
    
        $criteria = new CDbCriteria();
        $criteria->addInCondition('organization_category_id', $childCategoriesIds);
        $result = self::model()->findAll($criteria);
    
        return $result;
    }
    

    And, finally, in OrganizationCategory:

    public static function getChildCategoriesIds($category)
    {
        $arr = array($category->primaryKey);
    
        if (!empty($category->children))
            foreach ($category->children as $child_category) $arr = array_merge($arr, self::getChildCategoriesIds($child_category));
    
        return $arr;
    }