diff --git a/app/DoctrineMigrations/Version20170719231144.php b/app/DoctrineMigrations/Version20170719231144.php new file mode 100644 index 000000000..0f5fa75ae --- /dev/null +++ b/app/DoctrineMigrations/Version20170719231144.php @@ -0,0 +1,103 @@ +container = $container; + } + + /** + * @param Schema $schema + */ + public function up(Schema $schema) + { + $this->skipIf($this->connection->getDatabasePlatform()->getName() === 'sqlite', 'Migration can only be executed safely on \'mysql\' or \'postgresql\'.'); + + // Find tags which need to be merged + $dupTags = $this->connection->query(' + SELECT LOWER(label) + FROM ' . $this->getTable('tag') . ' + GROUP BY LOWER(label) + HAVING COUNT(*) > 1' + ); + $dupTags->execute(); + + foreach ($dupTags->fetchAll() as $duplicates) { + $label = $duplicates['LOWER(label)']; + + // Retrieve all duplicate tags for a given tag + $tags = $this->connection->query(' + SELECT id + FROM ' . $this->getTable('tag') . " + WHERE LOWER(label) = '" . $label . "' + ORDER BY id ASC" + ); + $tags->execute(); + + $first = true; + $newId = null; + $ids = []; + + foreach ($tags->fetchAll() as $tag) { + // Ignore the first tag as we use it as the new reference tag + if ($first) { + $first = false; + $newId = $tag['id']; + } else { + $ids[] = $tag['id']; + } + } + + // Just in case... + if (count($ids) > 0) { + // Merge tags + $this->addSql(' + UPDATE ' . $this->getTable('entry_tag') . ' + SET tag_id = ' . $newId . ' + WHERE tag_id IN (' . implode(',', $ids) . ')' + ); + + // Delete unused tags + $this->addSql(' + DELETE FROM ' . $this->getTable('tag') . ' + WHERE id IN (' . implode(',', $ids) . ')' + ); + } + } + + // Iterate over all tags to lowercase them + $this->addSql(' + UPDATE ' . $this->getTable('tag') . ' + SET label = LOWER(label)' + ); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + throw new SkipMigrationException('Too complex ...'); + } + + private function getTable($tableName) + { + return $this->container->getParameter('database_table_prefix') . $tableName; + } +} diff --git a/src/Wallabag/CoreBundle/Entity/Tag.php b/src/Wallabag/CoreBundle/Entity/Tag.php index c19023af5..a6dc8c509 100644 --- a/src/Wallabag/CoreBundle/Entity/Tag.php +++ b/src/Wallabag/CoreBundle/Entity/Tag.php @@ -78,7 +78,7 @@ class Tag */ public function setLabel($label) { - $this->label = $label; + $this->label = mb_convert_case($label, MB_CASE_LOWER); return $this; } diff --git a/src/Wallabag/CoreBundle/Helper/TagsAssigner.php b/src/Wallabag/CoreBundle/Helper/TagsAssigner.php index a2fb0b9a9..0bfe5c572 100644 --- a/src/Wallabag/CoreBundle/Helper/TagsAssigner.php +++ b/src/Wallabag/CoreBundle/Helper/TagsAssigner.php @@ -45,7 +45,7 @@ class TagsAssigner } foreach ($tags as $label) { - $label = trim($label); + $label = trim(mb_convert_case($label, MB_CASE_LOWER)); // avoid empty tag if (0 === strlen($label)) { diff --git a/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php b/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php index be25a8b5e..5a973a7e0 100644 --- a/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php +++ b/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php @@ -9,6 +9,7 @@ use Wallabag\CoreBundle\Entity\Tag; class TagControllerTest extends WallabagCoreTestCase { public $tagName = 'opensource'; + public $caseTagName = 'OpenSource'; public function testList() { @@ -36,7 +37,7 @@ class TagControllerTest extends WallabagCoreTestCase $form = $crawler->filter('form[name=tag]')->form(); $data = [ - 'tag[label]' => $this->tagName, + 'tag[label]' => $this->caseTagName, ]; $client->submit($form, $data); @@ -45,6 +46,7 @@ class TagControllerTest extends WallabagCoreTestCase // be sure to reload the entry $entry = $this->getEntityManager()->getRepository(Entry::class)->find($entry->getId()); $this->assertCount(1, $entry->getTags()); + $this->assertContains($this->tagName, $entry->getTags()); // tag already exists and already assigned $client->submit($form, $data); @@ -80,7 +82,7 @@ class TagControllerTest extends WallabagCoreTestCase $form = $crawler->filter('form[name=tag]')->form(); $data = [ - 'tag[label]' => 'foo2, bar2', + 'tag[label]' => 'foo2, Bar2', ]; $client->submit($form, $data); diff --git a/tests/Wallabag/ImportBundle/Controller/PinboardControllerTest.php b/tests/Wallabag/ImportBundle/Controller/PinboardControllerTest.php index c307f96c9..9bb597664 100644 --- a/tests/Wallabag/ImportBundle/Controller/PinboardControllerTest.php +++ b/tests/Wallabag/ImportBundle/Controller/PinboardControllerTest.php @@ -125,7 +125,7 @@ class PinboardControllerTest extends WallabagCoreTestCase $tags = $content->getTags(); $this->assertContains('foot', $tags, 'It includes the "foot" tag'); $this->assertContains('varnish', $tags, 'It includes the "varnish" tag'); - $this->assertContains('PHP', $tags, 'It includes the "PHP" tag'); + $this->assertContains('php', $tags, 'It includes the "php" tag'); $this->assertSame(3, count($tags)); $this->assertInstanceOf(\DateTime::class, $content->getCreatedAt()); diff --git a/tests/Wallabag/ImportBundle/Controller/WallabagV1ControllerTest.php b/tests/Wallabag/ImportBundle/Controller/WallabagV1ControllerTest.php index 25625c35e..4bc982e0a 100644 --- a/tests/Wallabag/ImportBundle/Controller/WallabagV1ControllerTest.php +++ b/tests/Wallabag/ImportBundle/Controller/WallabagV1ControllerTest.php @@ -125,7 +125,7 @@ class WallabagV1ControllerTest extends WallabagCoreTestCase $tags = $content->getTags(); $this->assertContains('foot', $tags, 'It includes the "foot" tag'); - $this->assertContains('Framabag', $tags, 'It includes the "Framabag" tag'); + $this->assertContains('framabag', $tags, 'It includes the "framabag" tag'); $this->assertSame(2, count($tags)); $this->assertInstanceOf(\DateTime::class, $content->getCreatedAt());