在我的 CakePHP 2.0 项目中,我有这个模型场景(遵循伪代码):
model Product {
int id;
Video video;
}
model Video {
....
}
我想使用 cakephp $this-> 产品>查找('all') 来获取我的所有产品和相关视频。Cakephp 以这种方式在多维数组中给我结果:
{
Product: {
id: "3",
video_id: "1",
},
Video: {
id: "1",
url: "c",
},
{
Product: {
id: "3",
video_id: "1",
},
Video: {
id: "1",
url: "c",
}
如何通过以下方式获取父产品中的视频(子对象):
{
Product: {
id: "3",
video_id: "1",
Video: {
id: "1",
url: "c",
}
}
我知道对于这种特殊情况,创建一个新数组很容易,因为只有两个对象,但是无论如何都可以使它自动用于更大的关系,cakephp 可以处理这个问题吗?
试试这种方法。覆盖默认find('all')
,以便它接受自定义参数,这将允许重新格式化结果。把它放在 AppModel
,所以所有模型都可以访问它
根据注释中的要求进行编辑,以从重新格式化的结果中删除 HABTM 关联的空关联和联合数据:
class AppModel extends Model
{
protected function _findAll($state, $query, $results = array())
{
if ($state === 'before') {
return $query;
}
if (isset($query['reformat']) && $query['reformat'] === true) {
foreach ($results as &$_result) {
reset($_result);
$modelName = key($_result);
$modelPart = array_shift($_result);
if (!empty($query['filter']) && is_array($query['filter'])) {
$this->recursive_unset($_result, $query['filter']);
}
$_result = array(
$modelName => array_merge($modelPart, $_result)
);
}
}
return $results;
}
public function getHabtmKeys() {
$habtmKeys = array();
// 1. level inspection
foreach ($this->hasAndBelongsToMany as $name) {
$habtmKeys[] = $name['with'];
}
// 2. level inspection
$allAsssoc = array_merge(
$this->belongsTo,
$this->hasMany,
$this->hasOne
);
foreach ($allAsssoc as $assocName => $assocVal) {
foreach ($this->$assocName->hasAndBelongsToMany as $name) {
$habtmKeys[] = $name['with'];
}
}
return $habtmKeys;
}
private function recursive_unset(&$array, $keys_to_remove) {
foreach ($keys_to_remove as $_key) {
unset($array[$_key]);
}
foreach ($array as $key => &$val) {
if (is_array($val)) {
if (empty($val) || (!isset($val[0]) && empty($val['id']))) {
unset($array[$key]);
} else {
$this->recursive_unset($val, $keys_to_remove);
}
}
}
}
}
为了删除空关联和 HABTM 联合数据,我使用了递归未设置过程与相关模型的关联检查相结合。我无法通过配置查找、包含或任何其他方式来实现这一点。
接下来array_shift($_result)
$_result
数组分为两部分 - 运行find
的主模型(它始终是结果中的第一个键)和其余部分(所有关联),然后将这些数组合并到主模型的键下。当然,这仅在第一级重新格式化结果,但在更深的级别上默认嵌套关联,因此您无需关心它。
现在像往常一样使用 find('all')
,但提供自定义reformat
和filter
参数。如果您不提供它们,将以默认格式获取结果。
filter
是要从结果中删除的键数组getHabtmKeys()
动态获取模型的 HABTM 关联键数组(只有 1. 和 2. 级关联,可以进一步修改以更深入地检查)。
用法:
// To nest child associations in parent
$this->Product->find('all', array(
'reformat' => true
));
// To remove also joint data for HABTM and empty associations
$this->Product->find('all', array(
'reformat' => true,
'filter' => $this->Product->getHabtmKeys(),
));
// Keys to remove can be also manually added
$this->Product->find('all', array(
'reformat' => true,
'filter' => array_merge($this->Product->getHabtmKeys(), 'SomeExtraKey'),
));
另请参阅:检索数据>创建自定义查找类型
这将用于在查找中获取每个产品中的每个视频子项
$products = $this->Product->find('all')
foreach($products as $product) {
echo $product["Video"]["url"];
}
Cake 返回对象的方式是正确的,因为它正在访问连接并返回主查找对象中的数据。
如果您具有更深层次的递归或使用 containable 访问更深层次的关系,则会发生您正在谈论的对象中的对象。
例如
$this->Product->find('all');
将返回一个对象,例如
array(
'Product' => array(
'id' => '3',
'video_id' => '1',
),
'Video' => array(
'id' => '1',
'url' => c,
),
)
仅当该模型上存在 hasMany 或 HABTM 联接,或者您更改级别或使用 containable 然后查看联接模型的关系时,才会发生您所追求的对象布局。
我希望这是有道理的。