Магазин на Yii2, часть 25. Админка: главная страница и работа с заказами

30.08.2019

Теги: Web-разработкаYii2ЗаказИнтернетМагазинКаталогТоваровПанельУправленияПрактикаФреймворк

Главная страница

На главной странице панели управления будем показывать две таблицы — новые заказы и заказы в работе. Чтобы администратор магазина сразу видел, какие заказы надо обработать, у каких — отслеживать оплату и доставку, а какие — можно завершать. Итак, вносим изменения в контроллер DefaultController и view-шаболон default/index.php.

<?php
namespace app\modules\admin\controllers;

use yii\data\ActiveDataProvider;
use app\modules\admin\models\Order;

class DefaultController extends AdminController {

    public function actionIndex() {
        $queueOrders = new ActiveDataProvider([
            'query' => Order::find()
                ->where(['status' => 0])
                ->orderBy(['created' => SORT_ASC]),
            'sort' => false,
            'pagination' => [
                // три заказа на страницу
                'pageSize' => 3,
                // уникальный параметр пагинации
                'pageParam' => 'queue',

            ]
        ]);
        $processOrders = new ActiveDataProvider([
            'query' => Order::find()
                ->where(['IN', 'status', [1,2,3]])
                ->orderBy(['updated' => SORT_ASC]),
            'sort' => false,
            'pagination' => [
                // три заказа на страницу
                'pageSize' => 3,
                // уникальный параметр пагинации
                'pageParam' => 'process',

            ]
        ]);
        return $this->render('index', [
            'queueOrders' => $queueOrders,
            'processOrders' => $processOrders,
        ]);
    }
}

Поскольку на главной странице у нас две таблицы GridView, при переходе на вторую страницу списка новых заказов или списка заказов в работе, будет происходить переход на вторую страницу сразу для двух списков. Поэтому надо задать для каждого списка уникальный параметр пагинации pageParam. Тогда ссылки на вторую страницу для первого и второго списков будут иметь вид:

http://www.server.com/admin/default/index?queue=2&per-page=3
http://www.server.com/admin/default/index?process=2&per-page=3
<?php
/*
 * Файл view-шаблона modules/admin/views/default/index.php
 */
use yii\helpers\Html;
use yii\grid\GridView;

/* @var $this yii\web\View */
/* @var $queueOrders yii\data\ActiveDataProvider */
/* @var $processOrders yii\data\ActiveDataProvider */

$this->title = 'Текущее состояние';
?>

<h1><?= Html::encode($this->title) ?></h1>

<h2>Новые заказы</h2>

<?=
GridView::widget([
    'dataProvider' => $queueOrders,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],
        'id',
        'name',
        'email:email',
        'phone',
        'amount',
        [
            'attribute' => 'status',
            'value' => function ($data) {
                switch ($data->status) {
                    case 0: return '<span class="text-danger">Новый</span>';
                    case 1: return '<span class="text-warning">Обработан</span>';
                    case 2: return '<span class="text-warning">Оплачен</span>';
                    case 3: return '<span class="text-warning">Доставлен</span>';
                    case 4: return '<span class="text-success">Завершен</span>';
                    default: return 'Ошибка';
                }
            },
            'format' => 'html'
        ],
        'created',
        'updated'
    ],
]);
?>

<h2>Заказы в работе</h2>

<?=
GridView::widget([
    'dataProvider' => $processOrders,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],
        'id',
        'name',
        'email:email',
        'phone',
        'amount',
        [
            'attribute' => 'status',
            'value' => function ($data) {
                switch ($data->status) {
                    case 0: return '<span class="text-danger">Новый</span>';
                    case 1: return '<span class="text-warning">Обработан</span>';
                    case 2: return '<span class="text-warning">Оплачен</span>';
                    case 3: return '<span class="text-warning">Доставлен</span>';
                    case 4: return '<span class="text-success">Завершен</span>';
                    default: return 'Ошибка';
                }
            },
            'format' => 'html'
        ],
        'created',
        'updated'
    ],
]);
?>

Работа с заказами

Сейчас при просмотре заказа мы видим только данные покупателя, дату создания и обновления заказа. Но на странице просмотра нет данных о составе заказа. Давайте это исправим: создадим модель OrderItem и добавим в класс модели Order метод getItems():

<?php
namespace app\modules\admin\models;

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\modules\admin\models;

use yii\db\ActiveRecord;

class Order extends ActiveRecord {

    /*...*/

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

В представлении получим список товаров заказа и покажем таблицу:

<?php
/*
 * Файл view-шаблона modules/admin/views/order/view.php
 */
use yii\helpers\Html;
use yii\widgets\DetailView;

/* @var $this yii\web\View */
/* @var $model app\modules\admin\models\Order */

$this->title = 'Просмотр заказа № ' . $model->id;
?>

<h1><?= Html::encode($this->title); ?></h1>

<p>
    <?=
    Html::a(
        'Изменить',
        ['update', 'id' => $model->id],
        ['class' => 'btn btn-primary']
    );
    ?>
    <?=
    Html::a(
        'Удалить',
        ['delete', 'id' => $model->id],
        [
            'class' => 'btn btn-danger',
            'data' => [
                'confirm' => 'Вы уверены, что хотите удалить заказ?',
                'method' => 'post',
            ],
        ]
    );
    ?>
</p>

<?=
DetailView::widget([
    'model' => $model,
    'attributes' => [
        [
            'attribute' => 'status',
            'value' => function ($data) {
                switch ($data->status) {
                    case 0: return '<span class="text-danger">Новый</span>';
                    case 1: return '<span class="text-warning">Обработан</span>';
                    case 2: return '<span class="text-warning">Оплачен</span>';
                    case 3: return '<span class="text-warning">Доставлен</span>';
                    case 4: return '<span class="text-success">Завершен</span>';
                    default: return 'Ошибка';
                }
            },
            'format' => 'html'
        ],
        'name',
        'email:email',
        'phone',
        'address',
        'comment',
        'created',
        'updated'
    ],
]);
?>

<?php
$products = $model->items;
?>
<table class="table table-bordered table-striped">
    <tr>
        <th>Наименование</th>
        <th>Количество</th>
        <th>Цена</th>
        <th>Сумма</th>
    </tr>
    <?php foreach ($products as $product): ?>
       <tr>
           <td><?= $product->name; ?></td>
           <td class="text-right"><?= $product->quantity; ?></td>
           <td class="text-right"><?= $product->price; ?></td>
           <td class="text-right"><?= $product->cost; ?></td>
       </tr>
    <?php endforeach; ?>
    <tr>
        <th colspan="3" class="text-right">Итого</th>
        <th class="text-right"><?= $model->amount; ?></th>
    </tr>
</table>

Хорошо, с просмотром заказа разобрались, осталось еще подправить view-шаблон для редактирования заказа. Давайте посмотрим на код шаблона:

<?php
/*
 * Файл view-шаблона modules/admin/views/order/update.php
 */
use yii\helpers\Html;

/* @var $this yii\web\View */
/* @var $model app\modules\admin\models\Order */

$this->title = 'Редактирование заказа № ' . $model->id;
?>
<h1><?= Html::encode($this->title) ?></h1>

<?=
$this->render('_form', [
    'model' => $model,
]);
?>

Вопреки ожиданиям, формы там нет, она расположена в файле _form.php:

<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;

/* @var $this yii\web\View */
/* @var $model app\modules\admin\models\Order */
/* @var $form yii\widgets\ActiveForm */
?>

<?php $form = ActiveForm::begin(); ?>

    <?= $form->field($model, 'user_id')->textInput() ?>
    <?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?>
    <?= $form->field($model, 'email')->textInput(['maxlength' => true]) ?>
    <?= $form->field($model, 'phone')->textInput(['maxlength' => true]) ?>
    <?= $form->field($model, 'address')->textInput(['maxlength' => true]) ?>
    <?= $form->field($model, 'comment')->textInput(['maxlength' => true]) ?>
    <?= $form->field($model, 'amount')->textInput(['maxlength' => true]) ?>
    <?= $form->field($model, 'status')->textInput() ?>
    <?= $form->field($model, 'created')->textInput() ?>
    <?= $form->field($model, 'updated')->textInput() ?>
    <div class="form-group">
        <?= Html::submitButton('Save', ['class' => 'btn btn-success']) ?>
    </div>

<?php ActiveForm::end(); ?>

Давайте ее немного изменим — запретим редактировать сумму заказа, дату создания и обновления + заменим текстовое поле статуса заказа на выпадающий список.

<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;

/* @var $this yii\web\View */
/* @var $model app\modules\admin\models\Order */
/* @var $form yii\widgets\ActiveForm */
?>

<?php $form = ActiveForm::begin(); ?>

    <?php
    $items = [
        0 => 'Новый',
        1 => 'Обработан',
        2 => 'Оплачен',
        3 => 'Доставлен',
        4 => 'Завершен',
    ];
    echo $form->field($model, 'status')->dropDownList($items);
    echo $form->field($model, 'name')->textInput(['maxlength' => true]);
    echo $form->field($model, 'email')->textInput(['maxlength' => true]);
    echo $form->field($model, 'phone')->textInput(['maxlength' => true]);
    echo $form->field($model, 'address')->textarea(['rows' => 2, 'maxlength' => true]);
    echo $form->field($model, 'comment')->textarea(['rows' => 2, 'maxlength' => true]);
    echo $form->field($model, 'amount')->textInput(['readonly' => true]);
    echo $form->field($model, 'created')->textInput(['readonly' => true]);
    echo $form->field($model, 'updated')->textInput(['readonly' => true]);
    ?>
    <div class="form-group">
        <?= Html::submitButton('Сохранить', ['class' => 'btn btn-success']) ?>
    </div>

<?php ActiveForm::end(); ?>

Нам еще нужно изменять дату и время обновления заказа при редактировании. Чтобы правильно их сортировать на главной странице панели управления. Для этого добавим метод behaviors() классу модели Order:

<?php
namespace app\modules\admin\models;

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

class Order extends ActiveRecord {

    /*...*/

    public function behaviors() {
        return [
            [
                'class' => TimestampBehavior::class,
                'attributes' => [
                    // при обновлении существующей записи присвоить атрибуту
                    // updated значение метки времени UNIX
                    ActiveRecord::EVENT_BEFORE_UPDATE => ['updated'],
                ],
                // если вместо метки времени UNIX используется DATETIME
                'value' => new Expression('NOW()'),
            ],
        ];
    }

    /*...*/
}

И последнее, что осталось сделать — удалять записи из таблицы БД order_item при удалении заказа:

<?php
namespace app\modules\admin\models;

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

class Order extends ActiveRecord {
    /*...*/

    /**
     * Удаляет товары заказа при удалении заказа
     */
    public function afterDelete() {
        parent::afterDelete();
        OrderItem::deleteAll(['order_id' => $this->id]);
    }
    /*...*/
}

Поиск: Web-разработка • Yii2 • Заказ • Интернет магазин • Каталог товаров • Панель управления • Фреймворк • GridView • DataProvider

Каталог оборудования
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.