Cake php 2:排序第二级协会

时间:2013-09-26 18:16:58

标签: sorting associations cakephp-2.0

去年我写了post这个问题。第一部分,如何对一级协会进行排序,得到了回答(再次感谢!)但问题的第二部分,关于如何对二级协会进行排序,从未得到回答。这不是一个大问题,我们已经没时间了,所以我从未真正实现它。但现在我们正在更新网络,客户想要这个功能,即使用以下模型:

  • 公司所属城市
  • 城市属于国家,有很多公司
  • 国家/地区有很多城市

在公司页面中,我想对City.Country.name进行排序。即使把recursive = 2,它也行不通。蛋糕忽略了我的'订单'条件;在生成的SQL中根本就没有'order by'。

如果我按照City.name排序,它可以正常工作。

有没有办法做到这一点?我一直在搜索文档和Stackoverflow。我看过虚拟字段,自定义查询。

看起来很有希望的一种方法是在CompaniesController中使用Model-> query():

$ companies = $ this-> Company-> query(“SELECT * FROM companies com left cins c on c.cid = com.city_id left cast c2 on c2.id = c.country_id order by c2 .NAME“);

但是,这是最好/唯一的方法吗?我现在不必担心压倒性的分页吗?我不介意,但我仍然希望在公司的其他地方使用“正常”的内置分页。那可能吗?

此外,在文档中的示例中,它表示执行类似Model-> query('SELECT * FROM pictures AS Picture LIMIT 2')的操作,因此生成的数组将使用该模型将name命名为数组键。但是我如何使用复杂的查询来完成这项工作呢? “AS”会去哪里?

我当时希望我能够避免这样做。有没有更简单的方法呢?

修改

嗨,谢谢你的帮助。通过“分页技术”你的意思是蛋糕的内置分页?是的,这就是我想要的。我在控制器中的默认分页条件是:

$this->paginate = array('conditions' => 'order' => array('Company.name' => 'ASC');

它按公司名称排序。 SQL是

SELECT Company.id, etc. FROM companies AS Company LEFT JOIN cities AS City ON Company.city_id = City.id order by Company.name

当我在View中创建分页链接时

$paginator->sort('City.name')

它将这些参数添加到网址

... /企业/排序:City.name/direction:倒序

对城市名称进行排序。 SQL是

SELECT Company.id, etc. FROM companies AS Company LEFT JOIN cities AS City ON Company.city_id = City.id order by City.name

但是当我尝试这个时:

$paginator->sort('City.Country.name');

它将这些参数添加到网址

.../companies/sort:City.Country.name/direction:asc

,生成的SQL是

SELECT Company.id, etc. FROM companies LEFT JOIN cities AS City ON (Company.city_id = City.id)

它完全忽略了'排序'条件,并且根本没有“排序”。我不知道为什么。也许Cake不能这样做?我将'recursive'设置为2。

另一个选项是Model->查询,我尝试并开始工作,但我宁愿不使用因为我必须覆盖paginate和paginateCount方法,这并不难,但问题是在同一页面和其他页面上,我已经在为公司使用“普通”蛋糕分页。因此,如果我覆盖paginate和paginateCount,我是否不得不更改所有这些页面以使用新的,过度覆盖的分页?我想避免这种情况,因为它似乎有点矫枉过正,并且在其他地方工作得很好,除了这一例。

非常感谢任何帮助。

鲍勃

2 个答案:

答案 0 :(得分:1)

嗯,最后我在浏览了文档和许多在线示例之后对其进行了管理,如下所示:

首先,在Model中,声明并实现自定义findMethods。

class Company extends AppModel {

  public $findMethods = array('companiesOrderByCountry' =>  true);


protected function _findCompaniesOrderByCountry($state, $query, $results = array()) {
  if ($state === 'before') {
    $query['joins'] = array(
      array(
        'table' => 'cities',
        'alias' => 'City',
        'type' => 'LEFT',
        'conditions' => 'City.id = Company.city_id'
       ),
       array(
         'table' => 'countries',
         'alias' => 'Country',
         'type' => 'LEFT',
         'conditions' => 'Country.id = City.country_id'
        )
      );

      $query['order'] = array('Country.name' => 'asc');
      return $query;

  }

  return $results;
}

然后在Controller中,根据请求中的命名参数

有条件地调用它
if (!empty($this->request->params['named']['sort']) && $this->request->params['named']['sort'] == 'Country.name') {
  // here we need to sort on Country.name. Call custom findMethod in Model
  $this->paginate = array('companiesOrderByCountry','limit' => 10);
  $companies = $this->paginate();
  $this->set(compact('companies'));
} else {
  // do a normal search
  $this->paginate = array('limit' => 10,'conditions' => array('order' => array('Company.nombre' => 'ASC' ));
  $companies = $this->paginate('Company');
  $this->set('companies', $companies);
}

最后,在.ctp

中创建一个传递命名参数的链接
<?php $paginator = $this->Paginator; ?>
<?php echo $paginator->sort('Country.name', __('Country')); ?>

这可能是一种更优雅的方式,但我厌倦了处理它。生成的sql正是我需要的,现在我可以对Country进行排序,这是一个二级(公司 - &gt;城市 - >国家/地区)协会。

希望有一天能帮到某人!

鲍勃

答案 1 :(得分:0)

如果你想尝试使用查询方法,那么我就不会使用星号(*)。而是明确列出您想要的字段。

您的查询应如下所示: {我的个人最佳做法,在可能为NULL的字段上使用COALESCE - 尤其是在使用LEFT JOIN时}

SELECT companies.name AS CompanyName, 
       COALESCE(cities.name, 'Unknown') AS CityName,
       COALESCE(countries.name, 'Unknown') AS CountryName
FROM companies
LEFT JOIN cities
ON companies.city_id = cities.id
LEFT JOIN countries
ON cities.country_id = countries.id
ORDER BY CountryName, CityName

使用 AS 将字段与其别名分开。它还将表格与其别名分开(例如,您列出的示例。) AS 是可选的,但我觉得它增加了可读性。

-

(如果你想尝试分页技术,请显示当RECURSIVE = 2时失败的MySQL SELECT语句,以及控制器代码的样子 - 特别是'order'=&gt;数组)< / em>的