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

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


limb3_2007_4:ru:tutorials:shop:step6

Шаг6. Работа покупателей с корзиной заказа

Общая схема этого шага будет выглядеть следующим образом:

  • Корзина будет представлена классом Cart, который будет отнаследован от класса lmbObject. Это наследование позволит использовать get-методы для получения данных при выводе содержимого корзины в шаблоне (зачем, будет пояснено чуть позже).
  • Объект корзины мы будем хранить в сессии.
  • Корзина будет содержать несохраненные экземпляры класса OrderLine (до момента отправки заказа)
  • OrderLine будет содержать фабричный метод (factory method), который будет создавать объект OrderLine из объекта класса Product.
  • Все управление корзиной будет осуществляться через контроллер CartController

Классы модели для работы с корзиной

Класс OrderLine

Мы уже создали таблицу order_line в базе данных нашего приложения. Теперь нам потребуется класс OrderLine, объекты которого мы будем хранить в корзине.

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

class OrderLine extends lmbActiveRecord
{
}

Когда пользователь будет добавлять товары в корзину, он будет указывать идентификатор товара Product. Нам необходимо будет создавать экземпляр OrderLine из объекта Product. Для этого мы добавим фабричный метод в класс OrderLine:

class OrderLine extends lmbActiveRecord
{
  static function createForProduct($product)
  {
    $line = new OrderLine();
    $line->setProduct($product);
    $line->setQuantity(0);
    $line->setPrice($product->getPrice());
    return $line;
  }
}

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

Когда покупатель будет добавлять один и тот же товар в корзину дважды, мы не будем создавать экземпляры OrderLine - вместо этого мы будем только увеличивать количество единиц товара. Для этого введем метод OrderLine :: increaseQuantity($amount):

class OrderLine extends lmbActiveRecord
{
  [...]
  function increaseQuantity($amount = 1)
  {
    $this->setQuantity($this->getQuantity() + $amount);
  } 
}

Ну и последний штрих - это метод getSumm(), который возвращает сумму за эту позицию заказа:

class OrderLine extends lmbActiveRecord
{
  [...]
  function getSumm()
  {
    return $this->getQuantity() * $this->getPrice();
  }
}

Пока с OrderLine мы закончили, но обязательно вернемся, когда дойдем по оформления заказа покупателя.

Класс Cart

Класс Cart будет содержать список OrderLine, а также логику по добавлению элементов:

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

<?php
lmb_require('limb/core/src/lmbObject.class.php');
lmb_require('src/model/OrderLine.class.php');
 
class Cart extends lmbObject
{
  protected $line_items = array();
 
  function addProduct($product)
  {
    $id = $product->getId();
 
    if(!isset($this->line_items[$id]))
      $this->line_items[$id] = OrderLine :: createForProduct($product);
 
    $this->line_items[$id]->increaseQuantity(1);
  }
 
  function getItems()
  {
    return $this->line_items;
  }
}
?>

Для очистки корзины можно будет пользоваться методом Cart :: removeAll(), этот метод находится в классе lmbObject.

Скорее всего, нам потребуются методы для получения общей суммы и количества товарных позиций в корзине. Поэтому добавим методы getTotalSumm() и getItemsCount():

class Cart extends lmbObject
{
  [...]
  function getTotalSumm()
  {
    $result = 0;
    foreach($this->line_items as $item)
      $result += $item->getSumm();
    return $result;
  }
 
  function getItemsCount()
  {
    return sizeof($this->line_items);
  }
}

Этого вполне достаточно. Теперь можно перейти к контроллеру CartController.

Контроллер CartController. Хранение корзины в сессии

Создадим самую базовую реализацию CartController. Контроллер будет содержать метод для инициализации корзины и получения ее из сессии, а также методы для действий:

  • doAdd() - добавление товара в корзину
  • doDisplay() - отображение содержимого товара
  • doEmpty()- полная очистка корзины

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

<?php
lmb_require('src/model/Product.class.php');
lmb_require('src/model/Cart.class.php');
 
class CartController extends lmbController
{
  function doDisplay()
  {
    $this->view->set('cart', $this->_getCart());
  }
 
  function doEmpty()
  {
    $cart = $this->_getCart();
    $cart->removeAll();
    $this->redirect();
  }
 
  function doAdd()
  {
    $product_id = $this->request->getInteger('id');
    try
    {
      $product = lmbActiveRecord :: findById('Product', $product_id);
      $cart = $this->_getCart();
      $cart->addProduct($product);
      $this->flashMessage('Product "' . $product->getTitle() . '" added to your cart!');
    }
    catch(lmbARException $e)
    {
      $this->flashError('Wrong product!');
    }
 
    if(isset($_SERVER['HTTP_REFERER']))
      $this->redirect($_SERVER['HTTP_REFERER']);
    else
      $this->redirect();
  }
 
  protected function _getCart()
  {
    $session = $this->toolkit->getSession();
    if(!$cart = $session->get('cart'))
    {
      $cart = new Cart();
      $session->set('cart', $cart);
    }
 
    return $cart;
  }
}
?>

Поясним некоторые моменты.

  function doDisplay()
  {
    $this->view->set('cart', $this->_getCart());
  }

Мы передали объект корзины в шаблон.

  [...]
    try
    {
      $product = lmbActiveRecord :: findById('Product', $product_id);
      $cart = $this->_getCart();
      $cart->addProduct($product);
      $this->flashMessage('Product "' . $product->getTitle() . '" added to your cart!');
    }
    catch(lmbARException $e)
    {
      $this->flashError('Wrong product!');
    }

lmbActiveRecord :: findById генерирует исключение, если объект с указанным идентификатором загрузить не удалось. Чтобы не отображать фатальную ошибку, мы ловим это исключение (класса lmbARException) и передаем в шаблон сообщение об ошибке (flashError()). Если продукт был добавлен в корзину нормально, тогда мы передаем в шаблон информационное сообщение (flashMessage()).

Изменения в шаблонах

Изменения в product/display.html

Для того, чтобы добавить товар в корзину нам для начала нужно добавить ссылку на это действие в шаблон product/display.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/>
          <route_url params='controller:cart,action:add,id:{$id}'>Add to cart</route_url><br/>
         </dt>
         <dd>
            <img src='{$image_path}' class='img'/>
            {$description|nl2br|raw}
         </dd>
      </dl>
    </td>
  </tr>
  </list:item>
</table>
</list:list>
[...]

Шаблон cart/display.html для отображения содержимого корзины

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

<core:set title='Your Cart'/>
<core:WRAP file="page.html" as="content">
 
<core:datasource from='#cart'>
 
<core:optional for='items_count'>
Your cart contains {$items_count} items.
 
<list:LIST from="items">
<table cellpadding="0" cellspacing="0" class='list'>
  <thead>
  <tr>
    <th>Title</th>
    <th>Price</th>
    <th>Quantity</th>
    <th>Summ</th>
  </tr>
  </thead>
  <list:item>
  <tr class='{$Parity}'>
   <td>{$product.title}</td>
   <td>${$price|number:2, '.'}</td>
   <td>{$quantity}</td>
   <td>${$summ|number:2, '.'}</td>
  </tr>
  </list:item>
</table>
</list:LIST>
 
Total summ is : <b>${$total_summ|number:2, '.'}</b>
<br/>
<route_url params='action:empty'>Empty cart</route_url><br/>
<route_url params='action:checkout'>Checkout</route_url>
</core:optional>
 
<core:default for='items_count'>
You cart is empty at the moment!
</core:default>
 
</core:datasource>
 
</core:wrap>

В методе CartController :: doDisplay() мы передали объект корзины в шаблон. Это значит, что корзина доступна в корневом контейнере данных. Этим мы воспользовались, когда заполнили контейнер данных <core:datasource> при помощи атрибута from.

<core:datasource from='#cart'>
[...]
</core:datasource>

from='#cart' - означает получить из корневого контейнера переменную cart и сделать из нее текущий источник данных.

После этого внутри <core:datasource> мы можем обращаться к переменным корзины: {$items_count}, {$total_summ}.

Аналогичным образом мы заполнили содержимое тега <list:list>. <list:LIST from=«items»> - означает получить из текущего контейнера данных переменную items и использовать ее как итератор с данными.

Подробнее о передаче данных внутри WACT-шаблонов

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

Попробуйте добавить несколько товаров при помощи панели управления и добавить их в корзину. Вы должны получить нечто следующее:

}

Далее

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

После этого мы сможем приступить к оформлению заказав и сохранению их в базе данных. Этот пункт нашего плана покажет, как lmbActiveRecord поддерживает работу с различными отношениями между объектами, например, один-ко-многим или много-ко-многим.

Следующий шаг: Шаг7. Регистрация пользователей.

Обсуждение

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