behavior


Some  times we want to display in view combination of diferent fields of model. For example we want to have list box with full name (that combination of first_name last_name or prefix).

Also we want to paginate by this  column (full name).

 First class tasks is much more simple.

We can solve this problem in two way. First add column in after find callback, and after it we can use for examlpe $model->generateList method for such multiColumn. This method used in Autofield behavior.

Another class of tasks require sorting during fetching data from DB. In this case only one sollution possible. We need to add columns to fields list ib beforeFind callback. This method used in Truefield behavior.

<?php/* 
 * Autofield behavior for cakePHP 
 * comments, bug reports are welcome skie AT mail DOT ru 
 * @author Yevgeny Tomenko aka SkieDr 
 * @version 1.0.0.0
 
 configuration is
 mask is sprintf like mask
 
   array (‘newFieldName’ => array(‘fields’=>array(‘field1′,’field2’), ‘mask’=>'(%s,%s’),
            ‘newFieldName2’ => array(‘fields’=>array(‘field1′,’field3’), ‘mask’=>’%s: %s’)
            );
 
  
 */ 
class AutoFieldBehavior extends ModelBehavior 

{    var $settings null;
    
//var $_model = null;
    
    
function setup(&$model$config 
= array()) {
        
$this->autoFieldSetup(&$model$config
);
    }
    
    function 
AutoFieldSetup(&$model$config 
= array()) {
        
//$config = array(‘enabled’=>true);        foreach ($config as $newField => $fieldDsc

) {
            if (isset(
$fieldDsc[‘fields’
])){
                foreach (
$fieldDsc[‘fields’] as $field
) {
                    if(!
$model->hasField($field
)) {
                        
//user_error(“Model {$model->name} does not have a field called {$field}”, E_USER_ERROR);
                    
}
                }
            }
            if (!isset(
$config[$newField][‘fields’
])) {
                
$config[$newField][‘fields’
]=array();
            }
            if (!isset(
$config[$newField][‘mask’
])) {
                
$config[$newField][‘mask’]=
;
            }
        }
        $this->settings[$model->name] = $config;
    }
    
    
    
/**
     * After  find method. Called after all find
     *
     * Add aditional fields
     *
     * @param AppModel $model
     * @return boolean True to continue, false to abort the save
     */ 
    
function afterFind(&$model,  $results 
) {
        
$config=$this->settings[$model->name
]; 
        if (
is_array($results
)) {
            
$i 0
;
            while(isset(
$results[$i][$model->name]) && is_array($results[$i][$model->name
])) {
                if(
count($results[$i][$model->name])>0
) {
                    foreach (
$config as $newField => $fieldDsc
) {
                        
$fieldVals
=array();
                        foreach (
$fieldDsc[‘fields’] as $field
) {
                            if (isset(
$results[$i][$model->name][$field
])) {
                                
$fieldVals[]=$results[$i][$model->name][$field
];
                            } else {
                                
$fieldVals[]=
;
                            }
                        }
                        
$results[$i][$model->name][$newField]=vsprintf($fieldDsc[‘mask’],$fieldVals
);
                    }
                }
                
$i
++;
            }
        }
        return 
$results
;
    }    
}
?>

<?php/* 
 * True Field behavior for cakePHP 
 * comments, bug reports are welcome skie AT mail DOT ru 
 * @author Yevgeny Tomenko aka SkieDr 
 * @version 1.0.0.0
 
 configuration is
 
   array ( //’newFieldName’ => ‘natave sql function calls’,
       ‘newFieldName2’ => ‘concat(‘(‘,id,’, ‘,numid,’)’)’
            );
 
  
 */ 

class TrueFieldBehavior extends ModelBehavior {    var $settings null

;
    
//var $_model = null;
    
    
function setup(&$model$config 
= array()) {
        
$this->trueFieldSetup(&$model$config
);
    }
    
    function 
TrueFieldSetup(&$model$config 
= array()) {
        foreach (
$config as $newField => $fieldDsc
) {
        }
        $this->settings[$model->name] = $config;
    }
    
    
    
/**
     * Before find method. Called before all find
     *
     * Set scope filer settings
     *
     * @param AppModel $model
     * @return boolean True to continue, false to abort the save
     */ 
    
function beforeFind(&$model$cond
) {
        
$model->log(array(‘true columns: beforeFind’=>$cond‘conf’=>$this->settings[$model->name
]));
        
$config=$this->settings[$model->name
]; 
        
$conds
=array();
        foreach (
$config as $newField => $fieldDsc
) {
            
$conds[]=“$fieldDsc as {$model->name}__$newField”
;
        }
        if (
count($conds)>0
) {
            if (
is_array($cond[‘fields’
])) {
                
$cond[‘fields’]=am($cond[‘fields’],$conds
);
            } elseif (
$cond[‘fields’]!=
) {
                
$cond[‘fields’]=am($cond[‘fields’],$conds
);
            } else {
                
$cond[‘fields’]=$conds
;
            }
            
$cond[‘fields’][]=“{$model->name}.*”
;
            foreach (
$model->belongsTo as $assoc => $assocDsc
) {
                
$cond[‘fields’][]=“$assoc.*”
;
            }
        }
        
        return 
$cond
;
    } 
 
    
    
/**
     * After  find method. Called after all find
     *
     * Add aditional fields
     *
     * @param AppModel $model
     * @return boolean True to continue, false to abort the save
     */ 
     
    
function afterFind(&$model,  $results 
) {
        
$config=$this->settings[$model->name
]; 
        if (
is_array($results
)) {
            
$i 0
;
            while(isset(
$results[$i][$model->name]) && is_array($results[$i][$model->name
])) {
                foreach(
$results[$i] as $key => $value
) {
                    if(
is_numeric($key
)) {
                        
$cleanList
=array();
                        foreach (
$value as $field => $fieldVal
) {
                            
$fieldDsc preg_split(‘/__/’,$field
);
                            if (
count($fieldDsc)==2
) {
                                
$results[$i][$fieldDsc[0]][$fieldDsc[1]]=$fieldVal
;
                                
$cleanList[]=$field
;
                            }
                        }
                        foreach (
$cleanList as $field
) {
                            unset(
$results[$i][$key][$field
]);
                        }
                        if (
count($results[$i][$key])==0
) {
                            unset(
$results[$i][$key
]);
                        }
                    }
                }
                
$i
++;
            }
        }
        return 
$results
;
    }
    
}
?>

Advertisements

This behavior allow to limit selected and update rows of model with some scope.

Example of using if you want to scope articles with scope user_id then in beforeFiler of ArticlesController we place next code.
Value ‘User.id’ placed into session during login.


   $this->Article->scopeSetup(array('user_id'=>$this->Session->read('User.id')));
   $this->Article->scopeEnable();

After this all insert and read will scoped with user_id value. 
Now for example possible to call $this->paginate() without any additional conditions.

Also before create and delete record behavior check that record from required scope. 

<?php /* 
 * Scope behavior for cakePHP 
 * comments, bug reports are welcome skie AT mail DOT ru 
 * @author Yevgeny Tomenko aka SkieDr 
 * @version 1.0.0.1 
 
 configuration is
 
 1)  array (‘scope’ => array(‘parent_id’=>$parentIdValue, ‘secondParent’=> $secondParentValue), ‘enabled’ => true);
 
  2) array(‘parent_id’=>$parentIdValue, ‘secondParent’=> $secondParentValue);
  3) array (‘enabled’ => false);
  
 */ 

class ScopeBehavior extends ModelBehavior {     var $settings null

;
    
    function 
setup(&$model$config 
= array()) {
        
$this->scopeSetup(&$model$config
);
    }
    
    function 
scopeSetup(&$model$config 
= array()) {
        
$settings = array(‘enabled’=>true
);
        if (isset(
$config[‘scope’
])) {
            
$settings[‘scope’]=$config[‘scope’
];
        } else{
            
$settings[‘scope’]=$config
;
        }
        if (isset(
$config[‘enabled’
])) {
            
$settings[‘enabled’]=$config[‘enabled’
];
        }        
        
$this->settings[$model->name] = $settings
;
    }
    
    function 
scopeEnable (&$model
){
        
$this->settings[$model->name][‘enabled’] = true
;        
    }
    function scopeDisable (&$model){
        
$this->settings[$model->name][‘enabled’] = false
;        
    }
    
    
/**
     * Before find method. Called before all find
     *
     * Set scope filer settings
     *
     * @param AppModel $model
     * @return boolean True to continue, false to abort the save
     */ 
    
function beforeFind(&$model$cond
) {
        if (!
$this->settings[$model->name][‘enabled’]) return true
;
        if (!
is_array($cond[‘conditions’
])) {
            
$cond[‘conditions’]=array($cond[‘conditions’
]);
        }
        foreach (
$this->settings[$model->name][‘scope’] as $key => $value
) {
            
$cond[‘conditions’][$model->name.‘.’.$key]=$value
;
        }    
        return 
$cond
;
    }      function 
beforeSave(&$model

) {
        if (!
$this->settings[$model->name][‘enabled’]) return true
;
        if (empty(
$model->data[$model->name][$model->primaryKey])) { 
//add
            
foreach ($this->settings[$model->name][‘scope’] as $key => $value
) {
                
$model->data[$model->name][$key]=$value
;
            }
        } else { 
//update
            // now nothing to do
        
}
        return 
true
;
    } 
    function beforeDelete(&$model) {        
        if (!
$this->settings[$model->name][‘enabled’]) return true
;
        
        if (
$model->id!==false
) {
            
$curr=$model->read(null,$model->id
);
        }
        
        foreach (
$this->settings[$model->name][‘scope’] as $key => $value
) {
            if (
$curr[$model->name][$key]!=$value) return false
;
        }
        
        return 
true
;
    } 
    
}
?>