Магазин на Yii2, часть 32. Админка: удаление категорий и CRUD для страниц

17.09.2019

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

Перед удалением категории нужно выполнить две проверки. Первая — что категория не содержит товары. Вторая — что категория не имеет дочерних категорий. Если хотя бы одно условие ложно, категорию удалять нельзя. Добавим метод beforeDelete() в класс модели Category:

class Category extends ActiveRecord {
    /*...*/

    /**
     * Проверка перед удалением категории
     */
    public function beforeDelete() {
        $children = self::find()->where(['parent_id' => $this->id])->all();
        $products = Product::find()->where(['category_id' => $this->id])->all();
        if (!empty($children) || !empty($products)) {
            Yii::$app->session->setFlash(
                'warning',
                'Нельзя удалить категорию, которая имеет товары или дочерние категории'
            );
            return false;
        }
        return parent::beforeDelete();
    }
    /*...*/
}

Мы записываем в сессию сообщение об ошибке, которое покажем в layout-шаблоне:

<?php
/*
 * Layout-шаблон, файл modules/views/layouts/main.php
 */

/* @var $this \yii\web\View */
/* @var $content string */

use yii\helpers\Html;
use yii\bootstrap\Nav;
use yii\bootstrap\NavBar;
use yii\helpers\Url;
use app\assets\AppAsset;

AppAsset::register($this);
?>
<?php $this->beginPage() ?>
<!DOCTYPE html>
<html lang="<?= Yii::$app->language ?>">
<head>
    <meta charset="<?= Yii::$app->charset ?>">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <?php $this->registerCsrfMetaTags() ?>
    <title><?= Html::encode($this->title) ?> | Панель управления</title>
    <?php $this->head() ?>
</head>
<body>
<?php $this->beginBody() ?>

<header>
    <!-- .......... -->
</header>

<div class="container">
    <?php if (Yii::$app->session->hasFlash('warning')): ?>
        <div class="alert alert-warning alert-dismissible" role="alert">
            <button type="button" class="close"
                    data-dismiss="alert" aria-label="Закрыть">
                <span aria-hidden="true">&times;</span>
            </button>
            <p><?= Yii::$app->session->getFlash('warning'); ?></p>
        </div>
    <?php endif; ?>
    <?= $content; ?>
</div>

<footer class="footer">
    <!-- .......... -->
</footer>

<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage() ?>

По аналогии с категориями, добавим метод beforeDelete() в класс модели Brand:

class Brand extends ActiveRecord {
    /*...*/

    /**
     * Проверка перед удалением бренда
     */
    public function beforeDelete() {
        $products = Product::find()->where(['brand_id' => $this->id])->all();
        if (!empty($products)) {
            Yii::$app->session->setFlash(
                'warning',
                'Нельзя удалить бренд, у которого есть товары'
            );
            return false;
        }
        return parent::beforeDelete();
    }
    /*...*/
}

Создаем модель и CRUD-контроллер для страниц

У нас по дизайну предусмотрено несколько страниц — «Доставка», «Оплата», «Контакты». Но пока нет возможности добавить эти страницы и динамически показывать список этих страниц в публичной части. Давайте это исправим — создадим таблицу базы данных page, создадим для нее класс модели и возможность выполнения CRUD-операций над страницами.

CREATE TABLE `page` (
  `id` int(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT 'Уникальный идентификатор',
  `parent_id` int(10) UNSIGNED NOT NULL COMMENT 'Родительская страница',
  `name` varchar(100) NOT NULL COMMENT 'Заголовок страницы',
  `slug` varchar(100) NOT NULL UNIQUE KEY COMMENT 'Для создания ссылки',
  `content` text COMMENT 'Содержимое страницы',
  `keywords` varchar(255) DEFAULT NULL COMMENT 'Мета-тег keywords',
  `description` varchar(255) DEFAULT NULL COMMENT 'Мета-тег description'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Как обычно, воспользуемся генератором кода Gii. Переходим по ссылке «Model Generator», задаем имя таблицы БД, имя класса модели и пространство имен:

Table Name: page
Model Class Name: Page
Namespace: app\modules\admin\models
<?php
namespace app\modules\admin\models;

use Yii;
use yii\db\ActiveRecord;

/**
 * This is the model class for table "page".
 *
 * @property int $id Уникальный идентификатор
 * @property int $parent_id Родительская страница
 * @property string $name Заголовок страницы
 * @property string $slug Для создания ссылки
 * @property string $content Содержимое страницы
 * @property string $keywords Мета-тег keywords
 * @property string $description Мета-тег description
 */
class Page extends ActiveRecord {
    /**
     * {@inheritdoc}
     */
    public static function tableName() {
        return 'page';
    }

    /**
     * {@inheritdoc}
     */
    public function rules() {
        return [
            [['parent_id', 'name', 'slug'], 'required'],
            [['parent_id'], 'integer'],
            [['content'], 'string'],
            [['name', 'slug'], 'string', 'max' => 100],
            [['keywords', 'description'], 'string', 'max' => 255],
            [['slug'], 'unique'],
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function attributeLabels() {
        return [
            'id' => 'ID',
            'parent_id' => 'Parent',
            'name' => 'Name',
            'slug' => 'Slug',
            'content' => 'Content',
            'keywords' => 'Keywords',
            'description' => 'Description',
        ];
    }
}

Теперь используем «CRUD Generator», который создаст нам контроллер и view-шаблоны. И мы получим готовой код для создания, просмотра, редактирования и удаления страниц.

Model Class: app\modules\admin\models\Page
Controller Class: app\modules\admin\controllers\PageController
View Path: @app/modules/admin/views/page
Base Controller Class: app\modules\admin\controllers\AdminController
<?php
namespace app\modules\admin\controllers;

use Yii;
use app\modules\admin\models\Page;
use yii\data\ActiveDataProvider;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;

/**
 * PageController implements the CRUD actions for Page model.
 */
class PageController extends AdminController {
    /**
     * {@inheritdoc}
     */
    public function behaviors() {
        return [
            'verbs' => [
                'class' => VerbFilter::class,
                'actions' => [
                    'delete' => ['POST'],
                ],
            ],
        ];
    }

    /**
     * Lists all Page models.
     * @return mixed
     */
    public function actionIndex() {
        $dataProvider = new ActiveDataProvider([
            'query' => Page::find(),
        ]);

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

    /**
     * Displays a single Page model.
     * @param integer $id
     * @return mixed
     * @throws NotFoundHttpException if the model cannot be found
     */
    public function actionView($id) {
        return $this->render('view', [
            'model' => $this->findModel($id),
        ]);
    }

    /**
     * Creates a new Page model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     * @return mixed
     */
    public function actionCreate() {
        $model = new Page();

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        }

        return $this->render('create', [
            'model' => $model,
        ]);
    }

    /**
     * Updates an existing Page model.
     * If update is successful, the browser will be redirected to the 'view' page.
     * @param integer $id
     * @return mixed
     * @throws NotFoundHttpException if the model cannot be found
     */
    public function actionUpdate($id) {
        $model = $this->findModel($id);

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        }
        return $this->render('update', [
            'model' => $model,
        ]);
    }

    /**
     * Deletes an existing Page model.
     * If deletion is successful, the browser will be redirected to the 'index' page.
     * @param integer $id
     * @return mixed
     * @throws NotFoundHttpException if the model cannot be found
     */
    public function actionDelete($id) {
        $this->findModel($id)->delete();
        return $this->redirect(['index']);
    }

    /**
     * Finds the Page model based on its primary key value.
     * If the model is not found, a 404 HTTP exception will be thrown.
     * @param integer $id
     * @return Page the loaded model
     * @throws NotFoundHttpException if the model cannot be found
     */
    protected function findModel($id) {
        if (($model = Page::findOne($id)) !== null) {
            return $model;
        }

        throw new NotFoundHttpException('The requested page does not exist.');
    }
}

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

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