Php 具有唯一属性验证规则的Laravel更新模型
我有一个laravelPhp 具有唯一属性验证规则的Laravel更新模型,php,laravel,validation,eloquent,Php,Laravel,Validation,Eloquent,我有一个laravel用户模型,它在用户名和电子邮件上有一个唯一的验证规则。在我的存储库中,当我更新模型时,我会重新验证字段,以便不出现所需规则验证的问题: public function update($id, $data) { $user = $this->findById($id); $user->fill($data); $this->validate($user->toArray()); $user->save();
用户
模型,它在用户名
和电子邮件
上有一个唯一的验证规则。在我的存储库中,当我更新模型时,我会重新验证字段,以便不出现所需规则验证的问题:
public function update($id, $data) {
$user = $this->findById($id);
$user->fill($data);
$this->validate($user->toArray());
$user->save();
return $user;
}
这在测试中失败
ValidationException: {"username":["The username has already been taken."],"email":["The email has already been taken."]}
有没有办法优雅地解决这个问题?将当前正在更新的实例的
id
附加到验证器中
id
,以忽略唯一验证器//rules
'email' => 'unique:users,email_address,' . $userId,
如果要创建,请照常进行:
//rules
'email' => 'unique:users,email_address',
根据我的问题:
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,
];
}
}
另一种优雅的方式
在模型中,创建静态函数:
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));
很好。我有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上测试)Laravel 5兼容和通用方式:
<?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,
];
}
}
我只是遇到了同样的问题,并以一种通用的方式解决了它。如果您创建一个项目,它将使用默认规则;如果您更新一个项目,它将检查您的规则是否为: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;
}
}
并在控制器中验证它们。如果模型未验证,它将自动重定向回带有相应验证错误的表单。如果没有发生验证错误,它将在验证后继续执行代码
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->getUpdateRules()
我调用不同的验证类来存储和更新。在我的例子中,我不想更新每个字段,所以我有创建和编辑公共字段的基本规则。为每个类添加额外的验证类。我希望我的例子有帮助。我用的是Laravel4
型号:
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();
}
}
角色更新的一个简单示例
Laravel中具有不同列ID的唯一验证
'UserEmail'=>"required|email|unique:users,UserEmail,$userID,UserID"
我也有同样的问题。
我所做的:在我的视图隐藏字段中添加一个模型的id,并在验证器中检查唯一性,前提是我从视图中获得了一些id
$this->validate(
$request,
[
'index' => implode('|', ['required', $request->input('id') ? '' : 'unique:members']),
'name' => 'required',
'surname' => 'required',
]
);
你可以试试下面的代码
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',
];
如果您有另一列用作外键或索引,那么您必须在规则中也这样指定它
'phone' => [
"required",
"phone",
Rule::unique('shops')->ignore($shopId, 'id')->where(function ($query) {
$query->where('user_id', Auth::id());
}),
],
或者您可以在您的申请表中做什么(对于Laravel 5.3+)
我已经在Laravel 5.6中完成了这项工作,并且工作正常。对于自定义FormRequest和Laravel 5.7+您可以获得更新模型的id,如下所示:
public function rules()
{
return [
'name' => 'required|min:5|max:255|unique:schools,name,'.\Request::instance()->id
];
}
Laravel 5.8简单易用
您可以在一个表单请求中完成这一切,非常好地
首先创建一个字段,通过该字段可以以正常编辑形式传递id(不可见)。i、 e
<div class="form-group d-none">
<input class="form-control" name="id" type="text" value="{{ $example->id }}" >
</div>
。。。添加忽略当前id的唯一规则,如下所示:
public function rules()
{
return [
'example_field_1' => ['required', Rule::unique('example_table')->ignore($this->id)],
'example_field_2' => 'required',
];
。。。最后,在update方法中键入与store方法相同的hint表单请求,如下所示:
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);
}
这样,您就不会对使用表单请求的任何人重复不必要的代码:-)
就我而言,我尝试了以下所有方法,但均无效:
$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)],
];
}
很不错的!为了让我的邮件以这种方式工作,我需要以下内容:“email”=>“required”| email | unique:member”。($id?”,id,$id:“)
那么用户id与电子邮件地址相关吗?确定。假设,如果您正在更新已经存在的电子邮件地址,那么如何找到它?请查看此问题需要帮助@xcy7e웃: <代码>唯一:表,列,除了,idColumn
它是否仅适用于唯一
,意味着我在lte
中使用它作为“order”=>“lte:products,stock,2'
但它不起作用为什么?你在哪里发布ID?它适用于laravel 5.3版本你应该在答案中格式化代码(我为你做了)。另外,一般来说,答案不应该只是没有注释的代码-您可能需要添加一个简短的解释,说明为什么这个代码对这种情况有帮助。您能再解释一下吗?只有这个代码对我有效。因为在MongoDB中,主列是\u id
,所以其他答案对我来说并不适用。
public function rules()
{
return [
'name' => 'required|min:5|max:255|unique:schools,name,'.\Request::instance()->id
];
}
<div class="form-group d-none">
<input class="form-control" name="id" type="text" value="{{ $example->id }}" >
</div>
use Illuminate\Validation\Rule;
public function rules()
{
return [
'example_field_1' => ['required', Rule::unique('example_table')->ignore($this->id)],
'example_field_2' => 'required',
];
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);
}
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;
}
/**
* 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)],
];
}