SoftDelete behaviour is awesome and working as intended. However, I couldn't find a way to also soft delete related models. Any tips? Ideally there should be an event triggered for all related models
|
Aug '15 |
5 |
1757 |
0 |
So after typing up a very long response with examples, I came across this?
https://docs.phalcon.io/en/latest/reference/models.html#cascade-restrict-actions
<?php
namespace Store\Models;
use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Relation;
class Robots extends Model
{
public $id;
public $name;
public function initialize()
{
$this->hasMany('id', 'Store\\Models\Parts', 'robots_id', array(
'foreignKey' => array(
'action' => Relation::ACTION_CASCADE
)
));
}
}
Before I found that, here was my original message:
Just to clarify with an example, is this what you're looking for?
Example:
Table1 : table_1_id, status
Table2 : table_2_id, table_1_id, status
Table3: table_3_id, table_1_id, status
Step 1. [Soft]Delete a record in Table1 (Change "status" to "Deleted")
Step 2. Find all reacords in Table2 and Table3 that belong to Table1 via table_1_id
Step 3. Update the "status" of all records found in Step2 as "Deleted" as well
If thats the case, you should be able to easily implement this by adding the SoftDelete behavior to all related Models. Then in Table1, delete related records in afterDelete
. I haven't done thie before but here is the idea.
/**
* Table1
**/
class Table1 extends \Phalcon\Mvc\Model {
public $table_1_id;
public $status;
public function initialize()
{
$this->addBehavior(new \Phalcon\Mvc\Model\Behavior\SoftDelete(
[
'field' => 'status',
'value' => "Deleted"
]
));
$this->hasMany('table_1_id','Table2','table_1_id');
$this->hasMany('table_1_id','Table3','table_1_id');
}
public function afterDelete (){
$this->getTable2()->delete();
$this->getTable3()->delete();
}
}
/**
* Table2
**/
class Table2 extends \Phalcon\Mvc\Model {
public $table_2_id;
public $table_1_id;
public $status;
public function initialize()
{
$this->addBehavior(new \Phalcon\Mvc\Model\Behavior\SoftDelete(
[
'field' => 'status',
'value' => "Deleted"
]
));
$this->belongsTo('table_1_id', 'Table1','table_1_id',[
'foreignKey' => true
]);
}
}
/**
* Table3
**/
class Table2 extends \Phalcon\Mvc\Model {
public $table_3_id;
public $table_1_id;
public $status;
public function initialize()
{
$this->addBehavior(new \Phalcon\Mvc\Model\Behavior\SoftDelete(
[
'field' => 'status',
'value' => "Deleted"
]
));
$this->belongsTo('table_1_id', 'Table1','table_1_id',[
'foreignKey' => true
]);
}
}
I thought about the idea of creating the hasMany
references in Table1
to be foreign keys but decided against that because of the documentation:
https://docs.phalcon.io/en/latest/reference/models.html#virtual-foreign-keys
If you alter a belongsTo() relationship to act as foreign key, it will validate that the values inserted/updated on those fields have a valid value on the referenced model. Similarly, if a hasMany()/hasOne() is altered it will validate that the records cannot be deleted if that record is used on a referenced model.
Thank you for your suggestions. I will verify this, but my impression is that afterDelete() is never executed for SoftDelete. At least this is how I understand the code of SoftDelete.zep
Well, my experience is that afterDelete()
is not executed with SoftDelete. Also, see this forum topic where the same problem is being discussed.
Well, my experience is that
afterDelete()
is not executed with SoftDelete. Also, see this forum topic where the same problem is being discussed.
That was my bad. I believe you are correct. It turns out I actually use an afterUpdate to check on the status of the item to remove it from the search index. My bad!
You need to extend SoftDelete class or re-implement if necessary. Here is something close to what am saying, but for sure its not tested nor accurate:
class SoftDelete extends \Phalcon\Mvc\Model\Behavior\SoftDelete {
public function notify($type, \Phalcon\Mvc\ModelInterface $model) {
if ($type == 'beforeDelete') {
parent::notify($type, $model);
$hasMany = Di::getDefault()->getModelsManager()->getHasMany($model);
// $hasOne = Di::getDefault()->getModelsManager()->getHasOne($model);
// $hasManyToMany = Di::getDefault()->getModelsManager()->getHasManyToMany($model);
foreach ($hasMany as $manyRelation) {
$class = $manyRelation->getReferencedModel();
$referencedField = $manyRelation->getReferencedFields();
$modelField = $manyRelation->getFields();
$this->removeRef($class, $referencedField, $model->$modelField);
}
}
}
private function removeRef($class, $field, $value) {
$records = $class::query()
->where("{$field} = :field:", ['field' => $value])
->andWhere("isDeleted = :notDeleted:", ['notDeleted' => $class::NOT_DELETED])
->execute();
foreach($records as $record) {
$record->delete();
}
}
}