0

I can add record to many to many table tag_post successfully but I'm not able to remove any records from tag_post. Please bear in mind I only want to remove records from tag_post not the record from table post itself.

I have 3 tables post,tag and tag_post. tables tag_post contains relation between post and tag. the fields in table tag_post are :

  • tag_id
  • post_id

Mapping file for post:

    oneToMany:
    tagPostAssociations:
        targetEntity: Mockizart\Bundle\BlogBundle\Entity\MockblogTagPost
        mappedBy: "post"
        cascade: ["persist","remove"]

Mapping file for tag:

    oneToMany:
    tagPostAssociations:
        targetEntity: Mockizart\Bundle\BlogBundle\Entity\MockblogTagPost
        mappedBy: "tag"
        cascade: ["persist","remove"]

Mapping file for tag_post:

    manyToOne:
    post:
        associationKey: true
        targetEntity: Mockizart\Bundle\BlogBundle\Entity\MockblogPost
        inversedBy: "tagPostAssociations"
    tag:
        targetEntity: Mockizart\Bundle\BlogBundle\Entity\MockblogTag
        inversedBy: "tagPostAssociations"

My code for test:

    $post = $this->getDoctrine()->getManager()->find('MockizartBlogBundle:MockblogPost',6);
    $b = $this->getDoctrine()->getManager()->find('MockizartBlogBundle:MockblogTagPost',['tagId' => 20,'postId' => 6]);
    $post->removeTagPostAssociation($b);
    $this->getDoctrine()->getManager()->persist($post);
    $this->getDoctrine()->getManager()->flush();

My tag_post entity:

public function __construct($tag, $post)
{
    $this->tagId = $tag->getId();
    $this->postId = $post->getId();
    $this->post = $post;
    $this->tag = $tag;
}

My post entity:

public  $tagPostAssociations;

public function __construct() {
    $this->tagPostAssociations = new ArrayCollection();
}

public function addTagPostAssociation(MockblogTagPost $tagPostAssociations)
{
    $newTag = $tagPostAssociations;
    $this->newTags[$newTag->getTagId().$newTag->getPostId()] = $newTag;
    $hasTagPost = $this->hasTagPost($newTag);

    if (!$hasTagPost) {
        $this->tagPostAssociations[] = $tagPostAssociations;
    }

    return $this;
}


public function removeTagPostAssociation(MockblogTagPost $tagPost)
{
    $this->tagPostAssociations->removeElement($tagPost);


    return $this;
}

public function getTagPostAssociations()
{
    return $this->tagPostAssociations;
}

I only post codes that I think related to the case. if you want to see more code, please let me know.

Kakashi
  • 3,329
  • 4
  • 26
  • 37

1 Answers1

0

I can't test your setup, however I believe you've mixed up your understanding of the cascade attribute with Doctrine. See, if you did something like:

$post = $this->getDoctrine()->getManager()->find('MockizartBlogBundle:MockblogPost',6);
$this->getDoctrine()->getManager()->remove($post);
$this->getDoctrine()->getManager()->flush();

Then Doctrine would recognize that you are deleting the $post in question and would cascade operations to all of the associations that have the "remove" cascade rule defined, which would delete the tag_post entry in question. However you're not deleting your $post, so you must manually remove the tag_post after taking it out of your object:

$post = $this->getDoctrine()->getManager()->find('MockizartBlogBundle:MockblogPost',6);
$b = $this->getDoctrine()->getManager()->find('MockizartBlogBundle:MockblogTagPost',['tagId' => 20,'postId' => 6]);
$post->removeTagPostAssociation($b);
// This may need to come after the persist, haven't tested
$this->getDoctrine()->getManager()->remove($b);
$this->getDoctrine()->getManager()->persist($post);
$this->getDoctrine()->getManager()->flush();

This is obviously cumbersome if you're constantly removing entries, so perhaps an event listener could automate this process for you.

One other thing to note is that you may be able to get away with just removing the tag_post and not touching your post or tag objects at all:

$b = $this->getDoctrine()->getManager()->find('MockizartBlogBundle:MockblogTagPost',['tagId' => 20,'postId' => 6]);
$this->getDoctrine()->getManager()->remove($b);
$this->getDoctrine()->getManager()->flush();

Reason being is that all of the foreign reference columns "live" in the tag_post table, meaning there would be no integrity violations by simply removing a ManyToMany reference. Only thing is any loaded post or tag object would have out-of-date tagPostAssociations

sjagr
  • 15,983
  • 5
  • 40
  • 67
  • Thanks for the answer but I read this link (answered by @ethan ) [link](http://stackoverflow.com/questions/9653493/deleting-record-in-many-to-many-table) but he don't need to call remove() – Kakashi Nov 28 '14 at 03:08
  • @MuhammadRifkiMockie That question you refer to uses a true `ManyToMany` association, where you've decided to abstract a `ManyToMany` association with two `ManyToOne`s to a single entity so you can add attributes to the association. Doctrine does not handle the latter natively. – sjagr Nov 28 '14 at 03:13
  • I tested what you said above and it works. but I still don't get it why I can add to `tagPostAssociations` without `persist()` it separately but not able to remove them without `remove()`. do you have any link about this ? – Kakashi Nov 28 '14 at 03:19
  • @MuhammadRifkiMockie It is because `removeTagPostAssociation()` is **NOT** the same as `remove()`. The `addTagPostAssociation()` function also does _not_ trigger the `persist()` function either, it is your usage of `$this->getDoctrine()->getManager()->persist()` that triggers the `persist` cascade. Therefore, `removeTagPostAssocation()` does not trigger the `remove` cascade. I have no literature for you [except for the relevant documentation](http://doctrine-orm.readthedocs.org/en/latest/reference/working-with-associations.html#transitive-persistence-cascade-operations) – sjagr Nov 28 '14 at 03:26
  • In another code I only using `flush()` without `persist()` and it works (when updating post record and adding new record for `tagpost`). it is a must to call `persist()` when adding new record (add new `tagpost` when update `post`), isn't it? – Kakashi Nov 28 '14 at 03:31
  • @MuhammadRifkiMockie I'd have to see the other code. You are likely calling the `persist` cascade somewhere which triggers the rest. – sjagr Nov 28 '14 at 03:34
  • here is my code : [gist](https://gist.github.com/mockiemockiz/f1b40ac673deb2e57f50) if you don't mind to see the code :) Thank you @sjagr – Kakashi Nov 28 '14 at 03:43