I have the following tables (and entities in symfony2 / doctrine2):
+------------------+ +--------------------+
| forum_sections | | forum_categories |
+------------------+ +--------------------+
| id ├--------| | id |
| title | |---------| section |
| position | | position |
| created_at | | title |
+------------------+ | description |
+--------------------+
I want to archive the following html page (without the bullets ofcource):
I did some research on how to do this. So far I tried the following in my twig layout:
{% for section in sections %}
<h1>title</h1>
{% for category in categories %}
bla bla
{% endfor %}
{% endfor %}
Is this even possible with a 'findAll' query in Doctrine2? I tried some combinations, but they seem to get all the boards ignoring the sections.
I think the problem is in your entities, the way you define the relationship between entitites. You need to use bidirectional mapping http://doctrine-orm.readthedocs.org/en/latest/reference/association-mapping.html#one-to-many-bidirectional
I updated your entities to fit your needs.
ForumSection
entityForumSection
entity inversedBy
annotation to ForumCategory
entity to complete te relationshipThe entities;
ForumSection.php
namespace AppBundle\Entity;
/**
* @version 0.0.1
* @copyright (c) 2015 Ricardo Jacobs. All rights reserved.
* @license Proprietary and confidential source code.
*/
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* @ORM\Entity(repositoryClass="AppBundle\Entity\Repositories\Forum")
* @ORM\HasLifecycleCallbacks
* @ORM\Table(name="forum_sections")
*/
class ForumSection
{
/**
* @ORM\Column(type="integer", name="id")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\Column(type="string", length=255, name="title")
*/
private $title;
/**
* @ORM\Column(type="integer", name="position")
*/
private $position;
/**
* @ORM\Column(type="datetime")
*/
private $created_at;
/**
* @ORM\OneToMany(targetEntity="AppBundle\Entity\ForumCategory", mappedBy="section")
*/
private $categories;
public function __construct() {
$this->categories = new ArrayCollection();
}
public function getCategories() {
return $this->categories;
}
/**
* Add category
*
* @param AppBundle\Entity\ForumCategory
* @return ForumSection
*/
public function addCategory(\AppBundle\Entity\ForumCategory $category)
{
$this->categories[] = $category;
return $this;
}
/**
* Remove category
*
* @param AppBundle\Entity\ForumCategory $category
*/
public function removeCategory(\AppBundle\Entity\ForumCategory $category)
{
$this->categories->removeElement($category);
}
/**
* @ORM\PrePersist
* @ORM\PreUpdate
*/
public function updatedTimestamps() {
if ($this->getCreatedAt() == null) {
$this->setCreatedAt(new \DateTime('NOW'));
}
}
/**
* @return mixed
*/
public function getId() {
return $this->id;
}
/**
* @return mixed
*/
public function getTitle() {
return $this->title;
}
/**
* @param $title
* @return $this
*/
public function setTitle($title) {
$this->title = $title;
return $this;
}
/**
* @return mixed
*/
public function getPosition() {
return $this->position;
}
/**
* @param $position
* @return $this
*/
public function setPosition($position) {
$this->position = $position;
return $this;
}
/**
* @return Date
*/
public function getCreatedAt() {
return $this->created_at;
}
/**
* @param $date
*/
public function setCreatedAt($date) {
$this->created_at = $date;
return $this;
}
}
ForumCategory.php
<?php
namespace AppBundle\Entity;
/**
* @version 0.0.1
* @copyright (c) 2015 Ricardo Jacobs. All rights reserved.
* @license Proprietary and confidential source code.
*/
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="AppBundle\Entity\Repositories\Forum")
* @ORM\Table(name="forum_categories")
*/
class ForumCategory
{
/**
* @ORM\Column(type="integer", name="id")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\ForumSection", inversedBy="categories")
* @ORM\JoinColumn(name="section", referencedColumnName="id")
*/
private $section;
/**
* @ORM\Column(type="integer", name="position")
*/
private $position;
/**
* @ORM\Column(type="string", length=255, name="title")
*/
private $title;
/**
* @ORM\Column(type="string", length=255, nullable=true, name="description")
*/
private $description;
/**
* @return mixed
*/
public function getId() {
return $this->id;
}
/**
* @return mixed
*/
public function getSection() {
return $this->section;
}
/**
* @param $section
* @return $this
*/
public function setSection($section) {
$this->section = $section;
return $this;
}
/**
* @return mixed
*/
public function getPosition() {
return $this->position;
}
/**
* @param $position
* @return $this
*/
public function setPosition($position) {
$this->position = $position;
return $this;
}
/**
* @return mixed
*/
public function getTitle() {
return $this->title;
}
/**
* @param $title
* @return $this
*/
public function setTitle($title) {
$this->title = $title;
return $this;
}
/**
* @return mixed
*/
public function getDescription() {
return $this->description;
}
/**
* @param $description
* @return $this
*/
public function setDescription($description) {
$this->description = $description;
return $this;
}
}
The controller;
public function indexAction()
{
$em = $this->get('doctrine')->getManager();
$sections = $sections = $this->getDoctrine() ->getRepository('AppBundle:ForumSection') ->findAll();
return $this->render('AppBundle:Default:index.html.twig', array('sections'=>$sections));
}
The template;
<ol>
{% for forum in sections %}
<li>
<h2>{{forum.title}} </h2>
<ul>
{% for category in forum.getCategories() %}
<li>{{category.title}}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ol>
Now you have access to categories related to each forum_section row in your database.
And this is the output after I run the code
I have to mention that Doctrine uses lazy loading by default.Doctrine will perform extra queries to find categories related to forums. If you have n
forums you will have n + 1
queries. In my case I used 2 forum sections and here are the queries.
This one finds all the forum_sections;
SELECT
t0.id AS id1,
t0.title AS title2,
t0.position AS position3,
t0.created_at AS created_at4
FROM
forum_sections t0
Then for each forum, doctrine executes another query to find categories with different parameters. This queries don't get executed untill you call 'forum.getCategories()` method.
SELECT
t0.id AS id1,
t0.position AS position2,
t0.title AS title3,
t0.description AS description4,
t0.section AS section5
FROM
forum_categories t0
WHERE
t0.section = ? [Parameters: 1,2]
Check out fetch-join concept to learn more about lazy loading and alternatives.
http://blog.bemycto.com/good-practices/2015-05-31/understanding-doctrine-orm-lazy-load-fetch-join/