0

Rules in Yii2 models look like this:

[
    // checks if "level" is 1, 2 or 3
    ['level', 'in', 'range' => [1, 2, 3]],
]

Wouldn't it be better if they were objects like this?

[
  new RangeRule('level', [1, 2, 3])
]
Olle Härstedt
  • 3,799
  • 1
  • 24
  • 57
  • 1
    For performance optimization I guess. – Bizley Feb 07 '17 at 13:56
  • AFAIK, the performance difference is very minor between arrays and objects. – Olle Härstedt Feb 07 '17 at 14:01
  • See http://stackoverflow.com/questions/2193049/php-objects-vs-arrays and https://gist.github.com/Thinkscape/1136563 - PHP is getting better at array optimization with every version. – Bizley Feb 07 '17 at 14:06
  • 1
    Those benchmarks are still old. One for PHP 7 is needed, I think. – Olle Härstedt Feb 07 '17 at 14:15
  • Scroll second link to bottom. I see my examples are showing totally oposite - objects are better. So maybe they use array because it's more convenient. – Bizley Feb 07 '17 at 14:24
  • I think the readability is much worse in current way. Using objects would improve upon that. – Olle Härstedt Feb 07 '17 at 14:45
  • Simply because with this design, rules are created only when needed ! – soju Feb 07 '17 at 16:29
  • @soju The arrays are still created. How is that better than creating an object? – Olle Härstedt Feb 07 '17 at 16:31
  • Because you don't have to load the class file... And using array is handy, take a look at the code in accepted answer... – soju Feb 07 '17 at 20:08
  • 1
    Loading the class file is only done once. I think the arrays make the rules much harder to read, but if it's possible to use the objects instead if you want to, then no problem. – Olle Härstedt Feb 08 '17 at 09:09
  • @OlleHärstedt Moreover, prepared Validator object ensures more short "execution way", because mentioned assoc arrays will be "parsed", then will be normalized and will be used for creating the similar Validator objects. – IStranger Feb 08 '17 at 14:54

1 Answers1

1

You can use validator objects like this:

use yii\validators\Validator;
use yii\validators\NumberValidator;
use yii\validators\StringValidator;

class TestModel extends \yii\base\Model
{
    public $firstProperty;
    public $secondProperty;

    public function rules()
    {
        return [
            new NumberValidator(['attributes' => ['firstProperty'], 'integerOnly' => true, 'min' => 0, 'max' => 100]),
            new StringValidator(['attributes' => ['secondProperty'], 'max' => 5]),
        ];
    }
}

Moreover, you can decorate these objects as you want (using additional classes and methods):

class TestModel extends \yii\base\Model
{
    public $firstProperty;
    public $secondProperty;

    public function rules()
    {
        // Prepare Int validator
        $validatorInt              = new NumberValidator();
        $validatorInt->integerOnly = true;
        $validatorInt->min         = 0;
        $validatorInt->max         = 100;

        // Prepare String validator
        $validatorString      = new StringValidator();
        $validatorString->max = 5;

        // Make rules
        return [
            static::_makeRule(['firstProperty'], $validatorInt),
            static::_makeRule(['secondProperty'], $validatorString),
        ];
    }

    protected function _makeRule($attrName, Validator $validatorObj)
    {
        $validatorObj = clone $validatorObj;

        $validatorObj->attributes = (array)$attrName;

        $validatorObj->init();                          // Initializes validator and normalizes values

        return $validatorObj;
    }

}
IStranger
  • 1,868
  • 15
  • 23