ActiveRecord deletion

Question about delete() , not a deleteByPk.

I use Postgres and ofcouse i use cascade deletetion for table relations.

before/after Delete method(s) is good but when delete top model instance of models three

need control for removing records from BD and ofcouse need initialize each related model or write long sql.

May be i did not found method for cascade deletion.

I want call model->delete() and see how Yii run onDelete codes of each releted models without write this code and check conditions on each before/after Delete for each related model.

I think there is no cascaded deletion built into Yii.

In my opinion this work should be done in the database.

If you set your foreign keys the right way (on delete cascade) then you get exactly what you want.

there is definitely no built in cascade delete.

It’s one of the things where Yii is lacking in my opinion compared to other frameworks. But then it’s better than most other frameworks in many other aspects :)

I wish it would be an option though

You can setup your database to enforce cascade deletion.

Feature request is valid though, so I created a ticket for it. It may not be implemented until 1.1.

of course cascade deletion at the DBMS level beats having it done by Yii.

However, there are some instances where you need to do it at a framework level.

This is the case when you, for whatever reason, are stuck with MyISAM or you also need to create some files with every record that is being deleted.

It’s not a biggie really but it would be very convenient feature to have

All of this topic text do not touch MySQL + myIsam adepts.

Look at second row of start msg and read… ‘ofcouse i use cascade deletion’ …

DB do not take you do something before delete any rows in cascade.

I want know you methods for it.

Can Yii check find deleteion chain and try delete founded cascade but without send COMMIT , only for check.

And if deletion query is good run onBeforeDelete for each of models ?

Very simple example:

Model A related as HAS_MANY to models B

Each model B have file property and store the path to this file.

In A controller call A->delete() DB delete A and all related models B.

For delete files for each of deleted B need implement logic in A->onBeforeDelete()

And ofcouse 80% of this code duplicated in B->onBeforeDelete().

When logic is not so simple and need ask external services and check other point deletion is not so cool.

Is anybody have ideas how to do this ?

Thanks for ticket but i think that my current project never migrate to 1.1 series :(

icevan,

I don’t fully understand what you meant. For a moment, it seemed you used models even for files.

Generally it’s a good advice to put deletion script in beforeDelete() or afterDelete() so your code can be kept consistent. I’m not sure where your code could get duplicated.

Okey, more details.

If i want delete model A and place logic in model A->beforeDelete().

If A have related B and B related to C and etc

For do full check "is delete possible" in the A->beforeDelete() i must write full logic for check all models in the deletion chain.

But actualy onBeforeDelete() will be called once for deleted model A

and when yii run "delete from tableA where id=A.id" all related rows (models) will be erased.

Of couse i can write code for call onBeforeDelete on each model but this way is not beetter then write full logic in each onBeforeDelete()

my idea is

check delete query , whout send commit.

if OK call beforeDelete on each model in chain. (how all catch related row on DB level ?)

And of couse it should be configured for prevent using by mysql+myisam adepts.

Hello,

I wrote this simple behavior that does cascade delete on framework level:




class CascadeDeleteBehavior extends CActiveRecordBehavior

{

    public $relations = array();

    

    public function beforeDelete($event)

    {

        foreach($this->relations as $relation)

        {

            $objects = $this->Owner->getRelated($relation);

            

            if($objects !== null)

            {

                if(is_array($objects))

                {

                    foreach($objects as $object)

                    {

                        $object->delete();

                    }

                }

                else

                {

                    $objects->delete();

                }

            }

        }

        

        return true;

    }    

}



Usage example in model:




class MyModel extends CActiveRecord

{ 

    public function relations()

    {

        return array(

            'related' => array(self::HAS_MANY, 'MyRelatedModel', 'relatedId')

        );

    }


    public function behaviors()

    {

        return array(

            'CascadeDeleteBehavior' => array(

                'class' => 'application.components.behaviors.CascadeDeleteBehavior',

                'relations' => array('related'),

            )

        );

    }

}


$myModel = MyModel::model()->findByPk(1);


$myModel->delete(); // Will delete $myModel and call delete() method on all related MyRelatedModel objects



Nice. But please be aware that beforeDelete() will not be called when using any of the deleteBy…() or deleteAll…() methods! They perform a DELETE statement on the database without fetching all records before. Doing that would drastically decrease performance of mass deletions.

Agree! Good example!

I dont think about task in behaviors categories, my fault.

Need check how getRelated() work.

Becouse if models w/o sorting or sorted by relations writed in relation() this example is not a valid.

NOT all relations writed in realation() (How to get all related rows from all tables in RIGHT sorting?)