$this->save($data, true, array('fields', 'to', 'save'));
i left my validation inside the models, one in user.php and one in user_info.php
the "User" model validates, but before i want to save the data, i want to check if the "UserInfo" is valid as well. But it just skippes this second validation.
All data is inserted in the DB - although you could add all kinds of stuff to the "homepage" field of "UserData" right now.
USER MODEL:
class User extends AppModel {
var $name = 'User';
var $validate = array(
'username' => array(
'alphanumeric' => array(
'rule' => array('alphanumeric'),
'required' => true,
'message' => 'Username ungueltig'
),
'unique' => array(
'rule' => array('isUnique'),
'message' => 'Username gibt es schon'
)
),
'email' => array(
'email' => array(
'rule' => array('email'),
'required' => true,
'message' => 'Email ungueltig'
),
'unique' => array(
'rule' => array('isUnique'),
'message' => 'Email gibt es schon'
),
'between' => array(
'rule' => array('between', 4, 65),
'message' => 'Between 4 to 65 characters'
)
),
'password' => array(
'password_between' => array(
'rule' => array('between', 4, 65),
'required' => true,
'message' => 'Between 4 to 65 characters'
)
),
'pwd_repeat' => array(
'between' => array(
'rule' => array('between', 4, 65),
'required' => true,
'message' => 'Between 4 to 65 characters'
),
'identicalFieldValues' => array(
'rule' => array('identicalFieldValues','password'),
'message' => '** error **'
)
)
);
...
USERINFO MODEL:
class UserInfo extends AppModel {
var $name = 'UserInfo';
var $validate = array(
'homepage' => array('alphanumeric'),
'sex' => array('numeric'),
'zipcode' => array('alphanumeric'),
'city' => array('alphanumeric'),
'country_id' => array('numeric'),
'countries_province_id' => array('numeric'),
'job' => array('alphanumeric')
);
...
USERS CONTROLLER:
function register() {
$this->DarkAuth->redirectLoggedIn();
if (!empty($this->data)) {
$this->User->create();
$this->User->set($this->data['User']);
if ($this->User->validates() && $this->User->UserInfo->validates()) {
$this->data['User']['password']=DarkAuthComponent::hasher($this->data['User']['password']);
if ($this->User->save($this->data,false)) { // validation is already done
$this->data['UserInfo']['user_id'] = $this->User->id;
$this->User->UserInfo->save($this->data,false); // validation is already done (STILL NOT WORKING!)
$this->Session->setFlash(__('You have successfully registered', true));
$this->redirect(array('action'=>'registered'));
} else {
$this->Session->setFlash(__('Registration could not be continued', true));
}
} else {
$this->Session->setFlash(__('The Data could not be saved. Please, try again.', true));
}
}
//$groups = $this->User->Group->find('list');
//$this->set(compact('groups'));
}
Wow!, I was writing something like this, you saved me a lot of work. (However I hate you because it seemed like a cool thing to do :P ).
Just kidding, you did an awesome work! thank you!
Finally got an opportunity to play with this.
Firstly, it's a very elegant solution but I might have hit a (minor) snag.
The validation information is not passed to the view. Which means the $form->input() output doesn't autmatically highlight required fields.
For example: If you create a model with the validation sets validateRegister and validateEdit and don't create a default validate then the Registration form doesn't highlight the fields in validateRegister marked as required=true.
Here's my solution: In AppModel:
function setValidate($rule = null) {
if ($rule == null) {
$rule = 'validate' . Inflector::camelize(Router::getParam('action'));
if (!isset($this->$rule)) {
$rule = "validate";
}
}
$this->validate = $this->$rule;
}
In your controller method:
function register() {
$this->User->setValidate();
if(!empty($this->data)) {
$this->User->set($this->data);
if ($this->User->validates()) {
}
}
}
$this->User->setValidate() uses the validation rule named after the current action ($validateRegister in this case)
$this->User->setValidate("foo") uses the validation rule $foo set in the model
If you leave out $this->User->setValidate, it defaults to using the default $validate
Minor enhancement to AppModel:
function AppModel() {
parent::__construct();
$this->setValidate();
}
Now you don't have to explicitly user $this->Model->setValidate() in your controller method
:-)
explicitly set*
Just wanted to note that the following line:
$param = 'validate' . $validationSet;
Should be:
$param = 'validate' . $this->validationSet;
Cheers, just the approach I was looking for. Just a note to other readers, as this caught me up, retrieve the invalid fields from the model using:
$this->User->validationErrors;
It might be obvious, but calling:
$this->User->invalidFields();
Will run the validation over again, not using the rules you specifed in validates(). This tripped me up, but otherwise works really well.
Thanks for the article. I have been growing increasingly frustrated with Cake's current validation setup making it seemingly impossible for me to cater for different situations like registering, editing profile and changing password.
@Richard@Home: Is it possible to cater for more than one form on one page, each with different validation sets?
This is fantastic! Do you think it would be hard to get it working like CodeIgniter, where all the validation arrays can be stored in a global $config variable according to the model/action string? (See "Associating a Controller Function with a Rule Group" just a bit down on this page: http://codeigniter.com/user_guide/libraries/form_validation.html#savingtoconfig)
Again, thanks!
:-j
@Derick: Thanks... it's always the easy and logical step that I overlook...