Правило валидации, требующее выбора как минимум двух вариантов

У меня есть следующее правило проверки:

['dagen_ids', 'required', 'message' => 'Selecteer.', 'when' => function($model) {
    return $model->frequentie == 2;
}]

Атрибут dagen_ids массив, который заполняется виджетом Select2 (множественный выбор)

Чего я должен достичь, так это иметь правило валидации, которое требуется только тогда, когда $model->frequentie == 2и когда это так, пользователь должен выбрать как минимум 2 варианта.

Для второй части я попробовал следующий встроенный код проверки, но, к сожалению, он не дает никакого эффекта.

['dagen_ids', function ($attribute, $params) {
    if (count($this->$attribute) < 2) {
        $this->addError($attribute, 'Selecteer minimaal 2 dagen.');
    }
}]

Может ли кто-нибудь помочь мне немного дальше и объяснить, как объединить эти правила проверки?

РЕДАКТИРОВАТЬ

контроллер:

public function actionView($id) 
{
    $planning = $this->findModel($id);
    $post = Yii::$app->request->post();

    if (Yii::$app->request->isAjax && $planning->load($post) && $planning->validate() && $planning->save()) {
            Yii::$app->session->setFlash('success', [
                'type' => 'success',
                'duration' => 10000,
                'icon' => 'fa fa-check',
                'message' => 'Opdracht is succesvol bijgewerkt.'.Html::button(Icon::show('hand-o-right', ['class' => ''], Icon::FA). Yii::t('app', 'View'), ['class' => 'btn btn-sm btn-success modalButton pull-right', 'data-notify' => 'dismiss', 'data-content' => Url::to(['planning/view', 'id' => $id])]),
                'title' =>  Html::tag('span', 'Opdracht bijgewerkt', ['style' => 'font-weight: bold;']),
                'positonY' => 'top',
                'positonX' => 'right'
            ]);
    }
    else {
        return $this->renderAjax('view', ['planning' => $planning]); 
    }
}

JQuery:

$('body').on('beforeSubmit', 'form#view_form', function () {

    var form = $(this);
    // return false if form still have some validation errors
    if (form.find('.has-error').length) {
        return false;
    }

    // submit form
    $.ajax({
        url: form.attr('action'),
        data: form.serialize(),
        type: 'post'
    }).done(function(){
        $('.modal').modal('hide');
        console.log('Form send!');
        $.pjax.reload({
            container: '#planner_grid', 
            timeout: 10000, 
            replace: false
        });
    }).fail(function(){
        console.log('Server error...');
    }); 

    return false;
});

2 ответа

Цитата из исчерпывающего руководства по Yii 2.0: проверка ввода - встроенные валидаторы:

Примечание: по умолчанию встроенные валидаторы не будут применяться, если их связанные атрибуты получают пустые входные данные или если они уже не прошли некоторые правила валидации. Если вы хотите убедиться, что правило всегда применяется, вы можете настроить свойства skipOnEmpty и / или skipOnError на false в объявлениях правил.

Поэтому вам может потребоваться добавить эти 2 свойства в false, и вы также можете изменить свое условие, чтобы оно проверяло значение на frequentie:

['dagen_ids', function ($attribute, $params) {
    if ($this->frequentie == 2 && count($this->$attribute) < 2) {
        $this->addError($attribute, 'Selecteer minimaal 2 dagen.');
    }
}, 'skipOnEmpty' => false, 'skipOnError' => false]

Таким образом, вам не нужно иметь 2 разных правила проверки.

Наконец-то разобрался..

В этом случае с встроенным / автономным валидатором мне понадобилась проверка Ajax.

Я использую плагин DetailView, и он выглядит так:

echo DetailView::widget([
    'model' => $planning,
    'attributes' => $attributes,
    'mode' => 'view',
    'panel' => [
        'heading' => $planning->stopTitel, 
        'type' => DetailView::TYPE_PRIMARY,
    ],
    'bordered' => false,
    'responsive' => true,
    'hover' => true,
    'fadeDelay'=> 800,
    'deleteOptions' => [
        'params' => ['id' => $planning->planning_id, 'delete' => true],
        'url' => ['delete']
    ],
    'container' => ['id' => 'opdracht-bewerken'],
    'formOptions' => ['id' => 'view_form', 'action' => Url::current(['#' => 'opdracht-bewerken']), 'validationUrl' => Url::toRoute(['validate-form']), 'enableClientValidation' => true, /*'enableAjaxValidation' => true*/], // If you want Ajax validation on the whole form, uncomment this.
]);

Но я хочу, чтобы только одно поле было проверено Ajax, поэтому в моем случае мне нужно было добавить следующее к моему dagen_ids поле:

'fieldConfig' => ['enableAjaxValidation' => true] ( Документация)

Мои контроллеры выглядят так:

use yii\web\Response;
use yii\helpers\Json;
use kartik\widgets\ActiveForm;

    public function actionView($id) 
    {
        $planning = $this->findModel($id);
        $post = Yii::$app->request->post();

        if ($planning->load($post) && $planning->save()) {
            Yii::$app->session->setFlash('success', [
                'type' => 'success',
                'duration' => 10000,
                'icon' => 'fa fa-check',
                'message' => 'Opdracht is succesvol bijgewerkt.'.Html::button(Icon::show('hand-o-right', ['class' => ''], Icon::FA). Yii::t('app', 'View'), ['class' => 'btn btn-sm btn-success modalButton pull-right', 'data-notify' => 'dismiss', 'data-content' => Url::to(['planning/view', 'id' => $id])]),
                'title' =>  Html::tag('span', 'Opdracht bijgewerkt', ['style' => 'font-weight: bold;']),
                'positonY' => 'top',
                'positonX' => 'right'
            ]);
        }
        else {
            return $this->renderAjax('view', ['planning' => $planning]); 
        }
    }

    public function actionValidateForm() {
        Yii::$app->response->format = Response::FORMAT_JSON;

        $planning = new Planning();
        $post = Yii::$app->request->post();

        $planning->load($post);
        return ActiveForm::validate($planning);
    }

И мой автономный валидатор:

namespace backend\components\validators;

use yii\validators\Validator;

class DagenValidator extends Validator
{
    public function validateAttribute($model, $attribute)
    {
        if ($model->frequentie == 2 && count($model->$attribute) < 2) {
            $this->addError($model, $attribute, 'Selecteer minimaal 2 dagen.');
        }
    }
}

Теперь в моем Planning Модель я могу добавить к следующему правилу:

['dagen_ids', DagenValidator::className(), 'skipOnEmpty' => false, 'skipOnError' => false]
Другие вопросы по тегам