You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用CakePHP 3生成关联技术详情评分的分类树形结构

在CakePHP 3中生成分类父子树形结构并展示对应技术详情评分

先明确你的两张数据表结构:

  • ecategory(id, name, parent_id):分类表,通过parent_id字段构建父子层级关系
  • technical_detail(id, tech_interview_id, category_id):技术详情表,category_id作为外键关联分类表的id

表结构截图

Ecategory表结构
technical_details表结构

注意你现有的代码是CakePHP 2的写法,CakePHP 3已经不再使用recursive这类方式了,我们用官方推荐的TreeBehavior和ORM关联来实现需求,具体步骤如下:

第一步:配置模型的关联与树形行为

首先在分类表的模型文件src/Model/Table/EcategoryTable.php中,启用专门处理树形结构的TreeBehavior,同时建立和技术详情表的关联:

namespace App\Model\Table;

use Cake\ORM\Table;
use Cake\ORM\Behavior\TreeBehavior;

class EcategoryTable extends Table
{
    public function initialize(array $config): void
    {
        parent::initialize($config);
        
        // 启用TreeBehavior,自动处理父子分类的层级关系
        $this->addBehavior('Tree');
        
        // 关联技术详情表:一个分类对应多条技术详情
        $this->hasMany('TechnicalDetail', [
            'foreignKey' => 'category_id'
        ]);
    }
}

然后在技术详情表的模型src/Model/Table/TechnicalDetailTable.php中配置反向关联:

namespace App\Model\Table;

use Cake\ORM\Table;

class TechnicalDetailTable extends Table
{
    public function initialize(array $config): void
    {
        parent::initialize($config);
        
        // 关联分类表:一条技术详情属于一个分类
        $this->belongsTo('Ecategory', [
            'foreignKey' => 'category_id'
        ]);
    }
}

第二步:控制器中查询树形分类并关联评分数据

在控制器(比如EcategoriesController.php)里,用find('threaded')获取嵌套的树形结构,同时包含技术详情数据,还可以直接计算每个分类的评分(这里假设统计平均评分,你可以根据实际字段调整):

namespace App\Controller;

use App\Controller\AppController;

class EcategoriesController extends AppController
{
    public function index()
    {
        // 查询顶级分类(parent_id=0)的树形结构,同时包含技术详情并计算平均评分
        $ecategories = $this->Ecategory->find('threaded')
            ->select([
                'Ecategory.id',
                'Ecategory.name',
                'Ecategory.parent_id',
                // 子查询计算当前分类的平均评分,这里的score替换成你实际的评分字段
                'average_score' => $this->Ecategory->TechnicalDetail->find()
                    ->select(['avg' => 'AVG(score)'])
                    ->where(['category_id = Ecategory.id'])
                    ->limit(1)
            ])
            ->contain(['TechnicalDetail']) // 关联技术详情数据
            ->where(['Ecategory.parent_id' => 0])
            ->all();
        
        $this->set(compact('ecategories'));
    }
}

find('threaded')会自动返回嵌套数组,每个分类对象里的children属性就是它的子分类,非常方便处理树形结构。

第三步:视图中渲染树形结构和评分

在视图文件Template/Ecategories/index.ctp里,我们用递归元素来渲染层级结构:

<h1>分类树形结构及技术详情评分</h1>
<?= $this->element('category_tree', ['categories' => $ecategories]) ?>

然后创建一个元素文件Template/Element/category_tree.ctp,递归渲染分类、评分和对应的技术详情:

<ul>
    <?php foreach ($categories as $category): ?>
        <li>
            <strong><?= h($category->name) ?></strong>
            <?php if (isset($category->average_score)): ?>
                <span style="margin-left:10px;">平均评分:<?= number_format($category->average_score, 2) ?></span>
            <?php endif; ?>
            
            <!-- 展示当前分类的所有技术详情 -->
            <?php if (!empty($category->technical_detail)): ?>
                <ul style="margin-top:5px;">
                    <?php foreach ($category->technical_detail as $detail): ?>
                        <li>
                            技术详情ID:<?= h($detail->id) ?> | 关联面试ID:<?= h($detail->tech_interview_id) ?>
                        </li>
                    <?php endforeach; ?>
                </ul>
            <?php endif; ?>
            
            <!-- 递归渲染子分类 -->
            <?php if (!empty($category->children)): ?>
                <?= $this->element('category_tree', ['categories' => $category->children]) ?>
            <?php endif; ?>
        </li>
    <?php endforeach; ?>
</ul>

对你现有代码的小说明

你之前的代码是CakePHP 2的写法,CakePHP 3已经废弃了recursive属性,改用contain来关联数据,而且手动查询分类ID再查技术详情的方式不仅繁琐,效率也不如ORM的关联查询高,上面的方法更符合CakePHP 3的最佳实践。

内容的提问来源于stack exchange,提问作者Kosar Latif

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:19:54