Общая схема этого шага будет выглядеть следующим образом:
Мы уже создали таблицу 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 будет содержать список 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. Контроллер будет содержать метод для инициализации корзины и получения ее из сессии, а также методы для действий:
Файл 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:
[...] <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> [...]
Файл 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. Регистрация пользователей.
Обсуждение