Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
yii2:docs [2017/01/04 22:17] – [Статьи] mirocowyii2:docs [2019/04/18 13:17] (текущий) – [Active Record] mirocow
Строка 5: Строка 5:
 ===== Configuration ===== ===== Configuration =====
  
 +<code php>
 +<?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',
 +        ],
 +    ]
 +];
 +</code>
 ===== URL Management ===== ===== URL Management =====
  
Строка 14: Строка 43:
 echo \Yii::$app->urlManager->createAbsoluteUrl('blog/post/index'); echo \Yii::$app->urlManager->createAbsoluteUrl('blog/post/index');
 // http://www.example.com/index.php/blog/post/index/ // http://www.example.com/index.php/blog/post/index/
 +</code>
 +
 +<code php>
 +$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);
 </code> </code>
  
Строка 247: Строка 289:
       }).success(function(response) {       }).success(function(response) {
       });       });
 +</code>
 +
 +==== Form ====
 +
 +  * [[yii2:form|ActiveForm]]
 +  * [[yii2:form|HTML]]   
 +
 +**Подробно** https://github.com/yiisoft/yii2/blob/master/docs/guide/form.md
 +
 +===== Ajax =====
 +
 +  * [[yii2:Ajax|Active Form Ajax Validation]]
 +  * [[yii2:Ajax:select|Зависимый select от другого select'а]]
 +
 +==== Pjax ====
 +
 +<code php>
 +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;
 +    }
 +}  
 +</code>
 +
 +Вывод партиала в main.php
 +
 +<code php>
 +<?= $this->render('favorite', ['id' => 1, 'f_fav' => true);?>
 +</code>
 +
 +Отображаемая вьюха favorite.php
 +
 +<code 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(); ?>
 +</code>
 +
 +===== Виджеты / Widgets =====
 +
 +  * [[yii2:widgets:masked-input|]] - http://demos.krajee.com/masked-input
 +
 +===== Model / AR / DAO / Запросы к БД =====
 +
 +Как получить модель из модуля
 +
 +<code php>
 +        $user    = Yii::$app->getModule("user")->model("User", ["scenario" => "register"]);
 +        $profile = Yii::$app->getModule("user")->model("Profile");
 +</code>
 +
 +==== Active Record ====
 +
 +<code php>
 +class Post extends ActiveRecord
 +{
 +    public function getCreator()
 +    {
 +        return $this->hasOne('User', ['id' => 'user_id']);
 +    }
 +    public function getComments()
 +    {
 +        return $this->hasMany('Comment', ['post_id' => 'id']);
 +    }
 +    public function getTrustComments($isTrust = true)
 +    {
 +        return $this->hasMany('Comment', ['post_id' => 'id'])
 +            ->where('status = :status', [
 +                     ':status' => $isTrust ? self::TRUST : self::UNTRUST,
 +              ])
 +            ->orderBy('id');
 +    }
 +}
 +</code>
 +
 +<code php>
 +        $price = PriceItem::find()
 +            ->select(['price', 'create_time' => 'DATE_FORMAT(create_time, "%d.%m.%Y")'])
 +            ->where(['and', 
 +                ['price_list_form_id' => $price_list_form_ids], 
 +                ['>', 'create_time', '2015.01.01']
 +        ])->orderBy(['price' => SORT_ASC])->asArray()->one();
 +</code>
 +
 +<code php>
 +// 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(['id' => 10, 'status' => Post::READ])
 +   ->one();
 + 
 +// or easier: "where" condition can be transmitted directly to the factory method
 +$post = Post::find(['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(['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();
 +</code>
 +
 +<code php>
 +User::find()->where(['and', ['phone_number' => $phone], ['<>', 'id', $user->id] ])->exists();
 +User::find()->where(['or', ['phone_number' => $phone], ['=', 'id', $user->id] ])->exists();
 +</code>
 +
 +=== Ключи в эллементах коллекции AR ===
 +
 +<code php>
 +$query = SparesCategory::find()->where(['parent_id' => 0]);
 +$query->indexBy = function($row){ // Ключ в который будет помещена возвращаемая модель
 +    return $row->id;
 +};
 +$categories = $query->all();
 +</code>
 +
 +<code php>
 +        $quey = CarMark::find()->indexBy(function($row){
 +            return $row->id;
 +        })->all();
 +</code>
 +
 +=== Создание модели из возвращаемы данных Command (с помощью populateRecord()) ===
 +
 +<code php>
 +        $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
 +  
 +            }
 +        }
 +</code>
 +
 +  * [[Activedataprovider|Activedataprovider]]
 +  * [[SqlDataProvider|SqlDataProvider]]
 +  * [[ArrayDataProvider|ArrayDataProvider]]
 +==== Join ====
 +
 +=== with() ===
 +
 +Не делает SQL JOIN(), применяется не только в реляционых БД (NoSql)
 +Применяется только для построений конструкций вида **WHERE IN()**, плюс наполняют [[yii2:start#relation|relation]]
 +
 +=== leftJoin() ===
 +
 +Добавляет SQL LEFT JOIN(), применяется только в реляционыых БД, плюс наполняют [[yii2:start#relation|relation]]
 +
 +<code php>
 +$this->joinWith([[relation_name]], true, 'LEFT JOIN')
 +</code>
 +
 +=== joinWith() ===
 +
 +Добавляет SQL JOIN(), применяется только в реляционыых БД, плюс наполняют [[yii2:start#relation|relation]]
 +
 +<code php>
 +// Выбираем 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();
 +</code>
 +
 +https://github.com/yiisoft/yii2/blob/master/docs/guide/active-record.md#joining-with-relations
 +
 +=== innerJoinWith() ===
 +
 +==== Validate (Rules) ====
 +
 +<code php>
 +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',
 +                    // ...
 +                  ],
 +                  [
 +                    ['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
 +                    'except' => ['scenario1', 'scenario2', ...],
 +                    // the following name-value pairs will be used
 +                    // to initialize the validator properties
 +                    'property1' => 'value1',
 +                    'property2' => 'value2',
 +                    // ...
 +                  ],          
 +              ];
 +    }
 + 
 +}
 +</code>
 +
 +Пример использования в модели
 +<code php>
 +  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
 +      }
 +  }
 +</code>
 +
 +Пример применения валидатора без использования модели
 +<code php>
 +$email = 'test@example.com';
 +$validator = new yii\validators\EmailValidator();
 +if ($validator->validate($email, $error)) {
 +    echo 'Email is valid.';
 +} else {
 +    echo $error;
 +}
 +</code>
 +
 +  * **Подробно** https://github.com/yiisoft/yii2/blob/master/docs/guide/model.md
 +  * **Список базовых валидаторов:** https://github.com/yiisoft/yii2/blob/master/docs/guide/validation.md
 +
 +==== Scenario ====
 +
 +<code php>
 +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
 +        }
 +    }
 +}
 +</code>
 +
 +**Подробно** https://github.com/yiisoft/yii2/blob/master/docs/guide/structure-models.md#scenarios-
 +
 +==== Relation ====
 +
 +<code php>
 +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]);
 +    }
 +}
 +</code>
 +
 +<code php>
 +$customer = Customer::find(1);
 +$orders = $customer->orders;
 +$orders = $customer->getBigOrders(200)->all();
 +$customers = Customer::find()->olderThan(50)->all();
 +</code>
 +
 +<code php>
 +$customer = Customer::find(1);
 +$order = new Order();
 +$order->comment = '';
 +$customer->link('orders', $customer);
 +</code>
 +
 +==== Events ====
 +
 +<code php>
 +class Post extends ActiveRecord
 +{
 +  public function init()
 +  {
 +    $this->on('beforeAction', function($event) {
 +      // отменяем действие
 +      $event->isValid = false;
 +    });
 +  }
 +}
 +</code>
 +
 +<code php>
 +$component->on('beforeAction', $handler);
 +</code>
 +==== Как получить SQL и Параметры из ActiveQuery ====
 +
 +<code php>
 +$query = Post::find()->where(array('id' => 10, 'status' => Post::READ))->createCommand();
 +
 +// SQL
 +echo $query->sql
 +
 +// Params:
 +print_r($query->params)  
 +</code>
 +==== Объекты доступа к данным (Data Access Objects, DAO) ====
 +
 +=== Соеденение ===
 +
 +<code php>
 +$connection = \Yii::$app->db;
 +</code>
 +
 +**Подробно** 
 +
 +  * https://github.com/yiisoft/yii2/blob/master/docs/guide/database-basics.md
 +
 +=== Методы запроса ===
 +
 +  * queryOne()
 +  * queryAll()
 +  * query()
 +  * queryScalar()
 +  * queryColumn()
 +
 +**Подробно**  https://github.com/yiisoft/yii2/blob/master/framework/db/Command.php
 +
 +== createCommand ==
 +
 +<code php>
 +$command = $connection->createCommand('SELECT * FROM tbl_post WHERE id=1');
 +$post = $command->queryOne();
 +</code>
 +
 +<code php>
 +$connection->createCommand()->insert('tbl_user', [
 +    'name' => 'Sam',
 +    'age' => 30,
 +])->execute();
 +</code>
 +
 +<code php>
 +$command = $connection->createCommand('UPDATE tbl_post SET status=1 WHERE id=1');
 +$command->execute();
 +</code>
 +
 +<code php>
 +$connection->createCommand()->batchInsert('tbl_user', ['name', 'age'], [
 +    ['Tom', 30],
 +    ['Jane', 20],
 +    ['Linda', 25],
 +])->execute();
 +</code>
 +
 +<code php>
 +$connection->createCommand()->update('tbl_user', ['status' => 1], 'age > 30')->execute();
 +</code>
 +
 +<code php>
 +$connection->createCommand()->delete('tbl_user', 'status = 0')->execute();
 +</code>
 +
 +<code php>
 +$command = $connection->createCommand('SELECT * FROM tbl_post WHERE id=:id');
 +$command->bindValue(':id', $_GET['id']);
 +$post = $command->query();
 +</code>
 +
 +==== Построитель запросов (Query Builder and Query) ====
 +
 +<code php>
 +$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();
 +</code>
 +
 +<code php>
 +$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();
 +</code>
 +
 +Простой спооб получить записи из указанной БД
 +
 +<code php>
 +$rows = (new \yii\db\Query())
 +    ->select('id, name')
 +    ->from('user')
 +    //->where([...])
 +    //->innerJoin('', '', [...])
 +    ->limit(10)
 +    ->createComand(Yii::$app->some_bd)
 +    ->queryAll();
 +</code>
 +
 +**Подробно** 
 +
 +  * https://github.com/yiisoft/yii2/blob/master/docs/guide/db-query-builder.md
 +
 +==== Transactions ====
 +
 +<code php>
 +$transaction = $connection->beginTransaction();
 +try {
 +    $connection->createCommand($sql1)->execute();
 +    $connection->createCommand($sql2)->execute();
 +    // ... executing other SQL statements ...
 +    $transaction->commit();
 +} catch(Exception $e) {
 +    $transaction->rollback();
 +}
 +</code>
 +
 +==== Batch ====
 +
 +=== Batch ===
 +
 +
 +<code php>
 +foreach (Customer::find()->batch() as $customers) {
 +
 +}
 +
 +foreach (Customer::find()->batch(10) as $customers) {
 +    // $customers — массив из 10 или менее объектов Customer
 +}
 +</code>
 +
 +<code php>
 +$rows = [];
 +
 +foreach ($models as $model) {
 +    if (!$model->validate()) {
 +        // At least one model has invalid data
 +
 +        break;
 +    }
 +
 +    $rows[] = $model->attributes;
 +}
 +$rows =  \yii\helpers\ArrayHelper::getColumn($models, 'attributes;');
 +$postModel = new Post;
 +
 +Yii::$app->db->createCommand()->batchInsert(Post::tableName(), $postModel->attributes(), $rows)->execute();
 +</code>
 +
 +=== Each ===
 +
 +<code php>
 +foreach (Customer::find()->each() as $customers) {
 +
 +}
 +
 +foreach (Customer::find()->each(10) as $customers) {
 +    // $customers — массив из 10 или менее объектов Customer
 +}
 </code> </code>
  
Строка 268: Строка 911:
 **Подробно** https://github.com/yiisoft/yii2/blob/master/docs/guide/url.md **Подробно** https://github.com/yiisoft/yii2/blob/master/docs/guide/url.md
  
 +===== Module =====
 +
 +==== Submodule ====
 +
 +Для работы сабмодуля, необходимо выполнить его подключение, через указание submodule namespace модуля
 +<code php>
 +namespace mirocow\eav;
 +
 +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(str_replace('admin/','',$route));
 +      
 +    }  
 +  
 +}
 +</code>
 +
 +==== Helpers ====
 +
 +  * https://github.com/yiisoft/yii2/blob/master/docs/guide/security.md
 +
 +==== Behaviors/Filters ====
 +
 +<code php>
 +public function behaviors()
 +{
 +  return array(
 +    'access' => array(
 +      'class' => 'yii\web\AccessControl',
 +      'rules' => array(
 +        array('allow' => true, 'actions' => array('admin'), 'roles' => array('@')),
 +        array('allow' => false),
 +      ),
 +    ),
 +  );
 +}
 +</code>
 +
 +==== Behaviors/Date ====
 +
 +<code php>
 +public function behaviors() {
 +  return [
 +    [
 +      'class' => TimestampBehavior::className(),
 +      'createdAtAttribute' => 'create_time',
 +      //'updatedAtAttribute' => 'update_time',
 +      'value' => new Expression('NOW()'),
 +    ],
 +  ];
 +}
 +</code>
 ===== Session ===== ===== Session =====
  
Строка 326: Строка 1032:
    //    //
  }  }
 +</code>
 +
 +==== Params / Параметры ====
 +
 +<code php>
 +<?php
 +
 +namespace console\controllers;
 +
 +use yii\console\Controller;
 +
 +class QueueController extends Controller
 +{
 +    public $pid_file = '';
 +
 +    public function __get($name)
 +    {
 +        $name = str_replace('-', '_', $name);
 +
 +        return $this->$name;
 +    }
 +
 +    public function __set($name, $value)
 +    {
 +        $name = str_replace('-', '_', $name);
 +
 +        $this->$name = $value;
 +    }
 +
 +
 +    public function options($actionID)
 +    {
 +        return ['pid-file'];
 +    }
 +
 +    public function actionRun()
 +    {
 +
 +    }
 +}
 +</code>
 +
 +
 +===== User =====
 +
 +==== RBAC ====
 +
 +  * [[yii2:user:rbac|RBAC]]
 +
 +**Подробно** https://github.com/yiisoft/yii2/blob/master/docs/guide/authorization.md
 +
 +==== Access ====
 +
 +<code php>
 +    '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;                    
 +                            }
 +                    ],
 +            ],
 +    ],  
 +</code>
 +
 +
 +===== Components =====
 +
 +Создание объекта компанента
 +<code php>
 +$object = Yii::createObject(array(
 +    'class' => 'MyClass',
 +    'property1' => 'abc',
 +    'property2' => 'cde',
 +), $param1, $param2);
 +</code>
 +
 +===== Theme =====
 +
 +<code php>
 +'view' => array(
 +    'theme' => array(
 +        'pathMap' => array('@app/views' => '@webroot/themes/basic'),
 +        'baseUrl' => '@www/themes/basic',
 +    ),
 +),
 </code> </code>
  
Строка 421: Строка 1221:
   apt=get install php5-intl   apt=get install php5-intl
  
-===== Статьи =====+==== Перевод (локализация проекта) ==== 
 + 
 +  * https://github.com/lajax/yii2-translate-manager 
 + 
 +===== PHPUnit ===== 
 + 
 +добавить в конфигуратор композера composer.json 
 +<code> 
 +
 +    "require-dev":
 +        "phpunit/phpunit": "3.7.*" 
 +    } 
 +
 +</code> 
 + 
 +    * php composer.phar update 
 +    * php vendor/bin/phpunit vendor/yiisoft/yii2/yii/test/ 
 + 
 +====== Статьи ======
  
   * https://github.com/yiisoft/yii2/blob/master/docs/guide-ru/caching-data.md   * https://github.com/yiisoft/yii2/blob/master/docs/guide-ru/caching-data.md
Строка 427: Строка 1245:
   * http://habrahabr.ru/post/208328/   * http://habrahabr.ru/post/208328/
  
-===== Описание =====+====== Описание ======
  
   * https://github.com/yiisoft/yii2/blob/master/docs/guide/i18n.md#advanced-placeholder-formatting   * https://github.com/yiisoft/yii2/blob/master/docs/guide/i18n.md#advanced-placeholder-formatting