我不明白如何执行以下操作:
假设我有一张产品表和一张照片桌。 1产品有很多照片。所以在我做的产品模型中:
var $has_many = array("category", "photo");
现在我想获得所有产品并将他们的每张照片与他们联系起来。我怎样才能做到这一点?目前,在我的控制器中,我正在浏览每个产品并查询照片并以这种方式传递单独的数组。这不是理想的。我应该能够将每张照片直接绑定到特定产品吗?
从逻辑上讲,这可行(但不是吗?)
$product = new Product;
$products = $product->get_by_related_category('name', $where);
$photos = $product->photo->get();
看看我的目标是什么? 我很乐意将$ products变量传递给我的视图,能够通过它传播,并且每个产品对象都有一系列照片。
我怎样才能做到这一点?或者有更好的方法吗?
谢谢!
答案 0 :(得分:2)
使用“有很多”关系,您基本上有两种方法可以使用SQL获取相关信息:
您可以加入select products.*, photos.* from products left outer join photos on products.id = photos.product_id
中的其他表格。这样,您将拥有“重复”的产品数据,因此您需要相应地处理结果。遗憾的是include_related()
不直接支持此功能,它会创建重复的产品,每个产品都有一张相关照片。
您可以运行两个查询,首先获取产品(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查询,并为父对象的相关字段对象排序结果(不幸的是它有点长并且没有'支持多对多关系)。
/**
* 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上找到了它。
享受!