В общем выходит такая штука, кто как решал или решил задачу?
Пример. Есть блог "много-ко-многим". Нужно выбрать все записи этой рубрики и записи из всех её подрубрик.
Допустим, получили массив id-шников нужных подрубрик включая текущую $ids = array('13', '14', '22')
Т.к. одна запись может быть в нескольких рубриках нужен запрс с DISTINCT
Выбираем записи в блоге из нескольких рубрик
Код:
$posts = ORM::factory('Blog_Post')
->distinct(TRUE)
->join(array('blog_posts_rubrics', 'bpr'))
->on('bpr.post_id', '=', 'blog_post.id')
->where('enabled', '=', 1)
->where('bpr.rubric_id', 'IN', $ids);
Теперь перед find_all() нужна постраничка, т.е. нужно вызвать count_all()->reset(FALSE) и тут проблемка. Будет сгенерирован запрос
Код:
SELECT DISTINCT COUNT(*) AS `records_found`
FROM `blog_posts` AS `blog_post`
JOIN `blog_posts_rubrics` AS `bpr` ON (`bpr`.`post_id` = `blog_post`.`id`)
WHERE `enabled` = 1 AND `bpr`.`rubric_id` IN ('13', '14', '22')
т.е. этот DISTINCT ни начто не влияет и посчитает дубликаты, что нам не нужно.
Через билдер запрос строится так
Код:
...->select(array(DB::expr('COUNT(DISTINCT `id`)'), 'records_found'))
Через ORM я так и не понял как это сделать, поэтому расширил стандартный метод и получился такой костыль:
Код:
class ORM extends Kohana_ORM
{
public function count_all($reset = TRUE, $distinct = FALSE)
{
$selects = array();
foreach ($this->_db_pending as $key => $method)
{
if ($distinct)
{
if ($method['name'] == 'distinct')
{
$selects[] = $method;
unset($this->_db_pending[$key]);
}
}
if ($method['name'] == 'select')
{
$selects[] = $method;
unset($this->_db_pending[$key]);
}
}
if ( ! empty($this->_load_with))
{
foreach ($this->_load_with as $alias)
{
$this->with($alias);
}
}
$this->_build(Database::SELECT);
if ($distinct)
$records = $this->_db_builder
->from(array($this->_table_name, $this->_object_name))
->select(array(DB::expr('COUNT(DISTINCT(`'.$this->_primary_key.'`))'), 'records_found'))
->execute($this->_db)
->get('records_found');
else
$records = $this->_db_builder
->from(array($this->_table_name, $this->_object_name))
->select(array(DB::expr('COUNT(*)'), 'records_found'))
->execute($this->_db)
->get('records_found');
$this->_db_pending += $selects;
$this->reset($reset);
return $records;
}
}
Теперь количество считает верно
Код:
$posts = ORM::factory('Blog_Post')
->distinct(TRUE)
->join(array('blog_posts_rubrics', 'bpr'))
->on('bpr.post_id', '=', 'blog_post.id')
->where('enabled', '=', 1)
->where('bpr.rubric_id', 'IN', $ids);
$count = $posts->count_all(FALSE, TRUE);
$posts = $posts->find_all();
Получаются запросы, которые нам нужны: количество уникальных записей для постранички и список уникальных записей для вывода в шаблоне (постраничку для простоты убрал)
Код:
SELECT COUNT(DISTINCT(`id`)) AS `records_found`
FROM `blog_posts` AS `blog_post`
JOIN `blog_posts_rubrics` AS `bpr` ON (`bpr`.`post_id` = `blog_post`.`id`)
WHERE `enabled` = 1 AND `bpr`.`rubric_id` IN ('13', '14', '22')
Код:
SELECT DISTINCT `blog_post`.`id` AS `id`, `blog_post`.`title` AS `title`
FROM `blog_posts` AS `blog_post`
JOIN `blog_posts_rubrics` AS `bpr` ON (`bpr`.`post_id` = `blog_post`.`id`)
WHERE `enabled` = 1 AND `bpr`.`rubric_id` IN ('13', '14', '22')
Может я чего-то упустил или не знаю как это делается для ORM или это можно сделать изящнее.
Какие будут предложения?