i've this class in my project:
<?php
namespace app\models;
use Yii;
use yii\base\Model;
class Contact extends Model
{
public $fullname;
public $info;
public function rules()
{
return [
['fullname','info'],'required'
];
}
}
I want to do a custom validation on my 'contact' field. I want to validate it as a mail if the value on the field isn't a number.
Is there a method for doing it with conditional validators?
Thanks in advance for all the help
You can do allot of things in order to accomplish this custom validator, play with input in beforeValidate() and such. Personally, the best way to do it is to set scenario. In your controller before you validate model check if user input is numeric with (is_numeric()), if it is set scenario to 'something1' if it's not then set scenario to 'mail'. This way you will not have to worry about validation because you will set two rules for the same attribute with different scenarios. One rule will be email other can be integerOnly or something like that. Hope it helps.
You could define an inline function to validate a field in your rules. In your case, i guess you might do something like:
public function rules()
{
return [
['contact', 'validateContact'],
];
}
public function validateContact($attribute, $params)
{
if ( !is_numeric($this->$attribute) ) {
$validator = new yii\validators\EmailValidator();
if ($validator->validate($this->$attribute, $error)) {
echo 'Email is valid.';
} else {
echo $error;
}
} else {
echo 'Contact is number';
}
}
More info:
1) http://www.yiiframework.com/doc-2.0/guide-input-validation.html
2) http://www.yiiframework.com/doc-2.0/guide-input-validation.html#using-client-side-validation
Related
I have model form (SomeForm) and custom validation function in there:
use yii\base\Model;
class SomeForm extends Model
{
public $age;
public function custom_validation($attribute, $params){
if($this->age < 18){
$this->addError($attribute, 'Some error Text');
return true;
}
else{
return false;
}
}
public function rules(){
return [
['age', 'custom_validation']
];
}
}
I use this custom_validation in rules() function but form even submitting whatever value has age attribute.
Here is the form:
age.php
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'age')->label("Age") ?>
<div class="form-group">
<?= Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
and the controller:
use yii\web\Controller;
class SomeController extends Controller
{
//this controller is just for rendering
public function actionIndex(){
return $this->render('age');
}
public function actionSubmit(){
$model = new SomeForm();
if($model->load(Yii::$app->request->post()){
//do something here
}
}
}
You don't need to return anything just adding the error to the attribute is enough.
Since version 2.0.11 you can use yii\validators\InlineValidator::addError() for adding errors instead of using $this. That way the error message can be formatted using yii\i18n\I18N::format() right away.
Use {attribute} and {value} in the error message to refer to an attribute label (no need to get it manually) and attribute value accordingly:
What I suspect is the problem in your case is that you are missing the $formModel->validate() as in the model given above extends the yii\base\Model and not \yii\db\ActiveRecord and you must be saving some other ActiveRecord model and want to validate this FormModel before saving the ActiveRecord model, you have to call the $formModel->validate() to check if valid input is provided and trigger the model validation after loading the post array to the model.
And another thing to notice is by default, inline validators will not be applied if their associated attributes receive empty inputs or if they have already failed some validation rules. If you want to make sure a rule is always applied, you may configure the skipOnEmpty and/or skipOnError properties to be false in the rule declarations.
Your model should look like below you are missing the namespace in your model definition if that is not just intentional or due to sample code. just update you namespace according to the path where it is.
namespace frontend\models;
use yii\base\Model;
class SomeForm extends Model
{
public $age;
const AGE_LIMIT=18;
public function rules(){
return [
['age', 'custom_validation','skipOnEmpty' => false, 'skipOnError' => false]
];
}
public function custom_validation($attribute, $params,$validator){
if($this->$attribute< self::AGE_LIMIT){
$validator->addError($this, $attribute, 'The value "{value}" is not acceptable for {attribute}, should be greater than '.self::AGE_LIMIT.'.');
}
}
}
your controller/action should look like
public function actionTest()
{
//use appropriate namespace
$formModel = new \frontend\models\SomeForm();
$model= new \frontend\models\SomeActiveRecordModel();
if ($formModel->load(Yii::$app->request->post()) && $model->load(Yii::$app->request->post())) {
if ($formModel->validate()) {
// your code after validation to save other ActiveRecord model
if($model->save()){
Yii::$app->session->setFlash('success','Record added succesfully.')
}
}
}
return $this->render('test', ['model' => $model,'formModel'=>$formModel]);
}
The Input field age in the view file should use the $formMoedl object
echo $form->field($formModel, 'age')->textInput();
Actually I'm working on ajax validation in Yii 2. I am sending two public variables data into a column in DB. while loading a post values. How to validate custom onto that field.
My Code:
public $prefix;
public $mobile;
$model->phone = Yii::$app->request->post('prefix') . '' . Yii::$app->request->post('mobile');
and I want this
['phone, 'unique']
Thanks in advance
Add the rule to the class definition of the model, validate and do with the validation result what you want. E.g. return true when validated true or the error message when validated false.
class YourModel extends ActiveRecord {
public function rules()
{
return [
['phone', 'unique'],
];
}
}
$model->validate();
If you have more validation rules you can get the result for the phone attribute using $model->getErrors('phone').
You need to merge both variables before calling validate function on model.
Your controller action code should be like below :
$model->phone=model->prefix.$model->mobile;
$model->validate();
//rest of code
I have tried to extend the Form_validation library from Codeigniter with no success.
I have two functions that I'd like in this extended class but when the validation is run i get these messages in the log:
DEBUG - 06-07-2016 11:20:33 --> Unable to find validation rule: checkAccountnameForUpdate
DEBUG - 06-07-2016 11:20:33 --> Unable to find validation rule: checkEmailForUpdate
Here is my extended class which is placed in
application/libraries
<?php defined('BASEPATH') OR exit('No direct script access allowed');
class MY_Form_validation extends CI_Form_validation
{
public function __construct($rules = array())
{
// Pass the $rules to the parent constructor.
parent::__construct($rules);
// $this->CI is assigned in the parent constructor, no need to do it here.
}
public function checkAccountnameForUpdate($accountname, $id)
{
return 1;
}
public function checkEmailForUpdate($email, $id)
{
return 1;
}
}
And here's my rules:
$this->form_validation->set_rules('editAccountname', 'Brugernavn', 'required|checkAccountnameForUpdate[hiddenField]');
$this->form_validation->set_rules('editEmail', 'Email', 'required|checkEmailForUpdate[hiddenField]');
$this->form_validation->set_message('checkAccountnameForUpdate', 'Test2');
$this->form_validation->set_message('checkEmailForUpdate', 'Test');
// hiddenField is the name of a hiddenField containing the users ID.
I've googled around and tired some different stuff. I have no idea why it doesn't work.
EDIT 1:
I've tried to replace
$this->form_validation->set_rules('editAccountname', 'Brugernavn', 'required|checkAccountnameForUpdate[hiddenField]');
$this->form_validation->set_rules('editEmail', 'Email', 'required|checkEmailForUpdate[hiddenField]');
to
$this->form_validation->set_rules('editAccountname', 'Brugernavn', 'required|checkAccountnameForUpdate');
$this->form_validation->set_rules('editEmail', 'Email', 'required|checkEmailForUpdate');
No changes.
Here is my extension to the validation library. I have left a few functions out as they are site specific but do not affect the demo here.
APPPATH/libraries/MY_Form_validation.php
class MY_Form_validation extends CI_Form_validation
{
public function __construct($rules = array())
{
parent :: __construct($rules);
}
/*
* reformats the input to ###-###-#### and returns formatted string,
* if it cannot accomplish the format (of a non-empty input) it returns FALSE.
*/
public function phone_format($phone)
{
if(empty($phone))
{
//assume an empty field is OK.
//There needs to be a required rule to check a required field and that rule should
//be before this one in the list of rules
return TRUE;
}
$phone = preg_replace('/[^0-9]/', '', $phone);
$newPhone = preg_replace("/([0-9]{3})([0-9]{3})([0-9]{4})/", "$1-$2-$3", $phone);
if(preg_match('/((\d){3})?(\-){1}(\d){3}(\-){1}(\d){4}/', $newPhone))
{
//preg_replace was able to reformat it to the correct pattern - must be good
return $newPhone;
}
return FALSE;
}
/**
* field validation for zipcode
*/
public function check_zipcode($zipcode)
{
$result = (bool) preg_match("/^([0-9]{5})(-[0-9]{4})?$/i", $zipcode);
return $result;
}
}
We can test this class with the simple controller and view shown below. The test uses the phone_format validator function.
A couple things to note about how I'm using form_validation->set_rules().
First, I pass an array of rules instead of the usually demonstrated pipe separated string. eg. "trim|required". Why? Because set_rules() turns the string into an array anyway so why make it do the extra work?
Second. Notice I am passing a fourth argument. The fourth argument is not well documented. Its use is shown in the Setting Error Messages section but it is not described in the Class Reference section of the documentation. The argument accepts an array of error messages in the form ['rule_name' => 'This is the error message'].
I'm also in the habit of using the short syntax to create arrays eg. $this->data = []; instead of $this->data = array(); mostly because it's less typing.
Here's the test controller Testcase.php
class Testcase extends CI_Controller
{
protected $data;
function __construct()
{
parent::__construct();
$this->data = [];
$this->load->library('form_validation');
}
public function test_validation()
{
$this->form_validation->set_rules('phone', 'Phone'
, ['trim', 'required', 'phone_format']
, [
'phone_format' => 'Not a valid phone number.',
'required' => '<em>{field}</em> required.'
]
);
if($this->form_validation->run() == FALSE)
{
$this->load->view('test_form_v', $this->data);
}
else
{
echo "Passed Validation<br>";
echo $_POST['phone'];
}
}
}
And here is the view file test_form_v.php
<?php
echo form_open('testcase/test_validation');
echo form_input('phone', set_value('phone'));
echo form_error('phone');
echo form_submit('Submit', 'Submit');
echo form_close();
Run it by entering this url in a browser your_doman.whatever/testcase/test_validation
Submit without entering any input and you get the required error. Submit "123456789" and you get the invalid phone number error message. Submit "1234567890" and you get
Passed Validation
123-456-7890
This demonstrates that the extend class and its new validator works. I hope this helps you figure out your problem.
In CI's documentation, it says that you could create your own custom validation for use in form submission check. It shows how this can be done in a controller:
http://ellislab.com/codeigniter%20/user-guide/libraries/form_validation.html
But what if I want to have my custom validation function in a model?
I've found that the following did not work...
BOTH FUNCTIONS BELOW ARE IN A MODEL:
public function validate_form(){
$this->form_validation->set_rules('username', 'Username', 'callback_illegal_username_check');
$this->form_validation->run();
}
And here's my custom validation function:
public function illegal_username_check($string){
if($string == 'fcuk'){
$this->form_validation->set_message('illegal_username_check', 'Looks like you are trying to use some swear words in the %s field');
return FALSE;
}
else{
return TRUE;
}
}
I found that because my custom validation function is in the model, it did not get called when I run my "validate_form()" function. How do I resolve this?
Many thanks in advance!
You should put custom validation rules in a MY_Form_validation.php in the application/libraries folder.
Then, when you assign your rules you can do something like this..
$this->form_validation->set_rules('field1', 'Field one name', 'trim|required|xss_clean|your_custom_validator');
Note the custom validator doesn't require the callback_ keyword in front.
Here's an example My_Form_valdation.php file.
class MY_Form_validation extends CI_Form_validation {
function __construct($rules = array()) {
parent::__construct($rules);
$this->ci = & get_instance();
$this->ci->load->database();
}
function your_custom_validator($val) {
$this->set_message('your_custom_validator', 'this isn\'t right!');
return (!$val) ? FALSE : TRUE;
}
Note in the construct I've got the Ci instance and loaded the database class.
To use it i'd do something like this..
$this->ci->db->where('id', 1)->get('user')->row();
I have created a form with some entities (say name,address,etc.). And I have defined validation rules in model class. Client side validation is working perfectly as desired. Now I need to create custom validation rules. For that,in reference with http://www.yiiframework.com/wiki/168/create-your-own-validation-rule/#hh0 , I have created a method called valid_number() in my model, and defined a simple null checking (I know there are built in rules for validating null,email,password, etc.. Here I have demonstrated a simple method of validation, actually I'm planning to do some custom validations). Please refer the code below. And please let me know what I am doing wrong.
//model
class Employee extends CActiveRecord{
public $number;
public function rules(){
return array(
array('number','valid_number'),
);
}
public function valid_number($attribute,$params){
if($this->$attribute == '' ){
CModel::addError($attribute, 'Number is null');
}
}
//view
</fieldset>
<?php echo $form->textFieldRow($model, 'number'); ?>
</fieldset>
CModel::addError should be $this->addError.
<?php
$this->addError($attribute, 'Your error message');
?>
Why are you calling the static function CModel::addError?
You could just call addError of the object and it works:
public function valid_number($attribute, $params) {
if ($this->$attribute == '' ) {
$this->addError($attribute, 'Number is null');
}
}