#1581: [PATCH] Doctrine_Connection_UnitOfWork::buildFlushTree() removes wrong
objects by accident
-------------------------+--------------------------------------------------
  Reporter:  bschussek   |       Owner:  jwage                
      Type:  defect      |      Status:  closed               
  Priority:  critical    |   Milestone:                       
 Component:  Connection  |     Version:  0.11.0               
Resolution:  invalid     |    Keywords:                       
  Has_test:  0           |    Mystatus:  Pending Core Response
 Has_patch:  1           |  
-------------------------+--------------------------------------------------
Changes (by jwage):

  * status:  new => closed
  * resolution:  => invalid

Old description:

> When loading fixture files, Doctrine uses
> Doctrine_Connection_UnitOfWork::buildFlushTree() to find out in which
> order the fixture classes should be saved. Therefore the classes are
> given to the method and returned in the correct order.
>
> In certain situations, some of the classes that were put in are not put
> out, leading to fixture entries not being loaded into the database. I
> didn't really find out WHEN this happens, but I found out WHY and created
> a patch for it.
>
> The algorithm in buildFlushTree() uses unset() a couple of times to
> remove an object and add it at the end of the object. Example (line 725):
> {{{
>                     if ($relatedCompIndex !== false) {
>                         unset($flushList[$relatedCompIndex]);
>                     }
>
>                     array_splice($flushList, $index, 0,
> $relatedClassName);
>                     $index++;
> }}}
>
> Through the use of unset, the array keys have "holes" (1, 2, 4, ...
> instead of 1, 2, 3, ...). Now the critical part: array_splice() closes
> these holes (=alters the indices from 1, 2, 4,... to 1, 2, 3, ...), which
> is why $index is not correct anymore afterwards! Doctrine uses the $index
> later though, which can lead to wrong objects being removed! (e.g. in
> line 740, which is what happens in my case)
>
> A working solution for me is to replace all calls to array_splice() with
> calls to a custom method _arrayInsert(), which preserves the keys:
> {{{
>     private function _arrayInsert($array, $index, $data)
>     {
>         for ($j=max(array_keys($array)); $j>=$index; --$j)
>         {
>                 $array[$j+1] = $array[$j];
>         }
>
>         $array[$index] = $data;
>
>         return $array;
>     }
> }}}

New description:

 When loading fixture files, Doctrine uses
 Doctrine_Connection_UnitOfWork::buildFlushTree() to find out in which
 order the fixture classes should be saved. Therefore the classes are given
 to the method and returned in the correct order.

 In certain situations, some of the classes that were put in are not put
 out, leading to fixture entries not being loaded into the database. I
 didn't really find out WHEN this happens, but I found out WHY and created
 a patch for it.

 The algorithm in buildFlushTree() uses unset() a couple of times to remove
 an object and add it at the end of the object. Example (line 725):
 {{{
                     if ($relatedCompIndex !== false) {
                         unset($flushList[$relatedCompIndex]);
                     }

                     array_splice($flushList, $index, 0,
 $relatedClassName);
                     $index++;
 }}}

 Through the use of unset, the array keys have "holes" (1, 2, 4, ...
 instead of 1, 2, 3, ...). Now the critical part: array_splice() closes
 these holes (=alters the indices from 1, 2, 4,... to 1, 2, 3, ...), which
 is why $index is not correct anymore afterwards! Doctrine uses the $index
 later though, which can lead to wrong objects being removed! (e.g. in line
 740, which is what happens in my case)

 A working solution for me is to replace all calls to array_splice() with
 calls to a custom method _arrayInsert(), which preserves the keys:
 {{{
     private function _arrayInsert($array, $index, $data)
     {
         for ($j=max(array_keys($array)); $j>=$index; --$j)
         {
                 $array[$j+1] = $array[$j];
         }

         $array[$index] = $data;

         return $array;
     }
 }}}

-- 
Ticket URL: <http://trac.doctrine-project.org/ticket/1581#comment:6>
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