【问题标题】:How can I tie bespoke doctrine repositories to mapped entities in symfony?在 symfony 中,如何将定制的学说存储库与映射的实体联系起来?
【发布时间】:2017-09-07 12:11:57
【问题描述】:

我有两个实体。任务和部门。

一个部门可以有很多任务。

/**
 * @ORM\Entity
 * @ORM\Table(name="departments")
 */
class Department
{
    /**
     * @ORM\OneToMany(targetEntity="Task", mappedBy="department")
     */
    public $tasks;

    /**
     * @return ArrayCollection|Task[]
     */
    public function getTasks()
    {
        return $this->tasks;
    }
}

.

/**
 * @ORM\Entity
 * @ORM\Table(name="tasks")
 */
class Task
{
    /**
     * @ORM\ManyToOne(targetEntity="Department", inversedBy="tasks")
     */
    public $department;

    /**
     * @return Department
     */
    public function getDepartment()
    {
        return $this->department;
    }
}

我还有一个显示所有部门及其相关任务的视图。

{% for department in departments %}
    {% for task in department.tasks %}
        ...
    {% endfor %}
{% endfor %}

这给了我几列,每列都填满了任务。

我现在想更改此设置,以便每列仅显示按截止日期排序的最紧迫的任务(一周内到期)。

为此,我创建了带有自定义查询的TaskRepository 类:

class TaskRepository extends EntityRepository
{
    /**
     * @param Department $department
     * @return Task[]
     */
    public function findAllRecentTasksForGenus(Department $department)
    {
        return $this->createQueryBuilder('task')
            ->andWhere('task.department = :department')
            ->setParameter('department', $department)
            ->andWhere('task.dueDate> :dueDate')
            ->setParameter('dueDate', new \DateTime('-1 week'))
            ->orderBy('task.dueDate', 'DESC')
            ->getQuery()
            ->execute();
    }
}

现在,如果这是一个只有一个部门的页面,我只需在我的控制器中调用自定义查询,并将其拉入视图。

然而,我向所有部门展示所有迫在眉睫的任务这一事实使得控制器中的内容有点凌乱,因为这将迫使我建立一系列部门及其任务。

考虑到目前我只需要在 twig 中循环 department.tasks 并且它知道拉取与部门实体相关的任务,这感觉很难看。

我也知道我不应该(也不能轻易地)在我的部门实体的存储库中调用自定义查询。

所以我想知道的是 - 我是否可以以某种方式将描述的定制查询绑定到相关实体,以便学说知道当我要求一个部门的任务时,它必须去并且除了定义的子集之外没有得到所有?

理想情况下,我希望能够通过调用 tasksDueSoon 之类的东西来绕过像下面这样的树枝模板,而无需向控制器(或其他地方)添加大量额外的逻辑。

{% for department in departments %}
    {% for task in department.tasksDueSoon %}
        ...
    {% endfor %}
{% endfor %}

如果这是不可能的,我必须通过控制器沿着自定义数组的路线走,这当然很好,但感觉不对,所以希望在 Symfony 中有更好的方法来做到这一点,并告诉部门实体使用任务库什么的。

【问题讨论】:

  • 将您的查询移动到部门存储库并将其命名为 findDepartmentsWithRecentTasks。在 select 子句中,添加“任务”。因此,现在当您查询您的部门时,它们将仅包括最近的任务。无需更改树枝模板。
  • @Cerad - 这基本上就是我想要的,但我不能安静地让它工作。您介意用示例代码添加答案吗?

标签: php symfony doctrine twig symfony-3.3


【解决方案1】:

Department 类的 tasks 属性上有一个 @OrderBy-annotation,但据我所知,您无法将其设为更复杂的查询。

我通常做的是创建另一个 getter,使用 Collection Criteria 过滤掉我想要的孩子。

当然这有一些开销,因为它对从存储库获取的所有任务进行操作,但我发现在大多数情况下,对于我通常操作的规模来说,性能仍然非常好。当它变慢时,我通常会摔倒回到您不喜欢甚至更远的当前解决方案,并在必要时使用 NativeQuery 和/或部分结果。

【讨论】:

    【解决方案2】:

    我总是犹豫在没有测试实际代码的情况下发布答案,但这里是这样。诀窍是在加载部门的同时加载最近的任务。

    class DepartmentRepository
    {
        findDepartmentsAlongWithRecentTasks()
        {
            $qb = $this->createQueryBuilder('dept');
            $qb->select('dept','task');
            $qb->leftJoin('dept.tasks','task');
    
            $qb->andWhere('task.dueDate > :dueDate')
               ->setParameter('dueDate', new \DateTime('-1 week'))
               ->orderBy('task.dueDate', 'DESC');
    
            return $qb->getQuery()->execute();
    

    【讨论】:

    • 啊,然后在部门的控制器中调用它而不是 findAll!
    • 有一个陷阱。如果一个部门没有最近的任务,则不会加载它。如果这很重要,需要使用不同的连接。
    • 是的,不用担心,主要是在控制器中调用 repo 方法来加载所需的数据:-)
    【解决方案3】:

    我只想在 Department 实体中创建一个方法,getTasksOrderedByDueDate() 或其他东西。性能可能比 SQL 查询稍差,但对我来说似乎更干净。

    public function getTasksOrderedByDueDate(): array
    {
        $tasks = $this->getTasks();
        usort($tasks, function (Task $a, Task $b) {
            return $a->getDueDate()->getTimestamp() - $b->getDueDate()->getTimestamp();
        });
    
        return $tasks;
    }
    

    只需在 Twig 模板中使用它:

    {% for department in departments %}
        {% for task in department.tasksOrderedByDueDate %}
            ...
        {% endfor %}
    {% endfor %}
    

    现在除非它成为一个真正的问题,否则不要担心性能。

    【讨论】:

      猜你喜欢
      • 2016-03-20
      • 2021-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-18
      • 1970-01-01
      相关资源
      最近更新 更多