「Alfasado Inc. / LAB Inc. Advent Calendar 2023」の第1日目です。さて、今日は何月何日でしょう?という冗談はさておき、最近手掛けたプロジェクトでの気付きを少し書いてみたいと思います。
例えば記事のカテゴリに以下のような部署を設定したとします。
- IR室
- 人材開発室
- デジタル研究開発部
- 営業部
その上で、記事一覧を表示する際に公開日の降順、なおかつ上記のカテゴリの昇順で表示したいというご要望です。つまり、同日にIR室とデジタル研究開発部が記事を公開した場合はIR室の記事を先に表示したい、ということです。
PowerCMS Xでは記事(オブジェクト)をループで出力する際に第2ソートキーを指定することができますが、リレーションカラムをキーとして指定することはできません。リレーションのデータは「mt_relation」テーブルに格納されており、「mt_entry」テーブルにはないためです。さて、どのようにして解決すれば良いでしょうか?
私のようにまっすぐ過ぎる性格だとSQLでJOINして解決しようとしてしまうのですが、「mt_relation」と「mt_category」をJOINしてソートするのもなかなか大変です。そこで、タイトルにも書いたようにあえてテーブルを非正規形にする…「mt_entry」にカラムを追加(例えばdepertment_order)してカテゴリの表示順を「mt_entry.depertment_order」に保存しておくのです。こうすれば以下のように第2ソートキーが指定できるようになり、公開日の降順順かつカテゴリ表示順の昇順で記事を並べることができます。
<mt:entries sort_by="'published_on','depertment_order'" sort_order="'descend','ascend'">
depertment_orderカラムへのデータ保存はpost_saveコールバックを利用して行います。オブジェクトをロードして値をセットし保存する、という基礎的なコードです。
function post_save_entry ( &$cb, $app, &$obj, $original ) {
$categories = $app->load_related_objs(
$obj,
'category',
[],
['sort' => 'order', 'direction' => 'ascend', 'limit' => 1],
'order'
);
if ( ! empty( $categories ) ) {
$category = $categories[0];
if ( $category->order !== $obj->category_order ) {
$obj->depertment_order( $category->order );
$obj->save();
}
}
return true;
}
部署が追加になった時・部署の順を入れ替えた時は全記事のdepertment_orderカラムを更新する必要がありますが、記事オブジェクトをロードして上記のコードに通すだけですので、それほど大変ではないと考えます。きっと頻度もそれほど多くないのではないでしょうか?
複雑なソートの要件が出た場合の参考になれば幸いです。
※公開日の降順にする際、時刻が全て同一である必要があるのでalt-tmplで公開日をカスタマイズ(時刻を00:00:00に固定)する必要があります。