Знакомство с Yii 2 на основе создания простого блога

в 13:51, , рубрики: yii2, Песочница, метки:

Здравствуйте уважаемые хабрапользователи!

Как вы уже поняли из заголовка, в данной статье пойдёт речь о новой версии Yii. Я попробую коротко на живом примере познакомить вас с замечательным Yii 2.

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

Основные моменты

В Yii2 как вы уже заметили все построено на namespace, это пожалуй основная изюминка в новой версии.
Также очень важный момент «C» префикс из имён файлов был удалён.

Установка и создание первого приложения

За основу мы будем использовать basic приложение.
Как её установить очень хорошо описано на Github по этому сразу же переходим к следующим пунктам.

Структура приложения

Для примера я выбрал модульную структуру. Это позволит нам узнать и понять принцип работы модулей в Yii2.
Итак для того чтобы реализовать такую структуру, нам, как и в первой версии нужно создать основную папку всех модулей «modules», в которой мы уже будем создавать отдельные папки для отдельных модулей. Тут все как в первой версии.

Единственное что поменялось в модулях это название основного класса модуля. Как я понял теперь уже не обязательно писать суффикс «Module», по этому наши основные файлы будут иметь понятные имена без суффикса.

Пример:
Site.php, Users.php, Blogs.php, и.т.д.
Структуру вы сможете посмотреть уже на готовом примере, и останавливаться больше на этом не имеет смысла.

Настройка приложения: config/main.php

Как и в Yii 1.0 приложение настраивается через файла main.php, и многие элементы остались без изменений, но всё таки есть много переименованных параметров, что следует помнить в случае неработоспособности приложения после конфигурации.

Несколько примеров таких изменений и особенностей:

  • Приркутка модулей теперь содержит обязательный параметр «class», который хранит имя основного класса модуля, и без которого подключить модуль не получится.
    'modules' => array(
    ...
    		'users' => array(
    			'class' => 'appmodulesusersUsers'
    		),
    ...
    	),
    

  • Параметр «defaultController» убрали и вместо него используется «defaultRoute».
  • При настройки путей к директориям, можно использовать заданные алиасы "@app, @www, @wwwroot", что очень удобно.
  • В UrlManager тоже переименовали несколько параметров. Теперь «urlFormat» заменили на «enablePrettyUrl», «useStrictParsing» на «enableStrictParsing».
  • В компоненте «db» переименовали «connectionString» на «dsn».

В случае неработоспособности каких либо параметров, можно легко подсмотреть все в исходниках фрейма.
Как только мы настроили наше приложение и подключили наши модули, мы можем приступить к написанию нашего «CRUD».

CRUD

Подробный пример есть в демо коде, но если честно сильного отличия от первой версии нет. Единственно что появилось новое, это ранее метод контроллера: populate(), который был перенесён на днях в модель и переименован в load(). Ещё один важный момент касающийся «render()» функции — её теперь нужно явно выводить через «echo», вместо «return». (В инструкции об этом написано, хотя в basic приложении об этом пока забыли, но думаю стоит сразу писать правильно)

Пример:

public function actionCreate()
	{
		$model = new Blog();
		if ($model->load($_POST) && $model->validate()) {
			if ($model->save())
				return Yii::$app->response->redirect(array('view', 'id' => $model->id));
		} else {
			echo $this->render('create', array('model' => $model));
		}
	}

$model->load($_POST)
тоже самое что
if (isset($_POST['Blog'])) {
    $model->attributes = $_POST['Blog'];
}

Других особых различий в работе с CRUD нет.

Модель

Основным нововведением это метод «scenarios()» за счёт которого можно настроить валидаторы модели в зависимости от указанного сценария.

public function scenarios()
{
    return array(
        'backend' => array('email', 'role'),
        'frontend' => array('email', '!name'),
    );
}

Привязка модели делается за счёт функции formName() которая в итоге возвращает имя Класса модели к которой относится форма.
Также немаловажный момент — model() убрали, и теперь работа с моделью происходит как и с другим обычным классом:

 MyModel::getAuthor();

ActivRecord

Тут все переписали, теперь в Yii2 новый AR который реально радует.

Примеры нескольких нововведений:
«scopes()» были заменены на обычные методы AR модели, которые сейчас имеют такой вид:

public function active($query)
	{
		return $query->andWhere('status = ' . self::STATUS_ACTIVE);
	}

Также радикально были изменены «relations()», которые сейчас задаются в виде гетерров, что более правильно. Доступны два типа relations: «hasOne()», «hasMany()».

public function getAuthor()
	{
		return $this->hasOne('appmodulesusersmodelsUser', array('id' => 'author_id'));
                // первый параметр это у нас имя класса с которым мы настраиваем связь.
               // Во втором параметре в виде массива задаётся имя удалённого PK ключа  (id) и FK из текущей таблицы модели (author_id), которые связываются между собой
	}

Также были переписаны функции выборки из базы, и дополнены новыми.

$customers = Customer::find()
    ->where(array('status' => $active))
    ->orderBy('id')
    ->all();
// return the customer whose PK is 1
$customer = Customer::find(1);
$customers = Customer::find(array('status'=>$active));
$customers = Customer::find()->asArray()->all();
$customers = Customer::find()->active()->asArray()->all();

И последнее, AR теперь делает автоматическую привязку модели к базе, за счёт функции tableName()" которая по умолчанию возвращает такое значение «tbl_MODEL_NAME». Для примера, модель «User», будет привязана к таблице «tbl_user». Если же имя таблицы отличается, можно просто переопределить функцию.

События

В новой версии работать с событиями стало максимально просто. В демо приложении я привёл пример собственного события, хотя там можно использовать стандартные события которые доступны в Yii, как например «EVENT_AFTER_INSERT».

Для того чтобы определить событие достаточно в нужно месте вызвать «trigger()» функцию, а уже потом в нужном месте задать для события обработчик.

Пример:

файл appmodulesusersmodelsUser
...
public function afterSave($insert)
	{
               // Создаём событие
		$event = new ModelEvent;
		$this->trigger(self::EVENT_NEW_USER, $event);

		parent::afterSave($insert);
	}
...

файл appmodulesuserscontrollersDefaultController
...
public function actionSignup()
	{
		$model = new User();
		$model->scenario = 'signup';
		if ($model->load($_POST) && $model->validate()) {
			if (!$this->module->activeAfterRegistration)
                                // задаём наш обработчик событий, для события [[EVENT_NEW_USER]]
				$model->on($model::EVENT_NEW_USER, array($this->module, 'onNewUser'));
			if ($model->save()) {
				Yii::$app->session->setFlash('success');
				return Yii::$app->response->refresh();
			}
		} else {
			echo $this->render('signup', array('model' => $model));
		}
	}
...

Есть несколько способов привязки обработчика:

function ($event) { ... }         // Анонимная функция
array($object, 'handleClick')    // $object->handleClick()
array('Page', 'handleClick')     // Page::handleClick()
'handleClick'                    // глобальная  функция handleClick()

View

В Yii2 появился новый класс, который отвечает за все представления приложения, и который выполняет непосредственно вывод информации.
Теперь в view файлах переменная $this относится уже не к контроллеру а именно к новому классу «yiibaseView».
Для того чтобы вызвать определённую функцию контроллера или виджета к которому принадлежит представление нужно обратится к методу: «context».

Пример:

// Файл appmodulesblogsviewsdefaultindex
// $this->context относится к файлу appmodulesblogscontrollersDefaultController
// Простой вызов параметра модуля к которому относится контроллер из представления
echo $this->context->module->recordsPerPage; // Результат 10

//Файл appmodulescommentswidgetscommentsviewsindex
// $this->context относится к файлу appmodulescommentswidgetscommentsComments
if ($this->context->model['id'] == 10 ) {...}

Widgets

Виджеты были дополнены новыми методами, и как в случае с render() у контроллера, они должны быть непосредственно выведены через «echo».

Пример:

// Note that you have to "echo" the result to display it
echo yiiwidgetsMenu::widget(array('items' => $items));

// Passing an array to initialize the object properties
$form = yiiwidgetsActiveForm::begin(array(
    'options' => array('class' => 'form-horizontal'),
    'fieldConfig' => array('inputOptions' => array('class' => 'input-xlarge')),
));
... form inputs here ...
yiiwidgetsActiveForm::end();

Action Filters

В новой версии фильтры контроллеров реализованы в виде «behaviors».

public function behaviors()
	{
		return array(
			'access' => array(
				'class' => yiiwebAccessControl::className(),
				'rules' => array(
				    // allow authenticated users
					array(
						'allow' => true,
						'actions' => array('login', 'signup', 'activation'),
						'roles' => array('?')
					),
					array(
						'allow' => true,
						'actions' => array('logout'),
						'roles' => array('@')
					),
					array(
						'allow' => true,
						'actions' => array('index', 'view'),
						'roles' => array('guest')
					),
					array(
						'allow' => true,
						'actions' => array('edit', 'delete'),
						'roles' => array('@')
					),
					// deny all
					array(
						'allow' => false
					)
				)
			)
		);
	}

Меленький нюанс — из коробки остались только 2 роли:

  • @ — авторизованные
  • ? — гости
  • * — была удалена.

Static Helpers

В Yii2 добавлены много новых хелперов. Например как тот же SecurityHelper который ускоряет работу с паролями и генерированными кодами, ArrayHelper, Html, и другие. Что снова радует.

ActiveForm

Формы теперь создаются ещё быстрее и удобнее, за счёт ActiveField класса, который упрощает стиль написания кода что не может не радовать.

<?php $form = ActiveForm::begin(array('options' => array('class' => 'form-horizontal')));
echo $form->field($model, 'username')->textInput($model->isNewRecord ? array() : array('readonly' => true));
echo $form->field($model, 'email')->textInput();
if (!$model->isNewRecord) {
    if (Yii::$app->user->checkAccess('editProfile')) {
        echo $form->field($model, 'status')->dropDownList(array(
        	User::STATUS_ACTIVE => 'Active',
        	User::STATUS_INACTIVE => 'Inactive',
        	User::STATUS_DELETED => 'Deleted'
        ));
        echo $form->field($model, 'role')->dropDownList(array(
        	User::ROLE_USER => 'User',
        	User::ROLE_ADMIN => 'Admin'
        ));
    }
	echo $form->field($model, 'oldpassword')->passwordInput();
}
echo $form->field($model, 'password')->passwordInput();
echo $form->field($model, 'repassword')->passwordInput();
?>

<div class="form-actions">
	<?php echo Html::submitButton($model->isNewRecord ? 'Register' : 'Update', array('class' => 'btn btn-primary')); ?>
</div>

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

User and Identity

Робота с пользователями теперь осуществляется через класс yiiwebUser и интерфейс yiiwebIdentity что более гибко в использовании.
Из-за этих изменений атрибуты пользователя можно получить через метод identity пользователя.

Пример:

echo Yii::$app->user->identity->username;

URL Management

Тут чуток видоизменили стили записи правил.

Пример:

...
array(
  'dashboard' => 'site/index',
 'PUT post/<id:d+>' => 'post/update',
 'POST,PUT post/index' => 'post/create',
  'POST <controller:w+>s' => '<controller>/create',
  '<controller:w+>s' => '<controller>/index',
 'PUT <controller:w+>/<id:d+>'    => '<controller>/update',
 'DELETE <controller:w+>/<id:d+>' => '<controller>/delete',
 '<controller:w+>/<id:d+>'        => '<controller>/view',
);
...

RBAC

Работа с пользовательскими правами теперь доступна изначально из коробки без добавление своего кода, как например в случае с использованием файлового варианта в первой версии.
Ниже я напишу коротко инструкцию про RBAC и описание ролей в файле.

Для начала нам нужно создать свой класс который будет унаследоваться от yiirbacPhpManager.
В нашем примере он находится в модуле «rbac» в папке «components» под названием «PhpManager.php»
Код в нем простой. Мы просто задаём путь к нашему файлу с описанными ролями, и делаем привязку пользователя к нужной роли.

<?php 
namespace appmodulesrbaccomponents;

use Yii;

class PhpManager extends yiirbacPhpManager
{
    public function init()
    {
        if ($this->authFile === NULL)
            $this->authFile = Yii::getAlias('@app/modules/rbac/components/rbac') . '.php';
 
        parent::init();
 
        if (!Yii::$app->user->isGuest)
            $this->assign(Yii::$app->user->identity->id, Yii::$app->user->identity->role);
    }
}

После, в той же папке мы создаём файл «rbac.php» где описываем нужные нам роли. (Код можно увидеть в демо приложении в папке: @app/modules/rbac/components/rbac)

Ну и на напоследок нам осталось только настроить authManager в конфигурационном файле:

...
'authManager' => array(
			'class' => 'appmodulesrbaccomponentsPhpManager',
			'defaultRoles' => array('guest'),
		),
...

После чего в нужном нам месте мы можем смело делать проверки пользователя на наличие нужных прав:

if (Yii::$app->user->checkAccess('editOwnBlog', array('blog' => $model)) || Yii::$app->user->checkAccess('editBlog')) {
...
}

Это все что я успел узнать, но уверен ещё есть много чего не успелось.

На данный момент я не успел разобраться с ajax запросами в Yii 2, а именно как правильно создавать нужный ответ при валидации модели. В 1.0 это делается так:

echo CActiveForm::validate($model);

если кто знает пишите, уверен многим будет интересно.

Итог

Несмотря на ещё недоделанный вид, Yii 2 выглядит уже очень хорошо. Уверен впереди нас ждёт только лучшее.

Самому Yii 2 очень понравился. Если честно уже есть огромное желание начать писать рабочий проекты на новой версии, хотя до этого ещё очень рано.

Статья получилось большая, но по другому просто не знаю как.

Спасибо всем за внимание. Удачи!

Демо блог на Github. Инструкция по установке присутствует.
Рабочий пример блога.

Автор: cvsstudio

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js