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

18.09.2019

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

Код для работы со страницами уже работает, но нуждается в некоторой доработке. Нужно предоставить возможность выбора родителя для страницы, прикрутить WYSIWYG-редактор, добавить валидатор для slug, изменить надписи на кнопках и так далее. Все это мы уже делали для товаров, категорий и брендов, так что без подробностей.

Модель и контроллер

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

use Yii;
use yii\db\ActiveRecord;

/**
 * Это модель для таблицы БД `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 {

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

    /**
     * Возвращает данные о родительской странице
     */
    public function getParent() {
        return $this->hasOne(Page::class, ['id' => 'parent_id']);
    }

    /**
     * Возвращает наименование родительской страницы
     */
    public function getParentName() {
        $parent = $this->parent;
        return $parent ? $parent->name : '';
    }

    /**
     * Возвращает массив страниц верхнего уровня для
     * возможности выбора родителя
     */
    public static function getRootPages($exclude = 0) {
        $parents = [0 => 'Без родителя'];
        $root = Page::find()->where(['parent_id' => 0])->all();
        foreach ($root as $item) {
            if ($exclude == $item['id']) {
                continue;
            }
            $parents[$item['id']] = $item['name'];
        }
        return $parents;
    }

    /**
     * Правила валидации полей формы при создании и редактировании страницы
     */
    public function rules() {
        return [
            [['parent_id', 'name', 'slug'], 'required'],
            ['parent_id', 'integer'],
            // не должно быть двух страниц с одинаковым slug
            ['slug', 'unique'],
            // slug может содержать только латиницу, цифры, дефис и подчеркивание
            ['slug', 'match', 'pattern' => '/^[a-z][-_a-z0-9]*$/i'],
            ['content', 'string'],
            [['name', 'slug'], 'string', 'max' => 100],
            [['keywords', 'description'], 'string', 'max' => 255],
        ];
    }

    /**
     * Возвращает имена полей формы для создания и редактирования страницы
     */
    public function attributeLabels() {
        return [
            'id' => 'ID',
            'parent_id' => 'Родитель',
            'name' => 'Заголовок',
            'slug' => 'Для создания ссылки',
            'content' => 'Содержимое',
            'keywords' => 'Мета-тег keywords',
            'description' => 'Мета-тег description',
        ];
    }
}
<?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 {

    public function behaviors() {
        return [
            'verbs' => [
                'class' => VerbFilter::class,
                'actions' => [
                    'delete' => ['POST'],
                ],
            ],
        ];
    }

    /**
     * Список всех страниц сайта
     */
    public function actionIndex() {
        $dataProvider = new ActiveDataProvider([
            'query' => Page::find(),
        ]);

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

    /**
     * Просмотр данных существующей страницы
     */
    public function actionView($id) {
        return $this->render('view', [
            'model' => $this->findModel($id),
        ]);
    }

    /**
     * Создание новой страницы сайта
     */
    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,
        ]);
    }

    /**
     * Обновление существующей страницы
     */
    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,
        ]);
    }

    /**
     * Удаление существующей страницы
     */
    public function actionDelete($id) {
        $this->findModel($id)->delete();
        return $this->redirect(['index']);
    }

    /**
     * Поиск страницы по идентификатору
     */
    protected function findModel($id) {
        if (($model = Page::findOne($id)) !== null) {
            return $model;
        }

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

View-шаблоны для страниц

<?php
/*
 * Страница списка всех страниц, файл modules/admin/views/page/index.php
 */
use yii\helpers\Html;
use yii\grid\GridView;

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

$this->title = 'Все страницы';
?>

<h1><?= Html::encode($this->title); ?></h1>
<p>
    <?= Html::a('Добавить страницу', ['create'], ['class' => 'btn btn-success']); ?>
</p>

<?=
GridView::widget([
    'dataProvider' => $dataProvider,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],
        'name',
        'slug',
        [
            'attribute' => 'parent_id',
            'value' => function($data) {
                $parent = $data->getParentName();
                return empty($parent) ? 'Без родителя' : $parent;
            }
        ],
        [
            'attribute' => 'keywords',
            'value' => function($data) {
                return empty($data->keywords) ? 'Не задано' : $data->keywords;
            }
        ],
        [
            'attribute' => 'description',
            'value' => function($data) {
                return empty($data->description) ? 'Не задано' : $data->description;
            }
        ],
        ['class' => 'yii\grid\ActionColumn'],
    ],
]);
?>

<?php
/*
 * Страница просмотра страницы, файл modules/admin/views/page/view.php
 */
use yii\helpers\Html;
use yii\widgets\DetailView;

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

$this->title = 'Просмотр страницы: ' . $model->name;
?>

<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' => [
        'name',
        'slug',
        [
            'attribute' => 'parent_id',
            'value' =>  $model->getParentName()
        ],
        [
            'attribute' => 'content',
            'value' =>  empty($model->content) ? 'Не задано' : $model->content,
            'format' => 'html'
        ],
        [
            'attribute' => 'keywords',
            'value' =>  empty($model->keywords) ? 'Не задано' : $model->keywords
        ],
        [
            'attribute' => 'description',
            'value' =>  empty($model->description) ? 'Не задано' : $model->description
        ],
    ],
]);
?>

<?php
/*
 * Страница добавления новой страницы, файл modules/admin/views/page/create.php
 */
use yii\helpers\Html;

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

$this->title = 'Добавить страницу';
?>

<h1><?= Html::encode($this->title) ?></h1>
<?=
$this->render(
    '_form',
    ['model' => $model]
);
?>

<?php
/*
 * Страница редактирования страницы, файл modules/admin/views/page/update.php
 */
use yii\helpers\Html;

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

$this->title = 'Редактирование страницы: ' . $model->name;
?>

<h1><?= Html::encode($this->title); ?></h1>
<?=
$this->render(
    '_form',
    ['model' => $model]
);
?>

<?php
/*
 * Форма для добавления и редактирования страницы, файл modules/admin/views/page/_form.php
 */
use app\modules\admin\models\Page;
use mihaildev\ckeditor\CKEditor;
use yii\helpers\Html;
use yii\widgets\ActiveForm;

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

<?php $form = ActiveForm::begin(); ?>
    <?= $form->field($model, 'name')->textInput(['maxlength' => true]); ?>
    <?= $form->field($model, 'slug')->textInput(['maxlength' => true]); ?>
    <?php
    // при редактировании существующей страницы нельзя допустить,
    // чтобы в качестве родителя была выбрана эта же страница
    $exclude = 0;
    if (!empty($model->id)) {
        $exclude = $model->id;
    }
    echo $form->field($model, 'parent_id')->dropDownList(Page::getRootPages($exclude));
    ?>
    <?=
    $form->field($model, 'content')->widget(
        CKEditor::class,
        [
            'editorOptions' => [
                // разработанны стандартные настройки basic, standard, full
                'preset' => 'basic',
                'inline' => false, // по умолчанию false
            ],
        ]
    );
    ?>
    <?= $form->field($model, 'keywords')->textarea(['rows' => 2, 'maxlength' => true]); ?>
    <?= $form->field($model, 'description')->textarea(['rows' => 2, 'maxlength' => true]); ?>
    <div class="form-group">
        <?= Html::submitButton('Сохранить', ['class' => 'btn btn-success']) ?>
    </div>
<?php ActiveForm::end(); ?>

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

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