1

I'm trying to get manyToMany relationship with Doctrine and symfony. I'm new at Doctrine and Symfony. I came from Zend framework.

I've created the 3 tables: Post, PostCategory and junction table PostToCategory as you can see below.

Tables example

My goal is to do inner join and to get for every post its categories. This is what I've done so far:

//CMS/GBundle/Entity/PostContent

class PostContent
{

    /**
     * @ORM\ManyToMany(targetEntity="CMS\GBundle\Entity\PostCategory", inversedBy="posts")
     * @ORM\JoinTable(name="post_to_category")
     */
    protected $categories;

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

//CMS/GBundle/Entity/PostCategory

class PostCategory
{

    /**
     * @ORM\ManyToMany(targetEntity="CMS\GBundle\Entity\PostContent", mappedBy="categories")
     */
    protected $posts;

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

I would like now to create function that returns me joined data Post->PostCategories.

Where should I create function ? in PostToCategory Repository ? or somewhere else ? How should my query look like ?

I've tried a lot of options and I passed all the possible questions on Stack but I could not get it done..

Thanks in advance!

Update:

This is what i get when do findAll

This is what i get when i do findAll method on PostContent repository.

uncklegwebdev
  • 62
  • 2
  • 9
  • just to avoid confusion the field post_id in post_content table is foreing key for post table and has nothing to do with this relation, post_id in post_to_category is related with id from post_content table. – uncklegwebdev Oct 23 '16 at 12:48
  • Please watch the second part of this video: https://www.youtube.com/watch?v=Co8sbwZqztI The spoken language is dutch but if you keep the sound off you can just read what happens. – Frank B Oct 23 '16 at 21:48
  • +1 For video! Thanks this is what I was looking for, and on first I didnt understand your answer bellow. – uncklegwebdev Oct 23 '16 at 22:28
  • That is great news! wish you good luck, Chears – Frank B Oct 24 '16 at 06:46

3 Answers3

0

You can create repository class for your entity, for example:

CMS/GBundle/Repository/PostContentRepository.php

<?php

namespace CMS\GBundle\Repository;

use Doctrine\ORM\EntityRepository;

class PostContentRepository extends EntityRepository
{
    public function getPostsWithCategories()
    {
        $qb = $this->createQueryBuilder('post_content')
            ->select(['post_content', 'post_categories'])
            ->join('post_content.categories', 'post_categories')
        ;

        return $qb->getQuery()->getResult();
    }
}

CMS/GBundle/Entity/PostContent.php

<?php

namespace CMS\GBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="CMS\GBundle\Repository\PostContentRepository")
 */
class PostContent
{
    /* Your entity properties and methods */
}

And then you can use it in anywhere. For example, in the controller:

<?php

namespace CMS\GBundle\Controller;

use ;

class SomeController extends Controller
{
    public function someAction()
    {
        $posts = $this->getDoctrine()
            ->getManager()
            ->getRepository('CMSGBundle:PostContent')
            ->getPostsWithCategories()
        ;

        /* Your logic */
    }
}
Elnur U.
  • 11
  • 3
0

The preferred way to make a relationship is to create your entities like you did, then run a console command to extend your entity with some getters and setters:

$ bin/console doctrine:generate:entities AppBundle

and then let doctrine create your tables:

$ bin/console doctrine:schema:update --force

Now that is everything ready you have to fill some data in your database tables.

$category = new Category();
$categroy->setName('PHP Programming');
$em->persist($category);

$post = new Post();
$post->setTitle('My first Blogpost');
$post->addCategory($category);
$em->persist($post);

$em->flush();

After that can get it out. I just give you an example

public function indexAction($id)
{
    $em = $this->getDoctrine()->getManager();
    $category= $em->getRepository('AppBundle:PostCategory')->find($id);

    // test
    foreach($category->getPosts() as $post)
    {
        echo $post->getTitle() . '<br>';
    }
}

To load all the posts immediately instead of lazy loading i suggest to write your own query in the CategoryRepository class and change the find() method-name for your own method-name.

Frank B
  • 3,667
  • 1
  • 16
  • 22
  • I did everything you say, and when i go findAll on PostContenr repository i get joined categories with type PersistentCollection with arrayCollection that is empty.. – uncklegwebdev Oct 23 '16 at 13:06
  • To load all the posts immediately instead of lazy loading i suggest to write your own query in the CategoryRepository class and change the find() method-name for your own method-name. – Frank B Oct 23 '16 at 13:18
  • Every query failed, and i dont need to fetch categories i i need joined data structured like post:post-categories. – uncklegwebdev Oct 23 '16 at 13:23
  • Also i tried fetch="EAGER" but the result is same as on image. – uncklegwebdev Oct 23 '16 at 13:25
  • What do you want to show on the webpage from the data that you try to retrieve? – Frank B Oct 23 '16 at 13:31
  • I want to put post informations in table, here is image of table: https://s10.postimg.org/402etzssp/test.png – uncklegwebdev Oct 23 '16 at 13:34
  • When i start with edit and create it will be much easier because I will have post id and I can access to post categories more flexible than fetching data without params. – uncklegwebdev Oct 23 '16 at 13:36
  • i updated my answer with an example how to add data to the tables. Just try to find out what happens – Frank B Oct 23 '16 at 13:44
  • Like I said, the problem is not in adding or creating, i dont know how to fetch all data that is joined.. I know how can I create related content. – uncklegwebdev Oct 23 '16 at 14:02
  • If you mean that you want to retrieve the information from the join-table only than your way of thinking is not the way how doctrine works. You simply don't need to think about the join table. You work or with Post entities OR with Category entities. If with Post entities you retrieve the joined data with the getCategory() method and visa versa – Frank B Oct 23 '16 at 14:09
  • See my solution above. And if you have any specific advice for better code I would be greatefull! Thanks! – uncklegwebdev Oct 23 '16 at 21:22
0

As Frankbeen advised me i created my custom query:

public function getPostCategories() {

    $data = $this->createQueryBuilder('c')
        ->select('c.id, pc.name')
        ->innerJoin('CMSGBundle:PostToCategory', 'ptc', 'WITH', 'ptc.postId = c.id')
        ->innerJoin('CMSGBundle:PostCategory', 'pc', 'WITH', 'ptc.categoryId = pc.id')
        ->getQuery()
        ->getArrayResult();

    return $data;

}

In Method above I'm fetching just post.id that is related to post_to_category_post_id category name

In controller I generate two queries one to fetch all Posts second to fetch data using getPostCategories method.

Controller:

$em = $this->getDoctrine()->getManager();

    $posts = $em->getRepository('CMSGBundle:PostContent')->findAll();
    $postCategories = $em->getRepository('CMSGBundle:PostContent')->getPostCategories();

View:

{% for post in posts %}
   {% for category in categories %}
      {% if category.id == post.id %}

         {{ category.name }}       

      {% endif %}
   {% endfor %}
{% endfor %}

I know that this is not the best solution and please if anyone can suggest me with minifing same code or how to write it better I will be grateful!

uncklegwebdev
  • 62
  • 2
  • 9