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.
Related
I am new in Laravel, what I try to achieve is very simple thing, I would like to use FormRequest provided by Laravel to do validation of the request, but I encounter some puzzles (which I am sure is easy things to solve if you are experienced in Laravel).
Here is what I tried:
I have route maps to controller:
Route::put('user/{name}', 'UserController#show');
I can get the name parameter in show function:
class UserController {
public function show($name)
{
// validtion rules to apply
...
}
}
I have validation rules to apply to the request, so I decided to create form request by php artisan make:request ShowRequest, which creates the form request class:
class ShowRequest extends FormRequest {
public function authorize()
{
return true;
}
public function rules()
{
return [
// my validation rules here
];
}
}
Since I have above request class, so I refactored the show function in controller to receive the ShowRequest .
class UserController {
public function show(ShowRequest $request)
{
// now I don't need validtion rules in this function
// but how can I access the 'name' parameter now
...
}
}
I have two questions to ask:
Inside the refactored show function, how can I now access the route parameter name ?
If we forget about the parameter is a name (please don't focus on what to validate for name, imaging it is an object or value to validate in general). How to add custom logic for handling validation error instead of using Laravel default behaviour. I want to inject code like dummy code below:
if (!$validator->pass())
{
//my custom code for handling validation failure
}
Where to put my custom code for handling validation error now? I mean I don't know where to have this logic, in controller? in the request class? how?
You still can add the parameter $name in the show() method of your controller as it's part of the routed url more than the validated form/data. (recommanded)
class UserController {
public function show(ShowRequest $request, $name)
{
//...
}
}
You can also access it from the request object
class UserController {
public function show(ShowRequest $request)
{
$request->input('name');
}
}
As for the error messages (not the exception) you can add the messages() method to your ShowRequest::class
class ShowRequest extends FormRequest
{
/**
* #return array
*/
public function messages()
{
return [
'name.required' => 'The name is required',
'name.numeric' => 'The name must be a number',
//...
];
}
}
If you instead need to validate that the name catched by the route is only composed of letter OR really exists as a field in your DB (like a slug of a post) you need to add some validation in your route declaration.
Setup a route that catches request only if it is composed of letters.
Route::get('/user/{name}', 'Controller#show')->where(['name' => '[a-z]+']);
Setup a route that catches request only if the "name" exists in DB:
User.php
Class User //..
{
/**
* Get the route key for the model.
*
* #return string
*/
public function getRouteKeyName()
{
return 'name';
}
}
web.php
//
Route::get('/user/{user:name}', 'Controller#show');
And adapt your controller to take a user directly
class UserController {
public function show(ShowRequest $request, User $user)
{
//...
}
}
You can access the values of the Form Request using this
$validated = $request->validated();
The $validated will have all the values which had been validated by the FormRequest.
To answer your second question, if you want to throw custom validation, you can always use the following
throw ValidationException::withMessages(['name' => 'Something is wrong']);
Classic problem:
verify that a user accepted the contract terms but the value of the acceptance is not stored (bound) in the database...
Extend CFormModel rather than CActiveForm (because CActiveForm binds
values to DB)
Post a CFormModel to a controller action
Validate a CFormModel
I'm asking this question to answer it because the existing questions end in see the documentation...
extend CFormModle, define the rules and got to validate. With bound variables you validated as part of save. Now you validate() by itself but Validate requires a list of attributes which is not defined in CFormModel. So, what do you do? You do this:
$contract->validate($contract->attributeNames())
Here's the full example:
class Contract extends CFormModel
{
...
public $agree = false;
...
public function rules()
{
return array(
array('agree', 'required', 'requiredValue' => 1, 'message' => 'You must accept term to use our service'),
);
}
public function attributeLabels()
{
return array(
'agree'=>' I accept the contract terms'
);
}
}
Then in the controller you do this:
public function actionAgree(){
$contract = new Contract;
if(isset($_POST['Contract'])){
//$contract->attributes=$_POST['Contract']; //contract attributes not defined in CFormModel
...
$contract->agree = $_POST['Contract']['agree'];
...
}
if(!$contract->validate($contract->attributeNames())){
//re-render the form here and it will show up with validation errors marked!
}
The results:
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');
}
}
I have a function in my login form that checks if the email and password match the values in the database and if so it logs the user into the system.
I would like to display a validation error if this function returns false.
My problem is that I am unsure how to go about creating this. The message relates to both the password and email fields so I would not want a rule for each input field just display a single message.
I have tried using flashdata to achieve this but it only works when the page has been refreshed.
How can I created a new validation rule solely for the function $this->members_model->validate_member() ??
$this->form_validation->set_error_delimiters('<div class="error">', '</div>');
$this->form_validation->set_rules('email_address', '"Email address"', 'trim|required|valid_email');
$this->form_validation->set_rules('password', '"Password"', 'trim|required');
if ($this->form_validation->run() == FALSE)
{
$viewdata['main_content'] = 'members/login';
$this->load->view('includes/template', $viewdata);
}
else
{
if($this->members_model->validate_member())
{
You use the callback_ in your rules, see callbacks, for ex.
$this->form_validation->set_rules('email_address', '"Email address"', 'trim|required|valid_email|callback_validate_member');
and add the method in the controller. This method needs to return either TRUE or FALSE
function validate_member($str)
{
$field_value = $str; //this is redundant, but it's to show you how
//the content of the fields gets automatically passed to the method
if($this->members_model->validate_member($field_value))
{
return TRUE;
}
else
{
return FALSE;
}
}
You then need to create a corresponding error in case the validation fails
$this->form_validation->set_message('validate_member','Member is not valid!');
One best way to achieve this is extending CodeIgniter’s Form Validation library. Let say we want to create a custom validator named access_code_unique for the field access_code of the database table users.
All you have to do is creating a Class file named MY_Form_validation.php in application/libraries directory. The method should always return TRUE OR FALSE
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Form_validation extends CI_Form_validation {
protected $CI;
public function __construct() {
parent::__construct();
// reference to the CodeIgniter super object
$this->CI =& get_instance();
}
public function access_code_unique($access_code, $table_name) {
$this->CI->form_validation->set_message('access_code_unique', $this->CI->lang->line('access_code_invalid'));
$where = array (
'access_code' => $access_code
);
$query = $this->CI->db->limit(1)->get_where($table_name, $where);
return $query->num_rows() === 0;
}
}
Now you can easily add your new created rule
$this->form_validation->set_rules('access_code', $this->lang->line('access_code'), 'trim|xss_clean|access_code_unique[users]');