1

我去年写了一篇关于这个的帖子。第一部分,如何在 1 级关联中排序,得到了回答(再次感谢!),但问题的第二部分,关于如何在 2 级关联中排序,从未得到回答。这不是一个大问题,而且我们没时间了,所以我从未真正实施过它。但现在我们正在更新网络,客户想要这个功能,即使用以下模型:

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

在公司页面中,我想对 City.Country.name 进行排序。即使设置recursive=2,它也不起作用。Cake 忽略了我的“订单”条件;在生成的 SQL 中根本没有“order by”。

但是,如果我对 City.name 进行排序,则效果很好。

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

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

$companies = $this->Company->query("SELECT * FROM Companies com left join city c on c.id = com.city_id left join countries c2 on c2.id = c.country_id order by c2.name");

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

此外,在文档中的示例中,它说要执行类似 Model->query('SELECT * FROM pictures AS Picture LIMIT 2') 的操作,因此生成的数组将使用模型名称作为数组键。但是我怎么能用我的复杂查询来做到这一点呢?“AS”会去哪里?

我宁愿希望我能够避免这样做。有没有更简单的方法来做到这一点?

编辑

你好,谢谢你的帮助。您所说的“分页技术”是指 Cake 的内置分页吗?是的,这就是我想要的。我在控制器中的默认分页条件是:

$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

当我像这样在视图中创建分页链接时

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

它将这些参数添加到 url

.../companies/sort:City.name/direction:desc

它按城市名称排序。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');

它将这些参数添加到 url

.../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)

它完全忽略了“排序”条件,根本没有“排序依据”。我不确定为什么。也许蛋糕就是不能做到这一点?我将“递归”设置为 2。

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

非常感谢任何帮助。

鲍勃

4

2 回答 2

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中,根据request中的named params有条件地调用它

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 进行排序,这是一个 2 级(Company->City->Country)关联。

希望有一天这对某人有所帮助!

鲍勃

于 2013-10-08T13:43:31.623 回答
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'=> 数组)

于 2013-09-27T13:45:35.510 回答