Магазин на Yii2, часть 20. Оформление заказа, часть первая

28.07.2019

Теги: ActiveFormWeb-разработкаYii2БазаДанныхЗаказИнтернетМагазинКаталогТоваровКорзинаПрактикаФормаФреймворк

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

-- Структура таблицы `order`
CREATE TABLE `order` (
  `id` int(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT 'Идентификатор заказа',
  `user_id` int(11) NOT NULL DEFAULT '0' COMMENT 'Идентификатор пользователя',
  `name` varchar(50) NOT NULL DEFAULT '' COMMENT 'Имя и фамилия покупателя',
  `email` varchar(50) NOT NULL DEFAULT '' COMMENT 'Почта покупателя',
  `phone` varchar(50) NOT NULL DEFAULT '' COMMENT 'Телефон покупателя',
  `address` varchar(255) NOT NULL DEFAULT '' COMMENT 'Адрес доставки',
  `comment` varchar(255) NOT NULL DEFAULT '' COMMENT 'Комментарий к заказу',
  `amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT 'Сумма заказа',
  `status` tinyint(1) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Статус заказа',
  `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Дата и время создания',
  `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
   ON UPDATE CURRENT_TIMESTAMP COMMENT 'Дата и время обновления'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Структура таблицы `order_item`
CREATE TABLE `order_item` (
  `id` int(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT 'Идентификатор элемента',
  `order_id` int(10) UNSIGNED NOT NULL COMMENT 'Идентификатор заказа',
  `product_id` int(10) UNSIGNED NOT NULL COMMENT 'Идентификатор товара',
  `name` varchar(255) NOT NULL DEFAULT '' COMMENT 'Наименование товара',
  `price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT 'Цена товара',
  `quantity` smallint(5) UNSIGNED NOT NULL DEFAULT '1' COMMENT 'Количество в заказе',
  `cost` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT 'Стоимость = Цена * Кол-во'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Таблицы созданы, создаем классы моделей для них:

<?php
namespace app\models;

use Yii;
use yii\db\ActiveRecord;
use yii\behaviors\TimestampBehavior;

class Order extends ActiveRecord {

    /**
     * Метод возвращает имя таблицы БД
     */
    public static function tableName() {
        return 'order';
    }

    /**
     * Позволяет получить все товары этого заказа
     */
    public function getItems() {
        // связь таблицы БД `order` с таблицей `order_item`
        return $this->hasMany(OrderItem::class, ['order_id' => 'id']);
    }

    /**
     * Правила валидации атрибутов класса при сохранении
     */
    public function rules()
    {
        return [
            // эти четыре поля обязательны для заполнения
            [['name', 'email', 'phone', 'address'], 'required'],
            // поле email должно быть корректным адресом почты
            ['email', 'email'],
            // поле phone должно совпадать с шаблоном +7 (495) 123-45-67
            [
                'phone',
                'match',
                'pattern' => '~^\+7\s\([0-9]{3}\)\s[0-9]{3}-[0-9]{2}-[0-9]{2}$~',
                'message' => 'Номер телефона должен соответствовать шаблону +7 (495) 123-45-67'
            ],
            // эти три строки должны быть не более 50 символов
            [['name', 'email', 'phone'], 'string', 'max' => 50],
            // эти две строки должны быть не более 255 символов
            [['address', 'comment'], 'string', 'max' => 255],
        ];
    }

    public function attributeLabels() {
        return [
            'name' => 'Ваше имя',
            'email' => 'Адрес почты',
            'phone' => 'Номер телефона',
            'address' => 'Адрес доставки',
            'comment' => 'Комментарий к заказу',
        ];
    }
}
<?php
namespace app\models;

use Yii;
use yii\db\ActiveRecord;

class OrderItem extends ActiveRecord {

    /**
     * Возвращает имя таблицы БД
     */
    public static function tableName() {
        return 'order_item';
    }

    /**
     * Позволяет получить заказ, в который входит этот элемент
     */
    public function getOrder() {
        // связь таблицы БД `order_item` с таблицей `order`
        return $this->hasOne(Order::class, ['id' => 'order_id']);
    }
}

Добавляем класс контроллера:

<?php
namespace app\controllers;

use app\models\Order;
use app\models\OrderItem;

class OrderController extends AppController {
    public $defaultAction = 'checkout';

    public function actionCheckout() {
        $this->setMetaTags('Оформление заказа');
        $order = new Order();
        return $this->render('checkout', ['order' => $order]);
    }
}

И файл view-шаблона:

<?php
/*
 * Страница оформления заказа, файл views/order/checkout.php
 */

use app\components\TreeWidget;
use app\components\BrandsWidget;
use yii\widgets\ActiveForm;
use yii\helpers\Html;
use yii\helpers\Url;
?>

<section>
    <div class="container">
        <div class="row">
            <div class="col-sm-3">
                <div class="left-sidebar">
                    <h2>Каталог</h2>
                    <div class="category-products">
                        <?= TreeWidget::widget(); ?>
                    </div>

                    <h2>Бренды</h2>
                    <div class="brand-products">
                        <?= BrandsWidget::widget(); ?>
                    </div>
                </div>
            </div>

            <div class="col-sm-9">
                <h1>Оформление заказа</h1>
                <div id="checkout">
                    <?php
                    $form = ActiveForm::begin(
                        ['id' => 'checkout-form', 'class' => 'form-horizontal']
                    );
                    ?>
                    <?= $form->field($order, 'name')->textInput(); ?>
                    <?= $form->field($order, 'email')->input('email'); ?>
                    <?= $form->field($order, 'phone')->textInput(); ?>
                    <?= $form->field($order, 'address')->textarea(['rows' => 2]); ?>
                    <?= $form->field($order, 'comment')->textarea(['rows' => 2]); ?>
                    <?= Html::submitButton('Отправить', ['class' => 'btn btn-primary']); ?>
                    <?php ActiveForm::end(); ?>
                </div>
            </div>
        </div>
    </div>
</section>

Вот как теперь выглядит страница http://www.server.com/order/checkout:

Поиск: ActiveForm • Yii2 • База данных • Интернет магазин • Каталог товаров • Корзина • Практика • Форма • Фреймворк • Заказ • Order • Web-разработка • ActiveRecord • Basket

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.