1

これについては昨年、記事を書きました。最初の部分である第 1 レベルの関連付けでソートする方法については回答がありましたが (ありがとうございます!)、第 2 レベルの関連付けでソートする方法についての質問の 2 番目の部分については回答がありませんでした。それは大きな問題ではなく、時間がなくなったので、実際に実装することはありませんでした。しかし今、私たちは Web を更新しており、クライアントはこの機能、つまり次のモデルを必要としています。

  • 会社所属市区町村
  • 都市は国に属し、多くの企業を持っています
  • 国には多くの都市があります

[会社] ページで、City.Country.name で並べ替えます。recursive=2 を入れても動きません。Cake は私の「注文」条件を無視します。生成された SQL には、「順序付け」がまったくありません。

ただし、City.name でソートすると問題なく動作します。

これを行う方法はありますか?ドキュメントと Stackoverflow を精査してきました。仮想フィールド、カスタム クエリを見てきました。

有望に見える 1 つの方法は、CompanysController で 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に追加します

.../companys/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に設定しています。

もう 1 つのオプションは Model->query です。これは試してみて動作しましたが、paginate メソッドと paginateCount メソッドをオーバーライドする必要があるため、使用したくありません。これはそれほど難しくありませんが、問題は同じページにあることです。 、および他のページでは、企業向けの「通常の」 Cake ページングを既に使用しています。したがって、paginate と paginateCount をオーバーライドした場合、オーバーライドされた新しいページングを使用するために、これらすべてのページを変更する必要はありませんか? それはやり過ぎのように思え、この1つのケースを除いて他のどこでもうまく機能しているので、私はそれを避けたいです.

どんな支援も大歓迎です。

ボブ

4

2 に答える 2

1

さて、最終的には、次のようにドキュメントと多くの例をオンラインで熟読した後、それを管理しました。

まず、モデルで、カスタムの 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;
}

次に、コントローラーで、リクエストの名前付きパラメーターに基づいて、条件付きで呼び出します

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 はまさに私が必要としているものであり、今では第 2 レベル (会社 -> 都市 -> 国) の関連付けである国で並べ替えることができます。

これがいつか誰かを助けることを願っています!

ボブ

于 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 に答える