diff options
author | Kevin Decherf <kevin@kdecherf.com> | 2019-05-11 20:07:38 +0200 |
---|---|---|
committer | Kevin Decherf <kevin@kdecherf.com> | 2019-05-19 23:37:49 +0200 |
commit | feb239ea1006685ab3862c988309a1a5a9659559 (patch) | |
tree | 034e26b367d06796a4f7888847cff76b1401ad7a | |
parent | de1162b91a205a98a3f8ed01bd80285793b18380 (diff) | |
download | wallabag-feb239ea1006685ab3862c988309a1a5a9659559.tar.gz wallabag-feb239ea1006685ab3862c988309a1a5a9659559.tar.zst wallabag-feb239ea1006685ab3862c988309a1a5a9659559.zip |
mysql: change collation of tag table
utf8mb4_unicode_ci considers that 'caché' is equal to 'cache' which
can lead to attaching incorrect tags to entries. This issue is due to
some unicode normalization done by MySQL.
utf8mb4_bin makes no unicode normalization, letting wallabag to consider
'cache' and 'caché' as two different tags.
We change the collation of the whole table as Doctrine does not support
setting a collation on a column for a specific platform (it tries to
apply utf8mb4_bin even for pgsql and sqlite).
Fixes #3302
Signed-off-by: Kevin Decherf <kevin@kdecherf.com>
-rw-r--r-- | app/DoctrineMigrations/Version20190511165128.php | 30 | ||||
-rw-r--r-- | src/Wallabag/CoreBundle/Entity/Tag.php | 5 | ||||
-rw-r--r-- | tests/Wallabag/CoreBundle/Controller/TagControllerTest.php | 46 |
3 files changed, 80 insertions, 1 deletions
diff --git a/app/DoctrineMigrations/Version20190511165128.php b/app/DoctrineMigrations/Version20190511165128.php new file mode 100644 index 00000000..7b6b1bec --- /dev/null +++ b/app/DoctrineMigrations/Version20190511165128.php | |||
@@ -0,0 +1,30 @@ | |||
1 | <?php | ||
2 | |||
3 | declare(strict_types=1); | ||
4 | |||
5 | namespace Application\Migrations; | ||
6 | |||
7 | use Doctrine\DBAL\Schema\Schema; | ||
8 | use Wallabag\CoreBundle\Doctrine\WallabagMigration; | ||
9 | |||
10 | /** | ||
11 | * Convert tab label to utf8mb4_bin (MySQL only). | ||
12 | */ | ||
13 | final class Version20190511165128 extends WallabagMigration | ||
14 | { | ||
15 | public function up(Schema $schema): void | ||
16 | { | ||
17 | $this->skipIf('mysql' !== $this->connection->getDatabasePlatform()->getName(), 'This migration only apply to MySQL'); | ||
18 | |||
19 | $this->addSql('ALTER TABLE ' . $this->getTable('tag') . ' CHANGE `label` `label` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;'); | ||
20 | $this->addSql('ALTER TABLE ' . $this->getTable('tag') . ' CHANGE `slug` `slug` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;'); | ||
21 | } | ||
22 | |||
23 | public function down(Schema $schema): void | ||
24 | { | ||
25 | $this->skipIf('mysql' !== $this->connection->getDatabasePlatform()->getName(), 'This migration only apply to MySQL'); | ||
26 | |||
27 | $this->addSql('ALTER TABLE ' . $this->getTable('tag') . ' CHANGE `slug` `slug` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'); | ||
28 | $this->addSql('ALTER TABLE ' . $this->getTable('tag') . ' CHANGE `label` `label` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'); | ||
29 | } | ||
30 | } | ||
diff --git a/src/Wallabag/CoreBundle/Entity/Tag.php b/src/Wallabag/CoreBundle/Entity/Tag.php index a6dc8c50..95c47bbd 100644 --- a/src/Wallabag/CoreBundle/Entity/Tag.php +++ b/src/Wallabag/CoreBundle/Entity/Tag.php | |||
@@ -13,7 +13,10 @@ use JMS\Serializer\Annotation\XmlRoot; | |||
13 | * Tag. | 13 | * Tag. |
14 | * | 14 | * |
15 | * @XmlRoot("tag") | 15 | * @XmlRoot("tag") |
16 | * @ORM\Table(name="`tag`") | 16 | * @ORM\Table( |
17 | * name="`tag`", | ||
18 | * options={"collate"="utf8mb4_bin", "charset"="utf8mb4"}, | ||
19 | * ) | ||
17 | * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\TagRepository") | 20 | * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\TagRepository") |
18 | * @ExclusionPolicy("all") | 21 | * @ExclusionPolicy("all") |
19 | */ | 22 | */ |
diff --git a/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php b/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php index be17dcf5..47c83a7b 100644 --- a/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php +++ b/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php | |||
@@ -221,4 +221,50 @@ class TagControllerTest extends WallabagCoreTestCase | |||
221 | $this->assertInstanceOf(Tag::class, $newTag, 'Tag "specific label" exists.'); | 221 | $this->assertInstanceOf(Tag::class, $newTag, 'Tag "specific label" exists.'); |
222 | $this->assertTrue($newTag->hasEntry($freshEntry), 'Tag "specific label" is assigned to the entry.'); | 222 | $this->assertTrue($newTag->hasEntry($freshEntry), 'Tag "specific label" is assigned to the entry.'); |
223 | } | 223 | } |
224 | |||
225 | public function testAddUnicodeTagLabel() | ||
226 | { | ||
227 | $this->logInAs('admin'); | ||
228 | $client = $this->getClient(); | ||
229 | |||
230 | $entry = new Entry($this->getLoggedInUser()); | ||
231 | $entry->setUrl('http://0.0.0.0/tag-caché'); | ||
232 | $this->getEntityManager()->persist($entry); | ||
233 | $this->getEntityManager()->flush(); | ||
234 | $this->getEntityManager()->clear(); | ||
235 | |||
236 | $crawler = $client->request('GET', '/view/' . $entry->getId()); | ||
237 | |||
238 | $form = $crawler->filter('form[name=tag]')->form(); | ||
239 | |||
240 | $data = [ | ||
241 | 'tag[label]' => 'cache', | ||
242 | ]; | ||
243 | |||
244 | $client->submit($form, $data); | ||
245 | |||
246 | $crawler = $client->request('GET', '/view/' . $entry->getId()); | ||
247 | |||
248 | $form = $crawler->filter('form[name=tag]')->form(); | ||
249 | |||
250 | $data = [ | ||
251 | 'tag[label]' => 'caché', | ||
252 | ]; | ||
253 | |||
254 | $client->submit($form, $data); | ||
255 | |||
256 | $newEntry = $client->getContainer() | ||
257 | ->get('doctrine.orm.entity_manager') | ||
258 | ->getRepository('WallabagCoreBundle:Entry') | ||
259 | ->find($entry->getId()); | ||
260 | |||
261 | $tags = $newEntry->getTags()->toArray(); | ||
262 | foreach ($tags as $key => $tag) { | ||
263 | $tags[$key] = $tag->getLabel(); | ||
264 | } | ||
265 | |||
266 | $this->assertGreaterThanOrEqual(2, \count($tags)); | ||
267 | $this->assertNotFalse(array_search('cache', $tags, true), 'Tag cache is assigned to the entry'); | ||
268 | $this->assertNotFalse(array_search('caché', $tags, true), 'Tag caché is assigned to the entry'); | ||
269 | } | ||
224 | } | 270 | } |