Корзина товаров
Идея и мысли спионерены вот тут, т.к. тот проект похоже загнулся.
Установка:
Установить пакет добавив в composer.json
~~~
...
"require": {
...
"mavsan/laravel-cart": "^1.0"
}
~~~
или выполнив команду composer require mavsan/laravel-cart
.
Добавить сервис провайдер и алиас в config/app.php
(для Laravel >= 5.4 регистрация происходит автоматически):
[
'providers' => [
/*
* Корзина
*/
Mavsan\LaCart\Providers\CartProvider::class,
],
'aliases' => [
/*
* Корзина
*/
'Cart' => Mavsan\LaCart\Facades\CartFacade::class,
// по-желанию
'CartDiscount' => Mavsan\LaCart\Facades\CartDiscountFacade::class,
],
];
Опубликовать конфигурацию и языковые файлы php artisan vendor:publish
. В папку, с конфигурациями будет скопирован файл cart.php
. В resources_path()/lang/vendor/cart
будут скопированы языковые файлы.
Если во время установки пакета была прописана строка в aliases
, тогда обращаться к корзине можно используя фасад Cart
.
Добавление в корзину
Добавление в корзину осуществляется методом Cart::add(...)
.
$options
, здесь и далее опции добавляемой записи, везде не обязательный параметр методов, например ['color' => 'blue', 'size' => 'L']
). Влияет на rowID
, это означает, что если будут добавлены два одинаковых товара (с одинаковым id
), но разными опциями (один красный и маленький, другой синий и большой и т.д.), то в корзине будут созданы разные записи для этих товаров.
Cart::add($productID, $productTitle, $count, $price);
// или
Cart::add($productID, $productTitle, $count, $price, $options);
Так-же можно добавить в корзину передав массив:
Cart::add(['id' => 1, 'title' => 'Product Title', 'count' => 2, 'price' => 156, 'options' => ['color' => 'blue', 'size' => 'L']]);
// или
Cart::add(['id' => 1, 'title' => 'Product Title', 'count' => 2, 'price' => 156]);
Или, если модель продуктов реализует интерфейс Mavsan\LaCart\Interfaces\Buyable
, добавить можно передав экземпляр этой модели. В данном варианте в элементе корзины так-же сохранится информация о классе, который использовался при добавлении товара в корзину (свойство model
- будет храниться название класса).
Cart::add($model, $count, $options);
Cart::add($model, $count);
// количество добавленных единиц будет установлено в 1
Cart::add($model);
При любом из вышеперечисленных способов добавления, метод Cart::add()
возвращает экземпляр добавленной записи - Mavsan\LaCart\Models\CartItem
.
Добавление пачкой. Если по каким-то причинам необходимо добавить несколько товаров одновременно - необходимо передать в метод Cart::add()
массив этих товаров. Каждый элемент такого массива должен быть или моделью, реализующей интерфейс Buyable
(в данном случае кол-во добавляемых товаров будет = 1, для каждой такой модели), или массивом:
Cart::add([$product1, $product2, [
'id' => '',
'title' => '',
'count' => '',
'price' => '',
'options' => [...]]
]);
В данном случае метод Cart::add()
вернет Collection
элементами которой будут экземпляры CartItem
соответственно добавляемым товарам.
Получение записей
Cart::getItems();
Вернет экземпляр Collection
. Если в корзине оказались добавлены записи в количеством = 0 - они будут автоматически удалены.
Удаление из корзины
Для удаления элемента из корзины необходимо передать идентификатор строки CartItem::getRowID()
или экземпляр CartItem
в соответствующий метод:
Cart::removeItem($rowID);
Так-же удалить элемент из корзины можно обновив его, установив количество = 0.
Обновление данных в корзине
Необходимо получить CartItem $cartItem
: Cart::getItem($rowID)
, изменить требуемые параметры, затем вызвать метод Cart::updateItem($oldRowID, CartItem $cartItem)
.
Старый $rowID
здесь требуется на случай, если у обновляемого элемента корзины будет обновлено свойство от которого зависит rowID
(сейчас это id и options) и будет сформирован новый rowID
. В этом случае, если в корзине уже существует товар с таким rowID
- он будет обновлен и у него будет изменено количество на старое + новое.
Так-же обновить данные можно используя модель, реализующую интерфейс Buyable
или массив с новыми данными или просто обновить количество:
Cart::update($oldRowID, $buyableModel);
// обновит наименование
Cart::update($oldRowID, ['title' => 'newTitle']);
// обновит наименование и кол-во
Cart::update($oldRowID, ['count' => 10, 'title' => 'newTitle']);
// обновит количество
Cart::update($oldRowID, 5);
Если после обновления данных у записи количество будет = 0 - такая запись будет автоматически удалена из корзины.
Количество в корзине
Cart::count();
Очистка корзины
Cart::clear();
Были ли изменения в корзине
При добавлении, изменении, удалении товаров из корзины, а так-же при авто очистке от товаров с количеством = 0 и очистке - корзина изменяет свое состояние, проверить которое можно вызвав метод:
Cart::isChanged();
Это требуется, например для того, чтобы сохранить изменения в базу данных.
При этом необходимо иметь ввиду, что изменяя позицию в корзине таким образом, состояние корзины не изменится:
$item = Cart::getItem($itemRowID);
$item->set...();
Хотя содержимое элемента корзины изменится (т.к. передается по ссылке). Для недопущения этого - необходимо обновить элемент корзины, вызвав метод Cart::updateItem()
.
Сумма всего
Cart::totalPrice();
// форматированный вывод (number_format)
Cart::formatTotalPrice($decimals, $decimalSep, $thousandsSep);
Сумма всего с учетом скидки
В файле конфигурации настроить правила расчета скидок персональных для товаров и общей для корзины. Создать класс/функцию/замыкание, которое будет заполнять CartDiscount
и прописать это в файле конфигурации (можно не создавать, а инициировать настройки скидок, скажем в сервис провайдере):
// если зарегистрирован фасад:
// сумма покупки от 1000 руб, скидка 5% или фиксированная - 200 руб.
CartDiscount::add(1000, 5, 200);
// если фасад не зарегистрирован
// сумма покупки от 5000 руб, скидка 10%, 500 руб.
App::make('cartDiscount')->add(5000, 10, 500);
В зависимости от настроек в файле конфигурации при расчете итоговой суммы с учетом скидки может учитываться, а может и не учитываться персональная скидка для товара. К тому-же можно указать какой тип скидки использовать - процент, или абсолютное выражение. Если возникла необходимость для одного диапазона указать скидку в процентах, а для другого - абсолютное значение, можно сделать так (естественно расчет обоих типов скидки необходимо включить в настройках):
// в настройках расчета скидки для корзины указать percent,discount (или наоборот, если используется смешанная схема и
// вначале надо отнять фиксированную сумму, а затем уже процент)
// для покупки от 2000 до 4999,99 от суммы будет отниматься 500 руб
App::make('cartDiscount')->add(2000, 0, 500);
// для покупки от 5000 и выше будет отниматься 10%
App::make('cartDiscount')->add(5000, 10, 0);
Получение итого с учетом скидки:
Cart::totalDiscount();
// форматированный вывод (number_format)
Cart::formatTotalDiscount($decimals, $decimalSep, $thousandsSep);
Округление
Для автоматического округления вывода необходимо вызвать метод Cart::setRound(true)
. После этого при вызове методов Cart::totalPrice()
и Cart::totalDiscount()
результат автоматически округлится.
Вызов Cart::setRound(true)
не приведет к автоматическому округлению результатов расчета сумм для товаров, добавленных в корзину. Это сделано для повышения точности расчета, чтобы не терялись копейки. Чтобы округлялись и они необходимо вручную вызвать метод CartItem::setRound(true)
для каждого добавленного в корзину:
Cart::getItems()->each(function($item, $rowID){
$item->setRound(true);
Cart::updateItem($rowID, $item);
});
Поиск
При необходимости найти что-то в добавленных в корзину записях можно воспользоваться методом Cart::search(closure)
:
Cart::add(1, 'Product1', 3, 20, ['color' => 'yellow']);
Cart::add(2, 'Product2', 5, 30, ['color' => 'white']);
Cart::add(3, 'Product3', 2, 5, ['color' => 'white']);
$result = $cart->search(function ($item, $index){
/** @var \Mavsan\LaCart\Models\CartItem $item */
return $item->getOptions()['color'] == 'white';
});
В замыкание передается два параметра. Первый - экземпляр CartItem
, второй - rowID
этого экземпляра.
В результате будет возвращен Collection
, в котором будут результаты поиска.
Сохранение информации о модели
Т.к. иногда бывает, что товарные предложения представлены разными моделями - корзина позволяет сохранять информацию о модели добавляемого в корзину товара.
Если товар добавляется как модель и реализует интерфейс Buyable
- информация о модели сохраняется автоматически при добавлении (см раздел “Добавление в корзину”).
Ручное добавление информации о модели:
Cart::setModel($rowID, $model);
$rowID
идентификатор записи в которую сохраняется информация модели;$model
строковое название модели (Product::class, ‘App\Product’ и т.д.), либо экземпляр модели.
Во время сохранения информации о модели проверяется существование такого класса, если класса нет - будет выброшено исключение CartItemModelNotFoundException
.
Получение модели
Для получения сохраненной ранее модели необходимо вызвать метод корзины Cart::getModel($rowID, $asObject = false)
.
$rowID
идентификатор записи модель которой необходимо получить;$asObject
если true, то будет возвращен экземпляр объекта товара, модель должна содержать методfind($id)
, вызов которого вернет экземпляр объекта (если модель не была сохранена - будет вызвано исключениеCartItemModelNotFoundException
), если false, то будет возвращено строковое название модели.
Сохранение в базу данных
С корзиной идет миграция, путь к которой прописывается в сервис провайдере корзины. Т.е. все, что необходимо сделать после регистрации корзины в сервис-провайдере - выполнить php artisan migrate
, после этого будет создана таблица с именем cart
.
Сохранение выполняется в ручную, т.е. в нужный момент необходимо вызвать метод:
Cart::store($identifier, $updateIfExists = false);
где $identifier
уникальный идентификатор (ид пользователя к примеру, на данный момент мультикорзина не реализована, не факт, что будет когда-либо реализована), $updateIfExists
- обновлять ли, если запись с этим идентификатором уже есть в таблице. Сценарии:
$updateIfExists = false
, будет выполнена проверка наличия записи с таким идентификатором. Если есть - будет вызвано исключениеMavsan\LaCart\Exceptions\CartAlreadyStoredException
, если нет - будет выполнено сохранение.$updateIfExists = true
, если запись с этим идентификатором уже существует - она будет обновлена, если нет - вставлена.
Корзина после сохранения не очищается.
Получение корзины и базы данных
Как и сохранение - выполняется вручную методом Cart::restore($identifier)
. Если записи с указанным идентификатором не существует - ничего не произойдет, в противном случае к текущим записям в корзине будут добавлены восстановленные из базы данных, если какие-то записи совпадают - они буду перезаписаны теми, которые были сохранены с базе данных.
По окончании восстановления корзины - запись НЕ будет удалена из базы данных.
Удаление записи из базы данных
Для удаления записи из базы данных необходимо выполнить метод:
Cart::deleteCartFromDB($identifier);
Где лучше делать восстановление и сохранение корзины
По моему опыту лучше всего восстанавливать данные корзины из БД и сохранять в БД - в middleware, например, вот так:
class CartMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
// если залогинен - восстановление корзины из БД
if (Auth::check()) {
Cart::restore(Auth::id());
}
$result = $next($request);
// сохранение корзины в БД, если залогинен, переносить в terminate нельзя, т.к. не сохранится изменение в сессию
if (Auth::check() && Cart::isChanged()) {
Cart::store(Auth::id(), true);
Cart::clear();
}
return $result;
}
}
События
В процессе работы генерируются события:
cart.added
запись добавлена в корзину, слушателю отправляется созданный экземплярMavsan\LaCart\Models\CartItem
;cart.updated
запись обновлена в корзине, слушателю отправляется обновленный экземплярMavsan\LaCart\Models\CartItem
;cart.removed
запись удалена из корзины, слушателю отправляется обновленный экземплярMavsan\LaCart\Models\CartItem
;cart.stored
корзина сохранена в базу данных;cart.restored
корзина восстановлена из базы данных;cart.deletedFromDB
корзина удалена из базы данных;cart.itemUpdated
элемент корзины обновлен, слушателю отправляется экземпляр обновленного элемента корзины.
Исключения
\Mavsan\LaCart\Exceptions\CartInvalidRowIDException
- при попытке получить запись добавленную в корзину, если искомой записи не существует.
\Mavsan\LaCart\Exceptions\CartItemModelNotFoundException
- при сохранении информации о модели товара добавляемого в корзину;
- при попытке получить экземпляр модели товара, добавленного в корзину, если модель не была установлена.
InvalidArgumentException
- при установке не верного количества элементов в корзине, строка к примеру.
Mavsan\LaCart\Exceptions\CartAlreadyStoredException
- если при сохранении в базу данных оказалось, что запись с таким идентификатором уже есть.