瀏覽代碼

[Uploadable] Don't use UnitOfWork::scheduleExtraUpdate when inserting an entity.

comfortablynumb 12 年之前
父節點
當前提交
3eebab8f81
共有 2 個文件被更改,包括 79 次插入40 次删除
  1. 79 36
      lib/Gedmo/Uploadable/UploadableListener.php
  2. 0 4
      tests/Gedmo/Uploadable/UploadableEntityTest.php

+ 79 - 36
lib/Gedmo/Uploadable/UploadableListener.php

@@ -27,7 +27,8 @@ use Doctrine\Common\Persistence\ObjectManager,
     Gedmo\Uploadable\FileInfo\FileInfoArray,
     Gedmo\Uploadable\MimeType\MimeTypeGuesser,
     Gedmo\Uploadable\MimeType\MimeTypeGuesserInterface,
-    Gedmo\Uploadable\MimeType\MimeTypesExtensionsMap;
+    Gedmo\Uploadable\MimeType\MimeTypesExtensionsMap,
+    Doctrine\Common\NotifyPropertyChanged;
 
 /**
  * Uploadable listener
@@ -95,11 +96,40 @@ class UploadableListener extends MappedEventSubscriber
     {
         return array(
             'loadClassMetadata',
+            'prePersist',
+            'preFlush',
             'onFlush',
             'postFlush'
         );
     }
 
+    public function prePersist(EventArgs $args)
+    {
+        $ea = $this->getEventAdapter($args);
+
+        $this->processFile($ea, $ea->getObject(), self::ACTION_INSERT);
+    }
+
+    public function preFlush(EventArgs $args)
+    {
+        $ea = $this->getEventAdapter($args);
+        $om = $ea->getObjectManager();
+        $uow = $om->getUnitOfWork();
+
+        foreach ($this->fileInfoObjects as $info) {
+            $entity = $info['entity'];
+            if (!$uow->isScheduledForInsert($entity) &&
+                !$uow->isScheduledForUpdate($entity) &&
+                !$uow->isScheduledForDelete($entity)) {
+
+                // If we still have pending file info objects, probably it means the entities don't have any of their
+                // fields updated, except for the file. Doctrine doesn't consider this entities dirty, so update won't happen.
+                // We need to process them anyway as an update.
+                $this->processFile($ea, $entity, self::ACTION_UPDATE);
+            }
+        }
+    }
+
     /**
      * Handle file-uploading depending on the action
      * being done with objects
@@ -114,24 +144,8 @@ class UploadableListener extends MappedEventSubscriber
         $om = $ea->getObjectManager();
         $uow = $om->getUnitOfWork();
 
-        foreach ($ea->getScheduledObjectInsertions($uow) as $object) {
-            $meta = $om->getClassMetadata(get_class($object));
-
-            if ($config = $this->getConfiguration($om, $meta->name)) {
-                if (isset($config['uploadable']) && $config['uploadable']) {
-                    $this->processFile($uow, $ea, $meta, $config, $object, self::ACTION_INSERT);
-                }
-            }
-        }
-
         foreach ($ea->getScheduledObjectUpdates($uow) as $object) {
-            $meta = $om->getClassMetadata(get_class($object));
-
-            if ($config = $this->getConfiguration($om, $meta->name)) {
-                if (isset($config['uploadable']) && $config['uploadable']) {
-                    $this->processFile($uow, $ea, $meta, $config, $object, self::ACTION_UPDATE);
-                }
-            }
+            $this->processFile($ea, $object, self::ACTION_UPDATE);
         }
 
         foreach ($ea->getScheduledObjectDeletions($uow) as $object) {
@@ -167,27 +181,34 @@ class UploadableListener extends MappedEventSubscriber
      * If it's a Uploadable object, verify if the file was uploaded.
      * If that's the case, process it.
      *
-     * @param UnitOfWork
-     * @param AdapterInterface
-     * @param ClassMetadata
-     * @param array - Configuration
-     * @param object - The entity
-     * @param string - String representing the action (insert or update)
-     *
-     * @return void
+     * @param \Gedmo\Mapping\Event\AdapterInterface $ea
+     * @param $object
+     * @param $action
+     * @throws \Gedmo\Exception\UploadableNoPathDefinedException
+     * @throws \Gedmo\Exception\UploadableCouldntGuessMimeTypeException
+     * @throws \Gedmo\Exception\UploadableMaxSizeException
+     * @throws \Gedmo\Exception\UploadableInvalidMimeTypeException
      */
-    public function processFile(UnitOfWork $uow, AdapterInterface $ea, ClassMetadata $meta, array $config, $object, $action)
+    public function processFile(AdapterInterface $ea, $object, $action)
     {
-        $refl = $meta->getReflectionClass();
+        $om = $ea->getObjectManager();
+        $uow = $om->getUnitOfWork();
+        $meta = $om->getClassMetadata(get_class($object));
+        $config = $this->getConfiguration($om, $meta->name);
+
+        if (!$config || !isset($config['uploadable']) || !$config['uploadable']) {
+            // Nothing to do
+            return;
+        }
         $oid = spl_object_hash($object);
 
         if (!isset($this->fileInfoObjects[$oid])) {
             // Nothing to do
-
             return;
         }
 
-        $fileInfo = $this->fileInfoObjects[$oid];
+        $refl = $meta->getReflectionClass();
+        $fileInfo = $this->fileInfoObjects[$oid]['fileInfo'];
 
         // Validations
         if ($config['maxSize'] > 0 && $fileInfo->getSize() > $config['maxSize']) {
@@ -308,16 +329,23 @@ class UploadableListener extends MappedEventSubscriber
 
         if ($config['fileMimeTypeField']) {
             $changes[$config['fileMimeTypeField']] = array($fileMimeTypeField->getValue($object), $info['fileMimeType']);
-            $ea->setOriginalObjectProperty($uow, $oid, $config['fileMimeTypeField'], $info['fileMimeType']);
+
+            $this->updateField($object, $uow, $ea, $meta, $action, $config['fileMimeTypeField'], $info['fileMimeType']);
         }
 
         if ($config['fileSizeField']) {
             $changes[$config['fileSizeField']] = array($fileSizeField->getValue($object), $info['fileSize']);
-            $ea->setOriginalObjectProperty($uow, $oid, $config['fileSizeField'], $info['fileSize']);
+
+            $this->updateField($object, $uow, $ea, $meta, $action, $config['fileSizeField'], $info['fileSize']);
         }
 
-        $uow->scheduleExtraUpdate($object, $changes);
-        $ea->setOriginalObjectProperty($uow, $oid, $config['filePathField'], $info['filePath']);
+        $this->updateField($object, $uow, $ea, $meta, $action, $config['filePathField'], $info['filePath']);
+
+        // Only schedule an extra update if it's an update. If it's an insert, we're on the prePersist event, which means we don't
+        // need to recompute anything.
+        if ($action === self::ACTION_UPDATE) {
+            $uow->scheduleExtraUpdate($object, $changes);
+        }
 
         unset($this->fileInfoObjects[$oid]);
     }
@@ -562,7 +590,10 @@ class UploadableListener extends MappedEventSubscriber
             ));
         }
 
-        $this->fileInfoObjects[spl_object_hash($entity)] = $fileInfo;
+        $this->fileInfoObjects[spl_object_hash($entity)] = array(
+            'entity'        => $entity,
+            'fileInfo'      => $fileInfo
+        );
     }
 
     public function getEntityFileInfo($entity)
@@ -575,7 +606,7 @@ class UploadableListener extends MappedEventSubscriber
             ));
         }
 
-        return $this->fileInfoObjects[$oid];
+        return $this->fileInfoObjects[$oid]['fileInfo'];
     }
 
     /**
@@ -601,4 +632,16 @@ class UploadableListener extends MappedEventSubscriber
     {
         return $this->mimeTypeGuesser;
     }
+
+    protected function updateField($object, $uow, AdapterInterface $ea, $meta, $action, $field, $value)
+    {
+        $property = $meta->getReflectionProperty($field);
+        $oldValue = $property->getValue($object);
+        $property->setValue($object, $value);
+
+        if ($object instanceof NotifyPropertyChanged) {
+            $uow = $ea->getObjectManager()->getUnitOfWork();
+            $uow->propertyChanged($object, $field, $oldValue, $value);
+        }
+    }
 }

+ 0 - 4
tests/Gedmo/Uploadable/UploadableEntityTest.php

@@ -141,10 +141,6 @@ class UploadableEntityTest extends BaseTestCaseORM
         // We use a FileInfoInterface instance here
         $this->listener->addEntityFileInfo($image2, new FileInfoArray($fileInfo));
 
-        // For now, we need to force the update changing one of the managed fields. If we don't do this,
-        // entity won't be marked for update
-        $image2->setTitle($image2->getTitle().'7892');
-
         $this->em->flush();
 
         $this->em->refresh($image2);