Последовательность наших действий будет следующей:
Этого будет вполне достаточно чтобы продемонстрировать один из подходов реализации вывода данных с различными ограничениями при помощи Limb.
Во фронтальной части мы должны обеспечить следующее условие - отображению подлежат только «доступные» товары, то есть те, у которых стоит флаг is_available. Для этого мы создадим дополнительный статический метод findForFront():
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); } }
С классом lmbCriteria вы должны быть уже знакомы по реализации функционала по управлению пользователями. Здесь же мы использовали класс lmbSQLRawCriteria для вставки условия в запрос «как есть» (as is). Мы сразу решили использовать объектную форму критерии при вызове метода lmbActiveRecord :: find(), так как знаем, что нам придется в ближайшее время расширить этот функционал.
Применим новый метод для передачи данных в шаблон:
Файл shop/src/controller/ProductController.class.php:
<?php lmb_require('limb/cms/src/controller/lmbObjectController.class.php'); lmb_require('src/model/Product.class.php'); class ProductController extends lmbObjectController { protected $_object_class_name = 'Product'; function doDisplay() { $this->items = Product :: findForFront(); } }
Мы могли бы использовать PullView и получать данные непосредственно в шаблоне, но не будем этого делать, т.к. пока не знаем всех параметров выборки.
Файл 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"/}} <br/> {{list using="$#items"}} <table cellpadding="0" cellspacing="0" class='list'> {{list:item}} <tr> <td> <dl> <dt> <b>{$item.title}</b><br /> Price: <b>${$item.price|number:2, '.', ' '}</b><br/> </dt> <dd> <img src='{$item.image_path}' class='img'/> {$item.description|nl2br} </dd> </dl> </td> </tr> {{/list:item}} </table> {{/list}} {{/wrap}}
Получения данных в нашем случае происходит из переменной $this→items, которая заполняется методом findForFront(). Таким образом, во фронтальной части мы будем отображать только доступные товары.
Теперь можете попробовать зайти на страницу /product вашего приложения. Вы должны увидеть список товаров, разделенный на страницы (если элементов больше 5).
Теперь мы приступим к реализации поиска товаров по первым буквам. Это потребует отображения списка букв в шаблоне, а также наложения ограничений на выборку товаров, название которых начинается с выбранной буквы.
Что нам для этого нужно:
Весь этот функционал мы соберем в одном месте - классе AlphabetHelper.
Итак, список букв мы будем формировать при помощи класса AlphabetHelper. Если какая-либо буква является выбранной на данный момент, мы ее также помечаем определенным образом (метод isCurrent()).
Файл shop/src/helper/AlphabetHelper.class.php:
<?php class AlphabetHelper { protected $_request_param_name = 'letter'; protected $_current_letter = ''; function __construct() { $request = lmbToolkit :: instance()->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:
<?php lmb_require('limb/cms/src/controller/lmbObjectController.class.php'); lmb_require('src/model/Product.class.php'); lmb_require('src/helper/AlphabetHelper.class.php'); class ProductController extends lmbObjectController { protected $_object_class_name = 'Product'; function doDisplay() { $this->helper = new AlphabetHelper(); $this->items = Product :: findForFront($this->helper->getCurrentLetter()); } }
Теперь мы будем использовать новый AlphabetHelper в шаблоне для вывода списка букв. Для этого нам необходимо немного модифицировать шаблон product/display.phtml.
Файл shop/template/product/display.phtml:
[...] <a href="{{route_url params='controller:product'}}">Display all</a> {{list using="$#helper->getAlphabet()"}} {{list:item}} <? if ($this->helper->getCurrentLetter() == $item) { ?> <b>{$item|uppercase}</b> <? } else { ?> <?php $letter_param = AlphabetHelper :: REQUEST_PARAM_NAME; ?> <a href='/product?{$letter_param}={$item}'>{$item|uppercase}</a> <? } ?> {{/list:item}} {{/list}} [...]
Теперь нам необходимо, что метод Product :: findForFront() учитывал ограничения по первой букве названия товара, если необходимо.
Файл shop/src/model/Product.class.php:
<?php class Product extends lmbActiveRecord { [...] static function findForFront($title_begin = null) { $criteria = lmbSQLCriteria::equal('is_available', 1); if ($title_begin) $criteria->addAnd(lmbSQLCriteria :: like('title', $title_begin.'%')); return Product :: find($criteria); } [...]
Метод Product :: findForFront($title_begin) добавляет в $criteria дополнительное условие, если в него передают значение. Мы использовали метод addAnd() для добавления дополнительного условия. Обратите внимание, что знаки % для LIKE условия необходимо расставлять самостоятельно.
Сейчас можете попробовать этот новый функционал. Вы должны увидеть список букв и при нажатии на какую-либо из них, выборка товаров будет соответствующим образом ограничена:
Добавим новую форму для поиска товаров. Поиск будет доступен по названию продукта, а также по цене (больше какого-либо значения и(или) меньше).
Модификация файла shop/template/product/display.phtml:
[...] <p><strong>Search the products:</strong></p> {{form method="GET" id='search_form' name='search_form' action='product'}} <label for='title'>Product title:</label> {{input type="text" name="title" id="product" size='10'/}} <label for='price_greater'>Price greater:</label> {{input type="text" name="price_greater" id="price_greater" type="text" size='4'/}} <label for='price_less'>Price less:</label> {{input type="text" name="price_less" id="price_less" type="text" size='4'/}} <input type='submit' name='search' value="Search!" class='button'/><br/> {{/form}} [...]
Теперь нам необходимо модифицировать 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 :: 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', и нам не придется делать еще один передаваемый параметр.
Надеемся, что наши последние действия в комментариях не требуются, и все понятно.
У нас уже есть список доступных к продаже товаров, теперь настало время добавить потенциальным покупателям добавлять приглянувшиеся им товары к корзину и оформлять заказ.
Итак, следующий шаг: Шаг6. Работа покупателей с корзиной заказа
Обсуждение