【问题标题】:CakePHP Paginate Sort on Contain DataCakePHP对包含数据的分页排序
【发布时间】:2018-10-21 07:08:34
【问题描述】:

这是一个用于跟踪用户爱好的简单应用程序。一个用户可以有很多爱好,这些爱好被组织成不同的爱好组。

所以我有 4 个相关表:usersusers_hobbieshobbieshobby_groups

users 是通过 users_hobbies 连接表与爱好建立多属性关联的关系。 爱好属于-属于一个爱好组,爱好组有-很多爱好

有道理,到目前为止非常简单。

在 UsersHobbiesController 中,我有:

$paginate = [
    'contain' => [
        'Hobby' => [
            'fields' => ['id', 'name'],
            'HobbyGroup' => [
                'fields' => ['id', 'name']
            ]
        ]
    ]
];

另外,在我的 index() 函数中,我构建了分页。

$usersHobbies = $this->paginate('UsersHobby');
$this->set(compact('usersHobbies));

当我访问我的 index.ctp 视图文件中的 $usersHobbies 变量时,它具有我构建输出表所需的数据。它看起来像:

array(
    (int) 0 => array(
        'UsersHobby' => array(...),
        'Hobby' => array(
            'id' => 'abc-def-ghi',
            'name' => 'Jet Skiing',
            'HobbyGroup' => array(
                'id' => 'oiuy-trew-qldf',
                'name' => 'Watersports'
            )
        )
    )
    ....
)

为了对输出表进行排序,我添加了一些排序列:

<th><?php echo $this->Paginator->sort('Hobby.name', 'Hobby'); ?></th>
<th><?php echo $this->Paginator->sort('Hobby.HobbyGroup.id', 'Hobby'); ?></th>

第一个标题用于对爱好名称进行排序。但我无法获得第二个标题来为 HobbyGroup 排序。有没有简单的方法来做到这一点?

我在 StackOverflow 上搜索了几个小时,但似乎找不到适合我的答案。谢谢。

【问题讨论】:

    标签: php mysql cakephp pagination paginator


    【解决方案1】:

    由于 CakePHP 获取数据的方式,这不会像您期望的那样工作。

    根据您设置关系的方式,Cake 将首先选择爱好,然后然后再次查询爱好组。

    因此,当该数据映射到爱好列表时,您应用于第二个查询的任何排序通常都是无用的并且会丢失。

    所以你有

    SELECT hobbies....

    然后将发出另一个选择

    SELECT hooby_groups WHERE hobby_id IN [list of ids ] ORDER BY hobby_groups_id

    第二个选择的数据将映射到第一个,所以你的 order by 没有做太多!

    根据您使用的 CakePHP 版本,您可以做几件事:

    1. 定义关系以使用INNER JOIN 策略,以避免创建两个SELECT 语句。这样order by 原因将按照您的预期对所有数据进行排序。需要注意的是,INNER JOIN 没有任何关联组的爱好将永远不会被您的分页选择。

    2. 如果您使用的是 CakePHP 2.x,您可以查看 Custom Query Pagination 并根据需要构建查询以使其正常工作。

    3. 如果您使用的是 CakePHP 3.x,那么您有一个查询构建器,并且 Paginator 可以对任何查询进行分页,因此您可以在那里进行内部联接。

    为了帮助您,您可以使用 CakePHP 的 DebugKit 查看正在运行的实际查询以及调整这个和那个参数如何影响查询的生成方式。您将看到order by 的应用位置以及它可能不起作用的原因。

    在 CakePHP 2.x 中,您可以使用 type 来控制连接的完成方式。你需要使用INNER

    【讨论】:

    • 感谢您的回答,它帮助我指明了正确的方向。我实际上调整了我的 $paginate 变量以使用左连接而不是包含(我将 UserHobbies 左连接到用户、爱好和 HobbyGroups),这允许 HobbyGroup 直接在返回结果中进行排序。我还必须在对 paginate() 函数的调用中添加一个包含所有用于排序的列的数组作为白名单参数,以便仅对 HobbyGroup.id 进行排序,这一切都开始工作了。
    猜你喜欢
    • 1970-01-01
    • 2013-10-21
    • 1970-01-01
    • 2014-09-24
    • 2016-12-15
    • 2012-05-10
    • 1970-01-01
    • 2016-06-12
    • 2012-02-13
    相关资源
    最近更新 更多