Fix the way to remove a tag from all user entries

This commit is contained in:
Jeremy Benoist 2015-12-29 15:08:33 +01:00
parent 1bb1939ab7
commit 4059a061c0
3 changed files with 53 additions and 10 deletions

View file

@ -310,5 +310,12 @@ class WallabagRestControllerTest extends WallabagApiTestCase
$this->assertArrayHasKey('label', $content);
$this->assertEquals($tag['label'], $content['label']);
$this->assertEquals($tag['slug'], $content['slug']);
$entries = $entry = $this->client->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository('WallabagCoreBundle:Entry')
->findAllByTagId($this->user->getId(), $tag['id']);
$this->assertCount(0, $entries);
}
}

View file

@ -12,6 +12,11 @@ abstract class WallabagApiTestCase extends WebTestCase
*/
protected $client = null;
/**
* @var \FOS\UserBundle\Model\UserInterface
*/
protected $user;
public function setUp()
{
$this->client = $this->createAuthorizedClient();
@ -31,8 +36,8 @@ abstract class WallabagApiTestCase extends WebTestCase
$loginManager = $container->get('fos_user.security.login_manager');
$firewallName = $container->getParameter('fos_user.firewall_name');
$user = $userManager->findUserBy(array('username' => 'admin'));
$loginManager->loginUser($firewallName, $user);
$this->user = $userManager->findUserBy(array('username' => 'admin'));
$loginManager->loginUser($firewallName, $this->user);
// save the login token into the session and put it in a cookie
$container->get('session')->set('_security_'.$firewallName, serialize($container->get('security.token_storage')->getToken()));

View file

@ -183,19 +183,50 @@ class EntryRepository extends EntityRepository
/**
* Remove a tag from all user entries.
* We are using a native SQL query because Doctrine doesn't know EntryTag entity because it's a ManyToMany relation.
* Instead of that SQL query we should loop on every entry and remove the tag, could be really long ...
*
* We need to loop on each entry attached to the given tag to remove it, since Doctrine doesn't know EntryTag entity because it's a ManyToMany relation.
* It could be faster with one query but I don't know how to retrieve the table name `entry_tag` which can have a prefix.
*
* @param int $userId
* @param Tag $tag
*/
public function removeTag($userId, Tag $tag)
{
$sql = 'DELETE et FROM entry_tag et WHERE et.entry_id IN ( SELECT e.id FROM entry e WHERE e.user_id = :userId ) AND et.tag_id = :tagId';
$stmt = $this->getEntityManager()->getConnection()->prepare($sql);
$stmt->execute([
'userId' => $userId,
'tagId' => $tag->getId(),
]);
$entries = $this->getBuilderByUser($userId)
->innerJoin('e.tags', 't')
->andWhere('t.id = :tagId')->setParameter('tagId', $tag->getId())
->getQuery()
->getResult();
foreach ($entries as $entry) {
$entry->removeTag($tag);
}
$this->getEntityManager()->flush();
// An other solution can be to use raw query but I can't find a way to retrieve the `entry_tag` table name since it can be prefixed....
// $sql = 'DELETE et FROM entry_tag et WHERE et.entry_id IN ( SELECT e.id FROM entry e WHERE e.user_id = :userId ) AND et.tag_id = :tagId';
// $stmt = $this->getEntityManager()->getConnection()->prepare($sql);
// $stmt->execute([
// 'userId' => $userId,
// 'tagId' => $tag->getId(),
// ]);
}
/**
* Find all entries that are attached to a give tag id.
*
* @param int $userId
* @param int $tagId
*
* @return array
*/
public function findAllByTagId($userId, $tagId)
{
return $this->getBuilderByUser($userId)
->innerJoin('e.tags', 't')
->andWhere('t.id = :tagId')->setParameter('tagId', $tagId)
->getQuery()
->getResult();
}
}