2 · курс
0%
Главная/🚀Старт

03Первое приложение

Четыре шага из руководства «Первое знакомство» в одном месте: страница «Привет», форма с валидацией, список из базы данных и генерация CRUD в Gii.

⏱ ~6 мин 📚 4 главы руководства

Здесь весь путь новичка: действие и представление → модель и форма → Active Record с пагинацией → CRUD за минуту в Gii. Каждый шаг показывает одну часть MVC и знакомит с идеями, которые дальше разбираются подробно.

Шаг 1. Страница «Привет»: действие + представление#

Действие — публичный метод контроллера с префиксом action. Параметры действия берутся из $_GET по имени.

controllers/SiteController.phpPHP
namespace app\controllers;

use yii\web\Controller;

class SiteController extends Controller
{
    public function actionSay($message = 'Привет')
    {
        return $this->render('say', ['message' => $message]);
    }
}
views/site/say.phpPHP
<?php use yii\helpers\Html; ?>
<?= Html::encode($message) ?>

Открываем index.php?r=site/say&message=Привет+мир. Параметр r — это маршрут вида контроллер/действие; site/say → SiteController::actionSay().

Правила именования, которые нужно запомнить:

Идентификатор Класс / метод
контроллер siteapp\controllers\SiteController
контроллер post-commentapp\controllers\PostCommentController
действие sayactionSay()
действие create-commentactionCreateComment()
представление say контроллера siteviews/site/say.php

render() автоматически оборачивает результат в шаблон views/layouts/main.php — поэтому у новой страницы сразу есть шапка и подвал сайта.

Шаг 2. Форма: модель + валидация#

Модель формы наследует yii\base\Model: публичные свойства — это атрибуты, метод rules() — правила проверки.

models/EntryForm.phpPHP
namespace app\models;

use yii\base\Model;

class EntryForm extends Model
{
    public $name;
    public $email;

    public function rules()
    {
        return [
            [['name', 'email'], 'required'],
            ['email', 'email'],
        ];
    }
}
controllers/SiteController.phpPHP
public function actionEntry()
{
    $model = new EntryForm();

    // load() кладёт $_POST['EntryForm'] в атрибуты, validate() проверяет по rules()
    if ($model->load(Yii::$app->request->post()) && $model->validate()) {
        return $this->render('entry-confirm', ['model' => $model]);
    }

    return $this->render('entry', ['model' => $model]);   // первый показ или ошибки
}
views/site/entry.phpPHP
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
?>
<?php $form = ActiveForm::begin(); ?>
    <?= $form->field($model, 'name')->label('Ваше имя') ?>
    <?= $form->field($model, 'email') ?>
    <div class="form-group">
        <?= Html::submitButton('Отправить', ['class' => 'btn btn-primary']) ?>
    </div>
<?php ActiveForm::end(); ?>

Yii::$app — глобальный объект приложения и одновременно Service Locator: через него доступны компоненты request, response, db, user и другие.

Шаг 3. Данные из базы: Active Record + пагинация#

Подключение описано в config/db.php и доступно как Yii::$app->db:

config/db.phpPHP
return [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=localhost;dbname=yii2basic',
    'username' => 'root',
    'password' => '',
    'charset' => 'utf8',
];

Класс Active Record без единой строки кода уже умеет всё — имя таблицы выводится из имени класса (Country → country):

models/Country.phpPHP
namespace app\models;

use yii\db\ActiveRecord;

class Country extends ActiveRecord
{
}
PHP
$countries = Country::find()->orderBy('name')->all();   // все строки как объекты
$country = Country::findOne('US');                       // по первичному ключу
$country->name = 'U.S.A.';
$country->save();                                        // UPDATE

Контроллер со списком и постраничной разбивкой:

controllers/CountryController.phpPHP
namespace app\controllers;

use yii\web\Controller;
use yii\data\Pagination;
use app\models\Country;

class CountryController extends Controller
{
    public function actionIndex()
    {
        $query = Country::find();

        $pagination = new Pagination([
            'defaultPageSize' => 5,
            'totalCount' => $query->count(),
        ]);

        $countries = $query->orderBy('name')
            ->offset($pagination->offset)
            ->limit($pagination->limit)
            ->all();

        return $this->render('index', [
            'countries' => $countries,
            'pagination' => $pagination,
        ]);
    }
}
views/country/index.phpPHP
<?php
use yii\helpers\Html;
use yii\widgets\LinkPager;
?>
<h1>Countries</h1>
<ul>
<?php foreach ($countries as $country): ?>
    <li><?= Html::encode("{$country->code} ({$country->name})") ?>: <?= $country->population ?></li>
<?php endforeach; ?>
</ul>
<?= LinkPager::widget(['pagination' => $pagination]) ?>

Pagination считает LIMIT/OFFSET по параметру page из URL, а LinkPager рисует кнопки страниц. Всё это подробно — в разделах Active Record и Провайдеры данных.

Шаг 4. Gii: генерация модели и CRUD#

Gii — модуль, включённый в config/web.php только для YII_ENV_DEV:

PHP
if (YII_ENV_DEV) {
    $config['bootstrap'][] = 'gii';
    $config['modules']['gii'] = [
        'class' => 'yii\gii\Module',
        'allowedIPs' => ['127.0.0.1', '::1', '192.168.0.*'],   // по умолчанию только localhost
    ];
}

Открываем index.php?r=gii и:

  1. Model Generator: таблица country → класс Country. Кнопка Preview покажет файл, diff — отличия от существующего, флажок overwrite перезапишет.
  2. CRUD Generator: app\models\Country, поисковая модель app\models\CountrySearch, контроллер app\controllers\CountryController.
  3. Получаем controllers/CountryController.php, models/CountrySearch.php и views/country/*.php — таблицу с сортировкой и фильтрами, просмотр, создание, редактирование, удаление.
Проверь себя5

app\controllers\PostCommentController::actionCreateReply() — дефисы убираются, слова капитализируются, добавляются суффикс Controller и префикс action.

Копирует $_POST['EntryForm'] в безопасные атрибуты модели и возвращает true; если данных нет — false, и действие просто показывает форму.

И на клиенте (JavaScript, сгенерированный из rules()), и на сервере при вызове validate(). Доверять можно только серверной.

Только настроенное подключение db и таблица country в базе: имя таблицы, атрибуты и типы столбцов читаются из схемы автоматически.

Из соображений безопасности: генератор пишет файлы на диск. Разрешённые адреса задаются в allowedIPs.