【问题标题】:Laravel: Validation unique on updateLaravel:更新时唯一的验证
【发布时间】:2014-06-28 13:32:36
【问题描述】:

我知道这个问题以前被问过很多次,但没有人解释在模型中验证时如何获取 id。

'email' => 'unique:users,email_address,10'

我的验证规则在模型中,那么如何将记录的 ID 传递给验证规则。

这是我的模型/用户

protected $rules_update = [
    'email_address' => 'required|email|unique:users,email_address,'.$id,
    'first_name' => "required",
    'last_name' => "required",
    'password' => "required|min:6|same:password_confirm",
    'password_confirm' => "required:min:6|same:password",
    'password_current' => "required:min:6"
];

模型/基础模型

    protected $rules = array();

public $errors;

/*
    * @data: array, Data to be validated
    * @rules: string, rule name in model 
*/

public function validate($data, $rules = "rules") {

    $validation  = Validator::make($data, $this->$rules);

    if($validation->passes()) {
        return true;
    }

    $this->errors = $validation->messages();

    return false;
}

【问题讨论】:

  • 我也很想知道 $id 是如何传递给模型的。我正在使用 way/database 包并且有同样的问题。
  • 我在下面添加了我的答案。
  • 我也是,遇到同样的问题

标签: php validation laravel laravel-4


【解决方案1】:

Laravel 8.x 中你也可以使用Rule::unique 方法

强制使用唯一规则以忽略给定 ID:

use Illuminate\Validation\Rule;

public function update(Request $request, Post $post)
{
    $validatedData = $request->validate([
        'name' => ['required', 'max:60', Rule::unique('posts')->ignore($post->id)],
    ]);

    $post->update($validatedData);
    
    return redirect(route('posts.index'))->with('status', 'post updated successfully');
}

【讨论】:

    【解决方案2】:

    如果你有一个单独的规则方法。您可以使用更简单的以下语法。

    public function rules()
    {
        return [
            'email' => "required|unique:users,email,{$this->id}"
        ]; 
    }
    

    【讨论】:

      【解决方案3】:

      PUT/PATCH 请求不支持 multipart/form-data 并且不会填充 $_FILES 所以如果您使用 POST 方法UPDATE 然后在 switch 方法中使用路由名称。

      public function rules()
      {
          switch ($this->route()->getName()) {
          case 'users.update':
              $rules = [
              'name'                  => 'required|min:3',
              'gender'                => 'required',
              'email'                 => 'required|email|unique:users,id,:id',
              'password'              => 'required|min:5',
              'password_confirmation' => 'required|min:5|same:password',
              ];
              break;
      
          default:
              $rules = [
                  'name'                  => 'required|min:3',
                  'gender'                => 'required',
                  'email'                 => 'required|email|unique:users',
                  'password'              => 'required|min:5',
                  'password_confirmation' => 'required|min:5|same:password',
              ];
              break;
          }
      
          return $rules;
      }
      

      【讨论】:

        【解决方案4】:

        如果登录用户想要更新电子邮件,则 auth() 辅助函数将为我们提供登录用户 ID auth()->user()->id

        Laravel helpers#method-auth

           Validator::make($data, [
        'email' => [
            'required',
            Rule::unique('users')->ignore(auth()->user()->id),
        ],
        

        ]);

        如果管理员想要更改用户列表中的特定用户信息,那么验证将如下所示:

         Validator::make($data, [
        'email' => [
            'required',
            Rule::unique('users')->ignore($request->user),
        ],
        

        Laravel validation#rule-unique

        $request 对象包含当前路由相关的模型对象。这给出了模型。

        Try dd($request)
        

        【讨论】:

          【解决方案5】:

          很容易做到,

          把它写在你的控制器上

          $this->validate($request,[
               'email'=>['required',Rule::unique('yourTableName')->ignore($request->id)]
          ]);
          Note : Rule::unique('yourTableName')->ignore($idParameter) , here $idParameter you can receive from get url also you can get it from hidden field.
          Most important is don't forget to import Rule at the top.
          

          【讨论】:

            【解决方案6】:

            有一种简单而优雅的方法可以做到这一点。如果您在正文请求中或通过查询参数传递 user_id。 例如

            /update/profile?user_id=
            

            然后在你的请求规则中

              public function rules(Request $request)
                {
                    return [
                        'first_name' => 'required|string',
                        'last_name' => 'required|string',
                        'email' => ['required','email', 'string', Rule::unique('users')->ignore($request->user_id )],
                        'phone_number' => ['required', 'string', Rule::unique('users')->ignore($request->user_id )],
                    ];
                }
            
            

            更好的是,您可以传入auth->id() 代替$request->user_id 来获取登录用户ID。

            【讨论】:

              【解决方案7】:

              最好的选择在这里只尝试一次,当更新数据的唯一验证时不需要更多代码

              'email' => 'unique:users,email_address,' . $userId,
              

              这里email是字段名users是表名email_address是表属性名你想要唯一并且 $userid 正在更新行ID

              【讨论】:

                【解决方案8】:

                在对这个 laravel 验证主题(包括唯一列)进行了大量研究之后,终于找到了最好的方法。请看一下

                在你的控制器中

                    use Illuminate\Http\Request;
                    use Illuminate\Support\Facades\Validator;
                
                    class UserController extends Controller
                    {
                         public function saveUser(Request $request){
                                $validator = Validator::make($request->all(),User::rules($request->get('id')),User::$messages);
                                if($validator->fails()){
                                    return redirect()->back()->withErrors($validator)->withInput();
                                }
                            }
                    }
                

                可以调用saveUser方法添加/更新用户记录。

                在你的模型中

                class User extends Model
                {
                    public static function rules($id = null)
                    {
                        return [
                            'email_address' => 'required|email|unique:users,email_address,'.$id,
                            'first_name' => "required",
                            'last_name' => "required",
                            'password' => "required|min:6|same:password_confirm",
                            'password_confirm' => "required:min:6|same:password",
                            'password_current' => "required:min:6"
                        ];
                    }
                    public static $messages = [
                        'email_address.required' => 'Please enter email!',
                        'email_address.email' => 'Invalid email!',
                        'email_address.unique' => 'Email already exist!',
                        ...
                    ];
                }
                

                【讨论】:

                  【解决方案9】:

                  你可以试试这个。

                  protected $rules_update = [
                      'email_address' => 'required|email|unique:users,email_address,'. $this->id,
                      'first_name' => "required",
                      'last_name' => "required",
                      'password' => "required|min:6|same:password_confirm",
                      'password_confirm' => "required:min:6|same:password",
                      'password_current' => "required:min:6"
                  ];
                  

                  【讨论】:

                    【解决方案10】:

                    它就像一个可以尝试的魅力。在这里,我使用了软删除检查器。如果您的模型没有软删除实现,您可以省略最后一个:id,deleted_at, NULL

                    public function rules()
                    {
                        switch ($this->method()) {
                            case 'PUT':
                                $emailRules = "required|unique:users,email,{$this->id},id,deleted_at,NULL";
                                break;
                            default:
                                $emailRules = "required|unique:users,email,NULL,id,deleted_at,NULL";
                                break;
                        }
                    
                        return [
                            'email' => $emailRules,
                            'display_name' => 'nullable',
                            'description' => 'nullable',
                        ];
                    }
                    

                    谢谢。

                    【讨论】:

                      【解决方案11】:

                      由于您希望在执行更新时忽略正在更新的记录,因此您将希望使用其他人提到的ignore。但我更喜欢接收User 的实例,而不仅仅是一个ID。此方法还允许您对其他模型执行相同操作

                      控制器

                          public function update(UserRequest $request, User $user)
                          {
                              $user->update($request->all());
                      
                              return back();
                          }
                      

                      用户请求

                          public function rules()
                          {
                              return [
                                  'email' => [
                                      'required',
                                      \Illuminate\Validation\Rule::unique('users')->ignoreModel($this->route('user')),
                                  ],
                              ];
                          }
                      

                      更新:使用ignoreModel 代替ignore

                      【讨论】:

                        【解决方案12】:

                        测试以下代码:

                        'email' => 'required|email|unique:users,email_address,'. $id .'ID'
                        

                        其中 ID 是表的主 ID

                        【讨论】:

                          【解决方案13】:

                          测试以下代码:

                          $validator = Validator::make(
                                      array(
                                        'E-mail'=>$request['email'],
                                       ),
                                      array(
                                        'E-mail' => 'required|email|unique:users,email,'.$request['id'],
                                       ));
                          

                          【讨论】:

                          【解决方案14】:

                          如果您不想硬编码表名,也可以使用模型类路径。

                          function rules(){
                              return [
                                  'email' => ['required','string',
                                   Rule::unique(User::class,'email')->ignore($this->id)]
                              ];
                          }
                          

                          这里 $this->id 要么是 0 要么是要更新的记录 ID。

                          【讨论】:

                            【解决方案15】:

                            我阅读了上一篇文章,但没有人解决真正的问题。我们需要使用唯一的规则来应用添加和编辑案例。我在编辑和添加大小写时使用此规则并且工作正常。

                            在我的解决方案中,我使用请求类中的规则函数。

                            1. 我通过编辑表单上的隐藏输入表单字段发送了 ID。
                            2. 在规则功能上,我们通过唯一列查找并获取记录。
                            3. 现在评估情况。如果存在记录和 id 相等,则不能激活唯一性(即编辑记录)。

                            关于代码:

                            public function rules()
                                {
                                    //
                                    $user = User::where('email', $this->email)->first();
                                    //
                                    $this->id = isset($this->id) ? $this->id : null;
                                    $emailRule = (($user != null) && ($user->id == $this->id)) ? 'required|email:rfc,dns|max:255' : 'required|unique:users|email:rfc,dns|max:255';
                                    //        
                                    return [
                                        //
                                        'email'            =>  $emailRule,                
                                        //
                                    ];
                                    //
                            
                            
                                }
                            

                            【讨论】:

                              【解决方案16】:

                              用于 Laravel 6.0

                              use Illuminate\Validation\Rule;
                              
                              public function update(Request $request, $id)
                                  {
                                      // Form validation
                                      $request->validate([
                                          'category_name'   =>  [
                                              'required',
                                              'max:255',
                                               Rule::unique('categories')->ignore($id),
                                          ]
                                      ]);
                              }
                              

                              【讨论】:

                                【解决方案17】:

                                解决办法如下:

                                更新:

                                public function controllerName(Request $request, $id)
                                
                                {
                                
                                    $this->validate($request, [
                                        "form_field_name" => 'required|unique:db_table_name,db_table_column_name,'.$id
                                    ]);
                                
                                    // the rest code
                                }
                                

                                就是这样。快乐编码:)

                                【讨论】:

                                  【解决方案18】:

                                  顺便说一句,这个问题的大多数答案都是关于email_address,而在 Laravel 的内置身份验证系统中,电子邮件字段名称只是 email。这是一个如何验证唯一字段的示例,即有关更新的电子邮件:

                                  Form Request 中,您可以这样做:

                                  public function rules()
                                  {
                                    return [
                                        'email' => 'required|email|unique:users,email,'.$this->user->id,
                                    ];
                                  }
                                  

                                  或者,如果您直接在控制器中验证数据:

                                  public function update(Request $request, User $user)
                                  {
                                    $request->validate([
                                        'email' => 'required|email|unique:users,email,'.$user->id,
                                    ]);
                                  }
                                  

                                  更新: 如果您正在更新登录用户并且没有将User 模型注入您的路由,则在访问id 上的$this->user 时可能会遇到未定义的属性。在这种情况下,请使用:

                                  public function rules()
                                      {
                                        return [
                                            'email' => 'required|email|unique:users,email,'.$this->user()->id,
                                        ];
                                      }
                                  

                                  自 Laravel 5.7 以来更优雅的方式是:

                                  public function rules()
                                  {
                                      return [
                                          'email' => ['required', 'email', \Illuminate\Validation\Rule::unique('users')->ignore($this->user()->id)]
                                      ];
                                  }
                                  

                                  P.S:我添加了一些其他规则,即 required 和 email,以使这个示例对新手更清楚。

                                  【讨论】:

                                  • 我正在使用FormRequest,这正是我需要做的。
                                  • 我应该如何在 FormRequest 中访问/提供 $this->user() 或其他模型?像 ArticleFormRequest 中的 $this->article()
                                  • @KrzysztofDziuba 是否要访问已登录的用户?
                                  • 使用\Illuminate\Validation\Rule::unique()确实是最优雅的方式。对我来说,这是最好的建议。谢谢
                                  • 这非常适合独特的验证。现在我想验证图像以进行更新,但前提是用户上传新的。
                                  【解决方案19】:
                                  $rules = [
                                      "email" => "email|unique:users, email, '.$id.', user_id"
                                  ];
                                  

                                  在 Illuminate\Validation\Rules\Unique 中;

                                  唯一验证会将字符串验证解析为 Rule 对象

                                  唯一验证有模式:unique:%s,%s,%s,%s,%s'

                                  对应:表名、列、忽略、id列、格式wheres

                                  /**
                                   * Convert the rule to a validation string.
                                   *
                                   * @return string
                                   */
                                  public function __toString()
                                  {
                                      return rtrim(sprintf('unique:%s,%s,%s,%s,%s',
                                          $this->table,
                                          $this->column,
                                          $this->ignore ?: 'NULL',
                                          $this->idColumn,
                                          $this->formatWheres()
                                      ), ',');
                                  }
                                  

                                  【讨论】:

                                  • 我喜欢你到达那里的地方。但我只是不确定如何将其应用于模型的规则。我应该在哪里替换 {{$id}}?
                                  【解决方案20】:

                                  我会通过这样做来解决这个问题

                                  public function rules()
                                  {
                                      return [
                                           'name' => 
                                              'required|min:2|max:255|unique:courses,name,'.\Request::get('id'),
                                      ];
                                  }
                                  

                                  从请求中获取 id 并在规则中传递它

                                  【讨论】:

                                  【解决方案21】:

                                  对于控制器中的unique 规则——显然store 方法和update 方法会有所不同,我通常在控制器中为rules 创建一个函数,它将返回一组规则。

                                  protected function rules($request)
                                  {
                                      $commonRules = [
                                          'first_name' => "required",
                                          'last_name' => "required",
                                          'password' => "required|min:6|same:password_confirm",
                                          'password_confirm' => "required:min:6|same:password",
                                          'password_current' => "required:min:6"
                                      ];
                                  
                                      $uniqueRules = $request->id
                                  
                                            //update
                                          ? ['email_address' => ['required', 'email', 'unique:users,email' . $request->get('id')]]
                                  
                                            //store
                                          : ['email_address' => ['required', 'email', 'unique:users,email']];
                                  
                                  
                                      return array_merge($commonRules, $uinqueRules);
                                  }
                                  

                                  然后在各自的storeupdate 方法中

                                  $validatedData = $request->validate($this->rules($request));
                                  

                                  这省去了为存储和更新方法定义两个不同的规则集。

                                  如果你可以在可读性上妥协一点,也可以

                                  protected function rules($request)
                                  {
                                      return [
                                          'first_name' => "required",
                                          'last_name' => "required",
                                          'password' => "required|min:6|same:password_confirm",
                                          'password_confirm' => "required:min:6|same:password",
                                          'password_current' => "required:min:6",
                                          'email_address' => ['required', 'email', 'unique:users,email' . $request->id ?: null]
                                      ];
                                  }
                                  
                                  

                                  【讨论】:

                                  【解决方案22】:

                                  从 Laravel 5.7 开始,效果很好

                                  use Illuminate\Validation\Rule;
                                  
                                  Validator::make($data, [
                                      'email' => [
                                          'required',
                                          Rule::unique('users')->ignore($user->id),
                                      ],
                                  ]);
                                  

                                  Forcing A Unique Rule To Ignore A Given ID:

                                  【讨论】:

                                    【解决方案23】:

                                    使用 5.2 版测试的更简单的解决方案

                                    在你的模型中

                                    // validator rules
                                    public static $rules = array(
                                        ...
                                        'email_address' => 'email|required|unique:users,id'
                                    );
                                    

                                    【讨论】:

                                      【解决方案24】:

                                      在更新任何现有数据写入验证器时:

                                      'email' => ['required','email', Rule::unique('users')->ignore($user->id)]
                                      

                                      这将跳过/忽略现有用户 id 与特定列的唯一值匹配。

                                      【讨论】:

                                        【解决方案25】:

                                        一个简单的解决方案。

                                        在你的模型中

                                        protected $rules = [
                                            'email_address' => 'sometimes|required|email|unique:users',
                                            ..
                                        ];
                                        

                                        在您的控制器中,操作:更新

                                        ...
                                        $rules = User::$rules;
                                        $rules['email_address'] = $rules['email_address'] . ',id,' . $id;
                                        $validationCertificate  = Validator::make($input, $rules); 
                                        

                                        【讨论】:

                                        • 无法访问受保护的属性 App\User::$rules
                                        • @SoubhagyaKumarBarik 你的 Laravel 是什么版本?
                                        • 我的 laravel 版本是 7.x
                                        • @SoubhagyaKumarBarik 我的答案是在 2014 年,适用于 4.x 版。所以,我认为对于第 7 版,您有不同的解决方案。检查下面的其他答案,或在 Stack Overflow 上创建一个新问题,并在此处添加链接以帮助您。
                                        【解决方案26】:

                                        找到最简单的方法,在我使用 Laravel 5.2 时工作正常

                                        public function rules()
                                        
                                        {
                                        
                                        switch ($this->method()) {
                                            case 'PUT':
                                                $rules = [
                                                    'name'                  => 'required|min:3',
                                                    'gender'                => 'required',
                                                    'email'                 => 'required|email|unique:users,id,:id',
                                                    'password'              => 'required|min:5',
                                                    'password_confirmation' => 'required|min:5|same:password',
                                                ];
                                                break;
                                        
                                            default:
                                                $rules = [
                                                    'name'                  => 'required|min:3',
                                                    'gender'                => 'required',
                                                    'email'                 => 'required|email|unique:users',
                                                    'password'              => 'required|min:5',
                                                    'password_confirmation' => 'required|min:5|same:password',
                                                ];
                                                break;
                                        }
                                        
                                        return $rules;
                                        }
                                        

                                        【讨论】:

                                        • 在我的例子中,我无法使用 ":id" 提取 id,所以我做了这样的事情:if (in_array($this->method(), ['PUT', 'PATCH'])) { $rules['order'] .= ",{$this->route('videos')->id}"; }
                                        • "id,:id" 在编辑/更新模式下对我不起作用。谢谢。
                                        【解决方案27】:

                                        有一种优雅的方法可以做到这一点。如果您使用的是资源控制器,则编辑记录的链接将如下所示:

                                        /users/{user}/edit /users/1/edit

                                        在你的 UserRequest 中,规则应该是这样的:

                                        public function rules()
                                        {
                                            return [
                                                'name' => [
                                                    'required',
                                                    'unique:users,name,' . $this->user
                                                ],
                                            ];
                                        }
                                        

                                        或者,如果您的记录编辑链接如下所示:

                                        /users/edit/1

                                        你也可以试试这个:

                                        public function rules()
                                        {
                                            return [
                                                'name' => [
                                                    'required',
                                                    'unique:users,name,' . $this->id
                                                ],
                                            ];
                                        }
                                        

                                        【讨论】:

                                        • 这个答案是最好最优雅的。我有个问题。我的编辑记录的链接看起来像/users/{user}/edit,我想防止我的unique:users,name 能够被更新,而其他字段可以被更新。我将如何实现它?
                                        【解决方案28】:
                                        public function rules()
                                        {
                                        
                                            switch($this->method())
                                            {
                                                case 'GET':
                                                case 'DELETE':
                                                {
                                                    return [];
                                                }
                                                case 'POST':
                                                {
                                                    return [
                                                        'name' => 'required|unique:permissions|max:255',
                                                        'display_name' => 'required',
                                                    ];
                                                }
                                                case 'PUT':
                                                case 'PATCH':
                                                {
                                                    return [                    
                                                        'name' => 'unique:permissions,name,'.$this->get('id').'|max:255',
                                                        'display_name' => 'required',
                                                    ];
                                                }
                                                default:break;
                                            }    
                                        }
                                        

                                        【讨论】:

                                        • 有时,id 可能是 URL 的一部分,因此您会在路由参数中找到它:$this->route({field_name}) 例如:$this->route('id' )
                                        • 最好提及您从laracasts.com/discuss/channels/requests/…复制代码
                                        • 您必须传递带有 id 的隐藏字段才能使用 $this->get('id')
                                        【解决方案29】:

                                        我的解决方案:

                                        $rules = $user->isDirty('email') ? \User::$rules : array_except(\User::$rules, 'email');
                                        

                                        然后在验证中:

                                        $validator = \Validator::make(\Input::all(), $rules, \User::$messages);
                                        

                                        逻辑是如果表单中的email地址不同,我们需要验证它,如果email没有改变,我们不需要验证,所以从验证中删除该规则。

                                        【讨论】:

                                          【解决方案30】:

                                          这就是我最终要做的。我确信有一种更有效的方法可以做到这一点,但这就是我想出的。

                                          模型/用户.php

                                          protected $rules = [
                                              'email_address' => 'sometimes|required|email|unique:users,email_address, {{$id}}',
                                          ];
                                          

                                          模型/BaseModel.php

                                          public function validate($data, $id = null) {
                                          
                                          
                                                $rules = $this->$rules_string;
                                          
                                               //let's loop through and explode the validation rules
                                               foreach($rules as $keys => $value) {
                                          
                                                  $validations = explode('|', $value);
                                          
                                                  foreach($validations as $key=>$value) {
                                          
                                                      // Seearch for {{$id}} and replace it with $id
                                                      $validations[$key] = str_replace('{{$id}}', $id, $value);
                                          
                                                  }
                                                  //Let's create the pipe seperator 
                                                  $implode = implode("|", $validations);
                                                  $rules[$keys] = $implode;
                                          
                                               }
                                               ....
                                          
                                            }
                                          

                                          我将 $user_id 传递给控制器​​中的验证

                                          控制器/用户控制器.php

                                          public function update($id) { 
                                          
                                             .....
                                          
                                              $user = User::find($user_id);
                                          
                                              if($user->validate($formRequest, $user_id)) {
                                                //validation succcess 
                                              } 
                                          
                                              ....
                                          
                                          
                                          }
                                          

                                          【讨论】:

                                          • 我最终只使用了 watson/validating
                                          • 谢谢,我也去看看。
                                          猜你喜欢
                                          • 1970-01-01
                                          • 2014-08-20
                                          • 2018-07-17
                                          • 2018-08-09
                                          • 2019-02-26
                                          • 1970-01-01
                                          • 2021-09-16
                                          • 2015-04-24
                                          • 1970-01-01
                                          相关资源
                                          最近更新 更多