【问题标题】:Laravel validation 'unique' not working as expectedLaravel 验证“独特”未按预期工作
【发布时间】:2015-05-25 06:43:53
【问题描述】:

我正在为一个网站开发一个帮助中心,我已经在Laracast Forums 上提出了这个问题,不幸的是我还没有解决方案,这里是它的路由/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。

Section 请求也是如此,除了它只检查您要在其中创建它的指定类别中的 Sections。我已经对此进行了测试并且它可以工作。我可以将foo 和bar 插入Category 1 和foo 和bar 插入Category 2,但是如果我尝试将另一个foo 添加到Category 1 或Category 2 中,它不会t 验证因为它是重复的,这是正确的。但是,如果我尝试将Category 1 中的foo 更新为bar,它将不允许这样做,并且如果我尝试在不进行任何更改的情况下更新foo,它会忽略自身(行),允许它通过并不抛出验证错误。因此,一切正常。

现在对于我的文章验证,我使用了与部分验证完全相同的过程/查询验证,除了更改表/列/变量以适应,如下所示:

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.

我显然错了,否则它也会像我预期的那样工作,哈哈。但我就是看不出问题出在哪里?

这里是数据库架构,只是为了省去麻烦,并且可以确认表/列名匹配(同样删除了外键和额外列):

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 论坛链接中提到。您还可以找到 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.

【问题讨论】:

    标签: php laravel laravel-5 laravel-validation laravel-request


    【解决方案1】:

    嗯,首先你的代码很难分析,如果我是你,我会使用数组语法:

       $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 类来存储和更新,我通常会这样做:

    $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

    【讨论】:

    • 我的代码怎么难分析?我看不出你的数组方法和我的有什么不同,结果是完全一样的吗?只是写的不一样?我确实忘记提及$method 正在从Request::method() 获得它的价值,对此感到抱歉。我将尝试strtoupper 并将PUT 添加到语句中。分段方法对我来说似乎也不是很实用?除非我错过了什么?我知道$method 语句适用于类别和部分请求,我相信问题出在文章请求文件的'title' => '' 行。
    • @Joe 这更好,因为您可以更轻松地添加新条件甚至删除它们。正如我所展示的,最好对创建和更新的重复条件进行分组,对于更新,只需修改规则,而不是为创建和更新重复所有 3 条规则。这是它可以变得更好的唯一原因。可能在您的情况下,问题是缺少 PUT 并且可能是 PATCH/PUT 的字母大小写
    • 那是有道理的,那么用你的方法,我会采取这种方法。我还尝试将字符串转换为大写,并将put 添加到语句中,但它仍然不起作用。我还在 Laravel 文档中找到了Request::isMethod(),这似乎是一种更有保障的方法,但尝试if (Request::isMethod('put') || Request::isMethod('patch')) { 仍然无法正常工作,我也尝试过小写和大写。如此令人困惑的是为什么我不能让它按预期工作。感谢您迄今为止的帮助,尽管 Marcin!
    猜你喜欢
    • 2018-03-31
    • 2019-11-27
    • 2020-01-05
    • 2013-01-21
    • 1970-01-01
    • 2018-01-27
    • 2012-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多