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'),但提供自定义 reformatfilter 参数。如果您不提供它们,将以默认格式获取结果。

  • 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'),
));

另请参阅:Retrieving Your Data > Creating custom find types