cakephp 查找中父级内部的子关系对象
child relation object inside parent on cakephp find
在我的 cakephp 2.0 项目中,我有这个模型场景(遵循伪代码):
model Product {
int id;
Video video;
}
model Video {
....
}
我想使用 cakephp $this->Product->find('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 可以处理这个吗?
这将有助于获取 findall 中每个产品中的每个视频子项
$products = $this->Product->find('all')
foreach($products as $product) {
echo $product["Video"]["url"];
}
Cake returns 对象的方式是正确的,因为它正在访问连接并 returning 主查找对象中的数据。
如果你有更深层次的递归或者你使用 containable 来访问更深层次的关系,你正在谈论的对象中的对象就会发生。
例如
$this->Product->find('all');
会 return 像
这样的对象吗
array(
'Product' => array(
'id' => '3',
'video_id' => '1',
),
'Video' => array(
'id' => '1',
'url' => c,
),
)
只有在该模型上有 hasMany 或 HABTM 连接,或者您更改级别或使用 containable 来查看连接模型的关系时,才会出现您想要的对象布局。
我希望这是有道理的。
试试这个方法。覆盖默认 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 联合数据,我使用 recursive unset procedure 结合 关联检查 相关模型。我无法通过配置查找、包含或任何其他方式实现此目的。
接下来 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'),
));
在我的 cakephp 2.0 项目中,我有这个模型场景(遵循伪代码):
model Product {
int id;
Video video;
}
model Video {
....
}
我想使用 cakephp $this->Product->find('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 可以处理这个吗?
这将有助于获取 findall 中每个产品中的每个视频子项
$products = $this->Product->find('all')
foreach($products as $product) {
echo $product["Video"]["url"];
}
Cake returns 对象的方式是正确的,因为它正在访问连接并 returning 主查找对象中的数据。
如果你有更深层次的递归或者你使用 containable 来访问更深层次的关系,你正在谈论的对象中的对象就会发生。
例如
$this->Product->find('all');
会 return 像
这样的对象吗array(
'Product' => array(
'id' => '3',
'video_id' => '1',
),
'Video' => array(
'id' => '1',
'url' => c,
),
)
只有在该模型上有 hasMany 或 HABTM 连接,或者您更改级别或使用 containable 来查看连接模型的关系时,才会出现您想要的对象布局。
我希望这是有道理的。
试试这个方法。覆盖默认 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 联合数据,我使用 recursive unset procedure 结合 关联检查 相关模型。我无法通过配置查找、包含或任何其他方式实现此目的。
接下来 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'),
));