2

So, here is my scenario. I have got a model called URL. URL has the following attributes: link (required), scheme (required, but not safe.scheme is parsed from the link) and a few other attributes as well, which are not in context to this question.

Now, I made a custom validator for the scheme, which is following:

public function validateScheme($attribute, $param) {
    if(empty($this->scheme)){

        $this->addError('link', Yii::t('app', 'This is an invalid URL.'));

    }  
    if (!in_array($this->scheme, $this->allowedSchemes)) {
        $this->addError('link', Yii::t('app', 'This is an invalid URL.'));

    }
}

Rules for URL:

 public function rules() {
        return [
            ['link', 'required', 'message' => Yii::t('app', 'URL can\'t be blank.')],
            [['link'], 'safe'],
            [['link'], 'string'],
            ['scheme', 'validateScheme']
            ];
    }

This works fine when an invalid scheme is encountered, for example like let's say ftp.

However, when a completely invalid URL is entered, the scheme remains empty and the validateScheme is never triggered as, attribute scheme is not required. To verify, I called $model->validate() and it returns true even if it should not (or should may be, because the attribute is not required anyway).

So, my question number 2 : Is there a way to force the validateScheme be triggered no matter if the attribute is empty, or non empty? I do not seem to find a way to do this in documentation.

I then tried the other way around, and made scheme a required field. The problem with that is the fact that scheme field is not safe and not there in the form. So, the URL does not save, but no error is shown.

My question number 1, in that case would be: Is there a way to assign targetAttribute for scheme so that the error message is shown below link?

P.S. I know I can do this in the controller. I do not want to do that. I want to use the model only.

Gogol
  • 3,033
  • 4
  • 28
  • 57

2 Answers2

1

Another solution is, instead of having a default value, you could enable verify on empty (by default, it does not validate empty and not required fields). Something like this:

public function rules() {
    return [
        ['link', 'required', 'message' => Yii::t('app', 'URL can\'t be blank.')],
        [['link'], 'string'],
        ['scheme', 'validateScheme', 'skipOnEmpty' => false]
    ];
}

See more here.

Clyff
  • 4,046
  • 2
  • 17
  • 32
  • Yupp thanks man. Exactly what I was looking for. Not sure how I missed this one lol :) – Gogol Feb 07 '16 at 16:47
  • 1
    Sorry i forgot to mention.. you dont need to set `safe` if the field already have another rule. – Clyff Feb 07 '16 at 17:13
0

Okay, setting a default value in the rules() solved my problem. The modified rules():

public function rules() {
    return [
        ['link', 'required', 'message' => Yii::t('app', 'URL can\'t be blank.')],
        [['link'], 'safe'],
        [['link'], 'string'],
        ['scheme', 'default', 'value' => 0],
        ['scheme', 'validateScheme']
    ];
}
Gogol
  • 3,033
  • 4
  • 28
  • 57