Image

Imagebobalien wrote in Imagecakephp

another validation approach?

yes... another... and this one I believe is actually Cake-"recommended"

up until now I've been using the following:
http://wiki.cakephp.org/tutorials:complex_model_validation_routines

This method is not officially cake-supported, but I liked the flexibility it gave in customizing error messages for invalid fields.

Here's another method I tinkered with at some point too: http://cakebaker.wordpress.com/2006/02/06/yet-another-data-validation-approach/

Both were nice and flexible, but a little over-complicated, and not extremely "strict MVC".

Gwoo has recently turned me on to the Model::invalidate() method, which is new to 1.0 I believe, and after a bit of playing last night, it seems to work quite well, and is extremely simple to implement.

You can try and piece together some information about it here and here

In the above google groups link there's an expanded method where someone hacked the invalidates() function to also accept error messages (so the messages could be passed to the error display, instead of residing in the view) however, I could not get the hacked way to work properly. The basic invalidates() work very well tho, and plays nicely with the simple, traditional Cake validation method of having a $validate array in your model, something the other complex validation methods override.

Another point of note is that you can invalidate fields that aren't in your model (such as 'username_taken' or 'image_filesize') and display these errors accordingly in your view. Also, this method plays nice with the regular $html->tagErrorMsg() and doesn't require any additional helpers or edits to app_model.



In my model:
// basic model validation
var $validate = array(
	'username' => VALID_NOT_EMPTY,
	'password' => VALID_NOT_EMPTY 
);

// complex validation
function beforeValidate()
{
	if(!empty($this->data[$this->name]['username']) && ( strlen($this->data[$this->name]['username']) > MAX_USERNAME_LEN || strlen($this->data[$this->name]['username']) < MIN_USERNAME_LEN ))
	{
		$this->invalidate('username');
	}

	if(!empty($this->data[$this->name]['password']) && ( strlen($this->data[$this->name]['password']) > MAX_PWD_LEN || strlen($this->data[$this->name]['password']) < MIN_PWD_LEN ))
	{
		$this->invalidate('password');
	}		
	
	if(isset($this->data[$this->name]['password']) && ($this->data[$this->name]['password'] != $this->data[$this->name]['reppass']))
	{
		$this->invalidate('reppass');
	}

	// Userpic Validation
	if(isset($this->data[$this->name]['userpic_type']) && !empty($this->data[$this->name]['userpic_type']))
	{
		$validTypes = explode(',',VALID_IMAGE_TYPES);
		debug($validTypes);
		debug($this->data[$this->name]['userpic_type']);
		if(!in_array($this->data[$this->name]['userpic_type'],$validTypes))
		{
			$this->invalidate('userpic', 'Invalid File Format.');
		}			
	}		
	
	// i believe return true is necessary to move everything along to the next step
	return true;
}



In my view:
<div class="set-column">
	<div class="label">
		<label>Username:</label> required, unique, <?php echo MIN_USERNAME_LEN ?> to <?php echo MAX_USERNAME_LEN ?> characters
	</div>
	<div class="input">
		<?php echo $html->input('User/username') ?> 
		<?php echo $html->tagErrorMsg('User/username', 'Invalid Username.') ?>
		<?php echo $html->tagErrorMsg('User/username_taken', 'Username already taken.') ?>
	</div>
	<div class="clear">&nbsp</div>
</div>
<div class="set-column">
	<div class="label">
		<label>Password:</label> required, <?php echo MIN_PWD_LEN ?> to <?php echo MAX_PWD_LEN ?> characters
	</div>
	<div class="input">
		<?php echo $html->password('User/password', array('id' => 'user_password')) ?> 
		<?php echo $html->tagErrorMsg('User/password','Invalid Password.') ?>
	</div>
	<div class="clear">&nbsp</div>
</div>
<div class="set-column">
	<div class="label">
		<label>Repeat Password:</label> required
	</div>
	<div class="input">
		<?php echo $html->password('User/reppass', array('id' => 'user_reppass')) ?> 
		<?php echo $html->tagErrorMsg('User/reppass','Passwords do not match.') ?>

	</div>
	<div class="clear">&nbsp</div>
</div>	
<div class="set-column">
	<div class="label">
		<label>Your Userpic:</label> will be resized to fit 100x100 pixels (and a 50x50 pixel thumbnail)
	</div>
	<div class="input">
		<?php echo $html->file('userpic',  array('size'=>40)) ?> 
		<?php echo $html->tagErrorMsg('User/userpic', 'Invalid file format.') ?>
	</div>
	<div class="clear">&nbsp</div>
</div>	


In my controller:
// check if userpic uploaded, and if so, check that it is in a valid format
if(!empty($this->params['form']['userpic']['tmp_name']))
{
	$this->data['User']['userpic_type'] = $this->params['form']['userpic']['type'];
}

// check if Username is unique
if(!empty($this->data['User']['username']))
{
	$user = $this->User->findByUsername($this->data['User']['username']);
	if(!empty($user['User']['username']))
	{
		$this->User->invalidate('username_taken');
	}
}
		
//if($this->User->save($this->data))
if($this->User->save($this->data))
{
  // do some more stuff


Hopefully someone finds this useful!