Built-In Validators' Initialization And Performance

Dear all!

Working on administrative section of a site I intensively used built-in CRangeValidator to check whether data provided by administrator lays within valid range of values. To be more precise, I check whether foreign keys’ values being inserted into MySQL InnoDB table will not affect successful SQL query execution. It looks like this in rules() method of a model:


array(

    "init_node_id", "in",

    'on' => array("edit"),

    'range' => array_keys(Node::getNodeHierarchySelectOptions(array(

        'projectId' => intval($this->id),

        'updateCache' => true,

        'slidesOnly' => true,

        'full' => false

    ))),

    'message' => Yii::t("admin", "Field must be in allowed values' range.")

),

Profiling database queries I just see that the behavior is not the one I wanted.

  1. In CModel class all possible validators are created at once by createValidators() method even if they will not be used in current scenario. In my case Node::getNodeHierarchySelectOptions method to get a valid range deals with database executing not-cached queries to get relevant entries. This affects a performance but is acceptable price for rare administrative validations. Unfortunately, Node::getNodeHierarchySelectOptions will be invoked any time somebody uses the model for any another purpose (i.e. for searching).

  2. I want SQL queries to get valid foreign keys and to insert new row in a table with save() method being executed within a single transaction so it would be perfect if each validation rule initialized just before calling it to validate an attribute but I can see that the current implementation with a single rules() method doesn’t allow it.

I know that I can create a custom model method to validate an attribute but this way CRangeValidator (and maybe some other validators) remains useful only for simple cases when properties used to initialize a validator are predefined and can’t be changed in time.

That’s why I start this to topic to discuss a possibility to introduce some changes in further Yii releases that will help to improve built-in validators and allow them to be used in cases described above.

Validators are used to validate the user input… validation can be done by ajax too… so you cannot put in one transaction the validation and saving… the only way to get that in one transaction is for you to validate manually that value just before saving.

Also

You are using a wrong validator here… instead of checking that the input value is in range of all the related table PKs… you need to check if the input value is there… for that you can use the CExistValidator - http://www.yiiframework.com/doc/api/1.1/CExistValidator

Good time of a day, Maurizio.

You are right, I forgot to take ajax validation and client validation (using JavaScript) into consideration. But these types of validation are both for client-side validation providing fast and user-friendly way to validate input fields without need of reloading a page, aren’t they? They can’t prevent a generation of some $_GET or $_POST data that we don’t want to see in our database and pass them to a script that saves data only but doesn’t validate it. Taking this in mind I will always perform a validation of active record just before saving calling its save() method with runValidation parameter set to true. So I can easily wrap it by a transaction.

Also, as I can see, the difference between usual and ajax PHP validation is nothing more than executing two similar validation scripts in two separate requests. That’s why I can’t find out any reason preventing PHP initialization of only those validators that are required for specified scenario just before the actual validation. What’s the need to initialize all other validators that you don’t use in current scenario?

Thank you so much for pointing at CExistValidator but I was a little bit inaccurate telling that it’s enough to have a value that corresponds to existing foreign key. In real a method to get a list of valid values is more complex, depends on few dynamic conditions and consists of more than a single database query so not all foreign keys are supposed to be valid.