#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
-~----------~----~----~----~------~----~------~--~---

Reply via email to