laravel8のhasmany(リレーション)のwhere句を、検索条件に従って動的に変更したい!(親whereと子whereのAND検索がしたい!)
モデルオブジェクトが確定していれば、簡単にwhere句が付けられるんだけど、SQL発行する前のqueryでやりたいんだよね(何十万件もレコードがあるので)
1 2 |
$user = User::find(1); $user->posts()->where('active',1)->get(); |
whereHasだと遅いし、子where条件に引っかかった親レコードの紐づく子レコードが全部取得されてしまうから、子whereになっていない。
hasMany(子モデル)->where()を、検索条件に従って動的に変更したい!
参考URL
https://stackoverflow.com/questions/39448066/laravel-eloquent-dynamically-defined-relationship
1, 親モデルに、traitを追加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
// traitはclassの外側に記述 trait HasDynamicRelation { /** * Store the relations * * @var array */ private static $dynamic_relations = []; /** * Add a new relation * * @param $name * @param $closure */ public static function addDynamicRelation($name, $closure) { static::$dynamic_relations[$name] = $closure; } /** * Determine if a relation exists in dynamic relationships list * * @param $name * * @return bool */ public static function hasDynamicRelation($name) { return array_key_exists($name, static::$dynamic_relations); } /** * If the key exists in relations then * return call to relation or else * return the call to the parent * * @param $name * * @return mixed */ public function __get($name) { if (static::hasDynamicRelation($name)) { // check the cache first if ($this->relationLoaded($name)) { return $this->relations[$name]; } // load the relationship return $this->getRelationshipFromMethod($name); } return parent::__get($name); } /** * If the method exists in relations then * return the relation or else * return the call to the parent * * @param $name * @param $arguments * * @return mixed */ public function __call($name, $arguments) { if (static::hasDynamicRelation($name)) { return call_user_func(static::$dynamic_relations[$name], $this); } return parent::__call($name, $arguments); } } class User extends Model { use HasDynamicRelation; |
2. Controllerに記述
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class UserController extends Controller { // 検索 public function search(Request $request) { // requestの検索条件に従い、動的に子テーブルとのリレーション条件を定義する User::addDynamicRelation('posts', function(User $User) use ($request){ // 基本のリレーション定義を記述 $hasmany = $User->hasMany(Post::class); // 検索条件を追加していく if(!empty($request['title'])){ $hasmany->where('title', $request['title']); } return $hasmany->with('posts'); // withも付与できる }); |
思ったよりも綺麗に書けた。
デフォで出来るかと思ったけど、あんまり需要がないのかな?