【问题标题】:ManyToOne in a twig template树枝模板中的多对一
【发布时间】:2015-09-12 15:27:48
【问题描述】:

我有以下表格(以及 / 中的实体):

+------------------+                  +--------------------+
|  forum_sections  |                  |  forum_categories  |
+------------------+                  +--------------------+
| id               ├--------|         | id                 |
| title            |        |---------| section            |
| position         |                  | position           |
| created_at       |                  | title              |
+------------------+                  | description        |
                                      +--------------------+

我想归档以下 html 页面(不带项目符号):

  • 这是一个标题(来自 forum_sections->title)
    • 论坛 1(来自 forum_categories->title)
    • 论坛 2(来自 forum_categories->title)
  • 这是另一个标题(来自 forum_sections->title)
    • 论坛 3(来自 forum_categories->title)

我对如何做到这一点进行了一些研究。到目前为止,我在树枝布局中尝试了以下内容:

{% for section in sections %}
    <h1>title</h1>

    {% for category in categories %}
        bla bla
    {% endfor %}
{% endfor %}

这甚至可以通过 Doctrine2 中的“findAll”查询实现吗?我尝试了一些组合,但它们似乎让所有板都忽略了这些部分。

【问题讨论】:

标签: symfony2 doctrine2 php symfony doctrine-orm entities


【解决方案1】:

我认为问题在于您的实体,即您定义实体之间关系的方式。你需要使用双向映射http://doctrine-orm.readthedocs.org/en/latest/reference/association-mapping.html#one-to-many-bidirectional

我更新了您的实体以满足您的需求。

  • ForumSection 实体添加了类别
  • ForumSection实体添加了addCategory()、removeCategory()、getCategories()方法
  • ForumCategory实体添加inversedBy注解以完成关系
  • 我使用 getCategories() 方法来获取 twig 中该部分的所有类别。

实体;

论坛部分.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;
    }
}

论坛分类.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;
    }
}

控制器;

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));
 }

模板;

<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>

现在您可以访问与数据库中每个 forum_section 行相关的类别。

这是我运行代码后的输出

  1. 你好

    • 你好第 1 节
    • 你好第 2 节

  2. 世界

    • 世界部分 1
    • 世界第二部分

不得不提一下,Doctrine 默认使用延迟加载。Doctrine 会执行额外的查询来查找与论坛相关的类别。如果您有n 论坛,您将有n + 1 查询。就我而言,我使用了 2 个论坛部分,这里是查询。

这个找到所有的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

然后对于每个论坛,doctual 执行另一个查询以查找具有不同参数的类别。 在您调用 'forum.getCategories()` 方法之前,不会执行此查询。

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] 查看 fetch-join 概念以了解有关延迟加载和替代方案的更多信息。 http://blog.bemycto.com/good-practices/2015-05-31/understanding-doctrine-orm-lazy-load-fetch-join/

【讨论】:

  • 您的帖子非常清楚地说明了我做错的原因和位置,并且博客文章首先确认了我做错了什么。非常感谢您的建议,我会牢记这一点,以供将来的实体使用。
【解决方案2】:

Twig 不会更改循环内的上下文(与其他一些模板语言不同)。作用域与原生 PHP 基本相同。

如果您有一个 Section 实体(或关联数组)并且有许多 Category 实体/数组,那么您将在将 array('sections' =&gt; $sections) 传递给 Twig 渲染函数后执行此操作。

{% for section in sections %}
    <h1>{{ section.title }}</h1>

    <ul>
    {% for category in section.categories %}
        <li>{{ category.title }}</li>
    {% endfor %}
    </ul>
{% endfor %}

【讨论】:

  • 我已经尝试过您的解决方案,但这不是我的例外。我想这在 twig 中根本不可能,我必须更深入地进行查询。在此处查看屏幕截图:i.imgur.com/awWb1zQ.png
  • 您的查询可能有问题?您只是在查询水合部分实体的列表吗?
  • 是的,只需执行以下查询:$categories = $this-&gt;getDoctrine() -&gt;getRepository('AppBundle:ForumCategory') -&gt;findAll() 但我认为这对于 ManyToOne 来说还不够吗?
  • 您根本不需要明确地补充类别。只需将其提供给 Twig 模板 array('sections' =&gt; $this-&gt;getDoctrine() -&gt;getRepository('AppBundle:ForumSection') -&gt;findAll()) 即可。
猜你喜欢
  • 2012-07-27
  • 2013-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-22
  • 2018-08-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多