Это старая версия документа!
Документация по Yii 2 Framework
Configuration
<?php return [ 'components' => [ 'db' => [ 'class' => 'yii\db\Connection', 'dsn' => 'mysql:host=localhost;dbname=yii2', 'username' => 'yii2', 'password' => '<password>', ], 'cache' => [ 'class' => 'yii\caching\DummyCache', ], 'urlManager' => [ 'rules' => [ '<action:(login|logout|about)>' => 'site/<action>', // ... ['class' => 'app\components\CarUrlRule', 'connectionID' => 'db', ...], ], 'enablePrettyUrl' => true, 'enableStrictParsing' => true, 'showScriptName' => false, 'suffix' => '.html', ], ] ];
PHPUnit
добавить в конфигуратор композера composer.json
{ "require-dev": { "phpunit/phpunit": "3.7.*" } }
- php composer.phar update
- php vendor/bin/phpunit vendor/yiisoft/yii2/yii/test/
URL Management
$route = [ // ... path + params ]; $url = \Yii::$app->urlManager; $url->createUrl($route); $url->createAbsoluteUrl($route); $url = Yii::$app->urlManager->createUrl($route); $url = Yii::$app->urlManager->createAbsoluteUrl($route);
Request
GET
Yii::$app->request->get(); Yii::$app->request->getQueryParams(); Yii::$app->request->getQueryParam('File'); Yii::$app->request->get('File');
POST
Yii::$app->request->post(); Yii::$app->request->getBodyParams(); Yii::$app->request->getBodyParam('File'); Yii::$app->request->post('File');
View
Blocks
CSS
JS
Вставка кода внутри представления
В примере производится вставка JS кода из assets c применением переменной в скрипте JS_FABRIC_CAR_URL
$this = Yii::$app->view;
<?php $this->registerJs('var JS_FABRIC_CAR_URL = "' . Html::url(['/core/ajax/fabric-car']) . '";', View::POS_HEAD, 'js-fabric-car-url'); $publish = Yii::$app->assetManager->publish(Yii::getAlias('@app/modules/core/assets/js')); $this->registerJsFile($publish[1] . '/block-select-car.js', [yii\web\JqueryAsset::className()], ['position'=>View::POS_END]); ?>
Добавление csrfToken в Ajax запрос
$js_global_variables = ' $.ajaxSetup({ data: ' . \yii\helpers\Json::encode([ \yii::$app->request->csrfParam => \yii::$app->request->csrfToken, ]) . ' });' . PHP_EOL; $this->registerJs($js_global_variables, yii\web\View::POS_HEAD, 'js_global_variables');
или через header
$js_global_variables = ' $.ajaxPrefilter(function( options ) { if ( !options.beforeSend) { options.beforeSend = function (xhr) { xhr.setRequestHeader("HTTP_X_CSRF_TOKEN", ' . \yii::$app->request->csrfToken .'); } } });' . PHP_EOL; $this->registerJs($js_global_variables, yii\web\View::POS_HEAD, 'js_global_variables');
Image
yii\helpers\Url::toRoute
echo Url::toRoute([''], $schema = false); // currently active route echo Url::toRoute(['view', 'id' => 'contact'], $schema = false); // same controller, different action echo Url::toRoute(['post/index'], $schema = false); // same module, different controller and action echo Url::toRoute(['/site/index'], $schema = false); // absolute route no matter what controller is making this call echo Url::toRoute(['post/read', 'id' => 100, '#' => 'title'], $schema = false)
echo Url::toRoute('', $schema = false); // currently active route echo Url::toRoute('post/index', $schema = false); // same module, different controller and action echo Url::toRoute('/site/index', $schema = false); // absolute route no matter what controller is making this call
yii\helpers\Url::to
echo Url::to('', $schema = false); // currently active route echo Url::to('post/index', $schema = false); // same module, different controller and action echo Url::to('/site/index', $schema = false); // absolute route no matter what controller is making this call
echo Url::to('@web', $schema = false); echo Url::canonical(); // get canonical URL for the curent page echo Url::home(); // get home URL echo Url::remember(); // save URL to be used later echo Url::previous(); // get previously saved URL
- $schema = true - Абсолютный адрес
- $schema = 'https' - Указание на испоользование шифрованного протокола
Синоним для yii\helpers\Url::toRoute
echo Url::to([''], $schema = false); // currently active route echo Url::to(['view', 'id' => 'contact'], $schema = false); // same controller, different action echo Url::to(['post/index'], $schema = false); // same module, different controller and action echo Url::to(['/site/index'], $schema = false); // absolute route no matter what controller is making this call echo Url::to(['post/read', 'id' => 100, '#' => 'title'], $schema = false)
Примеры использоватия можно глянуть в тестах https://github.com/yiisoft/yii2/blob/master/tests/unit/framework/helpers/UrlTest.php
yii\helpers\Html::url (old)
echo Html::url(['']); // currently active route echo Html::url(['view', 'id' => 'contact']); // same controller, different action echo Html::url(['post/index']); // same module, different controller and action echo Html::url(['/site/index']); // absolute route no matter what controller is making this call echo Html::url(['post/read', 'id' => 100, '#' => 'title'])
echo Html::url(''); // currently active route echo Html::url('post/index'); // same module, different controller and action echo Html::url('/site/index'); // absolute route no matter what controller is making this call
вместо старых методов нада использовать yii\helpers\Url::to
Примеры использоватия можно глянуть в тестах https://github.com/yiisoft/yii2/blob/master/tests/unit/framework/helpers/UrlTest.php
createUrl
echo $this->createUrl([''], $schema = null); // currently active route echo $this->createUrl(['view', 'id' => 'contact'], $schema = null); // same controller, different action echo $this->createUrl(['post/index'], $schema = null); // same module, different controller and action echo $this->createUrl(['/site/index'], $schema = null); // absolute route no matter what controller is making this call echo $this->createUrl(['post/read', 'id' => 100, '#' => 'title'], $schema = null)
echo $this->createUrl('', $schema = null); // currently active route echo $this->createUrl('post/index', $schema = null); // same module, different controller and action echo $this->createUrl('/site/index', $schema = null); // absolute route no matter what controller is making this call
createAbsoluteUrl (old)
Усли $this - это yii\web\Controller
echo $this->createAbsoluteUrl([''], $schema = null); // currently active route echo $this->createAbsoluteUrl(['view', 'id' => 'contact'], $schema = null); // same controller, different action echo $this->createAbsoluteUrl(['post/index'], $schema = null); // same module, different controller and action echo $this->createAbsoluteUrl(['/site/index'], $schema = null); // absolute route no matter what controller is making this call echo $this->createAbsoluteUrl(['post/read', 'id' => 100, '#' => 'title'], $schema = null)
вместо старых методов нада использовать yii\helpers::toRoute
Усли $this - это yii\web\Controller
echo $this->createAbsoluteUrl('', $schema = null); // currently active route echo $this->createAbsoluteUrl('post/index', $schema = null); // same module, different controller and action echo $this->createAbsoluteUrl('/site/index', $schema = null); // absolute route no matter what controller is making this call
вместо старых методов нада использовать yii\helpers::toRoute
urlManager
echo \Yii::$app->urlManager->createUrl(['site/page', 'id' => 'about']); // /index.php/site/page/id/about/ echo \Yii::$app->urlManager->createUrl(['date-time/fast-forward', 'id' => 105]) // /index.php?r=date-time/fast-forward&id=105 echo \Yii::$app->urlManager->createAbsoluteUrl('blog/post/index'); // http://www.example.com/index.php/blog/post/index/
Custom
<?php return [ // ... 'components' => [ 'urlManager' => [ 'enablePrettyUrl' => true, 'showScriptName' => false, 'enableStrictParsing' => true, 'suffix' => '.html', 'rules' => [ '<action:(login|logout|about)>' => 'site/<action>', // ... ['class' => 'app\components\CarUrlRule', 'connectionID' => 'db', ...], ], ], ], ];
Controller
Как программно вызвать контроллер?
$className = 'backend\controllers\SiteController'; $controller = Yii::createObject($className, [$id, $this]);
yii\helpers\Html (old)
// ['label' => 'Добавление', 'url' => ['/admin/user/create']] Html::a("Log in here", ["user/reset", "hash" => $hash, "sid" => $sid]); Html::url(["user/reset", "hash" => $hash, "sid" => $sid]);
Подробно https://github.com/yiisoft/yii2/blob/master/docs/guide/url.md
Ajax
Pjax
use app\modules\cabinet\components\CabinetController; use app\models\Image; class CameraController extends CabinetController { public function actionFavorite() { $id = (int) Yii::$app->request->post('id'); if (!$id) { return false; } $image = Image::findOne($id); if ($image->f_fav) { Image::updateAll(['f_fav' => 0], ['id' => $id]); return $this->renderPartial('favorite', ['id' => $id, 'f_fav' => 0]); } else { Image::updateAll(['f_fav' => 1], ['id' => $id]); return $this->renderPartial('favorite', ['id' => $id, 'f_fav' => 1]); } return false; } }
Вывод партиала в main.php
<?= $this->render('favorite', ['id' => 1, 'f_fav' => true);?>
Отображаемая вьюха favorite.php
<?php use yii\widgets\Pjax; use yii\helpers\Html; ?> <?php Pjax::begin(); ?> <?= Html::beginForm(['favorite'], 'post', ['data-pjax' => '', 'class' => 'form-inline']); ?> <?= Html::hiddenInput('id', $id) ?> <?= Html::submitButton($f_fav ? '<i class="fa fa-star"></i>' : '<i class="fa fa-star-o"></i>', []) ?> <?= Html::endForm() ?> <?php Pjax::end(); ?>
User
RBAC
Access
'access' => [ 'class' => \yii\web\AccessControl::className(), 'rules' => [ [ 'actions' => ['index'], 'allow' => false, 'roles' => ['?'], ], [ 'actions' => ['index', 'update','view','create','delete'], 'allow' => true, 'matchCallback' => function() { return \Yii::$app->user->identity->role <= \Yii::$app->user->identity->MANAGER; } ], ], ],
Model
modules/user
$user = Yii::$app->getModule("user")->model("User", ["scenario" => "register"]); $profile = Yii::$app->getModule("user")->model("Profile"); if($user->load($_POST)){ if ($user->save()) { $profile->user_id = $user->id; $profile->save(false); } }
Join
with()
Не делает SQL JOIN(), применяется не только в реляционых БД (NoSql) Применяется только для построений конструкций вида WHERE IN(), плюс наполняют relation
leftJoin()
Добавляет SQL LEFT JOIN(), применяется только в реляционыых БД, плюс наполняют relation
$this->joinWith([[relation_name]], true, 'LEFT JOIN')
joinWith()
Добавляет SQL JOIN(), применяется только в реляционыых БД, плюс наполняют relation
// Выбираем MyModel с relation1 и relation2. // Все три забираем запросом с JOIN. $query = MyModel::find() ->joinWith(['relation1', 'relation2']); $countQuery = clone $query; $pages = new Pagination(['totalCount' => $countQuery->count(), 'pageSize' => 15]); $items = $query ->orderBy($sort->orders) ->offset($pages->offset) ->limit($pages->limit) // Забираем дополнительно relation3 и relation4. // Фильтровать по ним нам не нужно, так что будут // запросы вида WHERE ID IN (1,2,3,4) или аналоги // для noSQL. ->with(['relation3', 'relation4']) ->all();
https://github.com/yiisoft/yii2/blob/master/docs/guide/active-record.md#joining-with-relations
innerJoinWith()
Validate (Rules)
class User extends \yii\db\ActiveRecord { // ... public function rule() { return [ ['attribute1', 'attribute2', ...], 'validator class or alias', // specifies in which scenario(s) this rule is active. // if not given, it means it is active in all scenarios 'on' => ['scenario1', 'scenario2', ...], // the following name-value pairs will be used // to initialize the validator properties 'property1' => 'value1', 'property2' => 'value2', // ... ]; } }
Пример использования в модели
if ($User->load($_POST)) { $User = new User; $Profile = new Profile; // validate for ajax request $Profile->load($_POST); if (Yii::$app->request->isAjax) { Yii::$app->response->format = Response::FORMAT_JSON; return ActiveForm::validate($User, $Profile); } // validate for normal request if ($User->validate() and $Profile->validate()) { // do somthing } }
Пример применения валидатора без использования модели
$email = 'test@example.com'; $validator = new yii\validators\EmailValidator(); if ($validator->validate($email, $error)) { echo 'Email is valid.'; } else { echo $error; }
- Список базовых валидаторов: https://github.com/yiisoft/yii2/blob/master/docs/guide/validation.md
Scenario
class User extends \yii\db\ActiveRecord { // ... public function getProduct() { return $this->hasOne(Order::className(), ['product_id' => 'id']); } public function scenarios() { return [ 'userCreates' => [ 'attributes' => ['name', 'value'], 'atomic' => [self::OP_INSERT], ], ]; } public function afterSave($insert) { parent::afterSave($insert); if ($this->getScenario() ==== 'userCreates') { // FIXME: TODO: WIP, TBD } } }
Подробно https://github.com/yiisoft/yii2/blob/master/docs/guide/structure-models.md#scenarios-
Connection/Command/QueryBuilder
Connection
$connection = \Yii::$app->db;
Подробно
Command
- queryOne()
- queryAll()
- query()
- queryScalar()
- queryColumn()
Подробно https://github.com/yiisoft/yii2/blob/master/framework/db/Command.php
$command = $connection->createCommand('SELECT * FROM tbl_post WHERE id=1'); $post = $command->queryOne();
$connection->createCommand()->insert('tbl_user', [ 'name' => 'Sam', 'age' => 30, ])->execute();
$command = $connection->createCommand('UPDATE tbl_post SET status=1 WHERE id=1'); $command->execute();
$connection->createCommand()->batchInsert('tbl_user', ['name', 'age'], [ ['Tom', 30], ['Jane', 20], ['Linda', 25], ])->execute();
$connection->createCommand()->update('tbl_user', ['status' => 1], 'age > 30')->execute();
$connection->createCommand()->delete('tbl_user', 'status = 0')->execute();
$command = $connection->createCommand('SELECT * FROM tbl_post WHERE id=:id'); $command->bindValue(':id', $_GET['id']); $post = $command->query();
Query Builder and Query
$rows = (new \yii\db\Query()) ->select('id, name') ->from('user') ->limit(10) ->all(); // which is equivalent to the following code: $query = (new \yii\db\Query()) ->select('id, name') ->from('user') ->limit(10); // Create a command. You can get the actual SQL using $command->sql $command = $query->createCommand(); // Execute the command: $rows = $command->queryAll();
$query = (new \yii\db\Query()) ->select('id, name') ->from('user') ->limit(10); // Create a command. You can get the actual SQL using $command->sql $command = $query->createCommand(Yii::$app->db); // Execute the command: $rows = $command->queryAll();
Простой спооб получить записи из указанной БД
$rows = (new \yii\db\Query()) ->select('id, name') ->from('user') //->where([...]) //->innerJoin('', '', [...]) ->limit(10) ->createComand(Yii::$app->some_bd) ->queryAll();
Подробно
Transactions
$transaction = $connection->beginTransaction(); try { $connection->createCommand($sql1)->execute(); $connection->createCommand($sql2)->execute(); // ... executing other SQL statements ... $transaction->commit(); } catch(Exception $e) { $transaction->rollback(); }
Active Record
class Post extends ActiveRecord { public function getCreator() { return $this->hasOne('User', array('id' => 'user_id')); } public function getComments() { return $this->hasMany('Comment', array('post_id' => 'id')); } public function getTrustComments($isTrust = true) { return $this->hasMany('Comment', array('post_id' => 'id')) ->where('status = :status', array( ':status' => $isTrust ? self::TRUST : self::UNTRUST, )) ->orderBy('id'); } }
// we receive an ActiveQuery instance $query = Post::find(); // all posts $posts = $query->all(); // looking for all the posts with a condition $posts = $query ->where(array('status' => Post::DRAFT)) ->orderBy('time') ->all(); // looking for a post $post = $query ->where(array('id' => 10, 'status' => Post::READ)) ->one(); // or easier: "where" condition can be transmitted directly to the factory method $post = Post::find(array('id' => 10, 'status' => Post::READ)); // having transmitted to the factory method not a massive, but a number equivalent to the primary key search $post = Post::find(10) ->where(array('status' => Post::READ)) ->one(); // we index the result to a necessary attribute $posts = $query->indexBy('title')->all(); // the result as an array $posts = $query->asArray()->all();
Batch
foreach (Customer::find()->batch() as $customers) { } foreach (Customer::find()->batch(10) as $customers) { // $customers — массив из 10 или менее объектов Customer }
Each
foreach (Customer::find()->each() as $customers) { } foreach (Customer::find()->each(10) as $customers) { // $customers — массив из 10 или менее объектов Customer }
Ключи в эллементах коллекции AR
AR
$query = SparesCategory::find()->where(['parent_id' => 0]); $query->indexBy = function($row){ // Ключ в который будет помещена возвращаемая модель return $row->id; }; $categories = $query->all();
$quey = CarMark::find()->indexBy(function($row){ return $row->id; })->all();
Создание модели из возвращаемы данных Command (с помощью populateRecord())
$sql = "SELECT * FROM `tbl_spares_category` c LEFT JOIN tbl_form_spares_category fc ON fc.category_id = c.id WHERE fc.form_id = :form_id AND fc.category_id = :category_id"; $select_marks = Yii::$app->db->createCommand($sql, [ ':form_id' => $form_id, ':category_id' => $category_id, ])->queryAll(); foreach($marks as $row){ // Only yii2 alpha //$mark = SparesCategoryForm::create($row); $mark = new SparesCategoryForm; SparesCategoryForm::populateRecord($mark, $row); if(isset($mark->id)){ // do somethig } }
- Activedataprovider - Pager / Генерация страниц
- SqlDataProvider - Pager / Генерация страниц
Подробно:
Relation
class Customer extends \yii\db\ActiveRecord { // public function getOrders() { return $this->hasMany(Order::className(), ['customer_id' => 'id']); } // public function getBigOrders($threshold = 100) { return $this->hasMany(Order::className(), ['customer_id' => 'id']) ->where('subtotal > :threshold', [':threshold' => $threshold]) ->orderBy('id'); } // Вытащить данные из таблицы модели Item, используя связи из таблицы tbl_order_item public function getItems() { // Получить данные через таблицу tbl_order_item return $this->hasMany(Item::className(), ['id' => 'item_id']) ->viaTable('tbl_order_item', ['order_id' => 'id']); } // public static function olderThan($query, $age = 30) { $query->andWhere('age > :age', [':age' => $age]); } }
$customer = Customer::find(1); $orders = $customer->orders; $orders = $customer->getBigOrders(200)->all(); $customers = Customer::find()->olderThan(50)->all();
$customer = Customer::find(1); $order = new Order(); $order->comment = ''; $customer->link('orders', $customer);
Events
class Post extends ActiveRecord { public function init() { $this->on('beforeAction', function($event) { // отменяем действие $event->isValid = false; }); } }
$component->on('beforeAction', $handler);
Components
Создание объекта компанента
$object = Yii::createObject(array( 'class' => 'MyClass', 'property1' => 'abc', 'property2' => 'cde', ), $param1, $param2);
Theme
'view' => array( 'theme' => array( 'pathMap' => array('@app/views' => '@wwwroot/themes/basic'), 'baseUrl' => '@www/themes/basic', ), ),
Form
Assets
Console
Module
Submodule
Для работы сабмодуля, необходимо выполнить его подключение, через указание submodule namespace модуля
namespace yii\user; class Module extends \yii\base\Module { // ... public function init() { // .. $this->setModule('admin', 'yii\user\modules\admin\Module'); } // Пример перенаправления роута в саб модуль admin public function createController($route) { return $this->getModule('admin')->createController($route); } }
Helpers
Behaviors/Filters
public function behaviors() { return array( 'access' => array( 'class' => 'yii\web\AccessControl', 'rules' => array( array('allow' => true, 'actions' => array('admin'), 'roles' => array('@')), array('allow' => false), ), ), ); }
Статьи
Локализация - i18N/intl
apt=get install php5-intl
Session
Yii::$app->session->get('key'); Yii::$app->session->set('key', 'value');
Cache
// Создать зависимость от времени модификации файла example.txt. $dependency = new \yii\caching\FileDependency(['fileName' => 'example.txt']); // Данные устаревают через 30 секунд. // Данные могут устареть и раньше, если example.txt будет изменён. $cache->set($key, $data, 30, $dependency); // Кэш будет проверен, если данные устарели. // Он также будет проверен, если указанная зависимость была изменена. // Вернется false, если какое-либо из этих условий выполнено. $data = $cache->get($key);
Зависимости
- yii\caching\ChainedDependency: зависимость меняется, если любая зависимость в цепочке изменяется;
- yii\caching\DbDependency: зависимость меняется, если результат некоторого определенного SQL запроса изменён;
- yii\caching\ExpressionDependency: зависимость меняется, если результат определенного PHP выражения изменён;
- yii\caching\FileDependency: зависимость меняется, если изменилось время последней модификации файла;
- yii\caching\TagDependency: Связывает кэшированные данные элемента с одним или несколькими тегами. Вы можете аннулировать кэширование данных элементов с заданным тегом(тегами) по вызову. invalidate();
Кэширование запросов
$result = $db->cache(function ($db) { // Результат SQL запроса будет возвращен из кэша если // кэширование запросов включено и результат запроса присутствует в кэше return $db->createCommand('SELECT * FROM customer WHERE id=1')->queryOne(); }); $result = Customer::getDb()->cache(function ($db) { return Customer::find()->where(['id' => 1])->one(); });
$duration = 60; // кэширование результата на 60 секунд $dependency = ...; // параметры зависимости $result = $db->cache(function ($db) { // ... выполнять SQL запросы здесь ... return $result; }, $duration, $dependency);
$result = $db->cache(function ($db) { // SQL запросы, которые используют кэширование $db->noCache(function ($db) { // SQL запросы, которые не используют кэширование }); // ... return $result; });
// использовать кэширование запросов и установить срок действия кэша на 60 секунд $customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->cache(60)->queryOne();
$result = $db->cache(function ($db) { // Используется кэширование SQL запросов // не использовать кэширование запросов для этой команды $customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->noCache()->queryOne(); // ... return $result; });