From 191564b7f71d01fb4c597c9b9641e23db564278d Mon Sep 17 00:00:00 2001 From: Jeremy Benoist Date: Sat, 1 Oct 2016 14:01:13 +0200 Subject: [PATCH] Add custom doctrine subscriber for SQLite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since SQLite doesn’t handle cascade remove by default, we need to handle it manually. Also some refacto --- .../Repository/AnnotationRepository.php | 13 ++++ .../Controller/ConfigController.php | 41 ++++++++--- .../CoreBundle/Repository/EntryRepository.php | 13 ++++ .../CoreBundle/Resources/config/services.yml | 18 +++++ .../SQLiteCascadeDeleteSubscriber.php | 70 +++++++++++++++++++ 5 files changed, 144 insertions(+), 11 deletions(-) create mode 100644 src/Wallabag/CoreBundle/Subscriber/SQLiteCascadeDeleteSubscriber.php diff --git a/src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php b/src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php index 5f7da70ec..d999dc0f3 100644 --- a/src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php +++ b/src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php @@ -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(); + } } diff --git a/src/Wallabag/CoreBundle/Controller/ConfigController.php b/src/Wallabag/CoreBundle/Controller/ConfigController.php index ccbf550a9..faa85d168 100644 --- a/src/Wallabag/CoreBundle/Controller/ConfigController.php +++ b/src/Wallabag/CoreBundle/Controller/ConfigController.php @@ -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. * diff --git a/src/Wallabag/CoreBundle/Repository/EntryRepository.php b/src/Wallabag/CoreBundle/Repository/EntryRepository.php index cd2b47b9f..8704a2a6d 100644 --- a/src/Wallabag/CoreBundle/Repository/EntryRepository.php +++ b/src/Wallabag/CoreBundle/Repository/EntryRepository.php @@ -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(); + } } diff --git a/src/Wallabag/CoreBundle/Resources/config/services.yml b/src/Wallabag/CoreBundle/Resources/config/services.yml index a4b727f42..540d21f12 100644 --- a/src/Wallabag/CoreBundle/Resources/config/services.yml +++ b/src/Wallabag/CoreBundle/Resources/config/services.yml @@ -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 index 000000000..d51805770 --- /dev/null +++ b/src/Wallabag/CoreBundle/Subscriber/SQLiteCascadeDeleteSubscriber.php @@ -0,0 +1,70 @@ +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(); + } +}