Filter Out Unnecessary Recursive Relationships

By Mark aka "marklap"
Add a small function to your AppModel to filter out those recursive relationships that are unnecessary for a particular controller action.
I wrote this using the following articles for references. Thanks folks, they helped me write this snippet in about 15 minutes.

unbindAll by cornernote
Keeping bindModel and unbindModel out of your Controllers by TommyO
An improvement to unbindModel on model side by mariano

I didn't need the full functionality of some of these solutions. I just needed a way to quickly and succinctly filter out a particular model's associations.

Please comment with your observations, corrections, and/or comments.

Add this function to your AppModel:

Model Class:

Download code <?php 
class AppModel extends Model{

    
/**
     * Performs an 'unbindModel' on an array of associations
     * 
     * @param array $bindings An array of model associations to unbind from current model
     * @return null
     */
    
function filterBindings($bindings null) {
        if (empty(
$bindings) && !is_array($bindings)) {
            return 
false;
        }
        
$relations = array('hasOne''hasMany''belongsTo''hasAndBelongsToMany');
        
$unbind = array();
        foreach (
$bindings as $binding) {
            foreach (
$relations as $relation) {
                if (isset(
$this->$relation)) {
                    
$currentRelation $this->$relation;
                    if (isset(
$currentRelation) && isset($currentRelation[$binding])) {
                        
$unbind[$relation][] = $binding;
                    }
                }
            }
        }
        if (!empty(
$unbind)) {
            
$this->unbindModel($unbind);
        }
    }
}
?>


Then in your controller use the 'filterBindings' function:

Controller Class:

Download code <?php 
class PostsController extends AppController {

    var 
$name 'Posts';

    function 
index() {
        
$this->Post->recursive 2;

        
$this->Post->filterBindings(array('Comment''Rating'));
        
$this->Post->User->filterBindings(array('Status'));
    }
}
?>

Comments 646

CakePHP team comments Author comments

Comment

1 How is this easier than Bindable behavior

?

For example, what if your Post model changes? You would have to go back through all your code to find filterBindings() and re-write them to include any changes in Post's relationships.

Using Bindable behavior, you INclude all the models you need, rather than EXcluding them. Plus, you can do neat things like query based on HABTM conditions, select only certain fields from related models, and much more.

Plus, it sets the level of $recursive AND returns the value when you make a call to restrict().

I would suggest looking into Bindable if the above solution is too limited for your needs.
posted Mon, Apr 21st 2008, 12:35 by ambiguator

Comment

2 This is for version 1.1.x

The Bindable behavior looks great and I'll investigate it for when I upgrade to 1.2.x. Until then, this function works perfectly for my needs.
posted Tue, Apr 29th 2008, 15:59 by Mark

Login to Submit a Comment