Yii2 basic: Создаем контроллер, форму, делаем валидацию, миграцию, сохраняем в базу

· Yii2 basic · 10 мин чтения

В этой записи мы создадим форму, модель которая будет отвечать за проверку полей этой формы, воспользуемся миграцией и создадим новую таблицу с ее помощью, а так же научимся сохранять данные в базу в Yii2 basic.

Эта запись относится к курсу Yii2 basic.

Давайте создадим следующий функционал:

  • Добавлять новые автомобили (поля: название, марку, описание, дата создания и обновления)
  • Смотреть все добавленные автомобили с пагинацией (постраничный просмотр, например по 10 или 15 на страницу)
  • Изменять машины
  • Удалять машины

Создание ActiveRecord модели

Для начала, лучше всего создать модель, которая будет работать с базой данных.

Для этого нужно зайти в папку models и создать новый PHP файл. Назовем его Car:

<?php
namespace app\models;


use yii\db\ActiveRecord;

class Car extends ActiveRecord
{
    public static function tableName()
    {
        return 'cars';
    }
}

Как видим класс Car заимствует все методы из класса ActiveRecord. ActiveRecord — помогает работать с базой данных, а конкретнее с таблицей cars, которая указана в статическом методе tableName().

Сейчас этот класс бесполезен, потому что таблицу cars еще предстоит создать.

Сделать это можно двумя способами:

  1. Через phpMyAdmin
  2. Через миграции (лучший вариант)

Почему миграции лучше, я уже ранее описывал в этом курсе, если вы внимательно его читали. Ниже как раз секция о том, как это сделать с помощью миграций.

Создание новой таблицы, используем миграции

Давайте для начала создадим миграцию новой таблицы и назовем её — cars.

Зайдите в корневую папку проекта:

$ cd /var/www/yii-dev/

И напишите следующее:

$ php yii migrate/create create_cars_table

Где «create_cars_table» — это название миграции.

С помощью команды migrate/create вы указываете yii, что хотите создать новую миграцию.  

Полный список доступных команды вы можете посмотреть написав $ php yii и нажав «Enter».

В ответ у вас выведется следующее:

Yii Migration Tool (based on Yii v2.0.12)

Create new migration '/var/www/yii-dev/migrations/m170825_174453_create_cars_table.php'? (yes|no) [no]:

Вам нужно ввести «yes» и нажать «Enter».

После чего у вас должна создаться папка migrations, в которой появится новый файл с названием похожий на этот — m170825_174453_create_cars_table.php. Я написал «похожий», потому что часть «m170825_174453» будет различаться в зависимости от времени когда создавалась миграция.

«m170825_174453» можно расшифровать следующим образом — «m<ГГММДД_ЧЧММСС>_<Название>».

Файл m170825_174453_create_cars_table должен выглядеть следующее образом:

<?php

use yii\db\Migration;

/**
 * Handles the creation of table `cars`.
 */
class m170825_174453_create_cars_table extends Migration
{
    /**
     * @inheritdoc
     */
    public function up()
    {
        $this->createTable('cars', [
            'id' => $this->primaryKey(),
        ]);
    }

    /**
     * @inheritdoc
     */
    public function down()
    {
        $this->dropTable('cars');
    }
}

Метод up() используется для того, чтобы что-то изменять в базе вперед. То есть вы добавите новую таблицу, колонку, измените тип колонки и др.

Метод down() возвращает изменения, которые были сделаны в up(). То есть down() — это up()  в обратную сторону.

Эти два метода нужны для того, чтобы мы могли спокойно создать новую миграцию и если вас что-то не устроит в ней, использовать метод down() и вернуться обратно.

Yii2 знает о стандартный вариантам создания миграций, поэтому когда вы пишите «created_{название_таблицы}_table», то он понимает, что вы хотите создать новую таблицу и заранее подготавливает файл для этого, собственно как вы и можете видеть выше.

Но это не значит, что вся работа будет сделано за нас. Теперь нам нужно дописать дополнительные колонки для таблицы.

В конечном итоге из миграции выше, нам нужно изменить только метод up(), который отвечает за создание:

...

/**
 * @inheritdoc
 */
public function up()
{
    $this->createTable('cars', [
        'id' => $this->primaryKey(),
        'name' => $this->string(255)->notNull(),
        'model' => $this->string(255)->notNull(),
        'description' => $this->string(500)->null(),
        'created_at' => $this->integer()->notNull(),
        'updated_at' => $this->integer()->notNull()
    ]);
}

...
  • $this->string() означает, что поле будет строкой
  • $this->primaryKey() — что поле будет уникальным ключом числового типа
  • $this->integer() сделает поле числовым

Как параметр вы можете указать длину для $this->string() или $this->integer(), а так же многих других методов помощников. В примере выше это 255 и 500. Так же, можно указать null() или notNull()  — это разрешить полю быть NULL или нет.

Теперь если вы введете в корне проекта:

$ php yii migrate/up

Вы увидите следующее сообщение:

Yii Migration Tool (based on Yii v2.0.12)

Total 1 new migration to be applied:
  m170825_174453_create_cars_table

Apply the above migration? (yes|no) [no]:

Сообщение «Total 1 new migration to be applied:» означает, что у вас есть новые миграции, которые еще не были активированы и ниже список названий. Чтобы их запустить, вам нужно ввести «yes» и нажать «Enter».

Если все окей, у вас покажет следующее сообщение:

*** applying m170825_174453_create_cars_table
    > create table cars ... done (time: 0.027s)
*** applied m170825_174453_create_cars_table (time: 0.079s)


1 migration was applied.

Migrated up successfully.

Большая его часть будет зеленым.

Теперь вы можете зайти в phpMyAdmin, в базу yii_loc и проверить наличие таблицы cars, выглядит это все примерно следующим образом:

Yii2 basic успешная миграция

Создание контроллера, экшена и использование модели

Создадим новый контроллер в папку controllers и назовем его CarController:

<?php

namespace app\controllers;

use yii\web\Controller;

class CarController extends Controller
{
}

Теперь создадим action create, который будет отвечать за добавление новой машины.

<?php

namespace app\controllers;

use yii\web\Controller;

class CarController extends Controller
{
    public function actionCreate()
    {
        ...
    }
}

Теперь добавим все элементы этого action, новые строки выделы ниже:

<?php

namespace app\controllers;

use Yii;
use app\models\Car;
use yii\web\Controller;

class CarController extends Controller
{
    public function actionCreate()
    {
        $model = new Car();

        if( $model->load(Yii::$app->request->post()) && $model->validate() ) {
            if( $model->save() ) {
                return $this->refresh();
            }
        }

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

Внутри, нам нужно использовать модель Cars, которая будет проверять форму и возвращать ответ в шаблон create.php, который находиться в views/car/.

Для правильного отображения шаблонов контроллера, во views нужно создать папку car , и внутри создать файл create.php.

Чтобы не париться по поводу создания create.php, скопируйте все из views/site/login.php и подправьте код под. У вас должно получиться что-то похожее на это:

<?php

/* @var $this yii\web\View */
/* @var $form yii\bootstrap\ActiveForm */
/* @var $model app\models\Car */

use yii\helpers\Html;
use yii\bootstrap\ActiveForm;

$this->title = 'Добавить новую машину';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="site-login">
    <h1><?= Html::encode($this->title) ?></h1>


    <?php $form = ActiveForm::begin([
        'id' => 'add-new-car',
        'layout' => 'horizontal',
        'fieldConfig' => [
            'template' => "{label}\n<div class=\"col-lg-3\">{input}</div>\n<div class=\"col-lg-8\">{error}</div>",
            'labelOptions' => ['class' => 'col-lg-1 control-label'],
        ],
    ]); ?>

    <?= $form->field($model, 'name')->textInput() ?>

    <?= $form->field($model, 'model')->textInput() ?>


    <?= $form->field($model, 'description')->textarea() ?>


    <div class="form-group">
        <div class="col-lg-offset-1 col-lg-11">
            <?= Html::submitButton('Добавить', ['class' => 'btn btn-primary', 'name' => 'add-new-car--button']) ?>
        </div>
    </div>

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

Для создания формы лучше всегда использовать класс ActiveForm, потому что он заботится о безопасности, создавая скрытое поле с CSRF токеном и другие удобности в виде авто генерации полей формы, валидация и другой. У ActiveForm есть открывающийся формат и закрывающийся. Между ними пишутся элементы формы для ввода информации и, конечно же, кнопка отправки формы.

Обратите внимание на $this->title — этот атрибут задает название страницы в <head></head>.

Так же посмотрите на:

$this->params['breadcrumbs'][] = $this->title

Эта строка создает хлебные крошки, которые появятся автоматически над вашим шаблоном. А как название для хлебной крошки, мы так же используем $this->title, которые уже указали выше.

Открывающийся формат:

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

Закрывающийся:

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

Пример элемента формы:

<?= $form->field($model, 'name')->textInput() ?>

Этот элемент означает, что вы хотите создать обычный текстовый элемент формы, который равен следующему HTML:

<input type="text" id="cars-name" class="form-control" name="Car[name]">

Метод textarea() равен <textarea></textarea> элементу соответственно.

Обратите внимание, что название полей в форме точно такие же как названия колонок в таблице cars в базе данных. Это не случайно — они должны совпадать.

Вы уже можете зайти на car/create и посмотреть на форму, которую вы только что сами создали. Пока что она работает только на половину, не добавляя в базу именно те данные, которые вы напишите. Все поля будут пустыми.

Для того, чтобы все было как надо, вам нужно добавить правила проверки полей в класс Car.

Заходим в models/Car.php и меняем его следующим образом:

<?php

namespace app\models;

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

/**
 * Class Car
 *
 * @property string name Имя машины.
 * @property string model Название модели машины.
 * @property string description Описание машины.
 * @property integer updated_at Когда машина была обновлена.
 * @property integer created_at Когда машина была создана.
 *
 * @package app\models
 */
class Car extends ActiveRecord
{
    public static function tableName()
    {
        return 'cars';
    }

    public function rules()
    {
        return [
            [['name', 'model'], 'required'],
            [['name', 'model', 'description'], 'trim'],

            [['name', 'model'], 'string', 'max' => 255],
            ['description', 'string', 'max' => 500],
        ];
    }

    public function behaviors()
    {
        return [
            TimestampBehavior::className(),
        ];
    }
}

Добавились два новых метода: rules() и behaviors(). Оба метода перезаписываются из ActiveRecord.

  • rules() — это правила проверки полей формы. Самое первое правило — указывает на то, что поля name и model являются обязательными для заполнения, второе — что мы чистим поля name, model и description от лишних пробелов с помощью trim, третье — длинна строки для полей name и model не должно превышать 255 символов используя 'string', 'max' => 255, ну и четвертое правило — это почти повтор третьего, только длинна строки больше и все.
  • behaviors() — это поведение модели Car. Внутри может быть множество сценариев, но у нас будет только один — это TimestampBehavior. Этот класс отвечает за добавление дат при добавлении или обновлении информации (в данном случае о машине). То есть когда мы добавим новую машину, TimestampBehavior автоматически заполнит created_at и updated_at с нужной датой. При обновлении машины, он только обновим updated_at — как и должно быть.

 

Читать далее — Yii2 basic: Просмотр, изменение и удаление автомобилей