在cakephp找到的父母内部的子关系对象

时间:2015-01-07 13:08:26

标签: php arrays cakephp

在我的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中获取视频(子对象),这样:

{
  Product: {
      id: "3",
      video_id: "1",
      Video: {
         id: "1",
         url: "c",
      } 
}

我知道,对于这个特殊情况,它很容易创建一个新数组,因为只有两个对象,但无论如何都要使这个自动更大的关系,cakephp可以处理这个吗?

3 个答案:

答案 0 :(得分:2)

这将有助于在findall

中获取每个产品中的每个Video子项
$products = $this->Product->find('all') 

foreach($products as $product) {
  echo $product["Video"]["url"];
}

答案 1 :(得分:2)

Cake返回对象的方式是正确的,因为它正在访问连接并返回主find对象内的数据。

如果您有更深层次的递归或者使用可包含来访问更深层次的关系,则您正在讨论的对象内的对象会发生。

例如

$this->Product->find('all');

会返回像

这样的对象
array(
  'Product' => array(
    'id' => '3',
    'video_id' => '1',
  ),
  'Video' => array(
    'id' => '1',
    'url' => c,
  ),
)

只有在该模型上有hasMany或HABTM连接或您更改级别或使用可包含然后查看已连接模型的关系时,才会发生对象布局。

我希望这是有道理的。

答案 2 :(得分:2)

尝试这种方法。覆盖默认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 结合检查关联来获取相关模型。我无法通过配置find,contains或任何其他方式实现此目的。

下一个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