我可以在 CakePHP 3 线程查询中对不同于父项的子项进行排序吗?

Can I sort children different than parent in CakePHP 3 threaded query?

我有一个关于线程评论的问题。是否可以从此查询(或 table 级别)订购评论 DESC 和子评论 ASC,或者我应该在查询修改后进行排序?

您可以在下面找到我的查询,该查询将全部订购到 DESC。

```

$comments = $this->Comments
            ->find('threaded', ['order' => ['Comments.created' => 'DESC']])
            ->contain(['Users'])
            ->matching(
                'BoardItems',
                function ($q) use ($boardItemId) {
                    return $q->where(
                        [
                            'BoardItems.id' => $boardItemId
                        ]
                    );
                }
            )
            ->all();

```

在SQL级别

您应该能够应用 MySql: ORDER BY parent and child 中建议的解决方案,其中

  1. 首先使用 COALESCE 到 group/sort parent
  2. 通过测试非NULL parent ID
  3. 对children进行分组
  4. 对分组的 children
  5. 进行排序

在你的情况下,你会按 created 而不是 id 排序,例如

ORDER BY 
    COALESCE(Comments.parent_id, Comments.created) DESC, 
    Comments.parent_id IS NOT NULL, 
    Comments.created ASC

要以正确的查询 builder-ish 方式构建它,您必须使用 order()orderDesc() 方法,以便您可以使用查询表达式,行

$query = $this->Comments
    ->find('threaded');

$comments = $query
    // ->contain(...)
    // ->matching(...)

    // COALESCE(Comments.parent_id, Comments.created) DESC
    ->orderDesc($query->func()->coalesce([
        'Comments.parent_id' => 'identifier',
        'Comments.created' => 'identifier'
    ]))

    // Comments.parent_id IS NOT NULL
    ->order($query->newExpr()->isNotNull('Comments.parent_id'))

    // Comments.created ASC
    ->order(['Comments.created' => 'ASC'])

    ->all();

另见

在PHP水平

事后排序也是一种选择,例如使用递归结果格式化程序:

$sortChildren = function($row) use (&$sortChildren) {
    if (!empty($row['children'])) {
        $row['children'] =
            collection($row['children'])
                ->sortBy('created', SORT_ASC)
                ->map($sortChildren)
                ->toArray();
    }
    return $row;
};

$comments = $this->Comments
    ->find('threaded')
    // ->contain(...)
    // ->matching(...)
    ->order(['Comments.created' => 'DESC'])
    ->formatResults(function ($results) use ($sortChildren) {
        return $results->map($sortChildren);
    })
    ->all();

这将检索所有降序排序的内容,然后按 created 字段对所有 children 数组进行升序排序。类似地,您可以在视图中 output/use 之前对它们进行排序,具体取决于您打算如何处理结果。

如果您想将内容保留在 table 中,例如,您可以将其全部包装在自定义查找器中 and/or 通过 table 上的方法检索排序闭包class.

另见