
Olá a todos!
Bom, como todos sabem, existe a validação pelo lado do cliente, que é uma validação em javascript, sem a necessidade de usar validações em ajax, que dependendo do servidor haverá um lag na respostas.
Por esse motivo que a versão 2 do Yii Framework, vem por padrão a validação por "Client-Side" sem precisa setar nada no ActiveForm.
Mas vamos ao o que interessa, tive uma situação real, que o cliente queria que o formulário de busca contem-se 2 campos que houvesse validação, mais que seria obrigatório um ou outro, se caso nenhum dos dois forem selecionado ou preenchido, a validação indica que os campos é de seleção/preenchimento obrigatório, mas caso 1 dos campos seja selecionado, o outro campo deixa de ser obrigatório.
Na versão 2 do Yii Framework, existe a possibilidade de acrescentar sua própria validação, complementando ao padrão do formulário, para isso vamos usar o "Deffered Validation", que é parecido com o Transaction do MYSQL, é uma execução assíncrona em javascript, assim você consegue validar todos os campos e depois mostrar a mensagem.
Abaixo segue a estrutura do formulário:
<?php $this->registerJs('var stopValidation = false;');?> <?php $model = FormSearch; ?> <?php $form = ActiveForm::begin(['id' => 'search-form']); ?> <?php $list = ArrayHelper::map(Type::find()->all(), 'id', 'title'); ?> <?= $form->field($model, 'type')->dropDownList($list, ['prompt' => 'Select']); ?> <?= $form->field($model, 'query'); ?> <?php ActiveForm::end(); ?>
A class FormSearch:
<?php namespace app\models\form; use yii\base\Model; class FormSearch extends Model { public $type; public $query; public function rules() { return [ [['type', 'query'], 'safe'], [['type', 'query'], \app\components\FormSearchValidator::className()], ['query', 'filter', 'filter' => 'strip_tags'], ['query', 'filter', 'filter' => function($value) { return \yii\helpers\Html::encode($value); } ], ]; } public function attributeLabels() { return [ 'type' => 'Tipo', 'query' => 'Título', ]; } }
Agora vou postar uma class que se extende a class yii\validators\Validator.
namespace app\components; use yii\validators\Validator; class FormSearchValidator extends Validator { public function init() { parent::init(); $this->message = 'On of the fields is required.'; } public function validateAttribute($model, $attribute) { /*https://github.com/yiisoft/yii2/blob/master/docs/guide/input-validation.md#using-client-side-validation-*/ } public function clientValidateAttribute($model, $attribute, $view) { if (empty($model->type) && empty($model->query)) { $message = json_encode($this->message, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); return <<<JS var def = $.Deferred(); if (attribute.name=='type' && value != '') { stopValidation = true; def.reject(); } if (attribute.name=='query' && value != '') { stopValidation = true; def.reject(); } if (attribute.name=='type' && value == '') { if(stopValidation == true){ def.reject(); } else { messages.push($message); def.resolve(); } } if (attribute.name=='query' && value == '') { if(stopValidation == true){ def.reject(); } else { messages.push($message); def.resolve(); } } deferred.push(def); JS; } } }
Caso alguém tenha uma solução melhor, estamos aberto a troca de idéias.
Caso tenha alguma dúvida, não exite em postar.
Discussão