情况
用户可以属于多个组织,并通过名为employees
的数据透视表进行链接
正在使用的模型:User
,Employee
和Organizations
相关数据库列:
users
- id
employees
- user_id
- organization_id
organizations
- id
目标
一种有效的方法来检查用户1
和用户2
是否在organization_id
表中共享至少一个employees
用例
Api端点/api/v1/user/#
返回有关用户的其他元数据。
使用policy
,它检查当前用户和url中的用户ID是否相同,或者它们都是至少一个组织的雇员,organization_id
在在这个阶段,重要的是它是否匹配。
示例A
用户A(1
)是组织foo(1
)的雇员
用户B(2
)是组织栏(2
)的员工
员工表因此具有以下记录:
+-----------------+---------+
| organization_id | user_id |
+-----------------+---------+
| 1 | 1 |
| 2 | 2 |
+-----------------+---------+
在此示例中,查询应返回错误结果,因为用户A和B之间没有共享的organization_id
示例B
用户A(1
)是组织foo(1
)的雇员
用户A(1
)是组织foobar(3
)的雇员
用户B(2
)是组织栏(2
)的员工
用户B(2
)是组织foobar(3
)的雇员
员工表因此具有以下记录:
+-----------------+---------+
| organization_id | user_id |
+-----------------+---------+
| 1 | 1 |
| 2 | 2 |
| 3 | 1 |
| 3 | 2 |
+-----------------+---------+
在此示例中,查询应该返回真实结果,因为用户A和B之间共享organization_id
政策代码
/**
* Determine whether the user can view the model.
*
* @param \App\User $user
* @param \App\User $model
* @return mixed
*/
public function view(User $user, User $model)
{
if ($user->is($model)) {
return true;
} else {
// check if users share at least one organization
}
}
有效但效率不高的代码
foreach ($user->organizations()->with('users')->get() as $organization) {
if ($organization->users->where('id', $model->id)->first()) {
return true;
}
}
return false;
带有连接的实验代码,而不是使用laravel模型完成的
\Illuminate\Support\Facades\DB::table('employees as auth_employee')
->join('employees as other_employee', 'other_employee.organization_id', '=', 'auth_employee.organization_id')
// ->join('organizations', 'organizations.id', '=', 'organizations.id')
->where('auth_employee.id', 1)
->where('other_employee.id', 2)
->get()
请求的解决方案
一个有效的查询,以获取(可广播)布尔结果结果,无论是否有2个用户在organization_id
表上共享至少一个employees
,为使用laravel模型/查询提供“加分”建造者。
页脚
感谢阅读,这里有个土豆:
答案 0 :(得分:3)
假设您在Organization
模型中建立了用户关系,则可以使用whereHas方法:
$user->organizations()->whereHas('users', function ($query) use($model) {
$query->where('users.id', $model->id);
})->exists();
答案 1 :(得分:1)
作为原始查询,我可能会在这里使用EXISTS
,但是由于您需要将任何查询移植到Laravel / PHP代码,因此我建议使用自连接:
SELECT DISTINCT
e1.user_id, e2.user_id
FROM employees e1
INNER JOIN employees e2
ON e1.organization_id = e2.organization_id AND e1.user_id = 2
WHERE
e1.user_id = 1;
这只会返回user_id
对值(1, 2)
对。如果希望查询返回至少共享一个组织的所有成对的不同用户,则可以将此查询重写为:
SELECT DISTINCT
e1.user_id, e2.user_id
FROM employees e1
INNER JOIN employees e2
ON e1.organization_id = e2.organization_id AND e1.user_id <> e2.user_id;
答案 2 :(得分:1)
我能想到的最易读的示例是在用户模型中放置以下内容:
public function isColleagueWith(User $user): bool
{
return $this->organizations->intersectByKey($user->organizations)->count() > 0;
}
用法易于阅读和理解:
$userA->isColleagueWith($userB);
如果要使用较少的数据库查询,则可以直接查询数据透视表。在这里,您将获得雇用两个用户的所有组织,并检查列表中是否包含重复的组织ID。
use Illuminate\Database\Eloquent\Relations\Pivot;
class Employees extends Pivot
{
public function areColleagues(int $userIdA, int $userIdB): bool
{
$employments = $this->where('user_id', $userIdA)
->orWhere('user_id', $userIdB)
->get('organization_id');
return $employments->count() > $employments->unique()->count();
}
}
用法:
Employees::areColleagues($userIdA, $userIdB);
答案 3 :(得分:1)
要检查用户1和2是否共享一个或多个组织,请执行以下操作:
SELECT EXISTS (
SELECT 1 FROM employees AS a
JOIN employees AS b USING(organization_id)
WHERE a.user_id = 1
AND b.user_id = 2;
同时具有以下两个索引:
(user_id, organization_id)
(organization_id, user_id)