Laravel 验证 'unique' 未按预期工作
Laravel validation 'unique' not working as expected
我正在为一个站点开发一个帮助中心,我已经在 Laracast Forums 上提出了这个问题,不幸的是我还没有找到解决方案,这里是 routes/url 路径:
routes.php
Route::resource('admin/help-centre/category', 'AdminHelpCentreCategoryController');
Route::resource('admin/help-centre/category/{category}/section', 'AdminHelpCentreSectionController');
Route::resource('admin/help-centre/category/{category}/section/{section}/article', 'AdminHelpCentreArticleController');
类别和部分验证按预期工作,但出于某种原因,即使它们是相同的逻辑,据我所知,文章验证似乎没有按预期工作。这是我的验证规则(我删除了多余的部分并只留下了标题字段):
HelpCentreCategoryRequest.php
/* Insert ------------------------------------- */
$rules = [
'title' => 'required|min:3|unique:help_centre_categories',
];
/* Update ------------------------------------- */
if ($method == 'PATCH') {
$rules = [
'title' => 'required|min:3|unique:help_centre_categories,title,'.$this->category->id,
];
}
HelpCentreSectionRequest.php
/* Insert ------------------------------------- */
$rules = [
'title' => 'required|min:3|unique:help_centre_sections,title,NULL,id,category_id,'.$this->category->id,
];
/* Update ------------------------------------- */
if ($method == 'PATCH') {
$rules = [
'title' => 'required|min:3|unique:help_centre_sections,title,'.$this->section->id.',id,category_id,'.$this->category->id,
];
}
我将进行解释以澄清...对于类别,在 INSERT
上它会检查该标题是否已存在,如果存在,则不会验证。 UPDATE
做的完全一样,只是它在检查中忽略了自己,因此它仍然可以验证标题是否未更改。所以我输入了 2 个类别,一个叫 Category 1
,另一个叫 Category 2
.
部分请求也是如此,只是它只检查您在其中创建它的指定类别中的部分。我已经对此进行了测试并且可以正常工作。我可以将 foo
和 bar
插入 Category 1
,将 foo
和 bar
插入 Category 2
,但如果我尝试添加另一个 foo
到 Category 1
或 Category 2
中,它无法验证,因为它是重复的,这是正确的。但是如果我尝试将 Category 1
中的 foo
更新为 bar
它不会允许它,而且如果我尝试更新 foo
而不做任何更改,它会忽略自己(行)允许它通过而不抛出验证错误。因此一切正常。
现在,对于我的文章验证,我使用了与部分验证完全相同的 process/query 验证,除了更改 table/column/variables 以适应,如下所示:
HelpCentreArticleRequest.php
/* Insert ------------------------------------- */
$rules = [
'title' => 'required|min:3|unique:help_centre_articles,title,NULL,id,section_id,'.$this->section->id,
];
/* Update ------------------------------------- */
if ($method == 'PATCH') {
$rules = [
'title' => 'required|min:3|unique:help_centre_articles,title,'.$this->article->id.',id,section_id,'.$this->section->id,
];
}
这应该与 HelpCentreSectionRequest.php
完全相同,因此在一个类别的每个部分中只允许一个文章标题的副本,同时允许一个标题相同但在一个类别的不同部分中的文章.那部分工作正常,但是如果我在 Category 1 / Section 1
中插入 foo
和 bar
,然后将 foo
更新为 bar
它允许更改,对我来说,它不应该,因为 bar
已经存在于 Category 1 / Section 1
.
不过我显然是错的,否则它也会像我预期的那样工作哈。但是我就是看不出问题是什么?
这里是数据库模式,只是为了省去麻烦并且可以确认 table/column 名称匹配(同样删除了外键和额外的列):
Schema::create('help_centre_categories', function(Blueprint $table)
{
$table->increments('id')->unsigned();
$table->string('title');
});
Schema::create('help_centre_sections', function(Blueprint $table)
{
$table->increments('id')->unsigned();
$table->integer('category_id')->unsigned();
$table->string('title');
});
Schema::create('help_centre_articles', function(Blueprint $table)
{
$table->increments('id')->unsigned();
$table->integer('category_id')->unsigned();
$table->integer('section_id')->unsigned();
$table->string('title');
});
我还检查了文章请求中的 if
语句肯定会触发,这是在顶部的 Laracast 论坛 link 中提到的。您还可以找到 Valiation 文档 here,但为了便于阅读,这是我使用的主要部分:
Adding Additional Where Clauses
You may also specify more conditions that will be added as "where" clauses to the query:
'email' => 'unique:users,email_address,NULL,id,account_id,1'
In the rule above, only rows with an account_id of 1 would be included in the unique check.
嗯,首先你的代码很难分析,如果我是你,我会使用数组语法:
$rules = [
'title' => ['required'. 'min:3'],
];
$uniqueRule = 'unique:help_centre_categories';
/* Update ------------------------------------- */
if ($method == 'PATCH') {
$uniqueRule.='title,'.$this->category->id
}
$rules['title'][] = $uniqueRule;
第二个是$method
变量。我不知道它来自哪里,但假设它具有正确的值,您可能应该这样更改您的条件:
if (strtoupper($method) == 'PATCH' || strtoupper($method) == 'PUT') {
...
}
最后,如果我尝试使用一个 Request
class 来存储和更新,我通常这样做:
$segments = $this->segments();
$id = intval(end($segments));
if ($id != 0) {
// now you know it's update
}
如果你的方法不行,你可以试试上面的方法。
编辑
在您的 Request
对象中您可以使用 getMethod()
方法,例如:
public function rules()
{
$method = $this->getMethod();
if ($method == 'PUT' || $method == 'PATCH') {
// now you do what you want for update
}
// rest of code goes here
}
对于更新,您应该验证 $method 是 PUT
还是 PATCH
我正在为一个站点开发一个帮助中心,我已经在 Laracast Forums 上提出了这个问题,不幸的是我还没有找到解决方案,这里是 routes/url 路径:
routes.php
Route::resource('admin/help-centre/category', 'AdminHelpCentreCategoryController');
Route::resource('admin/help-centre/category/{category}/section', 'AdminHelpCentreSectionController');
Route::resource('admin/help-centre/category/{category}/section/{section}/article', 'AdminHelpCentreArticleController');
类别和部分验证按预期工作,但出于某种原因,即使它们是相同的逻辑,据我所知,文章验证似乎没有按预期工作。这是我的验证规则(我删除了多余的部分并只留下了标题字段):
HelpCentreCategoryRequest.php
/* Insert ------------------------------------- */
$rules = [
'title' => 'required|min:3|unique:help_centre_categories',
];
/* Update ------------------------------------- */
if ($method == 'PATCH') {
$rules = [
'title' => 'required|min:3|unique:help_centre_categories,title,'.$this->category->id,
];
}
HelpCentreSectionRequest.php
/* Insert ------------------------------------- */
$rules = [
'title' => 'required|min:3|unique:help_centre_sections,title,NULL,id,category_id,'.$this->category->id,
];
/* Update ------------------------------------- */
if ($method == 'PATCH') {
$rules = [
'title' => 'required|min:3|unique:help_centre_sections,title,'.$this->section->id.',id,category_id,'.$this->category->id,
];
}
我将进行解释以澄清...对于类别,在 INSERT
上它会检查该标题是否已存在,如果存在,则不会验证。 UPDATE
做的完全一样,只是它在检查中忽略了自己,因此它仍然可以验证标题是否未更改。所以我输入了 2 个类别,一个叫 Category 1
,另一个叫 Category 2
.
部分请求也是如此,只是它只检查您在其中创建它的指定类别中的部分。我已经对此进行了测试并且可以正常工作。我可以将 foo
和 bar
插入 Category 1
,将 foo
和 bar
插入 Category 2
,但如果我尝试添加另一个 foo
到 Category 1
或 Category 2
中,它无法验证,因为它是重复的,这是正确的。但是如果我尝试将 Category 1
中的 foo
更新为 bar
它不会允许它,而且如果我尝试更新 foo
而不做任何更改,它会忽略自己(行)允许它通过而不抛出验证错误。因此一切正常。
现在,对于我的文章验证,我使用了与部分验证完全相同的 process/query 验证,除了更改 table/column/variables 以适应,如下所示:
HelpCentreArticleRequest.php
/* Insert ------------------------------------- */
$rules = [
'title' => 'required|min:3|unique:help_centre_articles,title,NULL,id,section_id,'.$this->section->id,
];
/* Update ------------------------------------- */
if ($method == 'PATCH') {
$rules = [
'title' => 'required|min:3|unique:help_centre_articles,title,'.$this->article->id.',id,section_id,'.$this->section->id,
];
}
这应该与 HelpCentreSectionRequest.php
完全相同,因此在一个类别的每个部分中只允许一个文章标题的副本,同时允许一个标题相同但在一个类别的不同部分中的文章.那部分工作正常,但是如果我在 Category 1 / Section 1
中插入 foo
和 bar
,然后将 foo
更新为 bar
它允许更改,对我来说,它不应该,因为 bar
已经存在于 Category 1 / Section 1
.
不过我显然是错的,否则它也会像我预期的那样工作哈。但是我就是看不出问题是什么?
这里是数据库模式,只是为了省去麻烦并且可以确认 table/column 名称匹配(同样删除了外键和额外的列):
Schema::create('help_centre_categories', function(Blueprint $table)
{
$table->increments('id')->unsigned();
$table->string('title');
});
Schema::create('help_centre_sections', function(Blueprint $table)
{
$table->increments('id')->unsigned();
$table->integer('category_id')->unsigned();
$table->string('title');
});
Schema::create('help_centre_articles', function(Blueprint $table)
{
$table->increments('id')->unsigned();
$table->integer('category_id')->unsigned();
$table->integer('section_id')->unsigned();
$table->string('title');
});
我还检查了文章请求中的 if
语句肯定会触发,这是在顶部的 Laracast 论坛 link 中提到的。您还可以找到 Valiation 文档 here,但为了便于阅读,这是我使用的主要部分:
Adding Additional Where Clauses
You may also specify more conditions that will be added as "where" clauses to the query:
'email' => 'unique:users,email_address,NULL,id,account_id,1'
In the rule above, only rows with an account_id of 1 would be included in the unique check.
嗯,首先你的代码很难分析,如果我是你,我会使用数组语法:
$rules = [
'title' => ['required'. 'min:3'],
];
$uniqueRule = 'unique:help_centre_categories';
/* Update ------------------------------------- */
if ($method == 'PATCH') {
$uniqueRule.='title,'.$this->category->id
}
$rules['title'][] = $uniqueRule;
第二个是$method
变量。我不知道它来自哪里,但假设它具有正确的值,您可能应该这样更改您的条件:
if (strtoupper($method) == 'PATCH' || strtoupper($method) == 'PUT') {
...
}
最后,如果我尝试使用一个 Request
class 来存储和更新,我通常这样做:
$segments = $this->segments();
$id = intval(end($segments));
if ($id != 0) {
// now you know it's update
}
如果你的方法不行,你可以试试上面的方法。
编辑
在您的 Request
对象中您可以使用 getMethod()
方法,例如:
public function rules()
{
$method = $this->getMethod();
if ($method == 'PUT' || $method == 'PATCH') {
// now you do what you want for update
}
// rest of code goes here
}
对于更新,您应该验证 $method 是 PUT
还是 PATCH