【问题标题】:Laravel check for unique rule without sending the attribute as data rather as url parameterLaravel 检查唯一规则而不将属性作为数据而不是作为 url 参数发送
【发布时间】:2020-11-05 10:54:36
【问题描述】:

我有一个 products 表和一个 product_reports 表。用户可以举报一个产品,但他应该只能这样做一次,而不是两次或多次。

这是我的产品表:

id, heading, text, price, stock

这是我的产品报告:

id, product_id, user_id, reason

我的产品过期路线:

Route::post('product/{product}/report', ['as' => 'product.report', 'uses' => 'ProductController@report']);

现在我是位于App\Http\Requests 的 ProductReportRequest.php 文件。在那里我检查用户是否被授权,以及他是否发送了一个原因(值):

public function authorize()
{
    return Auth::check();
}

public function rules()
{
    return [
        'value' => [
            'required',
            'string',
            'max:65535'
        ],
    ];
}

我现在的问题如下:

如您所见,路由已包含我要为其存储用户报告的产品 (id)。所以我不是在发布请求中将产品 ID 作为属性发送,而是在看起来像这样的 url 中发送,例如:product/5/report

我现在的目标是添加一个规则,该规则检查 product_reports 表中是否已经有一个用于具有 user_id 的用户的条目,例如2,对于 product_id 为 5 的产品。 如果是这样,请求应该以422 http 代码结束,这是如果请求不符合规则的典型 http 代码。

但请记住,user_id 和 product_id 两者的组合必须是唯一的!因为一个用户可以举报多个产品,而一个产品可以被多个用户举报!

我已经在Laravel docs 中找到了unique 验证规则,但我认为它们只适用于请求属性而不是url。在不发送 user_id 和 product_id 作为请求属性的情况下,如何验证这一点?

PS:我使用的是 Laravel 6.x。

亲切的问候!

【问题讨论】:

    标签: php laravel validation eloquent request


    【解决方案1】:

    您可以从创建自定义规则开始:

    MyRules.php

    class MyRules {
        public static function existsForClient($table, $field) {
            return Rule::exists($table, $field)->where(function($query) {
                $query->where('user_id', Auth::user()->id);
            });
        }
    }
    

    并像这样使用该规则:

    function rules() {
      return [
        'value' => [
          'required',
          'string',
          'max:65535',
          MyRules::existsForUser('products', 'product_id'),
        ]
      ];
    
    }
    

    当然你需要为 MyRules 类添加有效的命名空间。

    【讨论】:

    • 那不行。我刚试过。同一用户可以多次为一种产品添加报告。另外,如何检查两列?只需添加第二个查询?
    • @Jan,我已经更新了我的答案,从唯一变为存在。试试看。
    • 不.. 遗憾的是没有工作。我仍然可以插入多个报告...
    • 即使我只想检查product_id 它也不起作用...我已经添加了'unique:products_reports,product_id' 但我仍然可以插入多个报告
    • @Jan 首先,您必须在迁移中做出该约束,换句话说,在数据库表中,您必须制作约束索引,只能保存一种相同的 user_id 和相同的 product_id 。然后,如果适合您的应用程序,您需要进行 PHP 验证,最后进行前端 JS/HTML 验证。此外,验证规则与保存数据无关。这意味着如果发生一些误解,DB 不会阻止保存。为此,您需要设置正确的索引/约束。 IE。 $table->index(['user_id', 'product_id']);Docs.
    【解决方案2】:

    你需要一个自定义规则,比如:

    <?php
    
    namespace App\Rules;
    
    use Illuminate\Contracts\Validation\Rule;
    
    class OneProductPerUser implements Rule
    {
        /**
         * @var int
         */
        private $userId;
        /**
         * @var int
         */
        private $productId;
    
        public function __construct($userId, $productId)
        {
            $this->userId = $userId;
            $this->productId = $this->productId;
        }
    
        /**
         * Determine if the validation rule passes.
         *
         * @param  string  $attribute
         * @param  mixed  $value
         * @return bool
         */
        public function passes($attribute, $value)
        {
            //import the correct Eloquent model of the ProductReport model
            $reports = ProductReport::where('user_id', $this->userId)->where('product_id', $this->productId)->count();
    
            return $reports === 0;
        }
    
        /**
         * Get the validation error message.
         *
         * @return string
         */
        public function message()
        {
            return 'User has already report for this product ID ' . $this->productId;
        }
    }
    

    然后在你的FormRequest 中你需要这样称呼它:

    public function rules()
    {
        return [
            'value' => [
                'required',
                'string',
                'max:65535',
                new OneProductPerUser(Auth::user()->id, $this->route('product'))
            ],
        ];
    }
    

    我还没有检查,但您可以使用 $this-&gt;user()-&gt;id 访问用户对象

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-20
      • 2017-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-28
      • 1970-01-01
      相关资源
      最近更新 更多