lmb_require('limb/dbal/src/criteria/lmbSQLRawCriteria.class.php');
class Product extends lmbActiveRecord
{
[...]
static function findForFront()
{
$criteria = new lmbSQLRawCriteria('is_available = 1');
return lmbActiveRecord :: find('Product', $criteria);
}
}
С классом [[..:..:packages:dbal:criteria|lmbCriteria]] вы должны быть уже знакомы по реализации функционала по управлению пользователями. Здесь же мы использовали класс **lmbSQLRawCriteria** для вставки условия в запрос "как есть" (as is). Мы сразу решили использовать объектную форму критерии при вызове метода lmbActiveRecord :: find(), так как знаем, что нам придется в ближайшее время расширить этот функционал.
==== Доработка ProductController ====
Применим новый метод для передачи данных в шаблон:
Файл shop/src/controller/ProductController.class.php:
items = Product :: findForFront();
}
}
Мы могли бы использовать PullView и получать данные непосредственно в шаблоне, но не будем этого делать, т.к. пока не знаем всех
параметров выборки.
==== Шаблон product/display.phtml ====
Файл shop/template/product/display.phtml:
$this->title ='Products'; ?>
{{wrap with="front_page_layout.phtml" into="content_zone"}}
{{include file='_admin/pager.phtml' items="$#items" per_page="5"/}}
{{list using="$#items"}}
{{list:item}}
-
{$item.title}
Price: ${$item.price|number:2, '.', ' '}
-
{$item.description|nl2br}
{{/list:item}}
{{/list}}
{{/wrap}}
Получения данных в нашем случае происходит из переменной $this->items, которая заполняется методом findForFront(). Таким образом, во фронтальной части мы будем отображать только доступные товары.
Теперь можете попробовать зайти на страницу /product вашего приложения. Вы должны увидеть список товаров, разделенный на страницы (если элементов больше 5).
===== Реализация ограничений по первой букве =====
Теперь мы приступим к реализации поиска товаров по первым буквам. Это потребует отображения списка букв в шаблоне, а также наложения ограничений на выборку товаров, название которых начинается с выбранной буквы.
Что нам для этого нужно:
* хранить где-то список букв
* хранить где-то текущую букву
Весь этот функционал мы соберем в одном месте - классе %%AlphabetHelper%%.
==== Класс AlphabetHelper ====
Итак, список букв мы будем формировать при помощи класса %%AlphabetHelper%%. Если какая-либо буква является выбранной на данный момент, мы ее также помечаем определенным образом (метод isCurrent()).
Файл %%shop/src/helper/AlphabetHelper.class.php%%:
getRequest();
if($request->has($this->_request_param_name))
$this->_current_letter = $request->get($this->_request_param_name);
}
function getAlphabet()
{
$result = array();
for($i = 'A'; $i <= 'Z'; $i++)
{
if(1 !== strlen($i))
continue;
$result[] = $i;
}
return $result;
}
function getCurrentLetter()
{
return $this->_current_letter;
}
}
Класс %%AlphabetFetcher%% отнаследован от класса lmbFetcher. **lmbFetcher** - это базовый класс, от которого наследуются все остальные fetcher-ы. Дочерние классы перекрывают метод _creataDataset(), из которого они должны обязательно возращать итератор.
==== Инстанцирование хэлпера ====
Связующей точкой модели, шаблона и запроса является контроллер. В нем мы и будем инстанцировать наш хэлпер.
Файл /shop/src/controller/ProductController.class.php:
helper = new AlphabetHelper();
$this->items = Product :: findForFront($this->helper->getCurrentLetter());
}
}
==== Изменения в шаблоне product/display.phtml ====
Теперь мы будем использовать новый %%AlphabetHelper%% в шаблоне для вывода списка букв. Для этого нам необходимо немного модифицировать шаблон product/display.phtml.
Файл shop/template/product/display.phtml:
[...]
Display all
{{list using="$#helper->getAlphabet()"}}
{{list:item}}
if ($this->helper->getCurrentLetter() == $item) { ?>
{$item|uppercase}
} else { ?>
{$item|uppercase}
} ?>
{{/list:item}}
{{/list}}
[...]
==== Изменения в классе Product для учитывания ограничений ====
Теперь нам необходимо, что метод Product :: findForFront() учитывал ограничения по первой букве названия товара, если необходимо.
Файл shop/src/model/Product.class.php:
addAnd(lmbSQLCriteria :: like('title', $title_begin.'%'));
return Product :: find($criteria);
}
[...]
Метод Product :: findForFront($title_begin) добавляет в $criteria дополнительное условие, если в него передают значение. Мы использовали метод addAnd() для добавления дополнительного условия. Обратите внимание, что знаки **%** для LIKE условия необходимо расставлять самостоятельно.
Сейчас можете попробовать этот новый функционал. Вы должны увидеть список букв и при нажатии на какую-либо из них, выборка товаров будет соответствующим образом ограничена:
{{limb3:ru:tutorials:shop:alphabet.png|поиск по алфавиту}}
===== Реализация формы поиска товаров =====
==== Добавление формы поиска в шаблон product/display.phtml ====
Добавим новую форму для поиска товаров. Поиск будет доступен по названию продукта, а также по цене (больше какого-либо значения и(или) меньше).
Модификация файла shop/template/product/display.phtml:
[...]
Search the products:
{{form method="GET" id='search_form' name='search_form' action='product'}}
{{input type="text" name="title" id="product" size='10'/}}
{{input type="text" name="price_greater" id="price_greater" type="text" size='4'/}}
{{input type="text" name="price_less" id="price_less" type="text" size='4'/}}
{{/form}}
[...]
==== Модификация контроллера ProductController ====
Теперь нам необходимо модифицировать %%ProductController%% и Product, чтобы они принимали новые параметры фильтрации.
Файл %%shop/src/controller/ProductController.class.php%%:
[...]
function doDisplay()
{
$this->helper = new AlphabetHelper();
$this->useForm('search_form');
$this->setFormDatasource($this->request);
$this->items = Product :: findForFront($this->_getSearchParams());
}
function _getSearchParams()
{
$params = array();
if($this->request->get('title'))
$params['title'] = $this->request->getSafe('title');
if($this->request->get('price_greater'))
$params['price_greater'] = $this->request->getInteger('price_greater');
if($this->request->get('price_less'))
$params['price_less'] = $this->request->getInteger('price_less');
return $params;
}
[...]
Как вы видите мы получаем из запроса параметры title, price_great, price_less, и передаем их в Product :: findForFront($params), предварительно отфильтровав. Мы могли бы передавать туда сам объект запроса (request), но это стало бы смешением уровней приложения.
==== Изменения в классе Product для учета новых критерий ====
Теперь можно модифицировать метод Product :: findForFront() для того, чтобы он учитывал данные, пришедшие с формы поиска.
Файл shop/src/model/Product.class.php:
[...]
static function findForFront($params = array())
{
$criteria = lmbSQLCriteria::equal('is_available', 1);
if (isset($params['title']))
$criteria->addAnd(lmbSQLCriteria :: like('title', $params['title'].'%'));
if (isset($params['price_greater']))
$criteria->addAnd(lmbSQLCriteria :: greater('price', (int) $params['price_greater']));
if (isset($params['price_less']))
$criteria->addAnd(lmbSQLCriteria :: less('price', (int) $params['price_less']));
return Product :: find($criteria);
}
[...]
Поиск по первой букве является по сути частным случаем поиска по названию. Поэтому мы можем изменить значение константы AlphabetHelper :: REQUEST_PARAM_NAME на 'title', и нам не придется делать еще один передаваемый параметр.
Надеемся, что наши последние действия в комментариях не требуются, и все понятно.
===== Предварительные итоги =====
Небольшой скриншот того, как должен выглядеть список товаров при использовании формы поиска:
{{limb3:ru:tutorials:shop:search_products.png|поиск продуктов}}
===== Далее =====
У нас уже есть список доступных к продаже товаров, теперь настало время добавить потенциальным покупателям добавлять приглянувшиеся им товары к корзину и оформлять заказ.
Итак, следующий шаг: [[step6|Шаг6. Работа покупателей с корзиной заказа]]