Yii2 provides a powerful and flexible way to handle forms and validation. In this guide, we will cover everything you need to know about forms, validation rules, ActiveForm widgets, and custom validators.
A form model extends yii\base\Model and is used for validation purposes.
namespace app\models;
use Yii;
use yii\base\Model;
class ContactForm extends Model
{
public $name;
public $email;
public $subject;
public $message;
public $agree;
public function rules()
{
return [
[['name', 'email', 'subject', 'message'], 'required'],
['email', 'email'],
['subject', 'string', 'max' => 255],
['message', 'string', 'min' => 10],
['agree', 'required', 'requiredValue' => 1, 'message' => 'You must agree to the terms.'],
];
}
}ActiveForm is used to generate forms in Yii2. Example:
use yii\widgets\ActiveForm;
use yii\helpers\Html;
$form = ActiveForm::begin();
echo $form->field($model, 'name')->textInput(['maxlength' => true]);
echo $form->field($model, 'email')->input('email');
echo $form->field($model, 'subject')->textInput();
echo $form->field($model, 'message')->textarea(['rows' => 6]);
echo $form->field($model, 'agree')->checkbox();
echo Html::submitButton('Submit', ['class' => 'btn btn-primary']);
ActiveForm::end();$form->field($model, 'name')->textInput();$form->field($model, 'password')->passwordInput();$form->field($model, 'message')->textarea(['rows' => 6]);$form->field($model, 'agree')->checkbox();$form->field($model, 'country')->dropDownList(['US' => 'USA', 'UK' => 'United Kingdom']);$form->field($model, 'gender')->radioList(['M' => 'Male', 'F' => 'Female']);$form->field($model, 'file')->fileInput();echo $form->field($model, 'dob')->widget(\yii\jui\DatePicker::class, ['dateFormat' => 'yyyy-MM-dd']);[['q2'], 'required', 'when' => function ($model) {
return $model->q1 == '1';
}]['state_code', 'unique', 'when' => function ($model, $attribute) {
return $this->state_model->$attribute != $model->$attribute;
}, 'targetClass' => MasterState::className(),
'message' => 'This District Code has already been added']['agree', 'required', 'requiredValue' => 1, 'message' => 'You must agree to the terms.'][['name'], 'required'][['subject'], 'string', 'min' => 3, 'max' => 255][['email'], 'email'][['age'], 'number'][['is_active'], 'boolean'][['password_repeat'], 'compare', 'compareAttribute' => 'password'][['dob'], 'date', 'format' => 'yyyy-MM-dd'][['status'], 'in', 'range' => [0, 1]][['name'], 'trim']You can add errors dynamically using addError():
if ($this->age < 18) {
$this->addError('age', 'You must be at least 18 years old.');
}namespace app\models;
use yii\validators\Validator;
class MyCustomValidator extends Validator
{
public function validateAttribute($model, $attribute)
{
if ($model->$attribute !== 'expected_value') {
$this->addError($model, $attribute, 'Invalid value for {attribute}.');
}
}
}['custom_field', MyCustomValidator::class]Enable AJAX validation by setting 'enableAjaxValidation' => true:
$form = ActiveForm::begin([
'enableClientValidation' => false,
'enableClientScript' => false,
'enableAjaxValidation' => true
]);_form.php
<?php $form = ActiveForm::begin([
'id' => 'permission-form',
'method' => 'POST',
'enableAjaxValidation' => true,
'enableClientValidation' => false,
'enableClientScript' => true,
'action' => $model->action_url,
'validationUrl' => $model->action_validate_url,
]); ?>ContactForm.php
public $action_url;
public $action_validate_url;SiteController.php
/**
* Validate Form
*
* @param [type] $id
* @return void
*/
public function actionValidate($id = null)
{
if ($id) {
$state_model = $this->findModel($id);
$model = new StateForm($state_model);
} else {
$model = new StateForm();
}
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return \yii\widgets\ActiveForm::validate($model);
}
}SiteController.php actioncreate
$model = new StateForm();
$model->action_url = Url::toRoute(['/site/create', 'form_id' => $form_id]);
$model->action_validate_url = Url::toRoute(['/site/validate']);Yii2 provides the match validator, which allows you to validate an attribute using a regular expression. This is useful for enforcing specific formats, such as email-like usernames, strong passwords, or specific text patterns.
matchThe match rule requires a pattern attribute where you define your regular expression.
public function rules()
{
return [
[['username'], 'match', 'pattern' => '/^[a-zA-Z0-9_-]{3,16}$/', 'message' => 'Username can only contain letters, numbers, underscores, and dashes (3-16 characters).'],
];
}This rule ensures that the username only contains letters, numbers, underscores, or dashes and is between 3 to 16 characters long.
You can enforce strong password rules using regex.
public function rules()
{
return [
[['password'], 'match', 'pattern' => '/^(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/',
'message' => 'Password must be at least 8 characters long, contain one uppercase letter, one number, and one special character.'],
];
}If a field should only contain digits, you can use:
public function rules()
{
return [
[['mobile_number'], 'match', 'pattern' => '/^\d{10}$/', 'message' => 'Mobile number must be exactly 10 digits.'],
];
}Sometimes, you may allow email-like usernames but don’t want to use the built-in email validator:
public function rules()
{
return [
[['email_username'], 'match', 'pattern' => '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/', 'message' => 'Invalid email format.'],
];
}If the built-in error message is not enough, you can customize it further:
public function rules()
{
return [
[['postal_code'], 'match', 'pattern' => '/^\d{5}(-\d{4})?$/', 'message' => 'Postal code must be in the format 12345 or 12345-6789.'],
];
}match validator to enforce specific formats.pattern using a regular expression.message for user-friendly error feedback.Let's modify the Word500Validator to be dynamic, allowing us to set a custom word limit.
Create a new file in common/validators/WordLimitValidator.php:
<?php
namespace common\validators;
use yii\validators\Validator;
/**
* Class WordLimitValidator
* A dynamic validator to limit the number of words in a text attribute.
*/
class WordLimitValidator extends Validator
{
public $maxWords = 500; // Default limit
public function validateAttribute($model, $attribute)
{
if (!empty($model->$attribute)) {
$wordCount = str_word_count($model->$attribute);
if ($wordCount > $this->maxWords) {
$this->addError($model, $attribute,
"{$model->getAttributeLabel($attribute)} cannot exceed {$this->maxWords} words. Currently: {$wordCount} words.");
}
}
}
}Now, apply this validator in your model’s rules() method:
public function rules()
{
return [
[['description'], 'required'],
[['description'], \common\validators\WordLimitValidator::className(), 'maxWords' => 300], // Set custom limit
];
}<?= $form->field($model, 'description')->textarea(['rows' => 6]) ?>Yii2 allows you to create validation rules using regular expressions (match rule) or by implementing custom validators. Below are some commonly used validation rules for various Indian identifiers using regex patterns.
A valid Aadhar number must be a 12-digit numeric value starting with a digit from 2-9.
[['aadhar_number'], 'match', 'pattern' => '/^[2-9]{1}[0-9]{3}[0-9]{4}[0-9]{4}$/', 'message' => 'Invalid Aadhar Number.']A bank account number should be between 9 and 18 digits.
[['bank_account_number'], 'match', 'pattern' => '/^[0-9]{9,18}+$/', 'message' => 'Invalid Bank Account Number.']An IFSC code consists of 4 uppercase letters, followed by 0, and then 6 alphanumeric characters.
[['ifsc_code'], 'match', 'pattern' => '/^[A-Z]{4}0[A-Z0-9]{6}$/', 'message' => 'Invalid IFSC Code.']A valid PAN card number follows the pattern: 5 letters, 4 digits, 1 letter.
[['pan_number'], 'match', 'pattern' => '/^([a-zA-Z]){5}([0-9]){4}([a-zA-Z]){1}?$/', 'message' => 'Invalid PAN Number.']A PIN code in India consists of exactly 6 digits.
[['pin_code'], 'match', 'pattern' => '/^[0-9]{6}+$/', 'message' => 'Invalid PIN Code.']A GSTIN (Goods and Services Tax Identification Number) in India follows a structured 15-character pattern.
[['gstin'], 'match', 'pattern' => '/^([0][1-9]|[1-2][0-9]|[3][0-5])([a-zA-Z]{5}[0-9]{4}[a-zA-Z]{1}[1-9a-zA-Z]{1}[zZ]{1}[0-9a-zA-Z]{1})+$/', 'message' => 'Invalid GSTIN.']A valid mobile number should be 10 digits and should not start with 0.
[['mobile_number'], 'match', 'pattern' => '/^[123456789]\d{9}$/', 'message' => 'Invalid Mobile / Phone Number.']Alternatively, using a custom validator:
public function validateMobile($attribute, $params)
{
if (!preg_match('/^[123456789]\d{9}$/', $this->$attribute)) {
$this->addError($attribute, 'Invalid Mobile / Phone Number.');
}
}Add this rule in the model:
[['mobile_number'], 'validateMobile']To apply these validators in your model:
public function rules()
{
return [
[['aadhar_number'], 'match', 'pattern' => '/^[2-9]{1}[0-9]{3}[0-9]{4}[0-9]{4}$/', 'message' => 'Invalid Aadhar Number.'],
[['bank_account_number'], 'match', 'pattern' => '/^[0-9]{9,18}+$/', 'message' => 'Invalid Bank Account Number.'],
[['ifsc_code'], 'match', 'pattern' => '/^[A-Z]{4}0[A-Z0-9]{6}$/', 'message' => 'Invalid IFSC Code.'],
[['pan_number'], 'match', 'pattern' => '/^([a-zA-Z]){5}([0-9]){4}([a-zA-Z]){1}?$/', 'message' => 'Invalid PAN Number.'],
[['pin_code'], 'match', 'pattern' => '/^[0-9]{6}+$/', 'message' => 'Invalid PIN Code.'],
[['gstin'], 'match', 'pattern' => '/^([0][1-9]|[1-2][0-9]|[3][0-5])([a-zA-Z]{5}[0-9]{4}[a-zA-Z]{1}[1-9a-zA-Z]{1}[zZ]{1}[0-9a-zA-Z]{1})+$/', 'message' => 'Invalid GSTIN.'],
[['mobile_number'], 'match', 'pattern' => '/^[123456789]\d{9}$/', 'message' => 'Invalid Mobile / Phone Number.'],
];
}This guide covers everything related to Yii2 forms and validation, including input widgets, rules, and custom validators. Now, you can build robust forms with Yii2!
Sign in to join the discussion and post comments.
Sign in