1

I have model form (SomeForm) and custom validation function in there:

use yii\base\Model; 
class SomeForm extends Model
{
      public $age;
      public function custom_validation($attribute, $params){
             if($this->age < 18){
                    $this->addError($attribute, 'Some error Text');
                    return true;
             }
             else{
                     return false;
             }
      }
      public function rules(){
             return [
                 ['age', 'custom_validation']
             ];
      }
}

I use this custom_validation in rules() function but form even submitting whatever value has age attribute.

Here is the form:

age.php

<?php $form = ActiveForm::begin(); ?>
    <?= $form->field($model, 'age')->label("Age") ?>
    <div class="form-group">
        <?= Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?>
    </div>
    <?php ActiveForm::end(); ?>

and the controller:

use yii\web\Controller;

class SomeController extends Controller
{
     //this controller is just for rendering
     public function actionIndex(){
             return $this->render('age');
     }
     public function actionSubmit(){
             $model = new SomeForm();
             if($model->load(Yii::$app->request->post()){
                   //do something here
             }
     }
}
godot
  • 3,422
  • 6
  • 25
  • 42

1 Answers1

4

You don't need to return anything just adding the error to the attribute is enough.

Since version 2.0.11 you can use yii\validators\InlineValidator::addError() for adding errors instead of using $this. That way the error message can be formatted using yii\i18n\I18N::format() right away.

Use {attribute} and {value} in the error message to refer to an attribute label (no need to get it manually) and attribute value accordingly:

What I suspect is the problem in your case is that you are missing the $formModel->validate() as in the model given above extends the yii\base\Model and not \yii\db\ActiveRecord and you must be saving some other ActiveRecord model and want to validate this FormModel before saving the ActiveRecord model, you have to call the $formModel->validate() to check if valid input is provided and trigger the model validation after loading the post array to the model.

And another thing to notice is by default, inline validators will not be applied if their associated attributes receive empty inputs or if they have already failed some validation rules. If you want to make sure a rule is always applied, you may configure the skipOnEmpty and/or skipOnError properties to be false in the rule declarations.

Your model should look like below you are missing the namespace in your model definition if that is not just intentional or due to sample code. just update you namespace according to the path where it is.

namespace frontend\models;

use yii\base\Model; 
class SomeForm extends Model
{
      public $age;
      const AGE_LIMIT=18;

      public function rules(){
             return [
                 ['age', 'custom_validation','skipOnEmpty' => false, 'skipOnError' => false]
             ];
      }

      public function custom_validation($attribute, $params,$validator){
          if($this->$attribute< self::AGE_LIMIT){
             $validator->addError($this, $attribute, 'The value "{value}" is not acceptable for {attribute}, should be greater than '.self::AGE_LIMIT.'.');
           }
      }
}

your controller/action should look like

public function actionTest()
    {
        //use appropriate namespace
        $formModel = new \frontend\models\SomeForm();
        $model= new \frontend\models\SomeActiveRecordModel();

        if ($formModel->load(Yii::$app->request->post()) && $model->load(Yii::$app->request->post())) {
            if ($formModel->validate()) {
             // your code after validation to save other ActiveRecord model
             if($model->save()){
              Yii::$app->session->setFlash('success','Record added succesfully.')
             }
            }
        }

        return $this->render('test', ['model' => $model,'formModel'=>$formModel]);
    }

The Input field age in the view file should use the $formMoedl object

echo $form->field($formModel, 'age')->textInput();
Muhammad Omer Aslam
  • 22,976
  • 9
  • 42
  • 68
  • 1
    I have one more question how can I validate with jquery? When I tried your solution it regularly submits data and page reloads. If you can answer shortly please write here and if not I'll add new question about jquery validation – godot Feb 05 '18 at 13:27
  • that would be a separate topic i think you should add a post and leave a link here i will guide you through how to make it work with frontend `ClientValidation` of the form i hope you are talking about validating the input on the fly and showing the error message? like it does with any default `yii2` form. @Godot – Muhammad Omer Aslam Feb 05 '18 at 13:30
  • Yes I mean exactly this – godot Feb 05 '18 at 13:32
  • no issue just add a question and leave a link here just make sure you provide all the code relevant to the topic like `ActiveForm` and `Model` and should be exact code rather than example code. – Muhammad Omer Aslam Feb 05 '18 at 13:33
  • so will I ask new question about jquery validating? – godot Feb 05 '18 at 13:34
  • question should be something like using custom validators with activeform or anything just add proper description and the tags that are relevant I am not on my seat at the moment will read your post as soon I reach – Muhammad Omer Aslam Feb 05 '18 at 13:39