Safe attributes tip

February 19th, 2009

In my last two posts [1, 2] I explained how to define scenario-based validation rules and safe attributes. Something I have noted is that whenever I end up specifying an attribute as “required” in the validation rules(), I also always end up specifying it as “safe” in safeAttributes() under the same scenario. This got me thinking – is it possible that every “required” attribute must also be “safe” on a given scenario? The answer to that seems to be yes. So I thought, why be redundant? So I went about the task of teaching Yii that all “required” attributes are also “safe”. It seems the most elegant way to do this is by extending getSafeAttributeNames() in your model. So that’s what I did. Now, I’ll share with you. Just drop this code in any model that you would like to have this behavior.

<?php
/*
* I extended this method so that yii will "automagically" understand that
* 'required' attributes (in the given scenario) are also 'safe'.  This way,
* when defining 'safe' attributes in the safeAttributes() method, you can
* neglect to define attributes as safe that you have already defined at "required"
* in your rules() method.  This basically saves typing (and in some cases stupid
* mistakes), which I am always a fan of.  This method could be moved to another model
* from which other models like this could inherit from if you wish.
* 
* You should NOT call this method directly but it is used by Yii internally
*/
public function getSafeAttributeNames($scenario='') {
	$safe = parent::getSafeAttributeNames($scenario);
 
	foreach ($this->validators as $validator) {
		if ((get_class($validator) != 'CRequiredValidator') || !$validator->applyTo($scenario)) continue;
		$safe = array_merge($safe, $validator->attributes);
	}
	return array_unique($safe);
}

Enjoy if you wish and give feedback.

One thing to worry about is speed however. Every time this method is called, it loops through all the validators. If you have a lot of validation rules this could be unwanted. On the other hand, yii only checks the safe attributes on CModel::setAttributes(), which is generally only called on requests with submitted POST data (e.g. forms, and users don’t often expect those pages to be lightning fast). Anyways, I’m making this code snipped sound slower than it actually is. It might be interesting to check how many times this method is called on a given request.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Technorati
  • Reddit
  • RSS
  • Twitter

Categories: Enhancement, Yii

Tags: Leave a comment

Leave a comment


five + 5 =

Feed

http://php-thoughts.cubedwater.com / Safe attributes tip