Create a dynamic conditional validation in Cakephp - php

I want to set these validation rule in CakePHP
Rule:
One of these fields is required but not both.
discount_percent
discount_amount
If discount_amount is input as 0 a NULL should be saved and then discount_percent is required to be > 1 but <=100.
If discount_percent is input a 0 then a NULL should be saved and then discount_amount is required to be > 0 but <= products.price for the selected product.
I have tried but not getting right way to perform this validation.
Modal Code:
App::uses('AppModel', 'Model');
class Code extends AppModel {
public $validate = array(
'discount_amount' => array(
'rule' => array('checkLimit'),
'message' => 'Please supply a valid discount_amount'
),
'discount_percent' => array(
'rule' => array('checkLimit'),
'message' => 'Please supply a valid discount_percent'
)
);
public function checkLimit($field) {
$passed = true;
if (isset($this->data[$this->alias]['discount_amount']) && empty($this->data[$this->alias]['discount_amount'])) {
??????
} else {
??????
}
}
}

Validation rules should not change any data!
So "if 0, save null" is not allowed in a validation rule.
You should implement that logic in a beforeSave() callback rather.
Regarding the validation, there is a second parameter provided containing all the $data you could use to validate other fields (and pull additional required data from the database - your product price probably).
Good documentation is at http://book.cakephp.org/2.0/en/models/data-validation.html#adding-your-own-validation-methods

Be careful using empty and isset, they're not exact opposites. empty('0') returns true, while isset('0') also return true. I think you want to use isset and !isset instead.
public function checkLimit($field) {
if ((!isset($this->data[$this->alias]['discount_amount']) && isset($this->data[$this->alias]['discount_percent'])) {
//only percent is set
if ($this->data[$this->alias]['discount_percent'] >= 1 && $this->data[$this->alias]['discount_percent'] <= 100) {
//percent is in correct range
return true;
}
} else if ((isset($this->data[$this->alias]['discount_amount']) && !isset($this->data[$this->alias]['discount_percent'])) {
//only amount is set
if ($this->data[$this->alias]['discount_amount'] >= 0 && $this->data[$this->alias]['discount_amount'] <= $products.price) {
//amount is in correct range
return true;
}
}
//either neither or both fields are set, or values aren't in correct range
return false;
}

Related

Callback function ignoring other validation rules and executes first

On the HTML form, I have a field such as:
<?php
$token = array(
'name' => 'pc_token',
'id' => 'pc_token',
'class' => 'form-control'
);
echo form_input($token, set_value('pc_token')); ?>
The validation rules set on the field are:
$this->form_validation->set_rules(
'pc_token', 'Token number', 'trim|required|min_length[5]|max_length[12]|callback_token_exists',
array(
'required' => 'You have not provided %s.',
'token_exists' => 'The %s is not valid. Please recheck again'
)
);
And here is the function for the callback
public function token_exists($key)
{
$this->load->model('tokens');
return $this->tokens->IsValidToken($key); // will return true if found in database or false if not found
}
The problem here is that when I keep the pc_token field empty/blank and submit the form, I don't get the expected error message printed on screen.
Current Output
The Token number is not valid. Please recheck again
Expected Output
You have not provided Token number
So why does CI ignore the previous rules (such as required, min_length etc) in this case? If my assumption is correct, the direction is left to right and if even one fails, it does not move to the next rule.
try this in your callback function
check for empty
public function token_exists($key='')
{
if(empty($key)){
$this->form_validation->set_message('token_exists', 'The {field} field is required.');
return FALSE;
}else{
$this->load->model('tokens');
return $this->tokens->IsValidToken($key);
}
// will return true if found in database or false if not found
}
I'll post the approach that I took. But I'll accept Abhishek's answer as he led me in the right direction. It's a bit sad that CI3 did not address it so I'm forced to use an alternate approach.
So, the validation rules become:
$this->form_validation->set_rules(
'pc_token', 'Token number', 'callback_token_exists'
);
And the callback function becomes:
public function token_exists($key)
{
if(trim($key) == "" || empty($key))
{
$this->form_validation->set_message('token_exists', 'You have not provided %s.');
return FALSE;
}
else if(strlen($key) < 5)
{
$this->form_validation->set_message('token_exists', '%s should be at least 5 characters long.');
return FALSE;
}
else if(strlen($key) > 12)
{
$this->form_validation->set_message('token_exists', '%s cannot be greater than 12 characters long.');
return FALSE;
}
else
{
$this->load->model('tokens');
$isValid = $this->tokens->IsValidToken($key);
if(! $isValid)
{
$this->form_validation->set_message('token_exists', 'You have not provided %s.');
}
return $isValid;
}
}

Custom Callback Validation Function to Achieve a Custom Error Message

I have a CI form with a field requiring a decimal number. Currently when the field fails validation the user gets an unhelpful message. "The field must be decimal". This is a poor user experience for a user that feels they should be able to use a leading period. e.g. ".4". I am trying to create a Custom callback validation function to achieve a custom error message. Here is my controller (simplified)...
<?php
class Form extends CI_Controller {
function index()
{
$this->load->helper(array('form', 'url'));
$this->load->library('form_validation');
$this->form_validation->set_rules('expenses', 'Expenses', 'trim|max_length[50]|callback_decimalcustom|xss_clean');
if ($this->form_validation->run() == FALSE)
{
$parent_data = array('country' => $countrydata, 'currency' => $currencydata, 'tour' => $tourdata, 'riders' => $ridersdata, 'measurement' => $measurementdata, 'tourdistance' => $tourdistance);
$this->load->view('myform', $parent_data);
}
else
{
$sql= array (
'expenses'=>$this->input->post('expenses'),
);
$ins = $this->db->insert('donations',$sql);
$this->load->view('formsuccess');
}
}
public function decimalcustom($str) //Custom decimal message
{
if (preg_match('/^[\-+]?[0-9]+\.[0-9]+$/', $str))
{
$this->form_validation->set_message('decimalcustom', 'The %s field is required in 0.00 format.');
return FALSE;
}
else
{
return TRUE;
}
}
}
?>
When testing, the error is not thrown, ever since I changed the validation from decimal to decimal custom. Am I missing something?
preg_match() returns TRUE when it's a valid number but you're trying to throw an error. Do the oposite.. (note the exclamation mark before preg_match)
if ( !preg_match('/^[\-+]?[0-9]+\.[0-9]+$/', $str) ) {
$this->form_validation->set_message('decimalcustom', 'The %s field is required in 0.00 format.');
return FALSE;
}
else {
return TRUE;
}

Custom validation rule in CakePHP

I'm trying to create a custom validation rule for when a checkbox is checked, an input field will need to be filled out in order to proceed to the next page. If unchecked, the input field will not be required.
Here's my code in View:
echo $this->Form->inputs(array(
'legend'=>'Certifications',
'rn_box'=>array(
'type'=>'checkbox',
'label'=>'RN',
'value' => $results['Education']['rn_box']
),
'rn_number'=>array(
'label'=>'RN Number:',
'value' => $results['Education']['rn_number']
),
));
In my Model I created a function:
public function rnCheck () {
if ($this->data['Education']['rn_box'] == '0') {
return false;
}
return true;
}
public $validate = array(
'rn_number' => array(
'rnCheck'=>array(
'rule'=>'rnCheck',
'message'=>'Please Provide a Number'
),
),
);
The checkbox returns a value of 1 if checked, and a value of 0 unchecked. The rn_number field is an input field that I'm trying to validate. I tried playing with 'required', 'allowEmpty', etc. with no luck. If anyone can point me in the right direct, that would be great, thanks!
You can probably just handle it all in the function callback for rn_number. I would also call the function and rule name rn_number to avoid any confusion.
For example, change your validate array to:
public $validate = array(
'rn_number' => array(
'rn_number'=>array(
'rule'=>'rn_number'
),
),
);
And then your custom validation function can look like:
public function rn_number () {
if ($this->data['Education']['rn_box'] == 1) {
if($this->data['Education']['rn_number'] == '')
$errors[] = "Please enter your RN Number.";
}
if (!empty($errors))
return implode("\n", $errors);
return true;
}
I'm handling the error message in the custom validation function - not in the validate array. Let me know if this doesn't work!

codeigniter/Pyro: making sure one of three fields is valid

I have three phone fields (work_phone, home_phone and cell_phone). I would like to make sure that the user fills out at least one of them. This is my validation so far.
array(
'field' => 'work_phone',
'label' => 'lang:employee.work_phone',
'rules' => 'max_length[10]|numeric|callback_check_phones[work_phone]'
),
array(
'field' => 'home_phone',
'label' => 'lang:employee.home_phone',
'rules' => 'max_length[10]|numeric|callback_check_phones[home_phone]'
),
array(
'field' => 'cell_phone',
'label' => 'lang:employee.cell_phone',
'rules' => 'max_length[10]|numeric|callback_check_phones[cell_phone]'
),
function check_phones($value,$name) {
if((!isset($_POST[$name]))) {
$this->form_validation->set_message('check_phones',
'You must enter at least one phone number');
return FALSE;
}
else
{
return TRUE;
}
}
The problem is that it makes ALL the phone fields required. If I try if((!isset($_POST[work_phone])) ||(!isset($_POST[home_phone])) ){ no error is returned.
What's the best way to check if one of the three fields is not null?
EDIT
I got this to work by using empty() instead of isset() and && instead of || I know have
function check_phones($value){
if((empty($_POST['work_phone'])) && (empty($_POST['home_phone'])) && (empty($_POST['cell_phone']))){
$this->form_validation->set_message('check_phones', 'You must enter at least one phone number');
return FALSE;
}
else
{
return TRUE;
}
}
Which works but returns the error three times
just change your !isset statements to isset:
if(isset($_POST['phone1') || isset($_POST['phone2']) || isset($_POST['phone3'])){
//at least 1 is filled.
}else{
//fail
}
how about using the CI input class... $this->input->post will return a false if its empty
if($this->input->post('work_phone') || $this->input->post('home_phone') || $this->input->post('cell_phone'))
{
echo "We have your phone!";
}
else
{
echo "Please enter at least one!";
}
Update for CI's validation...
If they haven't filled in any phone field, you could just add validation for the first one. Like so...
if($_SERVER['REQUEST_METHOD'] == "POST")
{
if($this->input->post('work_phone') || $this->input->post('home_phone') || $this->input->post('cell_phone'))
{
echo "At least one is in there";
}
else
{
$this->form_validation->set_rules('work_phone', '1 Phone', 'required');
// echo "Please enter at least one!";
}
}
The answer is to use empty() instead of isset() see above.

php form validation - the better way?

i've been doing form submission and validationss.
i have been writing long codes to pass data from the controller/php page to a validation class and then pass it back to be displayed on the view.
for instance:
controller
if (isset($_POST["btnSubmit")) {
$result = ClassSomething::validateForm($_POST);
if (!$result) { //no error
ClassSomething::insertRecord(...);
} else {
$error = $result;
}
}
class ClassSomething {
public function validateForm($str) {
if ($str == "") {
return "error messagesss";
}
}
}
and somewhere in the html, i would display $error
is there a better way to do validation in php??
is there validation codes which can be reuse rather then doing it for every form??
tks in adv.
How can I validate POST data for user login form with this class in Kohana:
$post = Validate::factory($_POST)
->rules('login', array(
'not_empty',
'alpha_dash',
'min_length' => array(3),
'max_length' => array(32)
))
->rules('password', array(
'not_empty',
'min_length' => array(4),
'max_length' => array(64)
));
if ($post->check())
{
// Proceed login
}
else
{
// $errors will contain an array of errors. If _POST array was empty - $errors will be an empty array.
$errors = $post->errors('');
}

Categories