Cakephp How to validate an array to make sure that it has at least five items or more - cakephp

Hie guys i need help with my code. I have a form where a student selects subjects, marks and grades they obtained. Subjects and grades are a dropdown menu and they are in a loop. I want a student to enter at least five subjects including english language. each subject is referenced by a subject code. Can you help me do this?
My Controller function is
subject_code' => $this->data['ApplicantOlevelQualification']['subject_code'][$i],
'grade' => $this->data['ApplicantOlevelQualification']['grade'][$i],
My model is as follows
public $validate = array(
'grade' => array(
'notempty' => array(
'rule' => array('notempty'),
// extra keys like on, required, etc. go here...
),
'ruleName2' => array(
'rule' => array('inList', array('A', 'B','C','D','E')),
'message' => 'Not in range.',
),
),
'subject_code' => array(
'numeric' => array(
'rule' => array('numeric'),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
//'required' => false,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),

You need to create a custom validation.
Have a look here:
http://book.cakephp.org/1.3/view/1179/Custom-Validation-Rules
An example:
<?php
class User extends AppModel {
var $name = 'User';
var $validate = array(
'promotion_code' => array(
'rule' => array('limitDuplicates', 25),
'message' => 'This code has been used too many times.'
)
);
function limitDuplicates($check, $limit){
//$check will have value: array('promomotion_code' => 'some-value')
//$limit will have value: 25
$existing_promo_count = $this->find( 'count', array('conditions' => $check, 'recursive' => -1) );
return $existing_promo_count < $limit;
}
}
?>

Related

isUnique Validation in CakePHP hasMany association

Database Structure
I have two tables, users and nicks.
In users table I have a field username and in nicks table I have a field nick_name
There is a hasMany association between users and nicks
public $hasMany = array(
'Nick' => array(
'className' => 'Nick',
'foreignKey' => 'user_id',
'dependent' => true
)
);
In the User model I am validating to allow only unique username during registration by
'username must be unique' => array(
'rule' => 'isUnique',
'message' => 'username is already taken'
)
but I also don't want to allow users to register any previously used nick names as their username. for that.
'somebody use that name as a nickname' => array(
'rule' => 'checkNickName',
'message' => 'That name is already in use'
)
and
public function checkNickName(){
$nick2 = $this->find('all');
$nickNames = array();
foreach($nick2 as $name2){
foreach($name2['Nick'] as $name1){
array_push($nickNames,strtolower($name1['nick_name']));
}
}
$username = strtolower($this->data['User']['username']);
return in_array($username,$nickNames);
}
But that's not working. What should I to make it work?
If I understand correctly, you want to ensure the username is unique but also that the username has not been used as a nickname by anybody also, so why not use something like this?
public function checkNickIsUnique($check = array()) {
$value = array_values($check);
$nicknameExists = $this->Nick->find('count', array(
'conditions' => array(
'Nick.nick_name' => $value[0]
)
));
return ($nicknameExists > 0) ? false : true;
}
And in your user model, assuming it's directly related to nick, have this in the validation.
public $validate = array(
'username' => array(
'isUnique' => array(
'rule' => 'isUnique',
'message' => 'That username has already been taken'
),
'checkNickIsUnique' => array(
'rule' => array('checkNickIsUnique'),
'message' => 'Your username has already been taken as a nickname'
)
),
);
All it's doing is passing the value from the validation to the method, and checking if that value exists as a nickname within the nicks table, if it does it fails validation otherwise it passes.
First find the nicknames.
$nick2 = $this->Nick->find('all');
Then the result array will be
nick2 = array(
0 => array( //first foreach
'Nick' => array(
nickname => 'TEST'
)
)
)
so remove the second foreach and save the value as using $name2['Nick']['nickname']
public function checkNickName(){
$nick2 = $this->Nick->find('all');
$nickNames = array();
foreach($nick2 as $name2){
array_push($nickNames,strtolower($name2['Nick']['nick_name']));
}
$username = strtolower($this->data['User']['username']);
return in_array($username,$nickNames);
}
just need use the username of the input form.
in your view example:
<?php echo $this->Form->input('username', array(
'label' => array(
'text' => 'Provide your username'
)
)); ?>
and in your model you need change
'username' => array(
'nonEmpty' => array(
'rule' => array('notEmpty'),
'message' => 'not empty please',
'allowEmpty' => false
),
'unique' => array(
'rule' => array('isUniqueUsername'),
'message' => 'username is already taken'
),
),
'nickname' => array(
'nonEmpty' => array(
'rule' => array('notEmpty'),
'message' => 'not empty',
'allowEmpty' => false
),
'unique' => array(
'rule' => array('checkNickName'),
'message' => 'That name is already in use'
)
)
your condition example for is validation is unique user name, use this:
EDIT
'username' => array(
'unique' => array(
'rule' => array('checkNickName'),
'message' => 'username is already taken'
),
),
in your function:
public function checkNickName($check) {
$this->loadModel('Nick');
$username = $this->Nick->find(
'first',
array(
'fields' => array(
'Nick.id',
'Nick.nickname'
),
'conditions' => array(
'Nick.nickname' => $check['username']
)
)
);
if(!empty($username)){
if($this->data[$this->alias]['id'] == $username['User']['id']){
return true;
}else{
return false;
}
}else{
return true;
}
}
A better solution that doesn't require tons of additional code is this:
$valid = $this->User->saveAll($this->request->data, array(
'atomic' => false,
'validate' => 'only'
));
debug($valid);
It will validate the record and all other records attached to it as well, no more code required, just make sure you have the isUnique rule in your associated nicknames model. It will as well invalidate the correct fields in your form.

Validation get's triggered even when custom validation rule is false. Why?

<?php
App::uses('AppModel', 'Model');
class Announcement extends AppModel {
public $validate = array(
'id' => array(
'notempty' => array(
'rule' => array('notempty'),
),
'numeric' => array(
'rule' => array('numeric'),
),
),
'enabled' => array(
'numeric' => array(
'rule' => array('numeric'),
),
'boolean' => array(
'rule' => array('boolean'),
),
),
'firstPageEnterDate' => array(
'datetime' => array(
'rule' => 'compareDates',
'message' => 'attention to data interval',
),
),
'firstPageLeaveDate' => array(
'datetime' => array(
'rule' => array('datetime'),
),
'notempty' => array(
'rule' => array('notempty'),
),
)
);
public function compareDates() {
if ($this->data[$this->alias]['enabled'] == 1) {
return $this->data[$this->alias]['firstPageEnterDate'] < $this->data[$this->alias]['firstPageLeaveDate'];
}
}
}
The problem is:
It displays the validation message set on firstPageEnterDate, regardless, if
$this->data[$this->alias]['enabled'] == 1 or not.
Please note that this condition:
$this->data[$this->alias]['enabled'] == 1 is not always true. But even when it's false, so the contents inside don't run, still the message appears.
So, it seems that, if Cake sees a rule enabled and a message, regardless what is inside rule, it triggers the validation message associated!
Any clue why?
'firstPageEnterDate' => array(
'datetime' => array(
'rule' => 'compareDates',
'message' => 'attention to data interval',
),
Return true in compareDates() if it is valid -- or if you don't want to check it because that counts as valid.
public function compareDates() {
if ($this->data[$this->alias]['enabled'] != 1) return true; // we don't want to check
return $this->data[$this->alias]['firstPageEnterDate'] < $this->data[$this->alias]['firstPageLeaveDate'];
}
You can also check in beforeValidate() callback the value of enabled and unset that validation rule from there.

CakePHP Custom Validation Method Not Called With allowEmpty

I have a model that has a first name, last name, and organization/company name field. The user must enter either a first name and a last name OR an organization name.
The issue is that my custom validation method ("validateNames") is never called. For debugging purposes, I have a "die" statement there, rather than real validation logic -- but the die statement is never reached.
My model looks like:
class Contact extends AppModel {
public $validate = array(
'first_name' => array(
'rule' => 'validateNames',
'allowEmpty' => true,
'required' => false
),
'last_name' => array(
'rule' => 'validateNames',
'allowEmpty' => true,
'required' => false
),
'organization' => array(
'rule' => 'validateNames',
'allowEmpty' => true,
'required' => false
)
);
public function validateNames($check) {
die('here');
}
}
The problem is that as long as I have 'allowEmpty' in the validation rules, my custom validation method is never called (and the 'die' statement is never reached). But if I remove 'allowEmpty', then an HTML "required" attribute is added to each INPUT field (even though I have 'required' => false) -- this prevents the form from being submitted unless all three fields are filled in, when only one (organization) or two (first and last names) are actually required.
You must have to pass in array if you want to call 2 or more validation with same fields
like
class Contact extends AppModel {
public $validate = array(
'first_name' => array(
'rule1' => array(
'rule' => 'validateNames',
'message' => 'Must be a valid first name',
'allowEmpty' => true
),
),
'last_name' => array(
'rule1' => array(
'rule' => 'validateNames',
'message' => 'Must be a valid names',
'allowEmpty' => true
),
'organization' => array(
'rule' => 'validateNames',
'allowEmpty' => true,
'required' => false
)
);
public function validateNames($check) {
die('here');
}
}
let me know if i can help you more.
Remove allowEmpty option from the validation rules and disable required option when outputting the field in your view. Try this:
Model:
class Contact extends AppModel {
public $validate = array(
'first_name' => array(
'rule' => 'validateNames'
),
'last_name' => array(
'rule' => 'validateNames'
),
'organization' => array(
'rule' => 'validateNames'
)
);
public function validateNames($check) {
die('here');
}
}
View:
echo $this->Form->input('first_name', array('required' => false));
echo $this->Form->input('last_name', array('required' => false));
echo $this->Form->input('organization', array('required' => false));

Form validation on a HMBTM field - CakePHP

I have a cakephp 2.2 app I'm working on that allows users to submit an expenses claim. The expenese claim is made up of many expenese which have an expense code. The relationships are as follows:
ExpenseClaim hasMany Expense
Expense belongsTo ExpenseClaim
Expense hasAndBelongsToMany ExpenseCode
I want to add validation to ensure when the form is completed the expense code must be complete for each expense but for some reason adding a normal validation rule to the expense model doesnt work, obviously I'm missing something.
Heres the validation in the expense model:
class Expense extends AppModel {
/**
* Display field
*
* #var string
*/
public $displayField = 'id';
/**
* Validation rules
*
* #var array
*/
public $validate = array(
'date' => array(
'notempty' => array(
'rule' => array('notempty'),
'message' => 'Date cannot be blank',
),
),
'sitename' => array(
'notempty' => array(
'rule' => array('notempty'),
'message' => 'Sitename cannot be blank',
),
),
'detail' => array(
'notempty' => array(
'rule' => array('notempty'),
'message' => 'Details cannot be blank',
),
),
'ExpenseCode' => array(
'multiple' => array(
'rule' => array('multiple', array('min' => 1)),
'message' => 'You need to select at least one tag',
),
),
When $this->request->data is submitted via the expenseClaim/add method it looks like this:
/app/Controller/ExpenseClaimsController.php (line 179)
array(
'submit' => 'Save',
'Expense' => array(
(int) 0 => array(
'date' => array(
'day' => '25',
'month' => '03',
'year' => '2013'
),
'sitename' => '123',
'detail' => 'test',
'ExpenseCode' => array(
'ExpenseCode' => ''
),
'billable' => '1',
'amount' => '100',
'miles' => '',
'total' => '100',
'billable_mileage' => '',
'recorded_global_mileage_rate' => '0.4'
)
),
'CashFloat' => array(
'amount' => ''
),
'ExpenseClaim' => array(
'user_id' => '16',
'claim_status_id' => '1',
'date_submitted' => '2013-03-25 18:20:53'
)
)
As you can see the ExpenseCode is empty... How can I ensure that this is not the case?
I managed to solve this by adding the following to my Expense model:
function beforeValidate() {
if (!isset($this->data['ExpenseCode']['ExpenseCode']) || empty($this->data['ExpenseCode']['ExpenseCode'])) {
$this->invalidate('ExpenseCode', 'Type cannot be blank');
}
return true;
}
Hope that helps someone.

cakephp 2.0 unique multiple field validation

im my database i have a discounts table, a user makes a discount for a specific "range","category","supplier" and product type. How do i make cakephp not allow multiple "discounts"?
eg a discount is
user_id 100
category_id 1
range_id 2
producttype "doors"
discount 10%
How to i ensure that another discount cant be created for that supplier,range,category and product type?
My Discount model has only one relation ship in it (not sure if that makes a difference)
<?php
App::uses('AppModel', 'Model');
/**
* Discount Model
*
* #property User $User
*/
class Discount extends AppModel {
/**
* Validation rules
*
* #var array
*/
//public $displayField = 'discount';
public $validate = array(
/*'title' => array(
'notempty' => array(
'rule' => array('notempty'),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
//'required' => false,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),*/
'user_id' => array(
'numeric' => array(
'rule' => array('numeric'),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
//'required' => false,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
'discount' => array(
'numeric' => array(
'rule' => array('numeric'),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
//'required' => false,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
);
//The Associations below have been created with all possible keys, those that are not needed can be removed
/**
* belongsTo associations
*
* #var array
*/
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
}
It's very simple to handle unique in cakephp with having multiple fields
In Model, for the discount validation rules like:
public $validate = array(
'discount' => array(
'numeric' => array(
'rule' => array('numeric'),
),
'isUnique' => array(
'rule' => array('isUnique',array('user_id','category_id','range_id','producttype'),false),
'message' => 'discount already Exist.'
)
),
);

Resources