I have an AJAX login form. I used CakePHP form helpers to create the form but not the error messages.
The forms data is sent to the controller:
public function login()
{
if ($this->request->is('ajax')) {
if($this->Auth->login()) {
echo "logged In";
} else {
echo "Login Failed";
}
exit;
}
}
I then have in my controller, a validation array:
public $validate = array(
'AccountEmail' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'Please Enter A Valid Email.'
)
),
'AccountPassword' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'Please Enter A Valid Password.'
)
)
);
At the moment, if I fill in the form with random characters it echos out 'login Failed' which is good.
But how can I access the validation data too see what failed?
Chris, the model validation rules are only used when attempting to Save or Update data on the User model.
You could though still return the validation messages by validating the data in your controller. Something similar to:
/**
* Set data against the data model
*/
$this->User->set($this->request->data);
/**
* Validate data and return any error messages
*/
$errors = $this->User->validates();
Related
I have a simple registration form and complete model validation.
public function add() {
// Has any form data been POSTed?
if ($this->request->is('post')) {
$this->User->set($this->request->data); //echo '<pre>'; print_r($this->data);exit;
if($this->User->validates()){
if ($this->User->save($this->request->data)) {
// Set a session flash message and redirect.
$this->Session->setFlash('User Saved!');
return $this->redirect('/users');
}
}
}
}
Modal validation code is below
class User extends AppModel {
public $validate = array(
'username' => array(
'alphaNumeric' => array(
'rule' => 'alphaNumeric',
'required' => true,
'message' => 'Alphabets and numbers only'
),
'between' => array(
'rule' => array('between', 5, 15),
'message' => 'Between 5 to 15 characters'
)
),
'password' => array(
'rule' => array('minLength', '8'),
'message' => 'Minimum 8 characters long'
),
'email' => 'email',
'born' => array(
'rule' => 'date',
'message' => 'Enter a valid date',
'allowEmpty' => true
)
);
}
The problem is that when i delete html fields using firebug and submit form it save data with blank entries . i think its a big problem i am facing because it not good practice to save blank entry and i want to stop it by the hacker or any one.
please help.
Add the validation rule 'notEmpty' for all fields which shouldn't be blank entries in the database.
Reference: cookbook
I am agree with semmelbroesel13
please use notEmpty rules as:
'rule' => array('notempty')
Updated:
Please try below code and check whats the query exactly
public function add() {
// Has any form data been POSTed?
if ($this->request->is('post')) {
$this->User->set($this->request->data); //echo '<pre>'; print_r($this->data);exit;
if($this->User->validates()){
if ($this->User->save($this->request->data)) {
$log=$this->User->getDataSource()->getLog(false, false);
echo "<pre>";print_r($log);exit;
// Set a session flash message and redirect.
$this->Session->setFlash('User Saved!');
return $this->redirect('/users');
}
}
}
}
I am using 'MultivalidatableBehavior' in cakephp. Though it worked fine with previous version. But its not working with Cakephp 2.4.0 version. Is their any changes with this behaviour. Because When I use this code.
var $validationSets = array( 'ruleset mentioned in it. ');
Though my request go through the Behaviour class but its not putting validation on the desired field. I have also checked $this->request->data Its also valid and for same Model where ruleset has been written.
I tried to debug using die in my MultivalidatableBehavior class. Though during valiation my request falls in the function of setValidation(&$model, $rules = array()) {. Please suggest if it is compatible with greater version of cakephp2.3.
My tried code..
Model Code :
var $actsAs = array('Multivalidatable');
var $validationSets = array(
'login' => array(
'username' => array('required' => array('rule' => array('notEmpty'), 'message' => 'Username is required !!')),
'password' => array('required' => array('rule' => array('notEmpty'), 'message' => 'Password is required !!')),
),
);
Controller Call.
$this->User->setValidation('login'); Fields are also with same name.
Its not validating If I put if($this->User->setValidation('login')) it returns false.
Thanks to Piotr Beschel for helping me out. I shouldn't use any sort of behaviour. It can also be achieved without behaviour. My Model code would be
public $validationAdmin = array(
'adminLogin' => array(
'username' => array('required' => array('rule' => array('notEmpty'), 'message' => 'Please enter your username !!')),
'password' => array('required' => array('rule' => array('notEmpty'), 'message' => 'Please enter your password !!')),
),
'adminForgotPassword' => array(
'email' => array('required' => array('rule' => array('notEmpty'), 'message' => 'Please enter your email address !!'),
'email' => array('rule' => array('email'), 'message' => 'Please enter valid mail address')),
),
);
That is simply creating variable named $valdiationAdmin I have named it as admin to know following rule set is for admin.
My sample controller code would be.
$this->Admin->validate = $this->Admin->validationAdmin['adminLogin'];
Just this way. If form has data to save it would move like butter. In case data is just validating I have to force form to validate it(In case login where data is not saved).
if ($this->Admin->validates()) {
} else {
$errors = $this->Admin->validationErrors;
$this->set('validationErrors', $errors);
}
It would validate my form. Even add error message to form field in ctp file. I need not to write $this->form->error('fieldname');
Thanks again to all the viewer. Suggest me something if more better. I am thinking to validate data of other form if associated with one form, with same implementation. Help if you can.
The method
$this->User->setValidation('login')
only chooses which validation Set will be used.
Use:
if ($this->User->validates()) {
...
to get the result of the validation.
I am querying database records to check if a username already exists this way:
$q = Doctrine_Query::create()
->from('Tcc_Model_User u')
->where('u.Username = ?', $input['Username']);
$object = $q->fetchOne();
if(is_object($object)) {
// not sure what to do here
} else {
// ok to record
What I cannot make it work is how to show a message that username is already taken next to the Username field of the submitted form. Could please anyone help me? Really appreciated any help. Thank you
EDITED:
Thanks to Drew010 I solved the above problem by adding:
$form->getElement('Username')->addError('Sorry, that username is already taken!');
in the first of the conditional statement. Thank again drew010.
Since you are using Zend_Form, there is a validator that can do this for you.
See Zend_Validate_DbNoRecordExists
They give an example for validating that a given username does not exist in the database.
Here is an example from one of my applications, the third validator checks that the username does not already exist:
$this->addElement('text', 'username', array(
'label' => 'User Name:',
'required' => true,
'validators' => array('NotEmpty'),
'decorators' => $this->elementDecorators,
'validators' => array(
array('StringLength', true, array('min' => 4,
'messages' => array(
Zend_Validate_StringLength::TOO_SHORT =>
'Account username must be at least %min% characters'
)
)),
array('Regex', true, array('pattern' => '/^\w(?:[\w\d\.\-_]+)(?:\w|\d)$/',
'messages' => array(
Zend_Validate_Regex::NOT_MATCH =>
"The username contained invalid characters"
)
)),
array('Db_NoRecordExists', true, array(
'table' => 'accounts', 'field' => 'username',
'messages' => array(
Zend_Validate_Db_NoRecordExists::ERROR_RECORD_FOUND =>
"An account with the username '%value%' is already registered"
)
))
)
));
Also, for future reference, if you do extended validation you can't do with a validator, you can add an error to a specific form element like this:
if ($something_was_wrong) {
$form->getElement('username')
->addError('Username already exists!');
}
I would create a separate Doctrine-based validator modeled on the Zend_Validate_Db_NoRecordExists validator and add that validator directly to the element
The validator:
class My_Validate_UsernameAvailable extends Zend_Validate_Abstract
implements Zend_Validate_Interface
{
const NOT_AVAILABLE = 'usernameAvailableNot';
protected $_messageTemplates = array(
self::NOT_AVAILABLE => "Username is not available",
);
public function isValid($value)
{
$q = Doctrine_Query::create()
->from('Tcc_Model_User u')
->where('u.Username = ?', $value);
if ($q->fetchOne()){
$this->_error(self::NOT_AVAILABLE);
return false;
}
return true;
}
}
Then in the form, attached to the username element:
'validators' => array(
// your other valiadators
array(new My_Validate_UsernameAvailable(), true),
),
Then there is no extra handling required in the controller.
I'm using a simple registration form for CakePHP.
This is my edit view:
<h2>Add User</h2>
<?php echo $form->create('User');
echo $form->input('first_name');
echo $form->input('last_name');
echo $form->input('email');
echo $form->input('address');
echo $form->input('phone');
echo $form->end('Edit');?>
These are my validation rules in User.php
class User extends AppModel {
var $name = 'User';
var $validate = array(
(... more rules here ...)
'password' => array('rule' => array('confirmPassword', 'password'),
'message' => 'Passwords do not match'),
'password_confirm' => array('rule' => 'alphanumeric',
'required' => true)
);
It's a stupid question, but when I use the edit form, the saving of the data fails, because I require a password input in the last rule. That rule was added for the register page, of course.
I've found billions of ways to bypass this problem (disable validation on saving, selecting which fields to save, ...), but I wonder what the "correct" CakePHP way of doing this is? Seems like such a simple problem, but I can't find any documentation on how it has to be done the clean way.
To make my question more clear: I don't want an edit user page where passwords can be changed.
the Cake way is to simply set the validation rule to apply only on create, allowing you to freely edit your data without having to validate the field again.
var $validate = array(
'fieldName' => array(
'rule' => 'ruleName'
'required' => true,
'allowEmpty' => false,
'on' => 'create', // or update <-- here
'message' => 'Your Error Message'
)
);
And of course, if you don't want the password field edited here, just remove the appropriate input
I use multiple validation sets:
In your model, or app_model, override the validates function with this:
function validates($options = array()) {
// copy the data over from a custom var, otherwise
$actionSet = 'validate' . Inflector::camelize(Router::getParam('action'));
if (isset($this->validationSet)) {
$temp = $this->validate;
$param = 'validate' . $this->validationSet;
$this->validate = $this->{$param};
} elseif (isset($this->{$actionSet})) {
$temp = $this->validate;
$param = $actionSet;
$this->validate = $this->{$param};
}
$errors = $this->invalidFields($options);
// copy it back
if (isset($temp)) {
$this->validate = $temp;
unset($this->validationSet);
}
if (is_array($errors)) {
return count($errors) === 0;
}
return $errors;
}
In your controller:
class UsersController extends AppController {
function forgot() {
$this->User->set($this->data);
$this->User->validationSet = 'forgotpassword';
if ($this->User->validates()) {
// send email to reset password and show success message
}
}
}
And finally back in your model, build a validation array, you can have your default validation array, then add a supplemental array such as
class User extends AppModel {
var $validate = array( ... );
var $validateForgotpassword = array( ... );
}
More details here:
http://snook.ca/archives/cakephp/multiple_validation_sets_cakephp
(note the code sample in the article has a bug in it, so be sure to change $param = 'validate' . $validationSet; to $param = 'validate' . $this->validationSet;)
remove your 'required' => true, it is not doing what you think its doing.
'required' => true means that the field should be present in any data that is saved. you are not passing it.
Can anyone help me with a clear and complete example on how to set validations for 2 fields, say an email and password, with error messages?
From my understanding, the correct format is:
var $validate = array(
'password' => array(
'rule' => array('minLength', '8'),
'message' => 'Minimum 8 characters long'
),
'email_id' => array('email')
);
but I can’t seem to get it work (show a validation message, or halt the execution of the action) in my tests.
Validations work fine but no way for the custom messages to appear!
EDIT
The validations and page redirections work fine now. Only the specific messages do not appear. That is, if I enter a password less than 8 characters, the message "minimum 8 characters needed" should appear immediately or after I click the register button. Is there any method to do this?
EDIT 2
My view file
<!-- File: /app/views/forms/index.ctp -->
<?php
echo $javascript->link('prototype.js');
echo $javascript->link('scriptaculous.js');
echo $html->css('main.css');
?>
<div id="register">
<h3>Register</h3>
<?php
echo $form->create('User',array('action'=>'register'));
echo $form->input('User.name');
echo $form->input('User.email_id');
echo $form->input('User.password');
echo $form->end('Register');
?>
</div>
<div id="login">
<h3>Login</h3>
<?php
echo $form->create('User',array('action'=>'login'));
echo $form->input('User.email_id');
echo $form->input('User.password');
echo $form->end('Login');
?>
</div>
Controller:
<?php
class UsersController extends AppController
{
var $name = 'Users';
var $uses=array('Form','User','Attribute','Result');
var $helpers=array('Html','Ajax','Javascript','Form');
function register()
{
$userId=$this->User->registerUser($this->data);
$this->User->data=$this->data;
if (!$this->User->validates())
{
$this->Flash('Please enter valid inputs','/forms' );
return;
}
$this->Flash('User account created','/forms/homepage/'.$userId);
}
function login()
{
$userId=$this->User->loginUser($this->data);
$this->User->data=$this->data;
if (!$this->User->validates())
{
$this->Flash('Please enter valid inputs','/forms' );
return;
}
if($userId>0){
$this->Flash('Login Successful');
$this->redirect('/forms/homepage/'.$userId);
break;
}
else{
$this->flash('Username and password do not match.','/forms');
}
}
}
?>
Model:
<?php
class User extends AppModel {
var $name = 'User';
var $components=array('Auth');
var $validate = array(
'name' => array(
'rule' => VALID_NOT_EMPTY,
'message' =>'Name cannot be null.'
),
'password' => array(
'rule' => array('minLength', '6'),
'message' => 'Minimum 6 characters long.'
),
'email_id' => array(
'rule'=> array('email'),
'message'=>'Invalid email.'
)
);
function registerUser($data)
{
if (!empty($data))
{
$this->data['User']['name']=$data['User']['name'];
$this->data['User']['email_id']=$data['User']['email_id'];
$this->data['User']['password']=$data['User']['password'];
if($this->save($this->data))
{
$this->data['User']['id']= $this->find('all',array('fields' => array('User.id'),
'order' => 'User.id DESC'
));
$userId=$this->data['User']['id'][0]['User']['id'];
return $userId;
}
}
}
function loginUser($data)
{
$this->data['User']['email_id']=$data['User']['email_id'];
$this->data['User']['password']=$data['User']['password'];
$login=$this->find('all');
foreach($login as $form):
if($this->data['User']['email_id']==$form['User']['email_id'] && $this->data['User']['password']==$form['User']['password'])
{
$this->data['User']['id']= $this->find('all',array('fields' => array('User.id'),
'conditions'=>array('User.email_id'=> $this->data['User']['email_id'],'User.password'=>$this->data['User']['password'])
));
$userId=$this->data['User']['id'][0]['User']['id'];
return $userId;
}
endforeach;
}
}
?>
Here is a live example from my project..
This is how you set up your validation in your model: Article model
Ignore the fact that I'm initializing the validate array from constructor, you can keep doing it like you're doing it now if you don't plan on implementing I18n and L10n.
Handling validation errors in controller: Articles controller
From line 266 to 280 you can see validation and save errors being handled with setFlash() + return.
That's pretty much all you need to do, just don't forget you need to use the FormHelper for your forms for the messages to work as expected.
Common error: you must not do a $this->redirect() after failed validation.
Hopefully this will set you on the right track :)
Why dont you try $this->modelName->invalidFields(), which will return you an array with the fields that failed validation and the message to display.
http://book.cakephp.org/view/1182/Validating-Data-from-the-Controller