首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >通过cakephp 3中的嵌套关联对查询结果进行排序

通过cakephp 3中的嵌套关联对查询结果进行排序
EN

Stack Overflow用户
提问于 2016-07-01 01:25:02
回答 2查看 4.6K关注 0票数 4

问题是:

我有一个cakephp 3.x查询对象,它有两个嵌套关联,Organizations.Positions.Skills,它被设置为视图变量$Organizations。我试图通过第一个嵌套关联中的列对查询的结果顶层数组进行排序。也就是说,我想按照$Organizations中的一个列(特别是Positions.Ended)对Positions进行排序。

代码语言:javascript
运行
复制
public function index()
{
    $this->loadModel('Organizations');
    $this->set('Organizations',
            $this->Organizations->find('all')
            ->contain([ //eager loading
            'Positions.Skills'
             ])
    );
}

模型信息

组织有许多职位

职位有很多技能

我做过的研究

订购选项

但是,根据烹饪书 find()有一个order选项:find()->order(['field']);find('all', ['order'=>'field DESC']);,这只适用于正在调用的表find()中的字段。在这种情况下,组织。例如,它通常是这样使用的。

代码语言:javascript
运行
复制
//This works.
//Sorts Organizations by the name of the organization in DESC.
$this->loadModel('Organizations');
$this->set('Organizations',
        $this->Organizations->find('all')
        ->contain([ //eager loading
            'Positions.Skills'
         ])
        ->order(['organization DESC'])
);

但是,尝试将其用于嵌套关联是行不通的:

代码语言:javascript
运行
复制
$this->set('Organizations',
  this->Organizations->find(...)
    ->contain(...)
    ->order(['Organizations.Positions.ended DESC'])
);

Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Organizations.Positions.ended' in 'order clause'

修改它以引用将被嵌套的字段也不起作用:

代码语言:javascript
运行
复制
//also doesn't work.
$this->set('Organizations',
  $this->Organizations->find(...)
    ->contain(...)
    ->order([Positions.ended DESC])
);

Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Positions.ended' in 'order clause'

在这两种情况下,当cakephp执行查询生成的PDO语句时都会创建sql错误。

排序选项

类似地,根据烹饪书,急切的加载/关联有“排序”选项:$this->loadModel('Organizations');

代码语言:javascript
运行
复制
$this->set('Organizations',
    $this->Organizations->find('all')
    ->contain([ //eager loading
        'Positions.Skills',
        'Positions' => [
            'sort' => ['Positions.ended'=>'DESC']
        ]
    ])
);

但是,这只对嵌套的association.Specifically进行排序,对嵌套的关联进行排序。它不对嵌套关联(ergo,一种多维排序)的全部结果集进行排序。

例如:

本组织,组织C (org id 1),有两个职位:

  1. 职位5. 2012年终了
  2. 职位4. 2014年终了

本组织,组织B(组织编号2),有两个职位:

  1. 2013年终了的职位3
  2. 2015年终了的职位2

上面的代码和数据导致在计算查询时生成以下数组:

代码语言:javascript
运行
复制
Organizations => [
  0 => [
    'organization' => 'Organization A',
    positions => [
      0 => [
        'position' => 'Position 1',
        'ended' => '2016'
      ]
    ]
  ],
  1 => [
    'organization' => 'Organization C',
    'positions' => [
      0 => [
        'position' => 'Position 4',
        'ended' => '2014'
      ],
      1 => [
        'position' => 'Position 5',
        'ended' => '2012'
      ]
    ]
  ],
  2 => [
    'organization' => 'Organization B',
    'positions' => [
      0 => [
        'position' => 'Position 2',
        'ended' => '2015'
      ],
      1 => [
        'position' => 'Position 3',
        'ended' => '2013'
      ]
    ]
  ]
]

其他研究

同样,在我的研究中也出现了以下堆叠溢出问题:

代码语言:javascript
运行
复制
http://stackoverflow.com/questions/26859700/cakephp-order-not-working

http://stackoverflow.com/questions/17670986/order-by-doesnt-work-with-custom-model-find-while-paginating

http://stackoverflow.com/questions/18958410/cakephp-paginate-and-sort-2nd-level-association

http://stackoverflow.com/questions/34705257/cakephp-paginate-and-sort-hasmany-association 

此外,我知道PHP有自己的排序函数,如sort()multisort();但是,只有在对查询进行了评估之后才能调用这些函数(通过foreach)。或者,调用$organization->toArray(),然后使用multisort;但是,这必须在视图中完成,这将打破MVC的关注点分离约定(数据和查询由控制器和模型操作,而不是视图!),而且效率很低,因为它将在页面加载时被调用。

那么,如何按照cakephp的嵌套关联对其进行排序呢?

或者,更简单地说,如何对查询进行排序/排序,以便在计算时生成以下数组:

代码语言:javascript
运行
复制
Organizations => [
  0 => [
    'organization' => 'Organization A',
    'positions' => [
      0 => [
        'position' => 'Position 1',
        'ended' => '2016'
      ]
    ]
  ],
  0 => [
    'organization' => 'Organization B',
    'positions' => [
      0 => [
        'position' => 'Position 2',
        'ended' => '2015'
      ],
      1 => [
        'position' => 'Position 3',
        'ended' => '2013'
      ]
    ]
  ],
  1 => [
    'organization => 'Organization C',
    'positions' => [
      0 => [
        'position' => 'Position 4',
        'ended' => '2014'
       ],
      1 => [
        'position' => 'Position 5',
        'ended' => '2012'
      ]
    ]
  ]
]

背景和背景:

我正在用cakephp 3.2为自己构建一个投资组合网站,以展示我的web开发技能,并帮助我寻求开发职业生涯。对于我的简历页面,我用嵌套手风琴组织了大量的数据,以模仿招聘人员希望在实际简历上看到的简历风格。因此,我的看法如下:

  1. 循环遍历顶层视图变量(组织)
    1. 提供组织详细信息
    2. 循环遍历该组织的位置(仍在1)
      1. 提供职位详细信息
      2. 循环通过职位的相关技能
        1. 使每个技能w/通过该技能筛选的适当链接。

列表项目

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-07-01 02:37:54

只有hasOnebelongsTo关联是通过主查询上的联接检索的。hasMany关联是在单独的查询中检索的,因此当您试图引用Positions字段时会出现错误。

在SQL级别和PHP级别上,您想要的应该是相当容易解决的。

SQL级

在SQL级别上,您可以加入Positions,并按计算的max(Positions.ended)列进行排序,如下所示:

代码语言:javascript
运行
复制
$this->Organizations
    ->find('all')
    ->select(['max_ended' => $this->Organizations->query()->func()->max('Positions.ended')])
    ->select($this->Organizations)
    ->contain([
        'Positions.Skills',
        'Positions' => [
            'sort' => ['Positions.ended' => 'DESC']
        ]
    ])
    ->leftJoinWith('Positions')
    ->order([
        'max_ended' => 'DESC'
    ])
    ->group('Organizations.id');

仅此而已,这应该会给你你想要的结果。查询将类似于:

代码语言:javascript
运行
复制
SELECT
    MAX(Positions.ended) AS max_ended,
    ... 
FROM
    organizations Organizations     
LEFT JOIN
    positions Positions 
        ON Organizations.id = (
            Positions.organization_id
        )   
GROUP BY
    Organizations.id   
ORDER BY
    max_ended DESC

PHP级

在PHP级别上,使用集合也很容易解决(注意,查询是集合--某种类型),但是只有当您打算检索所有行,或者必须处理一组无序行时,才会有意义。类似于:

代码语言:javascript
运行
复制
$Organizations->map(function ($organization) {
    $organization['positions'] =
        collection($organization['positions'])->sortBy('ended')->toList();
    return $organization;
});
$sorted = $sorted->sortBy(function ($organization) {
    return
        isset($organization['positions'][0]['ended']) ?
            $organization['positions'][0]['ended'] : 0;
});

这也可以在结果格式化程序中实现,因此,如果您坚持的话,在控制器或模型级别上会发生一些事情。

代码语言:javascript
运行
复制
$query->formatResults(function ($results) {
    /* @var $results \Cake\Datasource\ResultSetInterface|\Cake\Collection\CollectionInterface */
    $results = $results->map(function ($row) {
        $row['positions'] =
            collection($row['positions'])->sortBy('ended')->toList();
        return $row;
    });
    return $results->sortBy(function ($row) {
        return isset($row['positions'][0]['ended']) ?
            $row['positions'][0]['ended'] : 0;
    });
});

看见

票数 5
EN

Stack Overflow用户

发布于 2017-11-01 11:20:22

这对我起了作用:

代码语言:javascript
运行
复制
$this->Organizations->find('all')
->contain(['Positions' => ['sort' => ['Positions.ended' => 'DESC']]])
->contain('Postions.Skills');
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38135670

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档