Yii2 shopping cart extension: корзина для інтернет магазину
Кошик - це обов'язковий компонент для будь-якого інтернет-магазину, але її функціональність в різних проектах може відрізнятися. На одному сайті корзина працює з сесією, на другому - з кукисам, а на третьому - з базою даних, також не виключено, що з часом сховище може змінюватися.
Теж стосується і підрахунку вартості, наприклад: потрібно вважати ціну товару зі знижкою в певний день тижня або в якесь свято, але це все неможливо передбачити при розробці кошика, тому повинна бути можливість зручної кастомізації в майбутньому.
розширення « devanych / yii2-cart »Вирішує ці проблеми і дозволяє дуже легко змінювати сховища і калькулятори, дає можливість підключати власні рішення.
Встановити розширення через «Composer»:
php composer.phar require devanych / yii2-cart "*"або прописати залежність в розділі require в файлі composer.json:
devanych / yii2-cart: "*"і виконати в терміналі composer update.
конфігурація
У файлі конфігурації Yii2 додатки (web.php в «basic» і main.php в «advanced») в секцію components поміщаємо наступний код.
return [// ... 'components' => [// ... 'cart' => [ 'class' => 'devanych \ cart \ Cart', 'storageClass' => 'devanych \ cart \ storage \ SessionStorage ',' calculatorClass '=>' devanych \ cart \ calculators \ SimpleCalculator ',' params '=> [' key '=>' cart ',' expire '=> 604800,' productClass '=>' app \ model \ Product ',' productFieldId '=>' id ',' productFieldPrice '=>' price ',],],] // ...];Властивість storageClass відповідає за сховище, що використовується кошиком, за замовчуванням це devanych \ cart \ storage \ SessionStorage. Сесійне сховище можна поміняти на devanych \ cart \ storage \ CookieStorage або на devanych \ cart \ storage \ DbSessionStorage.
DbSessionStorage використовує сесійне сховище для ВОНО НЕ БУДЕ користувачів і базу даних для авторизованих. Для його використання необхідно застосувати наступну міграцію.
php yii migrate --migrationPath = @ vendor / devanych / yii2-cart / migrationsЯкщо цих сховищ виявиться недостатньо, то ви можете створити власне. Для цього необхідно реалізувати інтерфейс devanych \ cart \ storage \ StorageInterface і вказати свій створений клас значенням властивості storageClass.
Властивості calculatorClass присвоєно ім'я класу калькулятора devanych \ cart \ calculators \ SimpleCalculator, цей клас підраховує загальну вартість і кількість всіх елементів кошика. Для реалізації власного калькулятора потрібно реалізувати інтерфейс devanych \ cart \ calculators \ CalculatorInterface.
Розберемо все додаткові настройки, що знаходяться в підмасиві params:
- key - ім'я необхідне для сесії і куки (за замовчуванням - cart);
- expire - термін життя cookie (за замовчуванням - 604800, тобто тиждень);
- productClass - клас товару ActiveRecord моделі (за замовчуванням - app \ model \ Product);
- productFieldId - первинний ключ моделі товару (за замовчуванням - id);
- productFieldId - властивість (поле в БД) ціни моделі товару (за замовчуванням - price).
Використання
Підключення кошика як компонента дає можливість звернення до неї практично з будь-якого місця програми, використовуючи сервіс локатор Yii :: $ app.
Використання кошика:
// Товар, об'єкт AR моделі $ product = Product :: findOne (1); // Компонент кошика $ cart = \ Yii :: $ app-> cart; // Створює елемент кошика з переданого товару і його кількості $ cart-> add ($ product, $ quantity); // Додає кількість існуючого елемента кошика $ cart-> plus ($ product-> id, $ quantity); // Змінює кількість існуючого елемента кошика $ cart-> change ($ product-> id, $ quantity); // Видаляє конкретний елемент з кошика, об'єкт `devanych \ cart \ CartItem` $ cart-> remove ($ product-> id); // Видаляє всі елемент з кошика $ cart-> clear (); // Отримує всі елемент з кошика $ cart-> getItems (); // Отримує конкретний елемент з кошика $ cart-> getItem ($ product-> id); // Отримує ідентифікатори всіх елементів $ cart-> getItemIds (); // Отримує загальну вартість всіх елементів $ cart-> getTotalCost (); // Отримує загальна кількість всіх елементів $ cart-> getTotalCount ();Використання елементів кошика:
// Товар, об'єкт AR моделі $ product = Product :: findOne (1); // Компонент кошика $ cart = \ Yii :: $ app-> cart; // Отримує конкретний елемент з кошика, об'єкт `devanych \ cart \ CartItem` $ item = $ cart-> getItem ($ product-> id); // Отримує ідентифікатор елемента рівному ідентифікатор товару $ item-> getId (); // Отримує ціну елемента дорівнює ціні товару $ item-> getPrice (); // Отримує товар, об'єкт AR моделі $ item-> getProduct (); // Отримує загальну вартість товару що зберігається в елементі по його кількості $ item-> getCost (); // Отримує загальна кількість товару, що зберігається в елементі кошика $ item-> getQuantity (); // Встановлює кількість товару що зберігається в елементі кошика $ item-> setQuantity ($ quantity);Варто відзначити, що метод getProduct () елемента кошика (devanych \ cart \ CartItem) повертає повноцінний об'єкт ActiveRecord моделі, це дуже зручно, якщо потрібно вивести якусь інформацію про зберігання в кошику товар.
Проста реалізація контролера та подання
Дане розширення дає можливість реалізації будь-якого уявлення для кошика. Я спеціально не став робити дефолтний контролер і уявлення, так як в кожному проекті кошик реалізовується по-різному: десь просто, десь без перезавантаження сторінки, де-то в модальному вікні, і т.д., а це значить, що і код буде відрізнятися.
У самому примітивному варіанті, якщо «запхати» все в контролер (хоча так робити не потрібно ;-)), клас контролера буде виглядати так.
<? Php namespace app \ controllers; use Yii; use yii \ helpers \ Html; use yii \ web \ Controller; use app \ models \ Product; class CartController extends Controller {/ ** * @var \ devanych \ cart \ Cart $ cart * / private $ cart; public function __construct ($ id, $ module, $ config = []) {parent :: __ construct ($ id, $ module, $ config); $ This-> cart = Yii :: $ app-> cart; } Public function actionIndex () {return $ this-> render ( 'index', [ 'cart' => $ this-> cart,]); } Public function actionAdd ($ id, $ qty = 1) {try {$ product = $ this-> getProduct ($ id); $ Quantity = $ this-> getQuantity ($ qty, $ product-> quantity); if ($ item = $ this-> cart-> getItem ($ product-> id)) {$ this-> cart-> plus ($ item-> getId (), $ quantity); } Else {$ this-> cart-> add ($ product, $ quantity); }} Catch (\ DomainException $ e) {Yii :: $ app-> errorHandler-> logException ($ e); Yii :: $ app-> session-> setFlash ( 'error', $ e-> getMessage ()); } Return $ this-> redirect ([ 'index']); } Public function actionChange ($ id, $ qty = 1) {try {$ product = $ this-> getProduct ($ id); $ Quantity = $ this-> getQuantity ($ qty, $ product-> quantity); if ($ item = $ this-> cart-> getItem ($ product-> id)) {$ this-> cart-> change ($ item-> getId (), $ quantity); }} Catch (\ DomainException $ e) {Yii :: $ app-> errorHandler-> logException ($ e); Yii :: $ app-> session-> setFlash ( 'error', $ e-> getMessage ()); } Return $ this-> redirect ([ 'index']); } Public function actionRemove ($ id) {try {$ product = $ this-> getProduct ($ id); $ This-> cart-> remove ($ product-> id); } Catch (\ DomainException $ e) {Yii :: $ app-> errorHandler-> logException ($ e); Yii :: $ app-> session-> setFlash ( 'error', $ e-> getMessage ()); } Return $ this-> redirect ([ 'index']); } Public function actionClear () {$ this-> cart-> clear (); return $ this-> redirect ([ 'index']); } / ** * @param integer $ id * @return Product the loaded model * @throws \ DomainException if the product can not be found * / private function getProduct ($ id) {if (($ product = Product :: findOne (( int) $ id))! == null) {return $ product; } Throw new \ DomainException ( 'Товар не знайдено'); } / ** * @param integer $ qty * @param integer $ maxQty * @return integer * @throws \ DomainException if the product can not be found * / private function getQuantity ($ qty, $ maxQty) {$ quantity = (int) $ qty> 0? (Int) $ qty: 1; if ($ quantity> $ maxQty) {throw new \ DomainException ( 'Товару в наявності всього'. Html :: encode ($ maxQty). 'шт.'); } Return $ quantity; }}Ну і залишилося створити уявлення index.php, в яке передається кошик, пройтися по ній в циклі і вивести інформацію про доданих товарах або використовувати GridView.
<? Php / * @var $ this yii \ web \ View * / / * @var $ cart \ devanych \ cart \ Cart * / / * @var $ item \ devanych \ cart \ CartItem * / use yii \ helpers \ Html ; use yii \ helpers \ Url; ?> <? Php if (! Empty ($ cartItems = $ cart-> getItems ())):?> <Div class = "table-responsive"> <table class = "table"> <thead> <tr class = "active"> <th> Фото </ th> <th> Найменування </ th> <th> Кількість </ th> <th> Ціна </ th> <th> Сума </ th> <th> < i aria-hidden = "true"> & times; </ i> </ th> </ tr> </ thead> <tbody> <? php foreach ($ cartItems as $ item):?> <tr> <td> <? = Html :: img ( "@ web {$ item-> getProduct () -> photo}", [ 'alt' => $ item-> getProduct () -> name, 'width' => 50]) ?> </ td> <td> <a href="<?=Url::to('@web/product/'. $item-> getProduct () -> alias)?> "> <? = $ item -> getProduct () -> name?> </a> </ td> <td> <? = $ item-> getQuantity ()?> </ td> <td> <? = $ item-> getPrice () ?> </ td> <td> <? = $ item-> getCost ()?> </ td> <td> <a href = "<? = Url :: to ([ 'cart / remove', 'id '=> $ item-> getId ()])?> "> Видалити </a> </ td> </ tr> <? php endforeach; ?> <Tr class = "active"> <td colspan = "4"> Загальна кількість: </ td> <td colspan = "2"> <? = $ Cart-> getTotalCount ()?> </ Td > </ tr> <tr class = "active"> <td colspan = "4"> Загальна сума: </ td> <td colspan = "2"> <? = $ cart-> getTotalCost ()?> </ td> </ tr> </ tbody> </ table> </ div> <? php else:?> <h3> Кошик порожній </ h3> <? php endif;?>Як бачите, все дійсно просто, потрібно замінити сховище, міняємо клас в конфігурації і все. З калькулятором вартості теж саме. Сподіваюся, цей компонент буде вам корисний, а на цьому статтю буду закінчувати. Якщо щось незрозуміло, пишіть в коментарях.
Lt;?Lt;?
Php / * @var $ this yii \ web \ View * / / * @var $ cart \ devanych \ cart \ Cart * / / * @var $ item \ devanych \ cart \ CartItem * / use yii \ helpers \ Html ; use yii \ helpers \ Url; ?
Php if (! Empty ($ cartItems = $ cart-> getItems ())):?
Php foreach ($ cartItems as $ item):?
Html :: img ( "@ web {$ item-> getProduct () -> photo}", [ 'alt' => $ item-> getProduct () -> name, 'width' => 50]) ?
Url::to('@web/product/'. $item-> getProduct () -> alias)?
Item -> getProduct () -> name?
Item-> getQuantity ()?