Инструменты пользователя

Инструменты сайта


limb3_2007_4:ru:tutorials:shop:step5

Шаг5. Отображение списка товаров для покупателей. Поиск товаров

Последовательность наших действий будет следующей:

  • Мы создадим контроллер ProductController и реализуем базовый шаблон product/display.html для отображения списка товаров.
  • Мы создадим специальный статический метод Product :: findForFront(), который будет возвращать только список доступных товаров ($is_available == true). Именно эти товары мы будем отображать на фронтальной части.
  • Мы создадим AlphabetFetcher, который вернет список букв алфавита. В шаблоне product/display.html мы предоставим возможность покупателям просматривать товары, начинающиеся с какой-либо конкретной буквы. В методе Product :: findForFront() мы сделаем соответствующие изменения, чтобы он анализировал пришедшие ограничения.
  • Мы создадим форму для поиска товаров, а в методе Product :: findForFront() добавим анализ дополнительных ограничивающих параметров. Для полноценной поддержки формы поиска мы также добавим немного кода в контроллер ProductController.

Этого будет вполне достаточно чтобы продемонстрировать один из подходов реализации вывода данных с различными ограничениями при помощи Limb3.

Первоначальный вывод товаров

Контроллер ProductController

Файл shop/src/controller/ProductController.class.php:

<?php
class ProductController extends lmbController
{
}
?>

Изменения в классе Product

Во фронтальной части мы должны обеспечить следующее условие - отображению подлежат только «доступные» товары, то есть те, у которых стоит флаг is_available. Для этого мы создадим дополнительный статический метод findForFront():

class Product extends lmbActiveRecord
{
  [...]
  static function findForFront()
  {
    lmb_require('limb/dbal/src/criteria/lmbSQLRawCriteria.class.php');
 
    $criteria = new lmbSQLRawCriteria('is_available = 1');
 
    return lmbActiveRecord :: find('Product', $criteria);
  }
}

С классом lmbCriteria вы должны быть уже знакомы по реализации функционала по управлению пользователями. Здесь же мы использовали класс lmbSQLRawCriteria для вставки условия в запрос «как есть» (as is). Мы сразу решили использовать объектную форму критерии при вызове метода lmbActiveRecord :: find(), так как знаем, что нам придется в ближайшее время расширить этот функционал.

Шаблон product/display.html

Файл shop/template/product/display.html:

<core:set title='Products'/>
<core:WRAP file="page.html" as="content">
 
<active_record:fetch using='src/model/Product' find='for_front' target="products" navigator='pager'/>
 
<core:include file='pager.html'/>
 
<list:list id="products">
<table cellpadding="0" cellspacing="0" class='list'>
  <thead>
  </thead>
  <list:item>
  <tr>
   <td>
      <dl>
        <dt>
          <b>{$title}</b><br />
          Price:<b>${$price|number:2, '.'}</b><br/>
         </dt>
         <dd>
            <img src='{$image_path}' class='img'/>
            {$description|nl2br|raw}
         </dd>
      </dl>
    </td>
  </tr>
  </list:item>
</table>
</list:list>
</core:wrap>

Обратите внимание на атрибут find тега <active_record:fetch>. Он указывает, какой метод должен быть вызван у ActiveRecord для получения данных. В нашем случае for_front указывает на метод findForFront(). Таким образом, во фронтальной части мы будем отображать только доступные товары.

Теперь можете попробовать зайти на страницу /product вашего приложения. Вы должны увидеть список товаров, разделенный на страницы (если элементов достаточно много).

Реализация ограничений по первой букве

Теперь мы приступим к реализации поиска товаров по первым буквам. Это потребует отображения списка букв в шаблоне, а также наложения ограничений на выборку товаров, название которых начинается с выбранной буквы.

Здесь мы разберем использование так называемых fetcher-ов, о которых мы упоминали в шаге 4.4(Отображение профайла пользователя). Fetcher-ы - это такие классы, которые можно использовать для получения данных прямо в шаблонах при помощи тега <fetch>.

Для вывода списка букв алфавита мы создадим специальный класс AlphabetFetcher, который будет создавать итератор с буквами.

Класс AlphabetFetcher для вывода алфавита

Итак, список букв мы будем формировать при помощи класса AlphabetFetcher. Если какая-либо буква является выбранной на данный момент, мы ее также помечаем определенным образом (поле current).

Файл shop/src/fetcher/AlphabetFetcher.class.php:

<?php
lmb_require('limb/core/src/lmbCollection.class.php');
lmb_require('limb/web_app/src/fetcher/lmbFetcher.class.php');
 
class AlphabetFetcher extends lmbFetcher
{
  function _createDataset()
  {
    $current_letter = '';
    $request = lmbToolkit :: instance()->getRequest();
    if($request->hasAttribute('letter'))
      $current_letter = $request->get('letter');
 
    return new lmbCollection($this->_getEnglishLetters($current_letter));
  }
 
  function _getEnglishLetters($current_letter = '')
  {
    $result = array();
    for($i = 'A'; $i <= 'Z'; $i++)
    {
      if(strlen($i) == 2)
        break;
 
      $result[$i]['letter'] = $i;
      if ($i == $current_letter)
        $result[$i]['current'] = true;
    }
 
    return $result;
  }
}
?> 

Класс AlphabetFetcher отнаследован от класса lmbFetcher. lmbFetcher - это базовый класс, от которого наследуются все остальные fetcher-ы. Дочерние классы перекрывают метод _creataDataset(), из которого они должны обязательно возращать итератор.

Изменения в шаблоне product/display.html

Теперь мы будем использовать новый AlphabetFetcher в шаблоне для вывода списка букв. Для этого нам необходимо немного модифицировать шаблон product/display.html.

Файл shop/template/product/display.html:

<core:set title='Products'/>
<core:WRAP file="page.html" as="content">
 
<active_record:fetch using='src/model/Product' find='for_front' target="products" navigator='pager'/>
<core:include file='pager.html'/>
 
<p/>
<fetch using="src/fetcher/AlphabetFetcher" target="alphabet" />
 
<route_url params='controller:product'>Display all</route_url>
 
<list:LIST id="alphabet">
  <list:ITEM>
    <core:OPTIONAL for='current'>
    <b>{$letter|uppercase}</b>
    </core:OPTIONAL>
    <core:DEFAULT for='current'>
    <a href='/product?letter={$letter}'>{$letter|uppercase}</a>
    </core:DEFAULT>
  </list:ITEM>
</list:LIST>
 
<list:list id="products">
<table cellpadding="0" cellspacing="0" class='list'>
[...]

Подробнее о fetcher-ах и о применении тега <fetch>.

Изменения в классе Product для учитывания ограничений

Теперь нам необходимо, что метод Product :: findForFront() учитывал ограничения по первой букве названия товара, если необходимо.

Файл shop/src/model/Product.class.php:

<?php
class Product extends lmbActiveRecord
{
  [...]
  static function findForFront()
  {
    $request = lmbToolkit :: instance()->getRequest();
 
    lmb_require('limb/dbal/src/criteria/lmbSQLFieldCriteria.class.php');
    lmb_require('limb/dbal/src/criteria/lmbSQLRawCriteria.class.php');
 
    $criteria = new lmbSQLRawCriteria('is_available = 1');
 
    self :: _appendLetterCriteria($criteria, $request);
 
    return lmbActiveRecord :: find('Product', $criteria);
  }
 
  static protected function _appendLetterCriteria($criteria, $request)
  {
    if($letter = $request->get('letter'))
    {
      $criteria->addAnd(new lmbSQLFieldCriteria('title', $letter . '%', lmbSQLFieldCriteria :: LIKE));
      return true;
    }
  }
}
?>

Метод Product :: _appendLetterCriteria($criteria, $request) добавляет в $criteria дополнительное условие, если в запросе $request есть поле letter. Мы использовали класс lmbSQLFieldCriteria для дополнительного условия. Обратите внимание, что знаки % для LIKE условия необходимо расставлять самостоятельно.

Сейчас можете попробовать этот новый функционал. Вы должны увидеть список букв и при нажатии на какую-либо из них, выборка товаров будет соответствующим образом ограничена:

поиск по алфавиту}

Реализация формы поиска товаров

Добавление формы поиска в шаблон product/display.html

Добавим новую форму для поиска товаров. Поиск будет доступен по названию продукта, а также по цене (больше какого-либо значения и(или) меньше).

Модификация файла shop/template/product/display.html:

[...]
<p/><b>Search the products:</b>
<form method="POST" id='search_form' runat='server' action='/product'>
 
  <label for='product'>Product title:</label>
  <input type="text" name="product" 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/>
  <input type='hidden' name='action' value='search' runat='client'/>
</form>
 
<list:list id="products">
<table cellpadding="0" cellspacing="0" class='list'>
[...]

Обратите внимание на hidden поле action со значением search. При помощи этого поля мы фактически заставим контроллер ProductController выполнять действие search, а не display.

Модификация контроллера ProductController

Для того, чтобы после отправки данных с формы поиска товаров у нас отраватывал все тот же product/display.html шаблон и чтобы форма поиска содержала те данные, которые были с нее отправлены, нам необходимо модифицировать контроллер ProductController.

Файл shop/src/controller/ProductController.class.php:

<?php
class ProductController extends lmbController
{
  function doSearch()
  {
    $this->setTemplate('product/display.html');
    $this->useForm('search_form');
    $this->setFormDatasource($this->request);
  }
}
?>

Мы реализовали doSearch() метод, который выполняется при действии search. При помощи метода lmbController :: setTemplate($template_path) мы установили нужное нам название шаблона. Две другие строки метода связывают $request с формой в шаблоне, что позволяет отображать значения в полях формы после ее отправки.

Изменения в классе Product для учета новых критерий

Теперь можно модифицировать метод Product :: findForFront() для того, чтобы он учитывал данные, пришедшие с формы поиска.

Файл shop/src/model/Product.class.php:

<?php
class Product extends lmbActiveRecord
{
  [...]
  static function findForFront()
  {
    $request = lmbToolkit :: instance()->getRequest();
 
    lmb_require('limb/dbal/src/criteria/lmbSQLFieldCriteria.class.php');
    lmb_require('limb/dbal/src/criteria/lmbSQLRawCriteria.class.php');
 
    $criteria = new lmbSQLRawCriteria('is_available = 1');
 
    if(!self :: _appendLetterCriteria($criteria, $request))
      self :: _appendSearchCriteria($criteria, $request);
 
    return lmbActiveRecord :: find('Product', $criteria);
  }
 
  static protected function _appendSearchCriteria($criteria, $request)
  {
    if(!$request->get('search'))
      return false;
 
    if($product = $request->get('product'))
      $criteria->addAnd(new lmbSQLFieldCriteria('title', '%' . $product . '%', lmbSQLFieldCriteria :: LIKE));
 
    if($price_less = $request->get('price_less'))
      $criteria->addAnd(new lmbSQLFieldCriteria('price', $price_less, lmbSQLFieldCriteria :: LESS));
 
    if($price_greater = $request->get('price_greater'))
      $criteria->addAnd(new lmbSQLFieldCriteria('price', $price_greater, lmbSQLFieldCriteria :: GREATER));
  }
 
  static protected function _appendLetterCriteria($criteria, $request)
  {
    [...]
  }
}
?>

Надеемся, что наши последние действия в комментариях не требуются, и все понятно.

Предварительные итоги

Небольшой скриншот того, как должен выглядеть список товаров при использовании формы поиска:

поиск продуктов}

Далее

У нас уже есть список доступных к продаже товаров, теперь настало время добавить потенциальным покупателям добавлять приглянувшиеся им товары к корзину и оформлять заказ.

Итак, следующий шаг: Шаг6. Работа покупателей с корзиной заказа

Обсуждение

Ваш комментарий. Вики-синтаксис разрешён:
   ___   _   __   ___  __  __  ____ 
  / _ \ | | / /  / _ ) \ \/ / / __ \
 / ___/ | |/ /  / _  |  \  / / /_/ /
/_/     |___/  /____/   /_/  \____/
 
limb3_2007_4/ru/tutorials/shop/step5.txt · Последние изменения: 2010/11/10 10:02 (внешнее изменение)