我试图定义一个验证,只包括满足特定条件的用户 - 主要是考虑其元数据(存储在另一个表中)具有字段 supplier_id
的用户值(value)。因此,我在 UpdateXRequest
类中完成了此操作:
public function rules()
{
$journey = $this->route()->parameter('journey');
return ['driver_id' => [
Rule::exists('users', 'id')
->where(function($query) use ($journey){
$query->join('users_meta', 'users.id', '=', 'users_meta.user_id')
->where('users_meta.key', 'supplier_id')
->where('users_meta.value', $journey->supplier_id);
})
]
];
}
但是,我得到 Column not found: 1054 Unknown column 'users_meta.key' in 'where clause' (SQL: select count(*) as aggregate from users where id = x and (users_meta.key = supplier_id 和 users_meta.value = y))
错误。
我怎样才能做到这一点?
我正在寻找使用默认 Laravel 逻辑的答案,而不是编写我自己的验证器
根据请求,这里是架构查询:
CREATE TABLE IF NOT EXISTS `users` (
`id` int(10) unsigned NOT NULL,
`email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`password` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
`role_id` int(10) unsigned NOT NULL
);
CREATE TABLE IF NOT EXISTS `users_meta` (
`id` int(10) unsigned NOT NULL,
`user_id` int(10) unsigned NOT NULL,
`type` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'null',
`key` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`value` text COLLATE utf8_unicode_ci,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL
);
ALTER TABLE `users`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `users_email_unique` (`email`);
ALTER TABLE `users`
MODIFY `id` int(10) unsigned NOT NULL AUTO_INCREMENT;
ALTER TABLE `users_meta`
ADD PRIMARY KEY (`id`),
ADD KEY `users_meta_user_id_index` (`user_id`),
ADD KEY `users_meta_key_index` (`key`);
ALTER TABLE `users_meta`
MODIFY `id` int(10) unsigned NOT NULL AUTO_INCREMENT;
INSERT INTO `users` (`id`, `email`, `password`, `created_at`, `updated_at`, `role_id`) VALUES (6898, 'a@b.com', '', '2017-08-09 12:15:05', '2017-08-09 13:19:56', 4);
INSERT INTO `users_meta` (`id`, `user_id`, `type`, `key`, `value`, `created_at`, `updated_at`) VALUES (18, 6898, 'string', 'supplier_id', '6897', '2017-08-09 12:15:05', '2017-08-09 12:15:05');
查询存在于 OP 中,但每个请求添加了从查询日志中生成的 SQL 查询:
select count(*) as aggregate from `users` where `id` = 7011 and (`users_meta`.`key` = supplier_id and `users_meta`.`value` = 6897)
仔细想想,为什么它不起作用是完全合理的——内部 join
没有任何条件(它没有出现在查询日志中仍然很奇怪 -也许这是 Laravel 所做的优化,避免不必要地为 where
而不是 select
连接表)。内部 where
目前在 users
上运行,而不是在来自 join
的表上运行 - 根据 https://laravel.com/docs/5.4/queries#joins (高级连接子句),它们需要在 join
内部才能工作(根据@DarkMukke 的回答)
最佳答案
不是 100% 肯定,但从逻辑上讲,这听起来像是你的连接的 where 条件应该在闭包中
public function rules()
{
$journey = $this->route()->parameter('journey');
return ['driver_id' => [
Rule::exists('users', 'id')
->where(function($query) use ($journey){
$query->join('users_meta', function ($join) use ($journey) {
$join->on('users.id', '=', 'users_meta.user_id')
->where('users_meta.key', 'supplier_id')
->where('users_meta.value', $journey->supplier_id);
});
})
]
];
}
即使那样,您也可能不需要第一个闭包,例如
我错了,where 与规则的条件有关,而不是查询构建器的 where 条件。
编辑:我没有尝试过这段代码,但根据我的经验,以及对文档的一些双重检查,这应该是正确的。
此外,由于条件都在连接上,您可以通过添加条件而不是连接更少的数据来加快速度
public function rules()
{
$journey = $this->route()->parameter('journey');
return [
'driver_id' => [
Rule::exists('users', 'id')
->where(function ($query) use ($journey) {
$query->join('users_meta', function ($join) use ($journey) {
$join->on('users.id', '=', 'users_meta.user_id')
->on('users_meta.key', '=', 'supplier_id')
->on('users_meta.value', '=', $journey->supplier_id);
});
})
]
];
}
关于php - 定义联接时进行验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45941355/