Ver Fonte

Some experimental work on SoftDeleteable extension

comfortablynumb há 13 anos atrás
pai
commit
fb08b6a206

+ 26 - 0
lib/Gedmo/Mapping/Annotation/SoftDeleteable.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace Gedmo\Mapping\Annotation;
+
+use Doctrine\Common\Annotations\Annotation;
+
+/**
+ * Group annotation for SoftDeleteable extension
+ *
+ * @author Gustavo Falco <comfortablynumb84@gmail.com>
+ * @package Gedmo.Mapping.Annotation
+ * @subpackage SoftDeleteable
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ *
+ * @Annotation
+ * @Target("CLASS")
+ */
+final class SoftDeleteable extends Annotation
+{
+    /** @var string */
+    public $fieldName = 'deletedAt';
+
+    /** @var bool */
+    public $autoMap = true;
+}

+ 79 - 0
lib/Gedmo/SoftDeleteable/Mapping/Driver/Annotation.php

@@ -0,0 +1,79 @@
+<?php
+
+namespace Gedmo\SoftDeleteable\Mapping\Driver;
+
+use Gedmo\Mapping\Driver\AnnotationDriverInterface,
+    Doctrine\Common\Persistence\Mapping\ClassMetadata,
+    Gedmo\Exception\InvalidMappingException;
+
+/**
+ * This is an annotation mapping driver for SoftDeleteable
+ * behavioral extension. Used for extraction of extended
+ * metadata from Annotations specificaly for SoftDeleteable
+ * extension.
+ *
+ * @author Gustavo Falco <comfortablynumb84@gmail.com>
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.SoftDeleteable.Mapping.Driver
+ * @subpackage Annotation
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class Annotation implements AnnotationDriverInterface
+{
+    /**
+     * Annotation to define that this object is loggable
+     */
+    const SOFT_DELETEABLE = 'Gedmo\\Mapping\\Annotation\\SoftDeleteable';
+
+    /**
+     * Annotation reader instance
+     *
+     * @var object
+     */
+    private $reader;
+
+    /**
+     * original driver if it is available
+     */
+    protected $_originalDriver = null;
+    /**
+     * {@inheritDoc}
+     */
+    public function setAnnotationReader($reader)
+    {
+        $this->reader = $reader;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function validateFullMetadata(ClassMetadata $meta, array $config)
+    {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function readExtendedMetadata(ClassMetadata $meta, array &$config)
+    {
+        $class = $meta->getReflectionClass();
+        // class annotations
+        if ($annot = $this->reader->getClassAnnotation($class, self::SOFT_DELETEABLE)) {
+            $config['softDeleteable'] = true;
+            $config['fieldName'] = $annot->fieldName;
+            $config['autoMap'] = $annot->autoMap;
+        }
+    }
+
+    /**
+     * Passes in the mapping read by original driver
+     *
+     * @param $driver
+     * @return void
+     */
+    public function setOriginalDriver($driver)
+    {
+        $this->_originalDriver = $driver;
+    }
+}

+ 30 - 0
lib/Gedmo/SoftDeleteable/SoftDeleteable.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace Gedmo\SoftDeleteable;
+
+/**
+ * This interface is not necessary but can be implemented for
+ * Domain Objects which in some cases needs to be identified as
+ * SoftDeleteable
+ *
+ * @author Gustavo Falco <comfortablynumb84@gmail.com>
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.SoftDeleteable
+ * @subpackage SoftDeleteable
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+interface SoftDeleteable
+{
+    // this interface is not necessary to implement
+    
+    /**
+     * @gedmo:SoftDeleteable
+     * to mark the class as SoftDeleteable use class annotation @gedmo:SoftDeleteable
+     * this object will be able to be soft deleted
+     * example:
+     * 
+     * @gedmo:SoftDeleteable
+     * class MyEntity
+     */
+}

+ 83 - 0
lib/Gedmo/SoftDeleteable/SoftDeleteableListener.php

@@ -0,0 +1,83 @@
+<?php
+
+namespace Gedmo\SoftDeleteable;
+
+use Doctrine\Common\Persistence\ObjectManager,
+    Doctrine\Common\Persistence\Mapping\ClassMetadata,
+    Gedmo\Mapping\MappedEventSubscriber,
+    Gedmo\Loggable\Mapping\Event\LoggableAdapter,
+    Doctrine\Common\EventArgs;
+
+/**
+ * SoftDeleteable listener
+ *
+ * @author Gustavo Falco <comfortablynumb84@gmail.com>
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.SoftDeleteable
+ * @subpackage SoftDeleteableListener
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class SoftDeleteableListener extends MappedEventSubscriber
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function getSubscribedEvents()
+    {
+        return array(
+            'loadClassMetadata',
+            'preRemove'
+        );
+    }
+
+    /**
+     * Mapps additional metadata
+     *
+     * @param EventArgs $eventArgs
+     * @return void
+     */
+    public function loadClassMetadata(EventArgs $eventArgs)
+    {
+        $ea = $this->getEventAdapter($eventArgs);
+        $om = $ea->getObjectManager();
+        $meta = $eventArgs->getClassMetadata();
+        $this->loadMetadataForObjectClass($ea->getObjectManager(), $eventArgs->getClassMetadata());
+        $config = isset($this->configurations[$meta->name]) ? $this->configurations[$meta->name] : array();
+        
+        if (isset($config['softDeleteable']) && $config['softDeleteable']) {
+            if ($config['autoMap']) {
+                $meta->mapField(array(
+                     'fieldName'         => $config['fieldName'],
+                     'id'                => false,
+                     'type'              => 'datetime',
+                     'nullable'          => true
+                ));
+
+                if ($cacheDriver = $om->getMetadataFactory()->getCacheDriver()) {
+                    $cacheDriver->save($meta->name."\$CLASSMETADATA", $meta, null);
+                }
+            }
+        }
+    }
+
+    /**
+     * If it's a SoftDeleteable object, update the "deletedAt" field
+     * and skip the removal of the object
+     *
+     * @param EventArgs $args
+     * @return void
+     */
+    public function preRemove(EventArgs $args)
+    {
+        
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function getNamespace()
+    {
+        return __NAMESPACE__;
+    }
+}

+ 53 - 0
tests/Gedmo/SoftDeleteable/Fixture/Entity/Article.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace SoftDeleteable\Fixture\Entity;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity
+ * @Gedmo\SoftDeleteable
+ */
+class Article
+{
+    /**
+     * @ORM\Column(name="id", type="integer")
+     * @ORM\Id
+     * @ORM\GeneratedValue(strategy="IDENTITY")
+     */
+    private $id;
+
+    /**
+     * @ORM\Column(name="title", type="string", length=8)
+     */
+    private $title;
+
+    /** Mapped by listener */
+    private $deletedAt;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function setDeletedAt($deletedAt)
+    {
+        $this->deletedAt = $deletedAt;
+    }
+
+    public function getDeletedAt()
+    {
+        return $this->deletedAt;
+    }
+}

+ 68 - 0
tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace Gedmo\SoftDeleteable;
+
+use Tool\BaseTestCaseORM;
+use Doctrine\Common\EventManager;
+use Doctrine\Common\Util\Debug,
+    SoftDeleteable\Fixture\Entity\Article,
+    Gedmo\SoftDeleteable\SoftDeleteableListener;
+
+/**
+ * These are tests for SoftDeleteable behavior
+ *
+ * @author Gustavo Falco <comfortablynumb84@gmail.com>
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.SoftDeleteable
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class SoftDeleteableEntityTest extends BaseTestCaseORM
+{
+    const ARTICLE_CLASS = 'SoftDeleteable\Fixture\Entity\Article';
+
+    private $softDeleteableListener;
+
+    protected function setUp()
+    {
+        parent::setUp();
+
+        $evm = new EventManager;
+        $this->softDeleteableListener = new SoftDeleteableListener();
+        $evm->addEventSubscriber($this->softDeleteableListener);
+
+        $this->em = $this->getMockSqliteEntityManager($evm);
+    }
+
+    public function testSoftDeleteable()
+    {
+        $art0 = new Article();
+        $art0->setTitle('Title 1');
+
+        $art1 = new Article();
+        $art1->setTitle('Title 2');
+
+        $this->em->persist($art0);
+        $this->em->persist($art1);
+
+        $this->em->flush();
+        
+        $meta = $this->em->getClassMetadata(self::ARTICLE_CLASS);
+
+        $this->assertArrayHasKey('deletedAt', $meta->fieldNames);
+
+        
+    }
+
+    protected function getUsedEntityFixtures()
+    {
+        return array(
+            self::ARTICLE
+        );
+    }
+
+    private function populate()
+    {
+        
+    }
+}

+ 1 - 0
tests/bootstrap.php

@@ -48,6 +48,7 @@ $loader->registerNamespaces(array(
     'Sortable\\Fixture'          => __DIR__.'/Gedmo',
     'Mapping\\Fixture'           => __DIR__.'/Gedmo',
     'Loggable\\Fixture'          => __DIR__.'/Gedmo',
+    'SoftDeleteable\\Fixture'    => __DIR__.'/Gedmo',
     'Wrapper\\Fixture'           => __DIR__.'/Gedmo',
 ));
 $loader->register();