DataMapper ORM - 如何获取所有模型和每个实例的相关数据

时间:2013-04-20 20:50:38

标签: php codeigniter orm codeigniter-datamapper

我不明白如何执行以下操作:

假设我有一张产品表和一张照片桌。 1产品有很多照片。所以在我做的产品模型中:

var $has_many = array("category", "photo");

现在我想获得所有产品并将他们的每张照片与他们联系起来。我怎样才能做到这一点?目前,在我的控制器中,我正在浏览每个产品并查询照片并以这种方式传递单独的数组。这不是理想的。我应该能够将每张照片直接绑定到特定产品吗?

从逻辑上讲,这可行(但不是吗?)

$product = new Product;
$products = $product->get_by_related_category('name', $where);
$photos = $product->photo->get();

看看我的目标是什么? 我很乐意将$ products变量传递给我的视图,能够通过它传播,并且每个产品对象都有一系列照片。

我怎样才能做到这一点?或者有更好的方法吗?

谢谢!

2 个答案:

答案 0 :(得分:2)

使用“有很多”关系,您基本上有两种方法可以使用SQL获取相关信息:

  1. 您可以加入select products.*, photos.* from products left outer join photos on products.id = photos.product_id中的其他表格。这样,您将拥有“重复”的产品数据,因此您需要相应地处理结果。遗憾的是include_related()不直接支持此功能,它会创建重复的产品,每个产品都有一张相关照片。

  2. 您可以运行两个查询,首先获取产品(select * from products where ...),然后使用所选产品的ID(select * from photos where product_id in (...))获取照片并整理出哪些照片行应该去什么产品在DMZ中没有内置的功能,但这是我为模型基类(扩展DataMapper类)编写的,可以像这样使用:

    $products = new Product;
    $products = $products
        ->get_by_related_category('name', $where) // first get the parent objects
        ->load_related('photo'); // then load in the related ones inside them
    foreach ($products as $product) {
        // unique product instances as before
        foreach ($product->photo as $photo) {
            // and every product has a list of related photos 
            // for each product individualy
        }
    }
    

    下面的方法将收集父对象的id,使用where_in()中的id运行一个SQL查询,并为父对象的相关字段对象排序结果(不幸的是它有点长并且没有'支持多对多关系)。


  3. /**
     * load_related
     * 
     * Loads related has_many objects efficiently
     *
     * @param string $related_field_name the name of the relation
     * @param callable $filter_function callback to place extra conditions on the related model query
     */ 
    public function load_related($related_field_name, $filter_function = null) {
        $related_properties = $this->_get_related_properties($related_field_name);
        $related_models = new $related_properties['class'];
        $join_field = $related_properties['join_self_as'].'_id';
    
        $ids = array_unique(array_filter(array_merge(array('id' => $this->id), array_column($this->all, 'id')), 'intval'));
        if (empty($ids)) {
            return $this;
        }
    
        $related_models->where_in($join_field, $ids);
        if (is_callable($filter_function)) {
            call_user_func($filter_function, $related_models);
        }
    
        $related_models = $related_models->get();
        $related_models = array_group_by($related_models, $join_field);
    
        foreach ($this->all as $i => $row) {
            $related_models_to_row = isset($related_models[$row->id]) ? $related_models[$row->id] : null;
            if ($related_models_to_row) {
                $this->all[$i]->{$related_field_name} = reset($related_models_to_row);
                $this->all[$i]->{$related_field_name}->all = $related_models_to_row;
            }
        }
    
        if (isset($related_models[$this->id])) {
            $this->{$related_field_name} = $related_models[$this->id];
        }
    
        return $this;
    }
    
    // The two array helper functions used above from my_array_helper.php
    function array_group_by($arr, $key, $index_by_col = false) {
        $re = array();
        foreach ($arr as $v) {
            if (!isset($re[$v[$key]])) {
                $re[$v[$key]] = array();
            }
            if ($index_by_col === false) {
                $re[$v[$key]][] = $v;
            } else {
                $re[$v[$key]][$v[$index_by_col]] = $v;
            }
        }
        return $re;
    }
    
    function array_column($arr, $key, $assoc = false) {
        if (empty($arr)) {
            return array();
        }
        $tmp = array();
        foreach ($arr as $k => $v) {
            if ($assoc === true) {
                $tmp[$k] = $v[$key];
            } elseif (is_string($assoc)) {
                $tmp[$v[$assoc]] = $v[$key];
            } else {
                $tmp[] =  $v[$key];
            }
        }
        return $tmp;
    }
    

答案 1 :(得分:0)

我现在正在探索DM一段时间,我需要相同的功能。起初,来自另一个答案的load_related函数似乎是解决此问题的方法。 我做了一些进一步的研究。我发现this回答了另一个问题,这让我想到是否没有办法自动填充某些关系。
嗯,有!!

如果在模型中建立关系,则可以设置此“选项”。

//Instead of doing this:
var $has_many = array('user_picture');

//Do this
var $has_many = array(
    'user_picture' => array(
        'auto_populate' => TRUE,
    ),
 );

现在,图片将在用户对象中可用。

foreach ($u as $user) {

    foreach ($user->user_picture as $picture) {
        // Do your thing with the pictures
    }

}

我在文档的this page上找到了它。

享受!