Zend Framework - Problem with Database Table Recursive Cascading Deletes
My situation may be a bit abnormal, but I have foreign keys defined in my MySQL database, while enforcing referential integrity in the Zend_Db_Table
classes. The tables use the InnoDB storage engine.
When deleting a record, the Zend Framework will properly identify immediate children via the $_referenceMap
in the table model and delete them. However, if there are any children of the immediate child, I am getting an error back from the database about violating the referential integrity of that foreign key: SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails
. It seems that the Zend_Db_Table_Abstract
doesn't enforce referential integrity in a recursive fashion.
Has anyone else encountered this? Is it a Zend Framework bug? Workarounds? Fixes?
UPDATE
Nearly a week later and I have no replies to this q开发者_StackOverflow社区uestion. I am thinking I'll have to extend the Zend_Db_Table_Row_Abstract
class myself to accomplish this.
I ended up extending the Zend_Db_Table_Abstract
class to accomplish this. The _cascadeDelete
public function makes a call to the database adapter delete
function. I made changes so that the delete
function from Zend_Db_Table_Row_Abstract
gets called instead. This makes record deletions recursive.
UPDATE: I have added code for when on delete is set to self::SET_NULL
.
Here's my modified version of _cascadeDelete
:
/**
* Called by parent table's class during delete() method.
*
* @param string $parentTableClassname
* @param array $primaryKey
* @return int Number of affected rows
*/
public function _cascadeDelete($parentTableClassname, array $primaryKey)
{
$this->_setupMetadata();
$rowsAffected = 0;
foreach ($this->_getReferenceMapNormalized() as $map) {
if ($map[self::REF_TABLE_CLASS] == $parentTableClassname && isset($map[self::ON_DELETE])) {
switch ($map[self::ON_DELETE]) {
case self::CASCADE:
$select = $this->select();
for ($i = 0; $i < count($map[self::COLUMNS]); ++$i) {
$col = $this->_db->foldCase($map[self::COLUMNS][$i]);
$refCol = $this->_db->foldCase($map[self::REF_COLUMNS][$i]);
$type = $this->_metadata[$col]['DATA_TYPE'];
$select->where($this->_db->quoteIdentifier($col, true) . ' = ?',
$primaryKey[$refCol], $type);
}
$rows = $this->fetchAll($select);
$rowsAffected += count($rows);
foreach ($rows as $row) {
$row->delete();
}
break;
case self::SET_NULL: {
$update = array();
$where = array();
for ($i = 0; $i < count($map[self::COLUMNS]); ++$i) {
$col = $this->_db->foldCase($map[self::COLUMNS][$i]);
$refCol = $this->_db->foldCase($map[self::REF_COLUMNS][$i]);
$type = $this->_metadata[$col]['DATA_TYPE'];
$update[$col] = null;
$where[] = $this->_db->quoteInto(
$this->_db->quoteIdentifier($col, true) . ' = ?',
$primaryKey[$refCol], $type);
}
$rowsAffected += $this->update($update, $where);
break;
}
default:
// no action
break;
}
}
}
return $rowsAffected;
}
精彩评论