1

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

假设我有一个产品表和一个照片表。1 产品有很多照片。所以在产品模型中我这样做:

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

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

从逻辑上讲,这会起作用(但它不起作用?)

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

看看我在说什么?我很想将 $products 变量传递给我的视图,能够通过它进行遍历,并将一组照片绑定到每个产品对象。

我怎样才能做到这一点?还是有更好的方法来做到这一点?

谢谢!

4

2 回答 2

2

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

  1. 您可以在 like 中加入另一张桌子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,使用 a 中的 id 运行一个 SQL 查询,where_in()并为父对象的相关字段对象排序结果(不幸的是它有点长,不支持多对多关系)。


/**
 * 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;
}
于 2013-04-20T22:21:34.820 回答
0

我现在有点探索 DM 并且我需要相同的功能。起初load_related,其他答案的功能似乎是解决这个问题的方法。不过我做了一些进一步的研究。我找到了另一个问题的答案,让我思考是否没有办法只自动填充一些关系。
嗯,有!!

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

//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
    }

}

我从文档的这个页面上找到了它。

享受!

于 2013-06-10T11:15:34.230 回答