YII 2, старт для новичка

imageЧтобы начать делать сайты на YII2, нам понадобится Веб-сервер, PHP 5.4, Git, Composer, знание «ООП в PHP» и АйКью > 103. Надо сказать, это будет не так уж и сложно, но и не просто. Эта статья поможет стартануть проект на YII2 самому дну веб-разработки: «школьникам» и старперам — адептам CodeIgniter. Другие статьи в Интернете либо еще не созданы (стабильной версии YII2 еще нет), либо написаны для тех, кто уже создал тысячу YII1 и сотню YII2 сайтов. Я не такой и статью я буду писать не такую, а простую и понятную, ведь эта статья — мой конспект, который я вел во время изучения YII2. Введение Установка Конфигурация Контроллер Модель Вью Виджеты Поведения и события Модули Послесловие Шаг 1. Введение.Короткие определения и пояснения перед тем, как идти дальше:

1) Composer. Эта программа обработает составленный нами composer.json, создаст папку vendor и закачает туда через Git последнюю версию YII2 и все другие «пакеты», от которых зависит фреймворк. Подробнее. Сразу предупрежу, в Windows можно столкнуться с кучей проблем при установке.

2) PSR-4. Разработчики постоянно холиварят, сколько пробелов должен быть таб, как называть переменные и т.д. Сейчас тренд такой, что таб — это 4ре пробела, а в качестве стандарта хранения и загрузки классов используется PSR-4. Именно в стандарте PSR-4 Компосер компонует скачанные файлы:

vendor/vendor_name/package_name/

После обработки composer.json, YII2 лежит в

vendor/yiisoft/yii2

Туда попадает содержимое папки framework из Гитхаба YII2.

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

3) Namespace. Пространства имен были введены в PHP 5.3. Для понимания всей кухни, откройте vendor/yiisoft/yii2/classes.php. Здесь перечислены классы, подгружаемые YII2. Главный класс для веб-приложений находится в web/application.php. Как видим, его неймспейс — yii\web. Что это значит? Да пока ничего, просто данный класс можно вызвать вот так:

$application = new \yii\web\Application;

А если потом в системе появится другой class Application, его мы вызовем через его уникальный неймспейс, вот так:

$application2 = new \vasya\megasoft\Application;

До PHP 5.3 в одном приложении нельзя было использовать два класса с одинаковым названием.

Все классы classes.php разделены по неймспейсам \yii\**\**, это создает абстрактную структуру фреймворка. Наше приложение мы точно также раскидаем по собственным неймспейсам и YII сможет по ним ориентироваться в нашей структуре.

4) MVC. Ничего лучше схемы MVC (модель-вид-контроллер) пока не было изобретено, почти все популярные фреймворки работают по этой схеме. Это значит, что любой запрос пользователя проходит через (обязательно) Контроллер и (возможно) Модель и (возможно) Вью. Это очень удобно, практично и красиво, следование этой цепочке позволит проекту держаться в собранном состоянии — ничего ни от куда не будет торчать (с ужасом вспомните ваш первый проект не на MVC).

Вот три класса YII2, расширяющие пользовательские классы контроллера и модели, а также файлы шаблона:

5) CRUD. Create, Read, Update, Delete. Почти все веб-приложения построены на этих четырех буквах. Мы создаем, читаем, обновляем, удаляем данные в базе данных.

Шаг 2. Установка. В корне проекта создадим composer.json с заполненной секцией require:

{ «minimum-stability»: «dev», «require»: { «yiisoft/yii2»:»*» } } Когда выйдет стабильная версия YII2, в первой строчке (minimum-stability) необходимость отпадет. Теперь передадим этот файл Компосеру. В Linux надо в папке с проектом выполнить composer install. В Windows советую при установке выбрать галочку «внедриться в проводник» и устанавливать пакеты через правую кнопку мыши (ПКМ по папке с composer.json).

Если все ОК, создастся папка vendor, в которую будет помещен YII2 и все нужные пакеты. В папке также будет лежать autoload.php, который загрузит все нужные классы.

В дальнейшем нам понадобятся еще некоторые пакеты — например, дебаговая панель и генератор кода. Сразу добавим все перечисленное в require:

{ «minimum-stability»: «dev», «require»: { «yiisoft/yii2»:»*», «yiisoft/yii2-debug»:»*», «yiisoft/yii2-gii»:»*» } } И выполним обновление: composer update.

После обучения мы будем клепать сайты на основе уже готовых каркасов. См. тут, как установить базовый или расширенный каркас YII2 сайта через Компосер, вместе с самим YII.

Шаг 3. Конфигурация. Следующий шаг после установки — конфигурация. Наше будущее приложение будет максимально походить на CodeIgniter по структуре. Но вообще, в YII2 можно (но лучше не надо) мутить с папками и неймспейсами что угодно.

Создаем папку application и в ней стандартный набор других папок: config, controllers, models, views, components, runtime (сюда YII будет записывать системные логи).

index.php выглядит так, он просто получает конфиг и передает его в \yii\web\Application:

//Автолодер компосера require 'vendor/autoload.php';

//Загрузка ядра require 'vendor/yiisoft/yii2/Yii.php';

//Подключение конфига $config = require dirname (__FILE__).'/application/config/config.php';

//Передача конфига в приложение $app = new \yii\web\Application ($config); //Экзекуция $app→run (); Вот на данном этапе важно понимать, что мы вообще делаем. yii\web\Application — это обычный класс, как и все остальное в YII. Каждый класс хорошо документирован. Например, вот документация на этот, в ней описано каждое свойство и метод. После конфигурации свойства будут заполнены нужными нам данными. Про «хорошо описано» — я слукавил, на самом деле «скоро будет хорошо описано», в данный момент YII2 в стадии беты и в документации куча неточностей.

Минимальный application/config/config.php для приложения, работающего с базой:

'HelloPage', 'name' => 'My first web application', 'basePath' => dirname (dirname (__FILE__)), 'vendorPath' => dirname (dirname (dirname (__FILE__))).'/vendor', 'components' => [ 'db' => [ 'class' => 'yii\db\Connection', 'dsn' => 'mysql: host=localhost; dbname=yii2', 'username' => 'root', 'password' => '***', ], ], //Другие компоненты YII2: ]; //На этапе разработки нам пригодится дебаговая панель и генератор кода if (YII_ENV_DEV) { $config['bootstrap'][] = 'debug'; $config['modules']['debug'] = 'yii\debug\Module';

$config['bootstrap'][] = 'gii'; $config['modules']['gii'] = 'yii\gii\Module'; }

return $config; Данный конфиг загрузит один компонент — класс работы с БД. И, если в index.php продефайнена константа разработки, пару модулей для всемиуважаемого разработчика.

Теперь проверим, все ли работает. Создаем в корне проекта папку assets с «хоршими» правами, вызываем модуль генератора кода site.lc/? r=gii. Попутно ценим дебаговую панель снизу. Сказка.

После прочтения статьи, домашним заданием будет сгенерировать модель на основе своей таблицы в БД, а также CRUD приложение.

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

Контроллер по умолчанию в YII2 — SiteController, он должен лежать в неймспейсе app\controllers (неймспейс можно изменить, задав в конфиге ключ controllerNamespace). Экшен по умолчанию — Index. Создаем application/controllers/SiteController.php. Помните про PSR? Так вот, классы рекомендуется называть с большой буквы, как и файлы, содержащие класс. А методы — с маленькой буквы.

use Yii; use \yii\web\Controller; //Наш контроллер будет наследовать этот класс YII2.

class SiteController extends Controller { public function actionIndex () { $message = «Hello, world!»; return $message; } } Тут все интуитивно понятно. Увидим хелло ворлд, вызвав главную страницу сайта. Кому все еще непонятно, зачем нужен контроллер вообще, тот может создать еще один экшн:

public function actionVasya () { return 'Hello, Vasya'; } И вызвать в браузере /? r=site/vasya. Матерь божья, да YII по _GET[r] определил, что запрашивается именно метод actionVasya класса SiteController. Далее в методах контроллера мы будем прописывать все условия if-else, получать все данные из базы через модель для передачи результата обработки запроса пользователя в шаблон (вью).

Читайте подробнее о уиишном классе yii\web\Controller, функционал которого заимствует наш класс контроллера.

Почти все наши приложения в бекенде будут содержать в своем контроллере CRUD методы: actionRead, actionUpdate, actionDelete, actionCreate, каждый будет заниматься своими делами, но все они будут использовать общую модель. Описание этих экшенов я упущу в этой статье. Разобраться, как работает каждый, вы сможете на примере готового кода, сгенерированного в домашнем задании.

Шаг 4. Модель. Модель в YII — самая главная вещь, именно через модель взаимодействуют все части системы, модель держит приложение в собранном состоянии. Модель в YII2 почти всегда привязана к базе данных. Есть таблица и есть модель, описывающая ее.

Тут я позволю себе отступление от YII. Прежде чем использовать модель в YII, надо понимать, что такое модель в программировании вообще. С точки зрения ООП, все в мире является объектом — речка, человек, песок, компьютер. Лучше, если человек тоже состоит из объектов — ноздря, пальцы ног и т.д. Ну да не будем заходить слишком далеко, вернемся к модели. Мы будем создавать приложение по управлению клиентами аудиторской фирмы, основной объект — общество с ограниченной ответственностью (ответственность можно ограничивать через private методы, но так далеко мы заходить не будем). Вокруг ООО крутятся все пироги фирмы, это ее основа, поэтому можно сделать вывод, что самое главное, что есть в веб-приложении фирмы — это модель ООО. Давайте создадим эту модель на основе PHP класса.

Создаем application/models/OOO.php

function __construct ($name, array $founders) { $this→name = $name; $this→founders = $founders; } }

Все, дальше мы можем подгрузить нашу модель в контроллере (use app\models), создать сколько угодно экземпляров с разными именами и учредителями, как угодно крутить-вертеть этими ООО в контроллере и вьюхах.

$ooo1 = new OOO ('Test1', array ('Vasya', 'Petya')); $ooo2 = new OOO ('Test2', array ('Nina')); Тут надо помнить, что ООО — это не только информация, но и различные действия. Например, слияния. Мы можем создать в модели метод merge, который будет делать нужные манипуляции, и передавать туда объект для слияния.

$ooo1 = new OOO ('Test1', array ('Vasya', 'Petya')); $ooo2 = new OOO ('Test2', array ('Nina')); $ooo1→merge ($ooo2); С помощью моделей можно описать всю жизнь. Чем нам в этом поможет YII2? Прежде всего — класс \yii\db\ActiveRecord (советую внимательно изучить), там куча всего, что поможет связать нашу модель данных с таблицами MySQL. Наследуем его и спользуем.

Кстати, важно понимать, что АктивРекорд тянет за собой наследование yii\base\Model, изучив этот класс, вы поймете, что является моделью в YII. Это правила валидации отправленных пользователем данных, это «атрибуты», это «поведения», это магические сеттеры и геттеры, которые взаимодействуют с созданным вами классом модели.

В базе данных будет три таблицы:

Портянка SQL CREATE TABLE IF NOT EXISTS `founders` (`id` int (11) NOT NULL, `name` varchar (255) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=3; INSERT INTO `founders` (`id`, `name`) VALUES (1, 'Vasya'),(2, 'Petya');

CREATE TABLE IF NOT EXISTS `founders_to_ooo` (`founder_id` int (11) NOT NULL,`ooo_id` int (11) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8; ALTER TABLE `founders` ADD PRIMARY KEY (`id`); INSERT INTO `founders_to_ooo` (`founder_id`, `ooo_id`) VALUES (1, 1),(2, 1);

CREATE TABLE IF NOT EXISTS `ooo` (`id` int (11) NOT NULL,`name` varchar (255) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2; ALTER TABLE `ooo` ADD PRIMARY KEY (`id`); INSERT INTO `ooo` (`id`, `name`) VALUES (1, 'Test1'); Основная — ooo. В founders будут храниться учредители. founders_to_ooo — связующая таблица, привязывающая сколько угодно учредителей к одной записи в таблице ooo.

Создаем application/models/OOO.php:

class OOO extends \yii\db\ActiveRecord {

public static function tableName () { return 'ooo'; }

//Этот метод будет вызван YII2 при обращении к несуществующему $ooo→founders //Это демонстрация прекрасных возможностей PHP 5 (магические геттеры-сеттеры) и yii\base\Model //Мы связываем две модели «via Table» и получаем нужный результат public function getFounders () { //А это демонстрация прекрасных возможностей ActiveRecord return $this→hasMany (Founder: className (), ['id' => 'founder_id'])→viaTable ('founders_to_ooo', ['ooo_id' => 'id']); }

public function setFounders ($ids) { //А этот метод будет вызван при инициализации $model→founders = [1,2,3]; //Сохраняем учредителей в базу }

//Описываем правила валидации для данных модели public function rules () { return [['name', 'required']]; }

//Присваиваем названия атрибутам public function attributeLabels () { return [ 'id' => 'Идентификатор', 'name' => 'Название', 'founders' => 'Учредители' ]; } } Для учредителей мы создаем отдельную модель Founder.

class Founder extends \yii\db\ActiveRecord {

public static function tableName () { return 'founders'; }

public function rules () { return [['name', 'required']]; }

public function attributeLabels () { return [ 'id' => 'Идентификатор', 'name' => 'Имя' ]; } } Далее, в контроллере добавляем use app\models\OOO; и выводим инфу о ООО с id=1

//$model = OOO: findOne (1); //Вот так выбираем одну ООО по ID $model = OOO: findAll (['id' => [1, 2]]); //Выбираем парочку ООО

//Выводим foreach ($model as $ooo) { echo $ooo→name; print_r ($ooo→founders); } Нот бэд.

А вот так можно (нужно) использовать метод yii\base\model\load () в комбинации с yii\db\ActiveRecord\save () для загрузки данных в модель и сохранения данных в БД:

if ($model→load (Yii::$app→request→post ()) && $model→save ()) { //Редиректим куда надо или делаем другие вещи } YII в load проверит всю валидацию, описанную в rules модели, и только если данные корректны, выполнит save (), если данные некорректны — во вьюхе будет выведена нужная ошибка рядом с полем. Разумеется, если мы вставляем данные в базу через АПИ YII, мы обезопасим себя от любого рода инъекций. Нот бэд.

Шаг 6. Вью. Это шаблон сайта. Контроллер возвращает результат рендеринга шаблона с переданными переменными ($this→render ('index', ['model' => $model]);) и этот результат выводится в браузер. В YII2 шаблон делится на два типа: слой и вью. Слои хранятся в views/layouts, вью — в views/{НазваниеКонтроллера}. Создаем папки /application/views/layouts/ и /application/views/site/

Создаем слой main.php (это слой по умолчанию). Примерно так выглядит слой YII2.

beginPage () ?> <?php echo Html::encode(\Yii::$app->name); ?> head () ?> beginBody () ?>

name); ?>

endBody () ?> endPage () ?> Зачем все эти endBody () ?> вместо обычного тега ? Чтобы фреймворк мог влиять на поведение этой части страницы при рендеринге, туда он будет подставлять свои скрипты и т.д.

Хелпер html будет использован почти во всех вьюхах, изучите документацию по нему.

Самые умные уже догадались, в $content слоя YII вернет вьюху, которую определит по названию экшена. Создаем application/views/site/index.php

ОООшки

  • name;?>

    founders); ?>
$model передается вью через экшен контроллера.

$model = OOO: findAll (['id' => [1, 2]]); return $this→render ('index', ['model' => $model]); Шаг 6. Виджеты. Основная цель фреймворка — ускорить процесс создания проекта. Чем меньше кода, тем лучше. А лучше короткого кода может быть только уже существующий код. Виджет — уже существующий код. Пример такого виджета — GridView, который выведет таблицу данных с возможностью сортировать по каждой колонке.

Видоизменяем нашу вью:

ООО

'ooo-grid', 'dataProvider' => $dataProvider, 'filterModel' => $searchModel, //Перечисляем колонки 'columns' => [ [ 'class' => CheckboxColumn: classname () ], [ 'class' => SerialColumn: className (), ], [ 'attribute' => 'name', 'format' => 'html', 'value' => function ($model) { return Html: a ($model['name'], ['view', 'id' => $model['id']]); } ], [ 'class' => ActionColumn: className (), 'header' => 'Управление' ] ] ]); Все, смотрим результат? Хотелось бы, но нет, нам не хватает $searchModel и $dataProvider. Первая переменная — отдельная модель ООО, осуществляющая поиск. Вторая переменная — эта наша старая $model, результат выборки, но несколько усложненный. Все сложнее, чем хотелось бы. Но на этом примере вы увидите, как через модель происходит «общение» между независимыми частями YII.

Модифицируем экшен.

$searchModel = new \app\models\OOOSearch; $dataProvider = $searchModel→search (Yii::$app→request→get ()); //Передаем _GET, которые будет передавать виджет

return $this→render ('index', [ 'dataProvider' => $dataProvider, 'searchModel' => $searchModel ]); Создаем модель OOOSearch

use Yii; use yii\base\Model; use yii\data\ActiveDataProvider; use app\models\OOO;

class OOOSearch extends Model {

public $name;

public function rules () { return [[['name'], 'string']]; }

public function search ($params) { $query = OOO: find (); $dataProvider = new ActiveDataProvider ([ 'query' => $query, 'pagination' => [ 'pageSize' => 10 ] ]); if (!($this→load ($params) && $this→validate ())) { return $dataProvider; }

$this→addCondition ($query, 'name', true);

return $dataProvider; }

protected function addCondition ($query, $attribute, $partialMatch = false) { $value = $this→$attribute; if (trim ($value) === '') { return; } if ($partialMatch) { $query→andWhere (['like', $attribute, $value]); } else { $query→andWhere ([$attribute => $value]); } } } Вот теперь получаем результат — табличку с пагинацией и возможностью фильтровать и сортировать содержимое. Побочный эффект от копирования и подгонки под себя готового кода — это довольно-таки нудное занятие. Благо, есть генератор кода CRUD (/? r=gii), с помощью него мы можем (не всегда, *троллфейс*) сгенерировать и поисковую модель, и вьюху с этим виджетом.

Отдельно стоит оставиться на виджете yii\widgets\ActiveForm. С помощью него создаются все формы на сайте. Данный виджет умеет выводить основные элементы формы и возьмет на себя функцию валидации данных перед отправкой на сервер. В целом — он крайне прост. Выводим форму и один инпут, передаем инпуту модель с rules, чтобы виджет знал, что должно быть введено в каждое поле:

field ($model, 'name')→textInput (['maxlength' => 255]) ?>

isNewRecord? 'Create' : 'Update', ['class' => $model→isNewRecord? 'btn btn-success' : 'btn btn-primary']) ?>
Повторюсь, в идеале всю эту гадость мы не будем писать, надо только освоить генератор кода, и вьюха будет сгенерирована на основе указанной таблицы.

Шаг 8. Поведения и события. Тут я процитирую предложение этой статьи.

В Yii существует такая вещь как поведения (behaviors).

Добавлю лишь, что поведения привязываются к событиям (ивентам). А саму статью читать пока незачем, она понятна только тем, кто уже написал тысячи поведений YII в своей жизни.

Поведение — это написанный нами код, который выполняется в какой-то момент и изменяет\дополняет поведение приложения. Это аналог хуков в WordPress. Мы можем установить готовый WP плагин, который через хуки изменит функционал WP блога. Каждое поведение цепляется за «ивент» (событие) в каком-то классе YII2. Давайте зацепися за класс контроллера yii\web\Controller, который наследуют все пользовательские контроллеры. Открываем документацию, перематываем до раздела Events. Ивента у данного объекта всего два, с говорящими названиями: EVENT_AFTER_ACTION и EVENT_BEFORE_ACTION. Зацепимся за первый — *ПОСЛЕ_ВЫПОЛНЕНИЯ_ЛЮБОГО_ЭКШЕНА* будем записывать в лог ИП адрес, время обращения, название класса и прочую инфу.

Как и все остальное в YII2, поведение является классом. Создаем класс application\components\Log.php в неймспейсе app\components

use yii; use yii\base\Behavior; use yii\web\Controller;

class Log extends Behavior {

public $custom_info = NULL;

public function events () { return [ Controller: EVENT_BEFORE_ACTION => 'writeLog', //Можно еще ща что-то зацепиться ]; }

public function writeLog () { $controller = $this→owner; file_put_contents ('log.txt',»{$_SERVER['REMOTE_ADDR']}|».time ().»|».$controller: className ().»|».$this→custom_info.»\n», FILE_APPEND); } } Теперь в любом контроллере добавляем наше поведение через объявление метода behaivors:

public function behaviors () { return [ 'notification' => [ 'class' => 'app\components\Log', 'custom_info' => 'Test' ], ]; } Готово! Теперь наш контроллер логируется, это поведение мы можем использовать во всех следующий сайтах. Пример несколько прост, более боевой пример в той же статье, теперь она должна стать более понятной вам. Правда, там «велосипед», сейчас в YII есть встроенное поведение yii\behaviors\SluggableBehavior, использующее yii\behaviors\AttributeBehavior (не знаю только, поддерживается ли кирилица, не проверял).

И еще про Ивенты. На любой ивент можно подписаться так:

$model = new OOO; //OOO наследует АктивРекорд //Подписываемся на событие $model→on ($model: EVENT_BEFORE_INSERT, function ($event) { /* Делаем что-то с данными */ }); $model→load (['OOO' => ['name' => 'Test Name']]); //Событие произойдет в этот момент, перед сохранением данных в базу $model→save (); Шаг 8. Модули. Как говорится, в хорошем ООП коде нет проблем, которые нельзя было бы решить вводом нового уровня абстракции. Кроме одной — слишком большой уровень абстракции. Модуль — дополнительный уровень абстракции в приложении. Модуль — это пачка. Пачка MVC, содержащая свои контроллеры, модели и вьюхи, отгороженные от других контроллеров, моделей и вьюх. Какой-то программист когда-то захотел добавить новый раздел на сайт, посмотрел на помойку уже созданных контроллеров и пообещал, что создаст свои контроллеры с блекджеком и шлюхами. Ну и добавил поддержку модулей в YII.Модули приложения перечисляются в конфигурации:

'bootstrap' => ['ooo'], 'modules' => [ 'ooo' => ['class' => 'application/modules/OOO'], //… ], Именно «модуль» представляет из себя генератор кода gii, который мы подключили изначально. Чтобы понять, что к чему, открываем vendor/yiisoft/yii2, видим класс модуля Module.php, папку controllers и views. Можно догадаться, что по тому же принципу мы смогли бы создать свой модуль OOO и использовать его на любом сайте через вызов /? r=ooo

Читаем эту статью. Там все приложение построено на модулях. Оно сложное, я сам сейчас копаюсь там.

Шаг 10. Послесловие. Тут лишь хочу описать свои ошущения от YII2 во время первого знакомства. До этого я пилил сайты на CodeIgniter и сделал свои тулзы для генерации кода, для автоматической валидации форм и т.д. Сейчас я вижу все это в YII2, но тут это реализовано действительно круто и универсально. Вот и все ощущения. Буду дальше изучать YII, осталось еще куча всего интересного.

© Habrahabr.ru