Posts hasMany Comments の関係で、最新のCommentsを3件だけ紐付けて取得したい場合を考える。

1. containに書く方法

再利用を考えなければ以下のように、containでクエリを書けばよい。

$Posts->find()
    ->contain([
        'Comments' => function (\Cake\ORM\Query $query) {
            // 最新3件
        	return $query->orderDesc('Comments.posted_at')->limit(3);
        },
        'Comments.CommentUsers', // <- コメント投稿者
    ]);

2. カスタムファインダーを定義する方法

カスタムファインダーを定義することで、再利用しやすくなる。

CommentsTable に findLatest3 というカスタムファインダーを定義する

class CommentsTable extends Table {
	// ... (snip)

	public function findLatest3(\Cake\ORM\Query $query, array $options)
	{
		return $query->orderDesc($this->aliasField('posted_at'))->limit(3);
	}
	
	// ... (snip)
}

containでfinderを指定して呼び出す。

$Posts->find()
    ->contain([
        'Comments' => ['finder' => 'latest3'],
        'Comments.CommentUsers', // <- コメント投稿者
    ]);

3. カスタムファインダー+専用アソシエーションを定義する方法

Postsに最新のCommentsを3件取得するアソシエーションを別途定義すると、さらに再利用しやすくなる。

class PostsTable extends Table {
	
	public function initialize(array $config)
	{
		// ... (snip)
		
		$this->hasMany('Comments'); // 元のリレーション

		$this->hasMany('LatestComments', [
            'className' => 'Comments',
            'foreignKey' => 'post_id',
            'finder' => 'latest3',
            'propertyName' => 'comments', // propertyNameを設定することで、Commentsリレーションと同プロパティ名で取得できるようにする
        ]);
	
		// ... (snip)
	}
}

containではLatestCommentsを呼び出す。

$Posts->find()
    ->contain([
        'LatestComments.CommentUsers',
    ]);