<?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.
Related
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.
I want to check two field combination validation for duplicate values. I have two fields name and area group.
$this->validate['Name'] = array(
'notEmpty' => array(
'rule' => array('notEmpty'),
'message' => __('err_required', array(__('lbl_Name', true))),
),
'Name' => array(
'rule' => array('uniqueClick', 'GroupID'),
'message' => __(__('lbl_Combination', true)),
)
);
$this->validate['GroupID'] = array(
'notempty' => array(
'rule' => array('notEmpty'),
'allowEmpty' => true,
'message' => __('err_required', array(__('lbl_GroupID', true))),
)
);
public function uniqueClick ($ip)
{
$count = $this->find('count', array(
'conditions' => array(
'Name' => $ip,
'GroupID' => $this->data[$this->alias]['GroupID'])
));
return $count == 0;
}
By this code it check combination in both add and update case ,i want to check combination in both case but by this code it check in edit case always after add. so please give me appropriate solution. reply fast.
Create a custom method use it in either in name or group and pass the value of name/group to custom function and and place the check in function:
$this->validate['Name'] = array(
'notEmpty' => array(
'rule' => array('notEmpty'),
'message' => __('err_required', array(__('lbl_Name', true))),
)
);
$this->validate['GroupID'] = array(
'notempty' => array(
'rule' => array('notEmpty'),
'message' => __('err_required', array(__('lbl_GroupID', true))),
),
'duplicate' => array(
'rule' => array('isDuplicate', $this->data['ModelName']['name']),
'message' => __('err_required', array(__('lbl_GroupID', true))),
)
);
public function isDuplicate($data, $name){
// check here
}
So, I have this method where I save a model and its associated models. It has validation rules, but not on the fields that are causing the errors.
The data being passed to the save method is ok, the return of the save method using atomic = false is true on every field except two, that do not have any validation.
The saveAll/saveAssociated fails, and the return of $this->Model->validationErrors is the list of the fields that are not being validated as a empty array.
I already had searched for this on web and found a similar problem to mine here on StackOverflow, but the answer didn't solve my problem.
EDIT
The link to the problem similar to mine: CakePHP save failing with validation errors set but empty
EDIT 2
Here's the code. The rest of the models are ok, so I won't post it here.
**Add Method**
public function add() {
if ($this->request->is('post')) {
if(empty($this->request->data['User']['referer'])) {
$this->request->data['Partner']['status'] = 1;
$this->request->data['User']['group_id'] = 2;
$this->request->data['User']['status'] = 1;
$this->request->data['Customer']['birthday'] = implode("-", array_reverse(explode("/", $this->request->data['Customer']['birthday'])));
$this->request->data['Customer']['newsletter'] = ($this->request->data['Customer']['newsletter'] == "1") ? true : false;
$this->request->data['Customer']['accept'] = ($this->request->data['Customer']['accept'] == "1") ? true : false;
if(!$this->request->data['Customer']['accept']) {
$this->Session->setFlash(__('You must accept the terms and conditions to proceed.'), 'danger');
} else {
$this->Customer->Partner->create();
var_dump($this->Customer->Partner->saveAssociated($this->request->data, array('atomic' => false)));
debug($this->Customer->Partner->validationErrors);
exit();
if($this->Partner->saveAll($this->request->data)) {
$this->Session->setFlash(__('Your profile has been saved. Welcome to Abaixo da Tabela.'), 'success');
$this->redirect(array('controller' => 'pages', 'action' => 'display', 'home', 'admin' => false));
} else {
$this->Session->setFlash('Ocorreu um erro ao tentar salvar seu perfil. Verifique se os campos estão preenchidos corretamente e tenta novamente.', 'danger');
}
}
}
}
}
** Partner Model **
class Partner extends AppModel {
public $validate = array(
'person_type' => array(
'notEmpty' => array(
'rule' => array('notEmpty'),
),
),
'status' => array(
'numeric' => array(
'rule' => array('numeric'),
),
),
);
public $hasMany = array(
'Address' => array(
'className' => 'Address',
'foreignKey' => 'partner_id',
),
'Contact' => array(
'className' => 'Contact',
'foreignKey' => 'partner_id',
),
'Customer' => array(
'className' => 'Customer',
'foreignKey' => 'partner_id',
),
'User' => array(
'className' => 'User',
'foreignKey' => 'partner_id',
),
);
}
** Address Model **
class Address extends AppModel {
public $validate = array(
'partner_id' => array(
'numeric' => array(
'rule' => array('numeric'),
),
),
'address' => array(
'notEmpty' => array(
'rule' => array('notEmpty'),
),
),
'number' => array(
'notEmpty' => array(
'rule' => array('notEmpty'),
),
),
'zip' => array(
'notEmpty' => array(
'rule' => array('notEmpty'),
),
),
'district' => array(
'notEmpty' => array(
'rule' => array('notEmpty'),
),
),
'city_id' => array(
'numeric' => array(
'rule' => array('numeric'),
),
),
'uf' => array(
'notEmpty' => array(
'rule' => array('notEmpty'),
),
),
);
public $belongsTo = array(
'Partner' => array(
'className' => 'Partner',
'foreignKey' => 'partner_id',
),
'City' => array(
'className' => 'City',
'foreignKey' => 'city_id',
)
);
}
** Customer Model **
class Customer extends AppModel {
public $validate = array(
'partner_id' => array(
'numeric' => array(
'rule' => array('numeric'),
),
),
'birthday' => array(
'date' => array(
'rule' => array('date'),
),
),
);
public $belongsTo = array(
'Partner' => array(
'className' => 'Partner',
'foreignKey' => 'partner_id',
),
'City' => array(
'className' => 'City',
'foreignKey' => 'city_id',
)
);
}
** debug($this->Customer->Partner->validationErrors) **
array (size=5)
'Partner' => boolean true
'Address' =>
array (size=7)
'zip' => boolean true
'address' => boolean true
'number' => boolean true
'adjunct' => boolean false
'district' => boolean true
'uf' => boolean true
'city_id' => boolean true
'Contact' =>
array (size=3)
'email' => boolean true
'phone_1' => boolean true
'phone_2' => boolean true
'User' =>
array (size=5)
'username' => boolean true
'password' => boolean true
'password_confirm' => boolean true
'group_id' => boolean true
'status' => boolean true
'Customer' =>
array (size=4)
'genre' => boolean true
'birthday' => boolean true
'newsletter' => boolean false
'accept' => boolean true
Note the two false responses in the return of the save method.
(Answered by a question edit. Converted to a community wiki answer. See Question with no answers, but issue solved in the comments (or extended in chat) )
The OP wrote:
Turned out that the error was in the view. The form fields for the associated models were like:
echo $this->Form->input('Customer.birthday')
echo $this->Form->input('Customer.newsletter')
echo $this->Form->input('Customer.accept')
When the correct way was:
echo $this->Form->input('Customer.0.birthday')
echo $this->Form->input('Customer.0.newsletter')
echo $this->Form->input('Customer.0.accept')
As in the Book, the fields for models with the hasMany association need a index, in that case, the 0.
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));
I have a custom validation rule to check if two passwords entered are the same, and if they arent I wish to have a message that says "Passwords do not match".
The rule works, however, when the passwords don't match it simply displays the normal error message, what's going on?
var $validate=array(
'passwd2' => array('rule' => 'alphanumeric',
'rule' => 'confirmPassword',
'required' => true,
'allowEmpty'=>false));
function confirmPassword($data)
{
$valid = false;
if ( Security::hash(Configure::read('Security.salt') .$data['passwd2']) == $this->data['User']['passwd'])
{
$valid = true;
$this->invalidate('passwd2', 'Passwords do not match');
}
return $valid;
}
It says "This field cannot be left blank"
EDIT:
The strange thing is, if I leave one of the password fields blank, both error messages say "This field cannot be left blank"
However, if I put something in both, then it correctly says "Passwords do not match"
I think you made it too complex. Here is how I do it:
// In the model
public $validate = array(
'password' => array(
'minLength' => array(
'rule' => array('minLength', '8')
),
'notEmpty' => array(
'rule' => 'notEmpty',
'required' => true
)
),
'confirm_password' => array(
'minLength' => array(
'rule' => array('minLength', '8'),
'required' => true
),
'notEmpty' => array(
'rule' => 'notEmpty'
),
'comparePasswords' => array(
'rule' => 'comparePasswords' // Protected function below
),
)
);
protected function comparePasswords($field = null){
return (Security::hash($field['confirm_password'], null, true) === $this->data['User']['password']);
}
// In the view
echo $form->input('confirm_password', array(
'label' => __('Password', true),
'type' => 'password',
'error' => array(
'comparePasswords' => __('Typed passwords did not match.', true),
'minLength' => __('The password should be at least 8 characters long.', true),
'notEmpty' => __('The password must not be empty.', true)
)
));
echo $form->input('password', array(
'label' => __('Repeat Password', true)
));
You should use the 'message' key in your $validate array to specify the message:
'message' => 'Your passwords do not match'
Further reading: http://book.cakephp.org/view/1143/Data-Validation
And then you can access the fields and the messages by $this->modelName->invalidFields(), which will return you the fields that didn't pass the validation and the message that you have setted for them...
In the controller I mean...
http://book.cakephp.org/view/1182/Validating-Data-from-the-Controller