Browse Source

[timestampable] single listener through event adapter

gediminasm 14 years ago
parent
commit
1f702d65b1

+ 35 - 0
lib/Gedmo/Timestampable/Mapping/Event/Adapter/ODM.php

@@ -0,0 +1,35 @@
+<?php
+
+namespace Gedmo\Timestampable\Mapping\Event\Adapter;
+
+use Gedmo\Mapping\Event\Adapter\ODM as BaseAdapterODM;
+use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo;
+
+/**
+ * Doctrine event adapter for ODM adapted
+ * for Timestampable behavior
+ *
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo\Timestampable\Mapping\Event\Adapter
+ * @subpackage ODM
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+final class ODM extends BaseAdapterODM
+{
+    /**
+     * Get the date value
+     *
+     * @param ClassMetadataInfo $meta
+     * @param string $field
+     * @return mixed
+     */
+    public function getDateValue(ClassMetadataInfo $meta, $field)
+    {
+        $mapping = $meta->getFieldMapping($field);
+        if (isset($mapping['type']) && $mapping['type'] === 'timestamp') {
+            return time();
+        }
+        return new \DateTime();
+    }
+}

+ 31 - 0
lib/Gedmo/Timestampable/Mapping/Event/Adapter/ORM.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace Gedmo\Timestampable\Mapping\Event\Adapter;
+
+use Gedmo\Mapping\Event\Adapter\ORM as BaseAdapterORM;
+use Doctrine\ORM\Mapping\ClassMetadataInfo;
+
+/**
+ * Doctrine event adapter for ORM adapted
+ * for Timestampable behavior
+ *
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo\Timestampable\Mapping\Event\Adapter
+ * @subpackage ORM
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+final class ORM extends BaseAdapterORM
+{
+    /**
+     * Get the date value
+     *
+     * @param ClassMetadataInfo $meta
+     * @param string $field
+     * @return mixed
+     */
+    public function getDateValue(ClassMetadataInfo $meta, $field)
+    {
+        return new \DateTime();
+    }
+}

+ 120 - 42
lib/Gedmo/Timestampable/TimestampableListener.php

@@ -2,81 +2,159 @@
 
 namespace Gedmo\Timestampable;
 
-use Doctrine\ORM\Events,
-    Doctrine\Common\Persistence\Mapping\ClassMetadata,
-    Doctrine\Common\EventArgs;
+use Doctrine\Common\Persistence\Mapping\ClassMetadata,
+    Doctrine\Common\EventArgs,
+    Gedmo\Mapping\MappedEventSubscriber;
 
 /**
  * The Timestampable listener handles the update of
- * dates on creation and update of entity.
- * 
+ * dates on creation and update.
+ *
  * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
  * @package Gedmo.Timestampable
  * @subpackage TimestampableListener
  * @link http://www.gediminasm.org
  * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  */
-class TimestampableListener extends AbstractTimestampableListener
+class TimestampableListener extends MappedEventSubscriber
 {
     /**
      * Specifies the list of events to listen
-     * 
+     *
      * @return array
      */
     public function getSubscribedEvents()
     {
         return array(
-            Events::prePersist,
-            Events::onFlush,
-            Events::loadClassMetadata
+            'prePersist',
+            'onFlush',
+            'loadClassMetadata'
         );
     }
-    
-    /**
-     * {@inheritdoc}
-     */
-    protected function getObjectManager(EventArgs $args)
-    {
-        return $args->getEntityManager();
-    }
-    
-    /**
-     * {@inheritdoc}
-     */
-    protected function getObject(EventArgs $args)
-    {
-        return $args->getEntity();
-    }
-    
+
     /**
-     * {@inheritdoc}
+     * Mapps additional metadata for the Entity
+     *
+     * @param EventArgs $eventArgs
+     * @return void
      */
-    protected function getObjectChangeSet($uow, $object)
+    public function loadClassMetadata(EventArgs $eventArgs)
     {
-        return $uow->getEntityChangeSet($object);
+        $ea = $this->getEventAdapter($eventArgs);
+        $this->loadMetadataForObjectClass($ea->getObjectManager(), $eventArgs->getClassMetadata());
     }
-    
+
     /**
-     * {@inheritdoc}
+     * Looks for Timestampable objects being updated
+     * to update modification date
+     *
+     * @param EventArgs $args
+     * @return void
      */
-    protected function getScheduledObjectUpdates($uow)
+    public function onFlush(EventArgs $args)
     {
-        return $uow->getScheduledEntityUpdates();
+        $ea = $this->getEventAdapter($args);
+        $om = $ea->getObjectManager();
+        $uow = $om->getUnitOfWork();
+        // check all scheduled updates
+        foreach ($ea->getScheduledObjectUpdates($uow) as $object) {
+            $meta = $om->getClassMetadata(get_class($object));
+            if ($config = $this->getConfiguration($om, $meta->name)) {
+                $changeSet = $ea->getObjectChangeSet($uow, $object);
+                $needChanges = false;
+
+                if (isset($config['update'])) {
+                    foreach ($config['update'] as $field) {
+                        if (!isset($changeSet[$field])) { // let manual values
+                            $needChanges = true;
+                            $meta->getReflectionProperty($field)->setValue($object, $ea->getDateValue($meta, $field));
+                        }
+                    }
+                }
+
+                if (isset($config['change'])) {
+                    foreach ($config['change'] as $options) {
+                        if (isset($changeSet[$options['field']])) {
+                            continue; // value was set manually
+                        }
+
+                        $tracked = $options['trackedField'];
+                        $trackedChild = null;
+                        $parts = explode('.', $tracked);
+                        if (isset($parts[1])) {
+                            $tracked = $parts[0];
+                            $trackedChild = $parts[1];
+                        }
+
+                        if (isset($changeSet[$tracked])) {
+                            $changes = $changeSet[$tracked];
+                            if (isset($trackedChild)) {
+                                $changingObject = $changes[1];
+                                if (!is_object($changingObject)) {
+                                    throw new \Gedmo\Exception\UnexpectedValueException("Field - [{$field}] is expected to be object in class - {$meta->name}");
+                                }
+                                $objectMeta = $om->getClassMetadata(get_class($changingObject));
+                                $trackedChild instanceof Proxy && $om->refresh($trackedChild);
+                                $value = $objectMeta->getReflectionProperty($trackedChild)
+                                    ->getValue($changingObject);
+                            } else {
+                                $value = $changes[1];
+                            }
+
+                            if ($options['value'] == $value) {
+                                $needChanges = true;
+                                $meta->getReflectionProperty($options['field'])
+                                    ->setValue($object, $ea->getDateValue($meta, $options['field']));
+                            }
+                        }
+                    }
+                }
+
+                if ($needChanges) {
+                    $ea->recomputeSingleObjectChangeSet($uow, $meta, $object);
+                }
+            }
+        }
     }
-    
+
     /**
-     * {@inheritdoc}
+     * Checks for persisted Timestampable objects
+     * to update creation and modification dates
+     *
+     * @param EventArgs $args
+     * @return void
      */
-    public function recomputeSingleObjectChangeSet($uow, ClassMetadata $meta, $object)
+    public function prePersist(EventArgs $args)
     {
-        $uow->recomputeSingleEntityChangeSet($meta, $object);
+        $ea = $this->getEventAdapter($args);
+        $om = $ea->getObjectManager();
+        $object = $ea->getObject();
+
+        $meta = $om->getClassMetadata(get_class($object));
+        if ($config = $this->getConfiguration($om, $meta->name)) {
+            if (isset($config['update'])) {
+                foreach ($config['update'] as $field) {
+                    if ($meta->getReflectionProperty($field)->getValue($object) === null) { // let manual values
+                        $meta->getReflectionProperty($field)->setValue($object, $ea->getDateValue($meta, $field));
+                    }
+                }
+            }
+
+            if (isset($config['create'])) {
+                foreach ($config['create'] as $field) {
+                    if ($meta->getReflectionProperty($field)->getValue($object) === null) { // let manual values
+                        $meta->getReflectionProperty($field)->setValue($object, $ea->getDateValue($meta, $field));
+                    }
+                }
+            }
+        }
     }
-    
+
     /**
-     * {@inheritdoc}
+     * {@inheritDoc}
      */
-    protected function getDateValue(ClassMetadata $meta, $field)
+    protected function getNamespace()
     {
-        return new \DateTime();
+        return __NAMESPACE__;
     }
 }

+ 1 - 1
tests/Gedmo/Timestampable/TimestampableDocumentTest.php

@@ -24,7 +24,7 @@ class TimestampableDocumentTest extends BaseTestCaseMongoODM
     {
         parent::setUp();
         $evm = new EventManager();
-        $evm->addEventSubscriber(new ODM\MongoDB\TimestampableListener);
+        $evm->addEventSubscriber(new TimestampableListener);
 
         $this->getMockDocumentManager($evm);
         $this->populate();