对于“有很多”关系,您基本上有两种使用 SQL 获取相关信息的方法:
您可以在 like 中加入另一张桌子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,使用 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;
}