Ich habe hunger

あふりかエンジニア、アフリカ向けのB2BのSaaSを開発する

Laravel4でリレーション先のupdated_atでリレーション元をソートしたかった件

Postモデル hasMany Commentモデル
みたいなリレーションの時に、コメントがついていれば
最新コメント順でPostを並べ替えたいと思っていました。

要は、管理画面とかでコメント着いた順に並んでて
それにアクセスしたいな、って感じが要望です。

問題

単純な問題として、orderByは呼び出してるModelにしか効かない。
で、Webで検索しててよく出て来たのがリレーション先のものをソートするというやつ。


php - Laravel Eloquent sort by relation table column - Stack Overflow

そうじゃないんだよな、感が強い。

解決

ぱっと思いついた話で言うとタイトルの通りなんですが、
極端な話、今回の要望に関してはコメントがポストに付与した時に
ポストのupdated_atが更新されればOKです。

$comment = new Comment;
$comment = Input::get('comment');
$comment->save();
$post = Post::find($id);
$post->updated_at = $comment->updated_at;
$post->save();

みたいなことをしようとしてましたw
まぁ、実際にコレをやるなら、PostモデルにaddCommentみたいな
メソッド作ってその中でやりそうですがw

で、こんなのやりたくないなーと思ったら神みたいな機能がLaravelについてました。

Laravelの機能 -> 親のタイムスタンプの更新

例えばCommentがPostに所属しているような場合、子供のモデルが変更された場合、所属している(belongsTo)親のタイムスタンプも変更されると便利です。Commentモデルが更新されたら、Postが持っているupdated_atタイムスタンプも自動的に更新したい場合などです。Eloquentでは簡単に実現できます。子供のモデルでtouchesプロパティーに、関連名を付け加えてください。

class Comment extends Eloquent {
 
    protected $touches = array('post');
 
    public function post()
    {
        return $this->belongsTo('Post');
    }
 
}

DB:Eloquent ORM


これだけでOK!

これで、Commentが更新されるとそれを所有している
Postのupdated_atまで同時に更新されるようになりました。

マジ最高っす。

ちょっとリアルにBaseModelか何かに
親のupdated_atを更新するsaveメソッドを作るところだったw
あぶねー。

で、ここまで出来たら

public function index()
{
  $posts = Post::orderBy('updated_at', 'desc')->get();
  return View::make('admin.posts.index', compact('posts'));
}

とやれば、コメント順に並びました。

めでたしめでたし。

おやすみなさい。