いけむランド

はてダからやってきました

Connection を切り替えて Relation の loading をしたかった時の話

以前 qiita で公開していた記事を引っ越してきたものです。最終更新からかなり経っているため、情報の正確性は落ちている可能性があります。

はじめに

そろそろ laravel 歴 1 年になりそうながら、まだまだ使いこなせていない @fd0 です。

今回は database 周りのとある処理で 2~3 日悩んだ時のことを書いてみたいと思います。

コードを追いきれていないため、もしかしたら、もっと簡単に解決する方法 or そもそもやり方が良くないかもしれませんので、その場合はコメントなどでツッコミをいただければと思います。

やりたかったこと

やりたかったことは単純に「とあるアクション内で slave に繋ぎたかった」だけなのですが、どうも Eloquent 経由で思ったとおりにいってくれませんでした。

最初は以下のようなコードを Controller で書いていました。

// default は master
$model
  ->setConnection('slave')
  ->where('foo', $value)
  ->with(['bar' => function ($q) { $q->where('baz'); } ])
  ->get();

ところがこれですと $model は slave を参照しますが、bar は master を参照してしまいました。

¥Illuminate¥Database¥Eloquent¥Model あたりを読んでみても、Relation に $this を渡してるように見えるため、何故動いてくれないのかさっぱりでした。

with ではなくて load かなと思っていろいろ試行錯誤してみましたが、やはり slave を参照してくれません。var_dump すると connection は slave になっているため、既に作成されている master の connection を使っているのかなと思いましたが、よくわかりません。

Eloquent を諦めて DB::connection('slave') で解決しようかと思ったのですが、そうなると取得結果を Illuminate¥Database¥Eloquent¥Collection として処理している部分を書き換えないといけないため、それはそれで面倒だなあと思ってしまいました。

そうやって 2~3 日過ぎていった後にようやくできるようになりました。

やってみたこと

とあるアクションの route だけ database の設定を config で上書きすることでやりたいことを実現することができました。

// filter.php
Route::filter('db.slave', function()
{
  Config::set('database.default', 'slave');
});
// route.php
Route::group(['before' => 'db.slave'], function()
{
  Route::get('/', 'HogeController@actionGununu');
});

slave を参照しているかどうかは DB::connection('slave')->getQueryLog() で確認しました。

おわりに

同じことで困ってる人はいないのかとググッてみても全然見つからなかったので、まとめてみましたが、もしかしたら誰も困ってないのかもしれません...。(;^ω^)

あと、issues に関係ありそうな感じの Request がありましたが close されてました。

github.com