Skip to content

Conversation

@Grafikart
Copy link
Contributor

@Grafikart Grafikart commented Feb 14, 2017

When a tag is detached from a post it stays in the Tag table filling the table over time. When we update (or delete a post) we clean up unused (unlinked tags)

Improvments ideas 💡

  • I wanted to add this behaviour in an EventSubscriber but I don't know how to detect when a tag relation is persisted
  • The query to get unused tag could be improved avoiding the double LEFT JOIN, but I don't know how to ask doctrine to limit the LEFT JOIN to the relation table.

* @var array
*
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Post", mappedBy="tags")
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stof: we don't need it. You never use it (and it does not really make sense to have it anyway as tags don't need to be aware of posts). #192 (diff)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put this relation to make the query in the TagRepository

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Grafikart, you can delete unused tags using just one SQL query.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and even in DQL, you don't need to have a relation to be able to do a join

if ($form->isSubmitted() && $form->isValid()) {
$post->setSlug($this->get('slugger')->slugify($post->getTitle()));
$entityManager->flush();
$this->getDoctrine()->getRepository(Tag::class)->cleanUnusedTags();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it necessary to do this? the unused tags could be used for new posts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personal choice mainly (I understand if you close the issue).

Having tags attached to nothing could create some problem if you choose to create a tagcloud later for instance.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as you do it using a separate query, you should wrap the flush and this query in a transaction, to be atomic.

*
* @return Tag
*/
public function addPost(\AppBundle\Entity\Post $post)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this adder is worse than anything else you did, because it will not add the post (as you don't update the owning side of the relation)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing everything from this entity sorry

use AppBundle\Entity\Tag;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query;
use Pagerfanta\Adapter\DoctrineORMAdapter;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why pagerfanta ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo sorry

* See http://symfony.com/doc/current/book/doctrine.html#custom-repository-classes
*
* @author Ryan Weaver <[email protected]>
* @author Javier Eguiluz <[email protected]>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

authors look wrong here

if ($form->isSubmitted() && $form->isValid()) {
$post->setSlug($this->get('slugger')->slugify($post->getTitle()));
$entityManager->flush();
$this->getDoctrine()->getRepository(Tag::class)->cleanUnusedTags();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could make this code much more efficient, by getting the old list of tags of the Post in an array before handleRequest, then comparing it to the list of new tags here. The difference will give you the list of tags removed from the post, which are the only ones you need to check for being unused

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, but it would add more code to the controller, is it acceptable ?

@Grafikart
Copy link
Contributor Author

I can't figure how to do this query using DQL https://github.com/symfony/symfony-demo/pull/474/files#diff-2629962eca7be81a3484a3f64ad18074R36 (can't find a way to do a join on the join table without having a ManyToMany between Tag and Post owned by Tag)

@voronkovich
Copy link
Contributor

if ($form->isSubmitted() && $form->isValid()) {
$post->setSlug($this->get('slugger')->slugify($post->getTitle()));
$entityManager->flush();
$entityManager->transactional(function ($entityManager) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate your contribution ... but using $entityManager->transactional is "light years" ahead of what we want to teach in the Symfony Demo app. I'm sorry but we can't use this obscure feature. We'll need to find a much simpler alternative solution. Thanks for understanding it.

$joinTable = $this->getEntityManager()->getClassMetadata(Post::class)->getAssociationMapping('tags')['joinTable']['name'];
$tagTable = $this->getClassMetadata()->getTableName();
$unused_tags = $this->getEntityManager()->createNativeQuery("
DELETE FROM `$tagTable` WHERE id IN
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Grafikart , try to use:

DELETE FROM tags t
LEFT JOIN tags_posts j ON j.tag_id = t.id
WHERE j.tag_id IS NULL

@Grafikart Grafikart closed this Mar 11, 2017
@Grafikart Grafikart deleted the unused-tag branch March 11, 2017 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants