In some of my projects I had a requirement to prevent deletion of the records, which had children. That’s why I create a small behaviour which checks these cases and prevent this.

Add this code in /app/models/behaviours/has_children.php

<?php
/**
 * Prevent deletion if child record found
 *
 * @author    Nik Chankov
 * @url    http://nik.chankov.net
 */

class HasChildrenBehavior extends ModelBehavior {
    /**
     * Empty Setup Function
    */

    function setup(&$model) {
        $this->model = $model;
    }
   
    /**
     * Run the check and cancel the deletion if child is found
     * @access public
     */

    function beforeDelete(){
        if(isset($this->model->hasMany)){
            foreach($this->model->hasMany as $key=>$value){
                $childRecords = $this->model->{$key}->findAll(array($value['foreignKey']=>$this->model->id));
                if(count($childRecords) > 0){
                    return false;
                }
            }
        }
        return false;
    }
}
?>


What that code doing? In the function beforeDelete check all models in the hasMany array /defined in your model/ and check if there are records related to the current model. if there is any return false, if there are none - return true which will continue deletion.

How to activate it?
if you want this behaviour to be valid for all models in your application, just add it in AppModel class with:

<?php
class AppModel extends Model{
...
var $actsAs = array('HasChildren');
...
?>

Or if you want only few models to be affected, just put this $actsAs only in them.

Now it will work, but unfortunately when we do Delete the normal code (generated from the /console/cake) in that action is something like:

<?php
...
function delete($id = null) {
        if (!$id) {
            $this->Session->setFlash(__('Invalid id for Category', true));
            $this->redirect(array('action'=>'index'), null, true);
        }
        if ($this->MyModel->del($id)) {
            $this->Session->setFlash(__('MyModel #', true).$id.__(' deleted', true));
            $this->redirect(array('action'=>'index'), null, true);
        }
    }
...
?>

Which when receive “return false” wont enter in the second if and the page will remain blank. To prevent such issue your delete actions should look like:

<?php
...
function delete($id = null) {
        if (!$id) {
            $this->Session->setFlash(__('Invalid id for Category', true));
            $this->redirect(array('action'=>'index'), null, true);
        }
        if ($this->MyModel->del($id)) {
            $this->Session->setFlash(__('MyModel #', true).$id.__(' deleted', true));
            $this->redirect(array('action'=>'index'), null, true);
        } else {
            $this->Session->setFlash(__(' The record cannot be deleted!', true));
            $this->redirect(array('action'=>'index'), null, true);
        }
    }
...
?>

The inconvenience coming from that, because you should make this in all of your controllers, but if you starting a new project and you modify your templates before start baking it shouldn’t be so big pain.

Tags: , , ,


Add to: del.icio.us:Check for existing children behaviour digg:Check for existing children behaviour spurl:Check for existing children behaviour wists:Check for existing children behaviour simpy:Check for existing children behaviour newsvine:Check for existing children behaviour blinklist:Check for existing children behaviour furl:Check for existing children behaviour reddit:Check for existing children behaviour fark:Check for existing children behaviour blogmarks:Check for existing children behaviour Y!:Check for existing children behaviour smarking:Check for existing children behaviour magnolia:Check for existing children behaviour segnalo:Check for existing children behaviour gifttagging:Check for existing children behaviour

Leave a Comment

*
To prove that you're not a bot, enter this code
Anti-Spam Image