У меня есть форма, созданная виджетом ActiveForm. Пользователь вводит там польский почтовый индекс. В соответствующий контроллер я помещаю введенные данные в БД, например:
$company_profile_data->postal_code = $_POST['CompanyProfiles']['postal_code'];
$company_profile_data->update();
Я решил использовать автономный валидатор для проверки почтового индекса. Правила для этого атрибута в модели:
public function rules() {
return [
//...some other rules...
['postal_code', 'string', 'length' => [6,6]],
['postal_code', PostalValidator::className()], //standalone validator
];
}
приложение / компоненты / валидаторы / код класса PostalValidator:
namespace app\components\validators;
use yii\validators\Validator;
use app\models\CompanyProfiles;
use app\models\Users;
class PostalValidator extends Validator {
public function init() {
parent::init();
}
public function validateAttribute($model, $attribute) {
if (!preg_match('/^[0-9]{2}-[0-9]{3}$/', $model->$attribute))
$model->addError($attribute, 'Wrong postal code format.');
}
public function clientValidateAttribute($model, $attribute, $view) { //want js-validation too
$message = 'Invalid status input.';
return <<<JS
if (!/^[0-9]{2}-[0-9]{3}$/.test("{$model->$attribute}")) {
messages.push("$message");
}
JS;
}
}
Итак, пример правильного кода 00-202.
Когда я (в роли пользователя) ввожу неверное значение, страница перезагружается, и я вижу Wrong postal code format.
сообщение, хотя я переопределил clientValidateAttribute
метод и написал JS-validation
, который, как я предположил, не позволит странице перезагрузиться. Затем я снова нажимаю кнопку отправки: на этот раз страница не перезагружается, и я вижу Invalid status input.
сообщение (так, срабатывает второе время нажатия JS). Но я, когда после этого ввожу правильный код, все равно вижу Invalid status input.
сообщение и ничего не происходит.
Итак, что не так с моим clientValidateAttribute()
метод? validateAttribute()
работает отлично.
ОБНОВИТЬ
Фрагмент из контроллера
public function actionProfile(){ //can't use massive assignment here, cause info from 2 (not 1) user models is needed
if (\Yii::$app->user->isGuest) {
return $this->redirect('/site/index/');
}
$is_user_admin = Users::findOne(['is_admin' => 1]);
if ($is_user_admin->id == \Yii::$app->user->id)
return $this->redirect('/admin/login/');
$is_user_blocked = Users::find()->where(['is_blocked' => 1, 'id' => \Yii::$app->user->id])->one();
if($is_user_blocked)
return $this->actionLogout();
//3 model instances to retrieve data from users && company_profiles && logo
$user_data = Users::find()->where(['id'=>\Yii::$app->user->id])->one();
$user_data->scenario = 'update';
$company_profile_data = CompanyProfiles::find()->where(['user_id'=>Yii::$app->user->id])->one();
$logo = LogoData::findOne(['user_id' => \Yii::$app->user->id]);
$logo_name = $logo->logo_name; //will be NULL, if user have never uploaded logo. In this case placeholder will be used
$upload_logo = new UploadLogo();
if (Yii::$app->request->isPost) {
$upload_logo->imageFile = UploadedFile::getInstance($upload_logo, 'imageFile');
if ($upload_logo->imageFile) { //1st part ($logo_data->imageFile) - whether user have uploaded logo
$logo_file_name = md5($user_data->id);
$is_uploaded = $upload_logo->upload($logo_file_name);
if ($is_uploaded) { //this cond is needed, cause validation for image fails (?)
//create record in 'logo_data' tbl, deleting previous
if ($logo_name) {
$logo->delete();
} else { //if upload logo first time, set val to $logo_name. Otherwise NULL val will pass to 'profile' view, and user wont see his new logo at once
$logo_name = $logo_file_name.'.'.$upload_logo->imageFile->extension;
}
$logo_data = new LogoData;
$logo_data->user_id = \Yii::$app->user->id;
$logo_data->logo_name = $logo_name;
$logo_data->save();
}
}
}
if (isset($_POST['CompanyProfiles'])){
$company_profile_data->firm_data = $_POST['CompanyProfiles']['firm_data'];
$company_profile_data->company_name = $_POST['CompanyProfiles']['company_name'];
$company_profile_data->regon = $_POST['CompanyProfiles']['regon'];
$company_profile_data->pesel = $_POST['CompanyProfiles']['pesel'];
$company_profile_data->postal_code = $_POST['CompanyProfiles']['postal_code'];
$company_profile_data->nip = $_POST['CompanyProfiles']['nip'];
$company_profile_data->country = $_POST['CompanyProfiles']['country'];
$company_profile_data->city = $_POST['CompanyProfiles']['city'];
$company_profile_data->address = $_POST['CompanyProfiles']['address'];
$company_profile_data->telephone_num = $_POST['CompanyProfiles']['telephone_num'];
$company_profile_data->email = $_POST['CompanyProfiles']['email'];
$company_profile_data->update();
}
if (isset($_POST['personal-data-button'])) {
$user_data->username = $_POST['Users']['username'];
$user_data->password_repeat = $user_data->password = md5($_POST['Users']['password']);
$user_data->update();
}
return $this->render('profile', ['user_data' => $user_data, 'company_profile_data' => $company_profile_data, 'upload_logo' => $upload_logo, 'logo_name' => $logo_name]);
}
Моя неточность была в clientValidateAttribute()
метод. Вместо $model->$attribute
во фрагменте кода:
if (!/^[0-9]{2}-[0-9]{3}$/.test("{$model->$attribute}")) {
…Я должен был использовать предопределенный JS-Var значение, потому что эта переменная изменяется при изменении введенного значения. Итак, мой новый код:
public function clientValidateAttribute($model, $attribute, $view) {
return <<<JS
if (!/^[0-9]{2}-[0-9]{3}$/.test(value)) {
messages.push("Wrong postal code format.");
}
JS;
}
Модель не загружает правила и поведение, пока не вызывается ни одна функция от модели. Когда вы звоните $company_profile_data->update();
вызов модели update
а также validate
функции.
Попробуй добавить после $company_profile_data = CompanyProfiles::find()
этот код:
$company_profile_data->validate();
Или просто использовать load
функция. Я думаю, что это поможет.