如何在CakePHP 3.5中设置模型关联?含多对多关联及Finder使用问询
嘿,我来一步步帮你搞定这个关联配置的问题,这部分在CakePHP里是很常用的,我给你拆解成三个部分来解答:
1. Table1中belongsToMany('Table4')的必填参数
在Table1Table.php里配置关联时,核心参数有三个,如果你中间表和字段名符合CakePHP的命名规范(比如中间表是table1_table4,外键是table1_id和table4_id),部分参数可以省略,但明确写出会让代码更易读,尤其是团队协作场景。
示例配置如下:
// src/Model/Table/Table1Table.php public function initialize(array $config) { parent::initialize($config); $this->belongsToMany('Table4', [ // 必须:中间表的名称(如果不符合"小写下划线的单数表名1_单数表名2"规范则必填) 'joinTable' => 'table1_table4', // 必须:当前表(Table1)在中间表的外键字段名 'foreignKey' => 'table1_id', // 必须:关联表(Table4)在中间表的外键字段名 'targetForeignKey' => 'table4_id', // 可选参数:按需添加 'fetch' => 'select', // 关联数据的加载策略,可选select/join 'sort' => ['Table4.name' => 'ASC'], // 默认排序规则 'conditions' => ['Table4.status' => 1], // 固定关联条件(也可以用finder替代) ]); }
每个参数的作用:
joinTable:指定关联的中间表,这是多对多关联的核心,CakePHP需要通过它来关联两个模型foreignKey:当前模型对应的外键字段,存放在中间表里targetForeignKey:关联模型对应的外键字段,同样存放在中间表里
2. Table4的反向关联配置
反向关联其实就是在Table4Table.php里也配置belongsToMany('Table1'),参数和Table1的配置对称,只需要调换foreignKey和targetForeignKey的值即可:
// src/Model/Table/Table4Table.php public function initialize(array $config) { parent::initialize($config); $this->belongsToMany('Table1', [ 'joinTable' => 'table1_table4', // 同一个中间表 'foreignKey' => 'table4_id', // 现在是Table4在中间表的外键 'targetForeignKey' => 'table1_id', // Table1在中间表的外键 // 同样可以添加可选参数,比如finder、sort等 ]); }
配置完反向关联后,你就可以通过Table4的实例直接获取关联的Table1数据,比如$table4->table1或者用contain查询。
3. 在belongsToMany中结合Finder实现关联查询
完全可以!CakePHP支持在关联配置中指定自定义的finder方法,或者直接用闭包定义临时查询条件,这样关联查询时会自动应用这些规则。
方式一:使用自定义Finder方法
首先在Table4Table.php里定义一个finder:
// src/Model/Table/Table4Table.php public function findActive(Query $query, array $options) { // 这里可以添加任意查询条件,比如只返回启用的记录 return $query->where(['Table4.is_active' => true]); }
然后在Table1的关联配置中指定这个finder:
// Table1Table.php的belongsToMany配置里添加 'finder' => 'active',
这样当你通过Table1查询关联的Table4时(比如$this->Table1->get($id, ['contain' => ['Table4']])),只会返回符合findActive条件的Table4记录。
方式二:使用闭包临时定义条件
如果只是临时的条件,不想单独写finder方法,也可以直接用闭包:
// Table1Table.php的belongsToMany配置 'finder' => function (Query $query) { return $query->where(['Table4.created >' => new \DateTime('-30 days')]); },
这种方式适合一次性的、不需要复用的关联条件。
内容的提问来源于stack exchange,提问作者Mihály Szalai

