Yii2 валидация полей по определенным сценариям

В Yii2 есть возможность добавления сценариев в модели, например для create() и update(). В этой записи, я покажу как создать сценарий и использовать одну и туже модель для валидации одной и той же формы в нескольких местах.

Где это может пригодиться?

Например, вы используете Yii2 advanced шаблон для разработки веб-приложения у которого должен быть админ центр для управления тем, что добавляют пользователя из frontend.

Представим, что вы хотите добавить возможность создания блог-записей на стороне обычного пользователя (frontend) и администратора (backend). Но скорее всего в backend будет больше полей для добавления, так как администратор должен иметь возможность добавлять и изменять все что угодно.

Если не использовать сценарии для модели, то в таком случае должно использоваться две модели. Одна в backend/models, а другая в frontend/models.

Но зачем себе утруждать жизнь, если можно создать сценарии и использовать одну модель, которая будет находиться в common/models. Удобно, не правда ли?

Создаем ActiveRecord модель и правила

Создали обычную модель, назвали её Post, она использовать методы из ActiveRecord, которая в свою очередь помогает работать с базой данных.

С помощью метода tableName() указываем название таблицы для этого класса, в нашем случае — это posts.

Далее указываем правила для модели с помощью метода rules() и метод authorExists() помогает проверить существует id автора в таблице пользователей.

В принципе, обычная модель, ничего сложного.

<?php

namespace common\models;

use yii\db\ActiveRecord;
use common\models\User;

/**
 * This is the Post model
 */
class Post extends ActiveRecord
{

    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'posts';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            ['image', 'safe'],

            [['post_title', 'post_body', 'author_id'], 'required'],

            [['post_title', 'type'], 'string', 'max' => 80],
            [['post_body'], 'string', 'max' => 3000],

            [['author_id'], 'integer'],

            ['author_id', 'authorExists']

        ];
    }

    /**
     * Проверка на существование пользователь по User модели
     * @return  mixed
     */
    public function authorExists($attribute, $params) {
        if( !$this->hasErrors() ) {
            $userExists = User::find()->where(['id' => $this->author_id])->exists();

            if( !$userExists ) {
                $this->addError($attribute, 'Ошибка, такого пользователя не существует.');
            }
        }
    }
}

Создаем сценарий

Теперь давайте разберемся со сценариями.

Сценарии я обозначил с помощью const, они идут как правило самыми первыми, перед всеми методами и значениями модели.

Название может быть любое, но лучше всего начинать с SCENARIO_ и далее само название.

И конечно же нужно перезаписать метод scenarios(), внутри которого мы добавили два новых значения — SCENARIO_ADMIN и SCENARIO_USER.

SCENARIO_ADMIN будет использоваться в админке, а SCENARIO_USER для обычного пользователя.

Разница в том, чтобы при создании поста, обычный пользователь не может изменить id автора, потому что это значение будет поставлено за него исходя из значения текущий сессии, которая храниться в Yii::$app->user->identity. (если конечно вы это используете, а лучше это делать :)).

Админ будет иметь возможность изменить автора поста, потому что теперь вы можете изменить сценарий и тем самым валидация полей будет происходит по разным правилам.

Теперь давайте посмотрим, что изменилось в классе после добавления всего что описано выше.

<?php

namespace common\models;

use yii\db\ActiveRecord;
use common\models\User;

/**
 * This is the Post model
 */
class Post extends ActiveRecord
{
    const SCENARIO_ADMIN = 'admin';
    const SCENARIO_USER = 'user';

    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'posts';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            ['image', 'safe'],

            [['post_title', 'post_body', 'author_id'], 'required'],


            [['post_title', 'type'], 'string', 'max' => 80],
            [['post_body'], 'string', 'max' => 3000],

            [['author_id'], 'integer'],

            ['author_id', 'authorExists']

        ];
    }


    /**
     * Сценарии
     * @return array
     */
    public function scenarios()
    {

        $scenarios = parent::scenarios();

        $scenarios[static::SCENARIO_ADMIN] = ['post_title', 'post_body', 'author_id'];
        $scenarios[static::SCENARIO_USER] = ['post_title', 'post_body'];

        return $scenarios;
    }

    /**
     * Проверка на существование пользователь по User модели
     * @return  mixed
     */
    public function authorExists($attribute, $params) {
        if( !$this->hasErrors() ) {
            $userExists = User::find()->where(['id' => $this->author_id])->exists();

            if( !$userExists ) {
                $this->addError($attribute, 'Ошибка, такого пользователя не существует.');
            }
        }
    }
}

Хочу еще обратить внимание на scenarios()

В этой сценарии вы не полностью перезаписываем его, потому что там есть SCENARIO_DEFAULT, который используется как стандартный для валидации всех правил модели.

И чтобы его не сносить, вы используем parent::scenarios(), то вызываем стандартный сценарий из ActiveRecord и уже к нему добавляем новые.

Для наглядности, я вытащил этот метод из класса выше, чтобы вы могли посмотреть на этой еще раз:

/**
 * Сценарии
 * @return array
 */
public function scenarios()
{

    $scenarios = parent::scenarios();

    $scenarios[static::SCENARIO_ADMIN] = ['post_title', 'post_body', 'author_id'];
    $scenarios[static::SCENARIO_USER] = ['post_title', 'post_body'];

    return $scenarios;
}

Как использовать сценарии в action’ах

Для создания нового поста, в action create вы можете добавить сценарий с помощью конструктора, то есть в следующей форме: new Post(['scenario' => Post::SCENARIO_USER]).

Если вы изменяете пост, то это так же можно сделать добавив параметр $model->scenario = Post::SCENARIO_USER.

Пример кода контроллера (controller) ниже:

<?php 

use yii\web\Controller; 

PostController extends Controller  {


  ...

  public function actionCreate() {
    $model = new Post(['scenario' => Post::SCENARIO_USER]);

    ... 
  }

  ...

  public function actionUpdate($id) {
    $model = $this->findModel($id);

    $model->scenario = Post::SCENARIO_USER;

    ...
  }

  protected function findModel($id)
  {
      if (($model = Post::findOne($id)) !== null) {
          return $model;
      } else {
          throw new NotFoundHttpException('Запрашиваемая страница не найдена');
      }
  }
}

 

https://stackoverflow.com/questions/30886437/yii2-required-validation-on-update

Сделать поле в нижнем регистре в Yii2

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

Sass цвета: используем функции помощники

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

Как в WordPress отключить комментарии?

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

Читать далее…

WordPress отключить плагин без админ центра

Иногда разработчики плагинов безответственно относятся к качеству написания кода и в итоговом продукте имеется масса багов. В этой записи, я покажу как в WordPress отключить плагин без доступа к админ центру. Я рассмотрю два способа — используя FTP и базу данных. 
Читать далее…

wget скачать все картинки сайта

Любому разработчику в определенный момент может понадобиться скачать все картинки с сайта по определенной ссылке. С wget скачать сайт или его части (наример, картинки, стили и т.д.) не составить проблемы. В этой записи, я покажу как скачать все картинки с сайта, а также как исправить возможные ошибки.
Читать далее…

WooCommerce: проверить если продукт/товар на распродаже

WooCommerce безумно вырос за последнее время и на текущий момент, многие дают предпочтение именно ему из всех, даже платных конкурентов. Если вы, как разработчик разберетесь в API этого плагина, тогда вам добавиться жирный плюс в резюме, потому что заказы связанные с ним будут появляться все чаще и чаще. Конкретно в этой записи я хочу рассмотреть то, как определить находится товар или продукт на распродаже или нет. 
Читать далее…

Старые записи »