#1589: M2M-unlink() is not transaction-safe
-----------------------+----------------------------------------------------
Reporter: floriank | Owner: romanb
Type: task | Status: reopened
Priority: major | Milestone: 1.0.4
Component: Record | Version: 1.0.3
Resolution: | Keywords: record transaction unlink
Has_test: 1 | Mystatus: Pending Core Response
Has_patch: 1 |
-----------------------+----------------------------------------------------
Changes (by floriank):
* status: closed => reopened
* type: defect => task
* resolution: invalid =>
Comment:
I noticed the break of some tests too (round about ten), thats why I
wanted my 'patch' just for discussion an '''not''' to be applied to trunk.
Because I needed a working version of unlink() which does not DELETE in
the database before calling Record->save() I wrote a simple helper to give
me the function I needed (it only supports single-field primary keys at
the related models):
{{{
class RecordHelper {
/**
* Unlinks an object from a m:n-relation
*
* WARNING: this method only supports related models with single-field
primary-keys
*
* @param Doctrine_Record $record the record from which a relation
should be unlinked
* @param int $idRecordRelated the id of the related object which is
to be unlinked
* @param string $relationAlias the (alias-) name of the relation in
$record
* @return Doctrine_Record the changed record-onject
*/
public static function unlink(Doctrine_Record $record, /* int */
$idRecordRelated, /* string */ $relationAlias) {
$key = 0;
$found = false;
$ref = $record->getReferences();
if (!isset($ref[$relationAlias]))
$record->loadReference($relationAlias);
foreach($record->{$relationAlias} as $key => $rec2) {
if ($rec2->id == $idRecordRelated) {
$found = true;
break;
}
}
if ($found) {
unset($record->{$relationAlias}[$key]);
}
return $record;
}
}
}}}
which can be used by
{{{
$user = Doctrine::getTable("Ticket_1589_User")->findOneByName('user1');
$group = Doctrine::getTable("Ticket_1589_Group")->findOneByName('group2');
RecordHelper::unlink($user, $group->id, 'Ticket_1589_Group');
}}}
When calling Record->save() on a model with many nested M2N-relations
which themselves have mutliple nested relations again I noticed the
performance hit already mentioned in my comment above. Therefore I changed
Collection->save() to call the internal save() for its data in the foreach
only if a record is 'really' dirty. To check if a record is dirty I added
a method Record->isDirty(). Please have a look at the second patch I
attached: with it I don't break testcases in my environment anymore
(actually there are two less than before: 17 before it, 15 after).
--
Ticket URL: <http://trac.doctrine-project.org/ticket/1589#comment:3>
Doctrine <http://www.phpdoctrine.org>
PHP Doctrine Object Relational Mapper
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"doctrine-svn" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.co.uk/group/doctrine-svn?hl=en-GB
-~----------~----~----~----~------~----~------~--~---