【问题标题】:Laravel update model with unique validation rule for attributeLaravel 更新模型,具有唯一的属性验证规则
【发布时间】:2014-04-19 18:56:34
【问题描述】:

我有一个 Laravel User 模型,它在 usernameemail 上有一个唯一的验证规则。在我的存储库中,当我更新模型时,我会重新验证字段,以免出现必需的规则验证问题:

public function update($id, $data) {
    $user = $this->findById($id);
    $user->fill($data);
    $this->validate($user->toArray());
    $user->save();

    return $user;
}

测试失败:

ValidationException: {"username":["用户名已经被 已采取。"],"email":["电子邮件已被采取。"]}

有没有办法优雅地解决这个问题?

【问题讨论】:

    标签: php laravel validation eloquent


    【解决方案1】:

    或者您可以在表单请求中执行的操作是(对于 Laravel 5.3+)

    public function rules()
    {
        return [ 
            'email' => 'required|email|unique:users,email,'. $this->user
             //here user is users/{user} from resource's route url
        ];
    }
    

    我已经在 Laravel 5.6 中完成了它,并且成功了。

    【讨论】:

    • 这是最简单最简单的答案
    【解决方案2】:

    它将工作 100% 我有两种案例实现,例如一种情况是数据库表产品中的相同表单字段,另一种是 products_name 是表单字段,在表中,它的名称是名称,我们如何在更新时验证和忽略该 id。我已经加密了,所以我解密了 id,如果你是加密的,那么你会解密,否则会通过它,因为它来自表单。

     $request->validate([
                    'product_code' => 'required|unique:products,product_code,'.decrypt($request->hiddenProductId),
                    'products_name' => 'required|unique:products,name,'.decrypt($request->hiddenProductId),
                    
                ]);
    

    【讨论】:

      【解决方案3】:

      对于任何使用表单请求的人

      就我而言,我尝试了以下所有方法,但都没有奏效:

      $this->id$this->user->id$this->user

      这是因为我无法直接访问模型 $id$id

      所以我从查询中得到了$id,它使用了我要验证的相同unique 字段:

          /**
       * Get the validation rules that apply to the request.
       *
       * @return array
       */
      public function rules()
      {
          $id = YourModel::where('unique_field',$this->request->get('unique_field'))->value('id');
          return [
              'unique_field' => ['rule1','rule2',Rule::unique('yourTable')->ignore($id)],
          ];
      }
      

      【讨论】:

        【解决方案4】:
        public function rules()
        {
            if ($this->method() == 'PUT') {
                $post_id = $this->segment(3);
                $rules = [
                    'post_title' => 'required|unique:posts,post_title,' . $post_id
                ];
            } else {
                $rules = [
                    'post_title' => 'required|unique:posts,post_title'
                ];
            }
            return $rules;
        }
        

        【讨论】:

          【解决方案5】:

          Laravel 5.8 简单易用

          你可以在一个表单请求中很好地完成这一切。 . .

          首先创建一个字段,您可以通过该字段在正常编辑表单中传递 id(不可见)。即,

           <div class="form-group d-none">
                <input class="form-control" name="id" type="text" value="{{ $example->id }}" >
           </div>
          

          ... 然后确保将 Rule 类添加到您的表单请求中,如下所示:

          use Illuminate\Validation\Rule;
          

          ... 添加唯一规则忽略当前 id,如下所示:

          public function rules()
          {
              return [
                    'example_field_1'  => ['required', Rule::unique('example_table')->ignore($this->id)],
                    'example_field_2'  => 'required',
          
              ];
          

          ... 最后在 update 方法中输入提示表单请求,就像在 store 方法中一样:

           public function update(ExampleValidation $request, Examle $example)
          {
              $example->example_field_1 = $request->example_field_1;
              ...
              $example->save();
          
              $message = "The aircraft was successully updated";
          
          
              return  back()->with('status', $message);
          
          
          }
          

          这样你就不会不必要地重复代码:-)

          【讨论】:

            【解决方案6】:

            对于自定义 FormRequest 和 Laravel 5.7+,您可以像这样获取更新模型的 id:

            public function rules()
                {
                    return [
                        'name' => 'required|min:5|max:255|unique:schools,name,'.\Request::instance()->id
                    ];
                }
            

            【讨论】:

              【解决方案7】:

              将当前正在更新的实例的id 附加到验证器。

              1. 传递实例的id 以忽略唯一验证器。

              2. 在验证器中,使用参数来检测您是更新还是创建资源。

              如果更新,强制唯一规则忽略给定的 id:

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

              如果创建,照常进行:

              //rules
              'email' => 'unique:users,email_address',
              

              【讨论】:

              • 那么 User-ID 与电子邮件地址相关还是什么?
              • 好的。假设,如果您正在更新已经存在的电子邮件地址,那么如何找到呢?
              • 请看这个问题需要帮助stackoverflow.com/questions/39591620/…
              • @xcy7e 웃: laravel.com/docs/5.3/validation unique:table,column,except,idColumn
              • 它是否仅适用于unique,意味着我在lte 中使用它作为'order'=&gt; 'lte:products,stock,2' 但它不起作用为什么?
              【解决方案8】:

              如果您有另一列用作外键或索引,那么您也必须在这样的规则中指定它。

              'phone' => [
                              "required",
                              "phone",
                              Rule::unique('shops')->ignore($shopId, 'id')->where(function ($query) {
                                  $query->where('user_id', Auth::id());
                              }),
                          ],
              

              【讨论】:

                【解决方案9】:

                你可以试试下面的代码

                return [
                    'email' => 'required|email|max:255|unique:users,email,' .$this->get('id'),
                    'username' => 'required|alpha_dash|max:50|unique:users,username,'.$this->get('id'),
                    'password' => 'required|min:6',
                    'confirm-password' => 'required|same:password',
                ];
                

                【讨论】:

                • 你能再解释一下吗?
                【解决方案10】:
                'email' => [
                    'required',
                    Rule::exists('staff')->where(function ($query) {
                        $query->where('account_id', 1);
                    }),
                ],
                
                'email' => [
                    'required',
                    Rule::unique('users')->ignore($user->id)->where(function ($query) {
                        $query->where('account_id', 1);
                    })
                ],
                

                【讨论】:

                • 它适用于 laravel 5.3 版本
                • 你应该在答案中格式化代码(我已经为你做了)。此外,一般来说,答案不应该只是没有备注的代码 - 您可能需要添加简短说明,说明为什么此特定代码对这种情况有帮助。
                【解决方案11】:

                我遇到了同样的问题。 我所做的:在我的视图中添加带有模型 id 的隐藏字段,并在验证器中检查唯一性,前提是我从视图中获得了一些 id。

                $this->validate(
                        $request,
                        [
                            'index'       => implode('|', ['required', $request->input('id') ? '' : 'unique:members']),
                            'name'        => 'required',
                            'surname'     => 'required',
                        ]
                );
                

                【讨论】:

                  【解决方案12】:

                  解决我的问题:

                  public function update($id, $data) {
                      $user = $this->findById($id);
                      $user->fill($data);
                      $this->validate($user->toArray(), $id);
                      $user->save();
                      return $user;
                  }
                  
                  
                  public function validate($data, $id=null) {
                      $rules = User::$rules;
                      if ($id !== null) {
                          $rules['username'] .= ",$id";
                          $rules['email'] .= ",$id";
                      }
                      $validation = Validator::make($data, $rules);
                      if ($validation->fails()) {
                          throw new ValidationException($validation);
                      }
                      return true;
                  }
                  

                  是我所做的,基于上面接受的答案。

                  编辑:使用表单请求,一切都变得更简单:

                  <?php namespace App\Http\Requests;
                  
                  class UpdateUserRequest extends Request
                  {
                      /**
                       * Determine if the user is authorized to make this request.
                       *
                       * @return bool
                       */
                      public function authorize()
                      {
                          return true;
                      }
                  
                      /**
                       * Get the validation rules that apply to the request.
                       *
                       * @return array
                       */
                      public function rules()
                      {
                          return [
                              'name' => 'required|unique:users,username,'.$this->id,
                              'email' => 'required|unique:users,email,'.$this->id,
                          ];
                      }
                  }
                  

                  您只需将 UpdateUserRequest 传递给您的更新方法,并确保 POST 模型 ID。

                  【讨论】:

                  • 您在哪里发布 ID?
                  【解决方案13】:

                  Laravel 中不同列 ID 的唯一验证

                  'UserEmail'=>"required|email|unique:users,UserEmail,$userID,UserID"
                  

                  【讨论】:

                  • 只有这个对我有用。因为在 MongoDB 中的主列是_id,所以其他答案对我不起作用。
                  【解决方案14】:
                  public static function custom_validation()
                  {
                      $rules = array('title' => 'required ','description'  => 'required','status' => 'required',);
                      $messages = array('title.required' => 'The Title must be required','status.required' => 'The Status must be required','description.required' => 'The Description must be required',);
                      $validation = Validator::make(Input::all(), $rules, $messages);
                      return $validation;
                  }
                  

                  【讨论】:

                    【解决方案15】:

                    Laravel 5 兼容和通用方式:

                    我刚刚遇到了同样的问题,并以通用的方式解决了它。如果您创建一个项目,它会使用默认规则,如果您更新一个项目,它将检查您的 :unique 规则并自动插入排除项(如果需要)。

                    创建一个BaseModel 类并让所有模型都继承自它:

                    <?php namespace App;
                    
                    use Illuminate\Database\Eloquent\Model;
                    
                    class BaseModel extends Model {
                    
                        /**
                         * The validation rules for this model
                         *
                         * @var array
                         */
                        protected static $rules = [];
                    
                        /**
                         * Return model validation rules
                         *
                         * @return array
                         */
                        public static function getRules() {
                            return static::$rules;
                        }
                    
                        /**
                         * Return model validation rules for an update
                         * Add exception to :unique validations where necessary
                         * That means: enforce unique if a unique field changed.
                         * But relax unique if a unique field did not change
                         *
                         * @return array;
                         */
                        public function getUpdateRules() {
                            $updateRules = [];
                            foreach(self::getRules() as $field => $rule) {
                                $newRule = [];
                                // Split rule up into parts
                                $ruleParts = explode('|',$rule);
                                // Check each part for unique
                                foreach($ruleParts as $part) {
                                    if(strpos($part,'unique:') === 0) {
                                        // Check if field was unchanged
                                        if ( ! $this->isDirty($field)) {
                                            // Field did not change, make exception for this model
                                            $part = $part . ',' . $field . ',' . $this->getAttribute($field) . ',' . $field;
                                        }
                                    }
                                    // All other go directly back to the newRule Array
                                    $newRule[] = $part;
                                }
                                // Add newRule to updateRules
                                $updateRules[$field] = join('|', $newRule);
                    
                            }
                            return $updateRules;
                        }
                    }    
                    

                    您现在可以像以前一样在模型中定义规则:

                    protected static $rules = [
                        'name' => 'required|alpha|unique:roles',
                        'displayName' => 'required|alpha_dash',
                        'permissions' => 'array',
                    ];
                    

                    并在您的控制器中验证它们。如果模型没有验证,它会自动重定向回带有相应验证错误的表单。如果没有发生验证错误,它将继续执行之后的代码。

                    public function postCreate(Request $request)
                    {
                        // Validate
                        $this->validate($request, Role::getRules());
                        // Validation successful -> create role
                        Role::create($request->all());
                        return redirect()->route('admin.role.index');
                    }
                    
                    public function postEdit(Request $request, Role $role)
                    {
                        // Validate
                        $this->validate($request, $role->getUpdateRules());
                        // Validation successful -> update role
                        $role->update($request->input());
                        return redirect()->route('admin.role.index');
                    }
                    

                    就是这样! :) 请注意,在创建时我们调用Role::getRules(),在编辑时我们调用$role-&gt;getUpdateRules()

                    【讨论】:

                      【解决方案16】:

                      角色更新的简单示例


                      // model/User.php
                      class User extends Eloquent
                      {
                      
                          public static function rolesUpdate($id)
                          {
                              return array(
                                  'username'              => 'required|alpha_dash|unique:users,username,' . $id,
                                  'email'                 => 'required|email|unique:users,email,'. $id,
                                  'password'              => 'between:4,11',
                              );
                          }
                      }       
                      

                      .

                      // controllers/UsersControllers.php
                      class UsersController extends Controller
                      {
                      
                          public function update($id)
                          {
                              $user = User::find($id);
                              $validation = Validator::make($input, User::rolesUpdate($user->id));
                      
                              if ($validation->passes())
                              {
                                  $user->update($input);
                      
                                  return Redirect::route('admin.user.show', $id);
                              }
                      
                              return Redirect::route('admin.user.edit', $id)->withInput()->withErrors($validation);
                          }
                      
                      }
                      

                      【讨论】:

                        【解决方案17】:

                        我正在为 Store 和 Update 调用不同的验证类。在我的情况下,我不想更新每个字段,所以我有用于创建和编辑的公共字段的基本规则。为每个添加额外的验证类。我希望我的例子有帮助。我正在使用 Laravel 4。

                        型号:

                        public static $baseRules = array(
                            'first_name' => 'required',
                            'last_name'  => 'required',
                            'description' => 'required',
                            'description2' => 'required',
                            'phone'  => 'required | numeric',
                            'video_link'  => 'required | url',
                            'video_title'  => 'required | max:87',
                            'video_description'  => 'required',
                            'sex' => 'in:M,F,B',
                            'title'  => 'required'
                        );
                        
                        public static function validate($data)
                        {
                            $createRule = static::$baseRules;
                            $createRule['email'] = 'required | email | unique:musicians';
                            $createRule['band'] = 'required | unique:musicians';
                            $createRule['style'] = 'required';
                            $createRule['instrument'] = 'required';
                            $createRule['myFile'] = 'required | image';
                        
                            return Validator::make($data, $createRule);
                        }
                        
                        public static function validateUpdate($data, $id)
                        {
                            $updateRule = static::$baseRules;
                            $updateRule['email'] = 'required | email | unique:musicians,email,' . $id;
                            $updateRule['band'] = 'required | unique:musicians,band,' . $id;
                            return Validator::make($data, $updateRule);
                        }
                        

                        控制器: 存储方式:

                        public function store()
                        {
                            $myInput = Input::all();
                            $validation = Musician::validate($myInput);
                            if($validation->fails())
                            {
                                $key = "errorMusician";
                                return Redirect::to('musician/create')
                                ->withErrors($validation, 'musicain')
                                ->withInput();
                            }
                        }
                        

                        更新方法:

                        public function update($id) 
                        {
                            $myInput = Input::all();
                            $validation = Musician::validateUpdate($myInput, $id);
                            if($validation->fails())
                            {
                                $key = "error";
                                $message = $validation->messages();
                                return Redirect::to('musician/' . $id)
                                ->withErrors($validation, 'musicain')
                                ->withInput();
                            }
                        }
                        

                        【讨论】:

                          【解决方案18】:

                          我有 BaseModel 类,所以我需要更通用的东西。

                          //app/BaseModel.php
                          public function rules()
                          {
                              return $rules = [];
                          }
                          public function isValid($id = '')
                          {
                          
                              $validation = Validator::make($this->attributes, $this->rules($id));
                          
                              if($validation->passes()) return true;
                              $this->errors = $validation->messages();
                              return false;
                          }
                          

                          在用户类中,假设我只需要验证电子邮件和姓名:

                          //app/User.php
                          //User extends BaseModel
                          public function rules($id = '')
                          {
                              $rules = [
                                          'name' => 'required|min:3',
                                          'email' => 'required|email|unique:users,email',
                                          'password' => 'required|alpha_num|between:6,12',
                                          'password_confirmation' => 'same:password|required|alpha_num|between:6,12',
                                      ];
                              if(!empty($id))
                              {
                                  $rules['email'].= ",$id";
                                  unset($rules['password']);
                                  unset($rules['password_confirmation']);
                              }
                          
                              return $rules;
                          }
                          

                          我用 phpunit 对此进行了测试并且工作正常。

                          //tests/models/UserTest.php 
                          public function testUpdateExistingUser()
                          {
                              $user = User::find(1);
                              $result = $user->id;
                              $this->assertEquals(true, $result);
                              $user->name = 'test update';
                              $user->email = 'ddd@test.si';
                              $user->save();
                          
                              $this->assertTrue($user->isValid($user->id), 'Expected to pass');
                          
                          }
                          

                          我希望对某人有所帮助,即使是为了获得更好的想法。也谢谢你分享你的。 (在 Laravel 5.0 上测试)

                          【讨论】:

                            【解决方案19】:

                            另一种优雅的方式...

                            在你的模型中,创建一个静态函数:

                            public static function rules ($id=0, $merge=[]) {
                                return array_merge(
                                    [
                                        'username'  => 'required|min:3|max:12|unique:users,username' . ($id ? ",$id" : ''),
                                        'email'     => 'required|email|unique:member'. ($id ? ",id,$id" : ''),
                                        'firstname' => 'required|min:2',
                                        'lastname'  => 'required|min:2',
                                        ...
                                    ], 
                                    $merge);
                            }
                            

                            创建时验证:

                            $validator = Validator::make($input, User::rules());
                            

                            更新验证:

                            $validator = Validator::make($input, User::rules($id));
                            

                            更新验证,附加一些规则:

                            $extend_rules = [
                                'password'       => 'required|min:6|same:password_again',
                                'password_again' => 'required'
                            ];
                            $validator = Validator::make($input, User::rules($id, $extend_rules));
                            

                            不错。

                            【讨论】:

                            • 非常好!为了让我以这种方式工作,我需要以下内容:'email' =&gt; 'required|email|unique:member'. ($id ? ",id,$id" : '')
                            猜你喜欢
                            • 2020-09-13
                            • 1970-01-01
                            • 2015-02-27
                            • 2016-04-08
                            • 2019-11-15
                            • 2018-05-24
                            • 1970-01-01
                            • 1970-01-01
                            相关资源
                            最近更新 更多