Просмотр исходного кода

[Uploadable] Simplified the code a little bit, and fixed problem in updates where the only field updated is the file itself.

comfortablynumb 13 лет назад
Родитель
Сommit
5576388616
1 измененных файлов с 48 добавлено и 34 удалено
  1. 48 34
      lib/Gedmo/Uploadable/UploadableListener.php

+ 48 - 34
lib/Gedmo/Uploadable/UploadableListener.php

@@ -99,36 +99,46 @@ 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);
-    }
-
+    /**
+     * This event is needed in special cases where the entity needs to be updated, but it only has the
+     * file field modified. Since we can't mark an entity as "dirty" in the "addEntityFileInfo" method,
+     * doctrine thinks the entity has no changes, which produces that the "onFlush" event gets never called.
+     * Here we mark the entity as dirty, so the "onFlush" event gets called, and the file is processed.
+     *
+     * @param \Doctrine\Common\EventArgs $args
+     */
     public function preFlush(EventArgs $args)
     {
+        if (empty($this->fileInfoObjects)) {
+            // Nothing to do
+            return;
+        }
+
         $ea = $this->getEventAdapter($args);
         $om = $ea->getObjectManager();
         $uow = $om->getUnitOfWork();
+        $first = reset($this->fileInfoObjects);
+        $meta = $om->getClassMetadata(get_class($first['entity']));
+        $config = $this->getConfiguration($om, $meta->name);
 
         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);
+
+            // If the entity is in the identity map, it means it will be updated. We need to force the
+            // "dirty check" here by "modifying" the path. We are actually setting the same value, but
+            // this will mark the entity as dirty, and the "onFlush" event will be fired, even if there's
+            // no other change in the entity's fields apart from the file itself.
+            if ($uow->isInIdentityMap($entity)) {
+                $path = $this->getFilePath($meta, $config, $entity);
+
+                $uow->propertyChanged($entity, $config['filePathField'], $path, $path);
+                $uow->scheduleForUpdate($entity);
             }
         }
     }
@@ -145,10 +155,21 @@ class UploadableListener extends MappedEventSubscriber
         $om = $ea->getObjectManager();
         $uow = $om->getUnitOfWork();
 
-        foreach ($ea->getScheduledObjectUpdates($uow) as $object) {
-            $this->processFile($ea, $object, self::ACTION_UPDATE);
+        // Do we need to upload files?
+        foreach ($this->fileInfoObjects as $info) {
+            $entity = $info['entity'];
+            $scheduledForInsert = $uow->isScheduledForInsert($entity);
+            $scheduledForUpdate = $uow->isScheduledForUpdate($entity);
+            $action = ($scheduledForInsert || $scheduledForUpdate) ?
+                ($scheduledForInsert ? self::ACTION_INSERT : self::ACTION_UPDATE) :
+                false;
+
+            if ($action) {
+                $this->processFile($ea, $entity, $action);
+            }
         }
 
+        // Do we need to remove any files?
         foreach ($ea->getScheduledObjectDeletions($uow) as $object) {
             $meta = $om->getClassMetadata(get_class($object));
             
@@ -174,6 +195,8 @@ class UploadableListener extends MappedEventSubscriber
 
             $this->pendingFileRemovals = array();
         }
+
+        $this->fileInfoObjects = array();
     }
 
     /**
@@ -190,6 +213,7 @@ class UploadableListener extends MappedEventSubscriber
      */
     public function processFile(AdapterInterface $ea, $object, $action)
     {
+        $oid = spl_object_hash($object);
         $om = $ea->getObjectManager();
         $uow = $om->getUnitOfWork();
         $meta = $om->getClassMetadata(get_class($object));
@@ -199,12 +223,6 @@ class UploadableListener extends MappedEventSubscriber
             // Nothing to do
             return;
         }
-        $oid = spl_object_hash($object);
-
-        if (!isset($this->fileInfoObjects[$oid])) {
-            // Nothing to do
-            return;
-        }
 
         $refl = $meta->getReflectionClass();
         $fileInfo = $this->fileInfoObjects[$oid]['fileInfo'];
@@ -341,22 +359,18 @@ class UploadableListener extends MappedEventSubscriber
         if ($config['fileMimeTypeField']) {
             $changes[$config['fileMimeTypeField']] = array($fileMimeTypeField->getValue($object), $info['fileMimeType']);
 
-            $this->updateField($object, $uow, $ea, $meta, $action, $config['fileMimeTypeField'], $info['fileMimeType']);
+            $this->updateField($object, $uow, $ea, $meta, $config['fileMimeTypeField'], $info['fileMimeType']);
         }
 
         if ($config['fileSizeField']) {
             $changes[$config['fileSizeField']] = array($fileSizeField->getValue($object), $info['fileSize']);
 
-            $this->updateField($object, $uow, $ea, $meta, $action, $config['fileSizeField'], $info['fileSize']);
+            $this->updateField($object, $uow, $ea, $meta, $config['fileSizeField'], $info['fileSize']);
         }
 
-        $this->updateField($object, $uow, $ea, $meta, $action, $config['filePathField'], $info['filePath']);
+        $this->updateField($object, $uow, $ea, $meta, $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);
-        }
+        $ea->recomputeSingleObjectChangeSet($uow, $meta, $object);
 
         if ($evm->hasListeners(Events::uploadablePostFileProcess)) {
             $evm->dispatchEvent(Events::uploadablePostFileProcess, new UploadablePostFileProcessEventArgs(
@@ -660,13 +674,13 @@ class UploadableListener extends MappedEventSubscriber
         return $this->mimeTypeGuesser;
     }
 
-    protected function updateField($object, $uow, AdapterInterface $ea, $meta, $action, $field, $value)
+    protected function updateField($object, $uow, AdapterInterface $ea, $meta, $field, $value, $notifyPropertyChanged = true)
     {
         $property = $meta->getReflectionProperty($field);
         $oldValue = $property->getValue($object);
         $property->setValue($object, $value);
 
-        if ($object instanceof NotifyPropertyChanged) {
+        if ($notifyPropertyChanged && $object instanceof NotifyPropertyChanged) {
             $uow = $ea->getObjectManager()->getUnitOfWork();
             $uow->propertyChanged($object, $field, $oldValue, $value);
         }