CakePHP - Validation rule 'last' not working - validation

I have two custom validation rules (I have tested they work correctly):
class PasswordResetKey extends AppModel {
public $validate = array(
'timestamp' => array(
'rule' => '_notExpired',
'message' => 'Your password reset link has expired. Please request another one.',
'last' => true
),
'key' => array(
'rule' => '_validFormat',
'message' => 'You do not appear to have used a valid password reset link. Please request another one.'
)
);
But no matter what I do, the errors returned are always:
Array
(
[key] => You do not appear to have used a valid password reset link. Please request another one.
[timestamp] => Your password reset link has expired. Please request another one.
)
Even when I check that the timestamp rule fails, it still goes on and checks the other rule for 'key' as well. I only want the timestamp error if it is there.

last is for multi rules per field. due to the fact that you only have one rule per field its always last and thus pointless.

My intuition says _notExpired should not fire if the reset link is wrong. I would have that rule raise a flag only if the link is correct but expired.

Related

Handling CodeIgniter form validation (rule keys and data types)

Okay, so I've been searching for a while this question, but couldn't find an answer (or at least some direct one) that explains this to me.
I've been using CodeIgniter 3.x Form Validation library, so I have some data like this:
// Just example data
$input_data = [
'id' => 1,
'logged_in' => TRUE,
'username' => 'alejandroivan'
];
Then, when I want to validate it, I use:
$this->form_validation->set_data($input_data);
$this->form_validation->set_rules([
[
'field' => 'id',
'label' => 'The ID to work on',
'rules' => 'required|min_length[1]|is_natural_no_zero'
],
[
'field' => 'username',
'label' => 'The username',
'rules' => 'required|min_length[1]|alpha_numeric|strtolower'
],
[
'field' => 'logged_in',
'label' => 'The login status of the user',
'rules' => 'required|in_list[0,1]'
]
]);
if ( $this->form_validation->run() === FALSE ) { /* failed */ }
So I have some questions here:
Is the label key really necessary? I'm not using the Form Validation auto-generated error messages in any way, I just want to know if the data passed validation or not. Will something else fail if I just omit it? As this will be a JSON API, I don't really want to print the description of the field, just a static error that I have already defined.
In the username field of my example, will the required rule check length? In other words, is min_length optional in this case? The same question for alpha_numeric... is the empty string considered alpha numeric?
In the logged_in field (which is boolean), how do I check for TRUE or FALSE? Would in_list[0,1] be sufficient? Should I include required too? Is there something like is_boolean?
Thank you in advance.
The "label" key is necessary, but it can be empty.
The "required" rule does not check length, nor does the "alpha_numeric". It checks that a value is present, it does not check the length of said value. For that, there is min_length[] and max_length[].
If you're only passing a 0 or 1, then this is probably the easiest and shortest route.

cakephp saveAssociated and validation foreign_key fails

I have two models that we're going to name Model and RelatedModel. Model has many RelatedModel. So if I add foreign key validation on validation array like:
public $validate = array(
'foreignKey' => array(
'rule' => 'numeric',
'required' => true,
'message' => 'The id of relatedmodel should be a number'
)
)
After I create a add() function to save new registers and in this function I use saveAssociated with validation true, this one fails throwing an error 'The id of relatedmodel should be a number'.
I'm debugging the code and saveAssociated checks validation of both models at the same time and before save Model.
Is this an issue?
I think what this function should do is to validate Model, save it, add foreignKey of RelatedModel and then validate it before save.
I came into this issue only recently. It's not an issue, saveAssociated() is designed to work this way unfortunately.
What you can do is alter the required => true on the fly using the model validator. Check out the book for more information.
http://book.cakephp.org/2.0/en/models/data-validation.html#dynamically-change-validation-rules
This is working as would be expected with your given rule. required in Cake means it expects the value of foreignKey to be set in the save data prior to saving. All the validation will happen before Cake saves the data (and therefore before foreignKey is generated).
You shouldn't need to validate that it is numeric if you are allowing Cake to generate this for you behind the scenes. If you want to check that it is being passed in the data for an UPDATE you could modify the required to be only for an update like this:-
public $validate = array(
'foreignKey' => array(
'rule' => 'numeric',
'required' => 'update',
'message' => 'The id of relatedmodel should be a number'
)
)
Personally I wouldn't bother validating foreign keys unless a user is setting them rather than Cake.
Update:
To validate the foreignKey if it exists in a form submission you can drop the required option from the validation rule:-
public $validate = array(
'foreignKey' => array(
'rule' => 'numeric',
'message' => 'The id of relatedmodel should be a number'
)
);
This will allow you to pass data where the foreignKey is not present without throwing a validation error whilst validating it if it is.

cakephp 2.x include userExists in validating login

I'm new to CakePhp, I'm using CakePhp 2.x.
I am probably going about solving the problem below the wrong way. And I just know I'm overlooked something real simple but,.....
I'm validating login details based on 'Between 5 to 15 characters' they are retuning errors as expected.
[The MODEL]
public $validate = array(
'username' => array(
'between' => array(
'rule' => array('between', 5, 15),
'message' => 'Between 5 to 15 characters'
)
),
'password' => array(
'rule' => array('minLength', '8'),
'message' => 'Minimum 8 characters long'
)
);
[The CONTROLLER]
public function login() {
if ($this->request->data) {
$this->User->set($this->request->data);
if ($this->User->validates() && $this->Auth->login()) {
if ($user = $this->Auth->user()) {
$this->render($this->Auth->redirect());
}else{
//??
}
}else{
$this->User->create();
pr($this->User->invalidFields());
$errors = $this->User->validationErrors;
$data = compact('errors');
$this->set('errors', $data);
$this->set('_serialize', array('errors'));
$this->Session->setFlash('Your username/password combination was incorrect');
}
}
}
So, the problem is, if the fields follow the rules in the model above even if the login details (the user) doesn't exist, no errors will be returned (no good). Would it be correct to add an other validation for this, adding another rule to check if that user actually exists? If so how!?
Or, do I work this into the controllers login function checking if the user exists? I'm a little confused now. Maybe I've been looking at the screen for too long.
Thanks.
Would it be correct to add an other validation for this, adding
another rule to check if that user actually exists? If so how!?
You can add as many rules as you want. In this case you want the rule "unique". Read this section of the book about data validation.
Or, do I work this into the controllers login function checking if the
user exists?
All data manipulation and validation should happen in the model layer of the MVC stack. So put everything into a model method and pass the post data to it and validate it there. You can put all logic into the controller to but that's stupid in terms of not following the MVC pattern. Models can be shared between shells and controllers for example, a controller not. Again you could instantiate a controller in a shell but doing all of this negates any benefit and idea the MVC pattern has. Also a model is competitively easy to test. And yes, you should unit test your code. Check how our users plugin is doing it for example.
You can specify multiple rules per field...
Follow this link to learn more about it...
http://book.cakephp.org/2.0/en/models/data-validation.html#multiple-rules-per-field
a sample code is given below
<?php
[IN The MODEL]
//the following code checks if the username is notempty, is a valid email and is it already taken or not...
public $validate = array(
'username' => array(
'notempty' => array(
'rule' => array('notempty'),
'message' => 'Please enter a valid email.',
),
'email' => array(
'rule' => array('email'),
'message' => 'Please enter a valid email.',
),
'isUnique' => array(
'rule' => 'isUnique',
'message' => 'This username has already been taken.'
)
)
);
?>

Boolean validation check cakephp not working

Hey trying to get a validation check working on a boolean field called 'activated'. Basically if the boolean is 1 then the account is active, meaning they can login. If it is anything else then users cannot login.
Here is my check from the User Model:
public $checkActive = array(
'activated'=>array(
'rule'=>array('equalTo', '1'),
'message'=>'The account must be activated, please check your email.'
));
Unfortunately users are able to login when they are not suppose to.
I believe that validation in models are only tested when data is being saved.
If you are using the Authentication component, you can define a 'scope' which is a condition which must equal true for the user to be authenticated.
'scope' => array('User.activated' => 1)
More info and an example: http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html)
If you have written your own authentication then you could add the condition to your current find statement.
$this->User->find('all', array('conditions' => array('username' => $username, 'password' => $password, 'activated' =>1);
Hope this answers your question.

Validation rule for a composite unique index (non-primary)

I am sure I am not the first who has composite unique keys in tables and who wants to validate them. I do not want to invent the bicycle so I ask here first. I have several tables that have 'id' columns as primary keys and two other columns as unique composite keys. It would be nice to have a validation rule to check that the submitted entry is unique and display a validation error if it is not. In Cakephp it could be done by a custom validation rule. I am pretty sure somebody has created such method already.
Ideally it would be a method in app_model.php that could be used by different models.
I am using that function:
function checkUnique($data, $fields) {
if (!is_array($fields)) {
$fields = array($fields);
}
foreach($fields as $key) {
$tmp[$key] = $this->data[$this->name][$key];
}
if (isset($this->data[$this->name][$this->primaryKey]) && $this->data[$this->name][$this->primaryKey] > 0) {
$tmp[$this->primaryKey." !="] = $this->data[$this->name][$this->primaryKey];
}
//return false;
return $this->isUnique($tmp, false);
}
basically the usage is:
'field1' => array(
'checkUnique' => array(
'rule' => array('checkUnique', array('field1', 'field2')),
'message' => 'This field need to be non-empty and the row need to be unique'
),
),
'field2' => array(
'checkUnique' => array(
'rule' => array('checkUnique', array('field1', 'field2')),
'message' => 'This field need to be non-empty and the row need to be unique'
),
),
So basically this will show the warning under each of the fields saying that it's not unique.
I am using this a lot and it's working properly.
In the CakePHP/2.x versions released in the last few years, the isUnique rule optionally accepts several columns:
You can validate that a set of fields are unique by providing multiple
fields and set $or to false:
public $validate = array(
'email' => array(
'rule' => array('isUnique', array('email', 'username'), false),
'message' => 'This username & email combination has already been used.'
)
);
I'm not sure of the exact version when the feature was available but there's a bug fixed in core as late as October 2014 filed against 2.3 and 2.4 branches.
You could put it in app model, but my suggestion would just be to add it to the model directly by placing the rule with it's $validate property.
Check out the built in isUnique rule.

Resources