こちらでははじめまして! Web制作コースとエンジニアコースを受講しておりました金子と申します。
中高生の頃にwebサイト、flashゲーム等を作っていたことからweb制作のお仕事につきたいと考えて受講させて頂きました。今後こちらでは、私が制作中に気がついたことや便利だなと思ったものを共有させて頂きたいなと考えております。皆様アドバイスお願いいたします!
今回のお題は、よくブログ記事の下についている↓こういうやつをCakePHP2で作りたい!
![]()
ので作りました。が、たったこれだけだったのにとんでもない大冒険になりました……ヘトヘトです。私の辿ったルートを晒して、もっと楽なルートを皆さんに教えて頂きたいな~と思い投稿させて頂きます。
(ベースになっているのはエンジニアコースphpレッスンで作成したview.ctpです。)
これじゃダメだった! 最初に試したこと
条件
・記事投稿者が、投稿済みの記事(=レコード)を削除できる
・テーブル構造は以下の通り(テーブル名:recipes)
IDはA_I設定です。

やりたいこと
・URL:〜view/3にアクセスした時、前のレコード(ID=1)へのリンクと次のレコード(ID=4)へのリンクを表示したい
・URL:〜view/1にアクセスした時、前のレコードは存在しないので、リンクも表示しない
・URL:〜view/4にアクセスした時、次のレコードは存在しないので、リンクも表示しない
方法
・今の記事のID±1の変数を作成して、リンクに組み込む
結果
失敗!
たとえばID=3の記事なら、前記事のID=2、次記事のID=4となるので、リンクがそうなるように変数を作っておけばOK…と思ったけれど…

皆さまお気付きのように、このテーブル、ID2の記事が既に削除されていて存在しないのです。ってことは、ID=3の前後記事のIDは1と4……!
そんなわけで「記事ID±1=前後の記事IDになるから、それでリンクを貼る」方法はダメということがわかりました。
じゃあ記事ID±1のIDが存在してるか確かめて、なかったらもう1件隣を見ていくか…めんどくさ! でもそれ以外に方法が思いつかないし……
debug($posts[$id])とかやっても、id≠配列のキーだから、欲しいレコードをピンポイントで綺麗に取ってこれないし! array_keys関数でいけるかとも思ったけどやっぱりダメ!
ものすご~く面倒だけど今の私にはとにかくこれしかできそうにない! ってことでやりました。
これで解決! CakePHP2で作る面倒な前後記事へのリンク
無事解決した際に書いたコードはこんな感じになりました。
ちょっと日本語力がやばくて分かりにくいかもしれませんが、どうぞ心で感じてください……。
//ここからはControllerに書くものです
//前後に投稿されているレシピを調べて、前後記事へのリンクを作る準備をする
$all_recipe = $this -> Recipe -> find('all'); //投稿済みの記事全部取得
$count = 0; //配列のキーとして設定
$now_recipe_id_key = ($all_recipe[$count]['Recipe']['id']); //1件目のデータのidを取得
$max = count($all_recipe); //投稿済みの記事件数
while($id != $now_recipe_id_key){
/* 1件目のデータのidと表示中の記事のidが一致するか最初から見ていき、
表示中の記事が、配列として何件目に位置するデータなのかを$countに記録 */
$count++;
$now_recipe_id_key = ($all_recipe[$count]['Recipe']['id']);
}
$prev = $count -1; //前記事が配列として何件目のデータなのか
$next = $count +1; //次記事が配列として何件目のデータなのか
if($prev < 0){
//$prevが負の値のとき前記事は存在しないので、前記事へのリンクを表示しないよう準備をする
$prev_link = false;
}else{ $prev_link = true; }
if($next >= $max){
//$nextが投稿済みの記事件数を上回るとき次記事は存在しないので、次記事へのリンクを表示しないよう準備をする
$next_link = false;
}else{
$next_link = true;
}
// viewでリンクを作る際に必要なのは配列のキーではなく記事IDであるため、viewに渡す前に変換しておく
if ($prev_link == true) {
$prev = $all_recipe[$prev]['Recipe']['id'];
}
if ($next_link == true) {
$next = $all_recipe[$next]['Recipe']['id'];
}
//前後記事へのリンクに関する変数をviewに渡す
$this -> set(compact('prev','next','prev_link','next_link'));
//Controllrに書くもの終わり
//ここからはview.ctpに書くものです
if($prev_link == true){
echo '<a href="'.$prev.'"><< 前のレシピへ</a>';
}
if($prev_link == true & $next_link == true){
echo ' | ';
}
if($next_link == true){
echo '<a href="'.$next.'">次のレシピへ >></a>';
}
//view.ctpに書くもの終わり
ここまで長かった…! 「前後記事へのリンク」なんて当たり前すぎるものなのに、自分で作ろうとするとこんなに大変な目にあうんですね。そういうやつやらなくていいWordPressの凄さたるや……。いや、個人的にはコードを書いてるときが楽し苦過ごせる時間なのでWordPressはさほど好みではないのですけれど……。
記事の公開・非公開・下書き…みたいな設定をつけて、公開以外は見れないようにしたい、っていう時も同じ手を使えそうです。
でもこんな面倒なことをしなくても、この方法を使えばサクッと作れるよ!というのをご存知の方はアドバイスをいただけると嬉しいです。
というか一発で前後記事取ってこられる関数とかが存在していてほしい……散々ネサフして見つけられなかったから、ないのかなあ……?
金子風月
最新記事 by 金子風月 (全て見る)
- vue.jsに触ってみた話 - 2019年3月26日
- DockerでCakePHP2の開発環境を作ってみた(Mac版) - 2019年3月15日
- CakePHP3+Authコンポーネントで任意のタイミングでログインさせる処理をつくる - 2019年3月14日
風月さんこんにちは!投稿ありがとうございます!
わーすごい大変でしたね!!
でも、そのロジックを考えたのはさすがですね!
私もいろいろ考えてはみたのですが(たとえば、ページングについてる添付のprev/nextが使えないかな…とか)、やっぱり考え方としては風月さんの考え方になりました。
もう少し効率的な書き方としては、全データをぐるぐるまわして表示中の記事のインデックスを取得していますが、
$posts = $this->Post->find('list'); //idの連想配列を取得 $ids = array_keys($posts); //連想配列を単純な配列に変換 $idx = array_search($id, $ids); //記事IDが配列の何番目かを取得で取得ができます。
あとは風月さんのやり方と同じになると思います!
前記事のIDは(あれば)
で取得ができますね。
どうやったら実現できるかな?と試行錯誤するのはすごく勉強になりますよね!
私も勉強になりました!!ありがとうございます!!
柳田さん、コメントありがとうございます! 褒めていただき嬉しいです。
教えて頂いたやり方、とても勉強になりました! 投稿した方法だと、データ数が増えていった時に重くなるんじゃないか…とも思っていたのですが、こちらの方法だとそういう事態にもならなそうですし、コードも綺麗です!
投稿してみてよかったです(*^-^*) ありがとうございました!