Deprecated: Assigning the return value of new by reference is deprecated in /home/spwebru/com/wp-settings.php on line 472

Deprecated: Assigning the return value of new by reference is deprecated in /home/spwebru/com/wp-settings.php on line 487

Deprecated: Assigning the return value of new by reference is deprecated in /home/spwebru/com/wp-settings.php on line 494

Deprecated: Assigning the return value of new by reference is deprecated in /home/spwebru/com/wp-settings.php on line 530

Deprecated: Assigning the return value of new by reference is deprecated in /home/spwebru/com/wp-includes/cache.php on line 103

Deprecated: Assigning the return value of new by reference is deprecated in /home/spwebru/com/wp-includes/query.php on line 21

Deprecated: Assigning the return value of new by reference is deprecated in /home/spwebru/com/wp-includes/theme.php on line 623
Фильтрация списка по категориям в CakePHP - Программируем на CakePHP


Сен 01 2008

Фильтрация списка по категориям в CakePHP

Раздел: Веб-разработкаМета @ 22:49

Допустим, есть у нас таблица категорий «categories», построенная по самому простому принципу — id, name, parent_id. И есть список товаров, привязанных к этим категориям по полю «category_id». Список довольно большой — свыше двух тысяч наименований. Стандартным шеллом CakePHP можно подготовить функции в контроллере и вид (view) для постраничного просмотра списка товаров с помощью PaginatorHelper. Но проматывать больше сотни страниц для того чтобы найти нужный товар, крайне непродуктивно. Соответственно, надо сделать фильтрацию по категории товаров.

Подразумевается, что связь hasMany между категориями и товарами уже настроена. Обязательно также нужна и обратная ей — belongsTo.

Создаем в виде форму для отображения списка категорий. С использованием AdminRoutes это будет файл views/products/admin_index.ctp.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="actions">
<?php
//Устанавливаем дополнительный параметр PaginatorHelper'а, 
//чтобы при переходе между страницами не терялась сортировка по категориям
$paginator->options(array('url' =>  $current_category));
//Создаем форму
echo $form->create('Product', array('action'=>'/index/'));
//Поясняющее сообщение и заодно ссылка, отменяющая фильтрацию
echo 'Показать ', $html->link('Все категории', '/admin/products/index/'), ' или выбрать из списка: ';
echo '<div align="left">';
//Здесь появится выпадающий список
echo $form->input('cat_id', array('label'=>'','options'=>$categories));
echo $form->end('Показать');
echo '</div>';
?>
</div>

Форма представляет собой простой выпадающий список со списком категорий. Первым пунктом будут идти «Все категории», а в остальных пунктах для отображения уровня вложенности категории будем использовать символ подчеркивания. Для правильного выбора всех категорий с учетом уровня вложенности нам понадобится дополнить модель категорий Category парой простых функций. Выборка производится рекурсивно, я намеренно не стал делать никаких оптимизаций для большей наглядности.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function get_rec_categories($parent_id = 0, $level = 1){
$ret_category = array();
$categories = $this->findall('parent_id = '.$parent_id, array('id', 'name', 'parent_id'));
foreach ($categories as $category) {
$ret_category[] = array('id' => $category['Category']['id'], 'name' => $category['Category']['name'], 'level' => $level-1);
$ret_category= $this->_ac($ret_category, $this->get_rec_categories($category['Category']['id'], $level+1));
}
return $ret_category;
}
 
function _ac($a1 = array(), $a2 = array()){
foreach ($a2 as $a) {
$a1[] = $a;
}
return $a1;
}

Вызов функции get_rec_categories() возвращает массив вида:

1
2
3
4
5
6
7
8
9
10
Array
(
[1] => Array
(
[id] => 1
[name] => Some Category Name
[level] => 1
)
...
)

Осталось вызвать эту функцию в контроллере, обработать ее результаты, передать в вид и если категория выбрана — отфильтровать товары. Дописываем все это в функцию admin_index() контроллера products_controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function admin_index($category_id=null) {
//Получаем все категории в порядке вложенности и с отметкой о уровне вложения из модели
$categories = $this->Product->Category->get_rec_categories();
//Первым пунктом в списке будет идти «Все категории»
$categories_prepared = array(0=>'Все категории');
//Добавляем перед названием количество подчеркиваний, соответствующее уровню вложения
foreach ($categories as $category) {
$categories_prepared[$category['id']]=str_repeat('_', $category['level']).$category['name'];
}
//Передаем список в вид
$this->set('categories', $categories_prepared);
//Получаем из формы номер выбранной категории
if ($this->data['Product']['category_id'] <> null) {
$category_id = intval($this->data['Product']['category_id']);
}
//Полученный из формы или из запроса номер категории надо обязательно привести к числовому типу,
//чтобы злоумышленник не мог подсунуть вместо номера категории sql-код
$category_id = intval($category_id);
//Если номер категории не ноль, то добавляем его к условиям поиска токара
if ($category_id <> 0) {
$conditions = array('category_id'=>$category_id);
} else {
$conditions = null;
}
//Передаем в вид номер текущей категории
$this->set('current_category',$category_id);
//А это чтобы в списке был выбран соответствующий пункт
$this->data['Product']['category_id'] = $category_id;
//Настраиваем параметры выбора списка товаров. Нам нужны только товары, по 30 штук на странице
$this->Product->recursive = 0;
$this->paginate['limit'] = 30;
//Передаем список товаров в вид
$this->set('products', $this->paginate(null, $conditions));
}

Теги: , ,

One Response to “Фильтрация списка по категориям в CakePHP”

  1. Веб-работа » Использование TreeBehavior в CakePHP says:

    [...] может быть обозначена префиксами, как в примере в моем предыдущем посте на эту [...]

Напиши комментарий!