]> git.immae.eu Git - github/wallabag/wallabag.git/commitdiff
Add custom doctrine subscriber for SQLite
authorJeremy Benoist <jeremy.benoist@gmail.com>
Sat, 1 Oct 2016 12:01:13 +0000 (14:01 +0200)
committerJeremy Benoist <jeremy.benoist@gmail.com>
Sat, 22 Oct 2016 11:13:07 +0000 (13:13 +0200)
Since SQLite doesn’t handle cascade remove by default, we need to handle it manually.

Also some refacto

src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php
src/Wallabag/CoreBundle/Controller/ConfigController.php
src/Wallabag/CoreBundle/Repository/EntryRepository.php
src/Wallabag/CoreBundle/Resources/config/services.yml
src/Wallabag/CoreBundle/Subscriber/SQLiteCascadeDeleteSubscriber.php [new file with mode: 0644]

index 5f7da70ecfa4cb1d375fdbc94f68d9a019c2c4ce..d999dc0f3c756bc85db536930f5666d6c5c011e4 100644 (file)
@@ -106,4 +106,17 @@ class AnnotationRepository extends EntityRepository
             ->getQuery()
             ->getSingleResult();
     }
+
+    /**
+     * Remove all annotations for a user id.
+     * Used when a user want to reset all informations
+     *
+     * @param  int $userId
+     */
+    public function removeAllByUserId($userId)
+    {
+        $this->getEntityManager()
+            ->createQuery('DELETE FROM Wallabag\AnnotationBundle\Entity\Annotation a WHERE a.user = '.$userId)
+            ->execute();
+    }
 }
index ccbf550a9f2eeed96f1ffc13f5f54ceef895f6e5..faa85d1686919b15bfb7d064e4cfc22889770389 100644 (file)
@@ -237,25 +237,26 @@ class ConfigController extends Controller
 
         switch ($type) {
             case 'annotations':
-                $em->createQuery('DELETE FROM Wallabag\AnnotationBundle\Entity\Annotation a WHERE a.user = '.$this->getUser()->getId())
-                    ->execute();
+                $this->getDoctrine()
+                    ->getRepository('WallabagAnnotationBundle:Annotation')
+                    ->removeAllByUserId($this->getUser()->getId());
                 break;
 
             case 'tags':
-                $tags = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findAllTags($this->getUser()->getId());
+                $this->removeAllTagsByUserId($this->getUser()->getId());
+                break;
 
-                if (empty($tags)) {
-                    break;
+            case 'entries':
+                // SQLite doesn't care about cascading remove, so we need to manually remove associated stuf
+                // otherwise they won't be removed ...
+                if ($this->get('doctrine')->getConnection()->getDriver() instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver) {
+                    $this->getDoctrine()->getRepository('WallabagAnnotationBundle:Annotation')->removeAllByUserId($this->getUser()->getId());
+                    $this->removeAllTagsByUserId($this->getUser()->getId());
                 }
 
                 $this->getDoctrine()
                     ->getRepository('WallabagCoreBundle:Entry')
-                    ->removeTags($this->getUser()->getId(), $tags);
-                break;
-
-            case 'entries':
-                $em->createQuery('DELETE FROM Wallabag\CoreBundle\Entity\Entry e WHERE e.user = '.$this->getUser()->getId())
-                    ->execute();
+                    ->removeAllByUserId($this->getUser()->getId());
         }
 
         $this->get('session')->getFlashBag()->add(
@@ -266,6 +267,24 @@ class ConfigController extends Controller
         return $this->redirect($this->generateUrl('config').'#set3');
     }
 
+    /**
+     * Remove all tags for a given user.
+     *
+     * @param  int $userId
+     */
+    private function removeAllTagsByUserId($userId)
+    {
+        $tags = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findAllTags($userId);
+
+        if (empty($tags)) {
+            return;
+        }
+
+        $this->getDoctrine()
+            ->getRepository('WallabagCoreBundle:Entry')
+            ->removeTags($userId, $tags);
+    }
+
     /**
      * Validate that a rule can be edited/deleted by the current user.
      *
index cd2b47b9f7c32b737d35910effe1cf53398adac8..8704a2a6d2fb1062f3b17c2b36b016349c55d563 100644 (file)
@@ -329,4 +329,17 @@ class EntryRepository extends EntityRepository
 
         return $qb->getQuery()->getSingleScalarResult();
     }
+
+    /**
+     * Remove all entries for a user id.
+     * Used when a user want to reset all informations
+     *
+     * @param  int $userId
+     */
+    public function removeAllByUserId($userId)
+    {
+        $this->getEntityManager()
+            ->createQuery('DELETE FROM Wallabag\CoreBundle\Entity\Entry e WHERE e.user = '.$userId)
+            ->execute();
+    }
 }
index a4b727f42b57d21ef4b3a9eedc881370ecca8cef..540d21f12e09f68142322d68748540718bf46e27 100644 (file)
@@ -88,6 +88,17 @@ services:
         arguments:
             - WallabagCoreBundle:Tag
 
+    wallabag_core.listener.registration_confirmed:
+        class: Wallabag\CoreBundle\EventListener\RegistrationConfirmedListener
+        arguments:
+            - "@doctrine.orm.entity_manager"
+            - "%wallabag_core.theme%"
+            - "%wallabag_core.items_on_page%"
+            - "%wallabag_core.rss_limit%"
+            - "%wallabag_core.language%"
+        tags:
+            - { name: kernel.event_subscriber }
+
     wallabag_core.helper.entries_export:
         class: Wallabag\CoreBundle\Helper\EntriesExport
         arguments:
@@ -129,3 +140,10 @@ services:
         arguments:
             - '@twig'
             - '%kernel.debug%'
+
+    wallabag_core.subscriber.sqlite_cascade_delete:
+        class:  Wallabag\CoreBundle\Subscriber\SQLiteCascadeDeleteSubscriber
+        arguments:
+            - "@doctrine"
+        tags:
+            - { name: doctrine.event_subscriber }
diff --git a/src/Wallabag/CoreBundle/Subscriber/SQLiteCascadeDeleteSubscriber.php b/src/Wallabag/CoreBundle/Subscriber/SQLiteCascadeDeleteSubscriber.php
new file mode 100644 (file)
index 0000000..d518057
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+namespace Wallabag\CoreBundle\Subscriber;
+
+use Doctrine\Common\EventSubscriber;
+use Doctrine\ORM\EntityManager;
+use Doctrine\ORM\Event\LifecycleEventArgs;
+use Wallabag\CoreBundle\Entity\Entry;
+use Doctrine\Bundle\DoctrineBundle\Registry;
+
+/**
+ * SQLite doesn't care about cascading remove, so we need to manually remove associated stuf for an Entry.
+ * Foreign Key Support can be enabled by running `PRAGMA foreign_keys = ON;` at runtime (AT RUNTIME !).
+ * But it needs a compilation flag that not all SQLite instance has ...
+ *
+ * @see https://www.sqlite.org/foreignkeys.html#fk_enable
+ */
+class SQLiteCascadeDeleteSubscriber implements EventSubscriber
+{
+    private $doctrine;
+
+    /**
+     * @param \Doctrine\Bundle\DoctrineBundle\Registry $doctrine
+     */
+    public function __construct(Registry $doctrine)
+    {
+        $this->doctrine = $doctrine;
+    }
+
+    /**
+     * @return array
+     */
+    public function getSubscribedEvents()
+    {
+        return [
+            'preRemove',
+        ];
+    }
+
+    /**
+     * We removed everything related to the upcoming removed entry because SQLite can't handle it on it own.
+     * We do it in the preRemove, because we can't retrieve tags in the postRemove (because the entry id is gone)
+     *
+     * @param LifecycleEventArgs $args
+     */
+    public function preRemove(LifecycleEventArgs $args)
+    {
+        $entity = $args->getEntity();
+
+        if (!$this->doctrine->getConnection()->getDriver() instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver ||
+            !$entity instanceof Entry) {
+            return;
+        }
+
+        $em = $this->doctrine->getManager();
+
+        if (null !== $entity->getTags()) {
+            foreach ($entity->getTags() as $tag) {
+                $entity->removeTag($tag);
+            }
+        }
+
+        if (null !== $entity->getAnnotations()) {
+            foreach ($entity->getAnnotations() as $annotation) {
+                $em->remove($annotation);
+            }
+        }
+
+        $em->flush();
+    }
+}