繁体   English   中英

Symfony 4:在同一树枝模板中渲染OneToMany关系实体的DRY和高性能方法

[英]Symfony 4 : DRY and performant way to render OneToMany relation entities in same twig template

我需要在同一树枝模板中渲染两个关系实体SalarieContrat的某些属性,基本上是从所有Salarie记录中渲染出来的,仅是从 附加到每个Salarie的 特定 Contrat中 渲染出来的

薪金实体

namespace App\Entity;

class Salarie
{
// ...

/**
     * @ORM\OneToMany(targetEntity="App\Entity\Contrat", mappedBy="salarie")
     * @ORM\OrderBy({"dateDebut" = "DESC"})
     */
    private $contrats;
//...

冲突实体

namespace App\Entity;

class Contrat
{
// ...
/**
     * @ORM\ManyToOne(targetEntity="App\Entity\Salarie", inversedBy="contrats")
     * @ORM\JoinColumn(nullable=false)
     */
    private $salarie;
// ...

工资控制器

class SalarieController extends AbstractController
{
    /**
     * @Route("/", name="salarie_index", methods={"GET"})
     */
    public function index(SalarieRepository $salarieRepository): Response
    {
        return $this->render('salarie/index.html.twig', [
            'salaries' => $salarieRepository->findAll(), //findAllWithLastContrat(),
        ]);
    }

乍一看,我认为在Salarie存储库中使用自定义查询会很简单,但是我一直在与联接,子查询和其他东西作斗争。 这是一个纯Twig的工作解决方案,但它根本不是DRY ,因为我必须为每个属性重复它,并且我敢打赌它也会对性能产生影响,因为当我只需要一些Contrat时,我会查询所有...

<tbody class="list">
    {% for salarie in salaries %}
        <tr>
            <td>{% for contrat in salarie.contrats  %}
                  {% if loop.first %}
                    {{ contrat.departement }}
                  {% endif %}
                {% endfor %}
            </td>
            <td>{% for contrat in salarie.contrats  %}
                  {% if loop.first %}
                    {{ contrat.service }}
                  {% endif %}
                {% endfor %} 
            </td>
        </tr>
        <!-- AND SO ON ABOUT 12 TIMES ! -->
    {% endfor %}

用@msg建议编辑

标准系统:冠军收集过滤中所述,我还尝试了从教义( 标准 )获得的出色功能

public function getLastContrat()
{
    $criteria = Criteria::create()
      ->orderBy(['dateDebut' => 'DESC']);
      ->setMaxResults(1);

    return $this->contrats->matching($criteria)->current();
}

然后在Twig中,我可以{{ dump(salarie.lastContrat) }}返回期望的对象。

在此处输入图片说明

但是没有办法从那里获取属性。 {{ salarie.lastContrat.someProperty }}不起作用。

salarie.lastContrat.someProperty

必须看到{{ salarie.lastContrat }}打印出Contrat __toString方法返回的事实。

我不会公开更多尝试,所以请问我的问题是: 如何从getLastContrat()上方呈现属性值,什么是实现这一目标的最干和最有效的方法?

除了循环,您还可以提取第一个元素:

{% if not empty salarie.contrats %}
    {% set contrat = salarie.contrats[0] %}
    {# you can also use salarie.contrats|first #}
    {{ contrat.departement }}
{% endif %}

即使只有一个元素, Criteria也会返回一个Collection ,因此您可以应用与上述相同的原理。

尽管您也可以在将结果传递给树枝之前将结果提取到控制器中,然后将它们作为实体而不是集合进行传递。 在上面的存储库中:

/**
 * @returns Contrat|null
 */
public function getLastContrat()
{
    $criteria = Criteria::create()
      ->orderBy(['dateDebut' => 'DESC'])
      ->setMaxResults(1);

    return $this->contrats->matching($criteria)->first();
}

您可以做的另一件事是将要呈现的相关对象的另一个变量传递到模板中(本例中的最后一项)。 因此,在控制器中,您首先要获取Salarie对象,然后获取所需的约束。 它不是最DRY的解决方案,但是如果您没有更多需要/想要重用一段代码的用例,则不能真正应用DRY。 因此,这种方法很好,因为您的实体不需要任何标准逻辑,而且性能很好,因为您只获取所需的信息。

如果您没有更多可以重用代码的用例,则不要过度优化,等待情况发生,然后您可以根据实际需求寻找共享代码的方法,不相信:)

干杯!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM