具有自定义数据透视表的高级Eloquent查询


Advanced Eloquent query with custom pivot table

这是给各位大师的。我有4张桌子。用户、厨师、地点、类型。

用户表

id
etc

厨师餐桌

id
user_id
etc

位置表

id
zip
etc

类型表

id
type_name
etc

创建的每个厨师帐户都是一个用户。创建的每个用户帐户不一定都是厨师。还有其他类型,但为了简单起见,我省略了它们。

厨师和用户模型

class Chef extends Eloquent {
    public function user() {
        return $this->belongsTo('User');
    }
}
class User extends Eloquent {
    public function chef() {
        return $this->hasOne('Chef');
    }
}

"users"表与"locations"表具有多对多关系。我还在"location_user"透视表中包含了"type_id"。

location_user数据透视表

id
location_id
user_id
type_id

位置模型

class Location extends Eloquent {
    public function users() {
        return $this->belongsToMany('User')->withTimestamps()->withPivot(['type_id']);
    }
}

我的目标是返回特定"zip"的所有Chef id,该字段位于"locations"表中。更多信息-数据透视表中可用的type_id值之一是"0"。如果成为厨师的用户不想为其厨师帐户创建单独的位置,则表示默认位置。每个用户都有其中一个,即type_id=0的相应pivot(location_User)条目。如果用户希望有一个单独的位置作为厨师,则会创建一个独立的"位置"表条目,并通过一个type_id=2的独立透视表条目进行链接。这样系统就知道要使用哪个位置。如果特定用户存在Chef帐户,但没有附带type_id=2的透视帐户,则使用透视帐户(该User_id和type_id=0)链接到的位置。

这是我搜索代码的一部分:

        if ($city_search || $zip_search) {
            $chef_ids = array();
            // TODO: Possibly bad for scaling.  Find a single Eloquent call for this
            $locations = Location::with('users')
                ->where('zip', 'LIKE', "%$city_search%")
                ->where('zip', 'LIKE', "%$zip_search%")
                ->get();
            foreach ($locations as $loc) {
                foreach ($loc->users as $user) {
                    $chef_ids[] = $user->chef->id;
                }
            }
        }
        if (count($chef_ids) == 0) return NULL;

问题是,如果一个用户也是一个厨师,他的厨师位置是默认的,但也有另一个[厨师以外的类型]位置,那么在透视表中该用户将有两条记录,一条类型_id=0(同时服务于默认和厨师位置),另一条类型id=?。如果默认Location不是查询到的'zip'值,而是另一个值,则会返回Chef的id。为了清晰起见,流程如下:使用zip=?获取所有位置?。从透视表中获取所有用户。

*其中一个用户也是厨师,但他的厨师帐户使用默认的Location(数据透视表中type_id=0的记录)。没有具有user_id值和type_id=2)的数据透视记录。*

从所有这些用户那里获取厨师和他们的id。该用户是否有一个位置id包含查询的zip值的透视帐户?是(适用于其他类型)。该用户是否有厨师帐户?对然后,即使他的chef帐户使用另一个zip中的默认Location,他的chef_id也会被返回。

有什么建议吗?

尝试:

$locations = Location::with('users.chef') [etc..]