在cakephp 3

时间:2016-07-01 01:25:02

标签: php sorting cakephp associations cakephp-3.x

问题:

我有一个cakephp 3.x查询对象,其中有两个嵌套关联Organizations.Positions.Skills,它们被设置为一个视图变量$Organizations。我正在尝试通过第一个嵌套关联中的列对查询生成的顶级数组进行排序。也就是说,我想按$Organizations中的一列Positions排序Positions.Ended,特别是 public function index() { $this->loadModel('Organizations'); $this->set('Organizations', $this->Organizations->find('all') ->contain([ //eager loading 'Positions.Skills' ]) ); }

find()->order(['field']);

模型信息

组织有很多职位

职位有很多技能

我完成的研究

订单选项

根据cookbook find()有一个订单选项:find('all', ['order'=>'field DESC']);//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']) ); 但是,这仅适用于调用表find()中的字段。在这种情况下,组织。例如,这是它通常使用的方式。

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

但是,尝试将其用于嵌套关联不起作用:     $这 - >设置( '组织',       这 - >组织 - >找到(...)          - >包含(...)          - > order(['Organizations.Positions.ended DESC'])     );

//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'

并改变它以引用'嵌套的字段也不起作用:

$this->set('Organizations',
    $this->Organizations->find('all')
    ->contain([ //eager loading
        'Positions.Skills',
        'Positions' => [
            'sort' => ['Positions.ended'=>'DESC']
        ]
    ])
);

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

排序选项

同样,根据cookbook,渴望加载/关联具有'sort'选项: $这 - > loadModel( '组织');

Organizations => [
  0 => [
    'organization => 'Plus Marketing Group',
    positions => [
      0 => [
        'position' => 'Energy Sales',
        'ended => '2016'
      ]
    ]
  ],
  1 => [
    'organization => 'Florida Tech',
    positions => [
      0 => [
        'position' => 'Research Assistant',
        'ended => '2014'
      ],
      1 => [
        'position' => 'Lab Technician',
        'ended => '2012'
      ]
    ]
  ],
  2 => [
    'organization' => 'Fit In Today',
    positions => [
      0 => [
        'position' => 'Full Stack Web Developer',
        'ended => '2015'
      ],
      1 => [
        'position' => 'market Data Analyst',
        'ended => '2013'
      ]
    ]
  ]
]

但是,这只对嵌套关联进行排序。具体来说,它会对嵌套的关联进行排序。它不会通过嵌套关联(ergo,多维排序)对整个结果集进行排序。

例如:

本组织佛罗里达理工学院(org id 1)有两个职位:

  1. 实验室技术员。截至2012年
  2. 研究助理。截至2014年
  3. 组织,Fit In Today(org id 2)有两个职位:

    1. 2013年结束的市场数据分析师
    2. Full Stack Web Developer Ended 2015
    3. 以上代码和数据导致在评估查询时生成以下数组:

      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 
      

      其他研究

      同样,我的研究中出现了以下stackoverflow问题:

      sort()

      此外,我知道PHP有自己的排序功能,如multisort()Organizations => [ 0 => [ 'organization => 'Plus Marketing Group', positions => [ 0 => [ 'position' => 'Energy Sales', 'ended => '2016' ] ] ], 0 => [ 'organization' => 'Fit In Today', 'positions' => [ 0 => [ 'position' => 'Full Stack Web Developer', 'ended => '2015' ], 1 => [ 'position' => 'market Data Analyst', 'ended => '2013' ] ] ], 1 => [ 'organization => 'Florida Tech', 'positions' => [ 0 => [ 'position' => 'Research Assistant', 'ended => '2014' ], 1 => [ 'position' => 'Lab Technician', 'ended => '2012' ] ] ] ] ;但是,只有在评估了查询后才能调用它们(通过foreach)。或者,然后使用multisort调用$ organization-> toArray();但是,这必须在视图中完成,会破坏关注点分离的MVC约定(数据和查询由控制器和模型操纵,而不是视图!),因为它将被调用,效率会非常低页面正在加载。

      那么,我如何通过嵌套关联对cakephp查询进行排序?

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

      function updateProgress() {
            var i = 0;
            var checkAmt = 0;
            var checkedAmt = 0;
            while (i <= document.getElementsByClassName("gun-check").length) {
            if (document.getElementsByClassName("gun-check")[i].checked == "true") {
                   checkAmt = checkAmt + 1;
              } 
              i = i + 1;
            }
          document.getElementById("progress-fill").style.width = (100 / 31) * checkAmt + "%";
          if ((100 / 31) * checkAmt > 5) {
              document.getElementById("progress-text").innerHTML = (100 / 31) * checkAmt + "%"; 
          }
      }
      

      背景&amp;背景

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

      1. 循环浏览顶级视图变量(组织)
        1. 呈现组织详细信息
        2. 循环通过该组织的职位(仍在1内)
        3. 呈现位置详情
        4. 循环通过该职位的相关技能
          1. 使用适当的链接渲染每种技能,以便按该技能进行过滤。

2 个答案:

答案 0 :(得分:3)

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

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

SQL级别

在SQL级别,您可以加入Positions,并按计算的max(Positions.ended)列排序,例如:

$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');

这就是全部,这应该会给你想要的结果。查询将类似于:

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级别上,使用集合也很容易解决(请注意,查询是集合的类型),但是只有在您打算检索所有行时才会有意义,或者必须无论出于何种原因处理一组无序行......如:

$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;
});

这也可以在结果格式化程序中实现,因此如果你坚持,就会在控制器或模型级别上发生。

$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;
    });
});

答案 1 :(得分:0)

这对我有用:

$this->Organizations->find('all')
->contain(['Positions' => ['sort' => ['Positions.ended' => 'DESC']]])
->contain('Postions.Skills');