php Laravel 更新模型,具有唯一的属性验证规则
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22405762/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Laravel update model with unique validation rule for attribute
提问by Tom Macdonald
I have a laravel Usermodel which has a unique validation rule on usernameand email. In my Repository, when I update the model, I revalidate the fields, so as to not have a problem with required rule validation:
我有一个 LaravelUser模型,它在username和上有一个独特的验证规则email。在我的 Repository 中,当我更新模型时,我会重新验证这些字段,以免出现所需规则验证的问题:
public function update($id, $data) {
$user = $this->findById($id);
$user->fill($data);
$this->validate($user->toArray());
$user->save();
return $user;
}
This fails in testing with
这在测试中失败
ValidationException: {"username":["The username has already been taken."],"email":["The email has already been taken."]}
Is there a way of fixing this elegantly?
有没有办法优雅地解决这个问题?
回答by marcanuy
Append the idof the instance currently being updated to the validator.
将id当前正在更新的实例的附加到验证器。
Pass the
idof your instance to ignore the unique validator.In the validator, use a parameter to detect if you are updatingor creatingthe resource.
传递
id您的实例的 以忽略唯一验证器。在验证器中,使用参数来检测您是在更新还是创建资源。
If updating, force the unique rule to ignore a given id:
如果更新,强制唯一规则忽略给定的 id:
//rules
'email' => 'unique:users,email_address,' . $userId,
If creating, proceed as usual:
如果创建,请照常进行:
//rules
'email' => 'unique:users,email_address',
回答by BaM
Another elegant way...
另一种优雅的方式......
In your model, create a static function:
在您的模型中,创建一个静态函数:
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);
}
Validation on create:
创建时验证:
$validator = Validator::make($input, User::rules());
Validation on update:
更新验证:
$validator = Validator::make($input, User::rules($id));
Validation on update, with some additional rules:
更新验证,以及一些附加规则:
$extend_rules = [
'password' => 'required|min:6|same:password_again',
'password_again' => 'required'
];
$validator = Validator::make($input, User::rules($id, $extend_rules));
Nice.
好的。
回答by Tom Macdonald
Working within my question:
在我的问题内工作:
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;
}
is what I did, based on the accepted answer above.
根据上面接受的答案,这是我所做的。
EDIT: With Form Requests, everything is made simpler:
编辑:使用表单请求,一切都变得更简单:
<?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,
];
}
}
You just need to pass the UpdateUserRequest to your update method, and be sure to POST the model id.
您只需要将 UpdateUserRequest 传递给您的更新方法,并确保发布模型 ID。
回答by user5797691
Unique Validation With Different Column ID In Laravel
Laravel 中不同列 ID 的唯一验证
'UserEmail'=>"required|email|unique:users,UserEmail,$userID,UserID"
回答by cgross
Laravel 5 compatible and generic way:
Laravel 5 兼容和通用方式:
I just had the same problem and solved it in a generic way. If you create an item it uses the default rules, if you update an item it will check your rules for :uniqueand insert an exclude automatically (if needed).
我只是遇到了同样的问题并以通用方式解决了它。如果您创建一个项目,它使用默认规则,如果您更新一个项目,它将检查您的规则 :unique并自动插入排除(如果需要)。
Create a BaseModelclass and let all your models inherit from it:
创建一个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;
}
}
You now define your rules in your model like you are used to:
您现在可以像以前一样在模型中定义规则:
protected static $rules = [
'name' => 'required|alpha|unique:roles',
'displayName' => 'required|alpha_dash',
'permissions' => 'array',
];
And validate them in your Controller. If the model does not validate, it will automatically redirect back to the form with the corresponding validation errors. If no validation errors occurred it will continue to execute the code after it.
并在您的控制器中验证它们。如果模型未验证,它将自动重定向回带有相应验证错误的表单。如果没有发生验证错误,它将在它之后继续执行代码。
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');
}
That's it! :) Note that on creation we call Role::getRules()and on edit we call $role->getUpdateRules().
就是这样!:) 请注意,在创建时我们调用Role::getRules(),在编辑时我们调用$role->getUpdateRules().
回答by Ricardo Canelas
A simple example for roles update
角色更新的简单示例
// 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);
}
}
回答by Angel M.
I have BaseModel class, so I needed something more generic.
我有 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;
}
In user class let's suppose I need only email and name to be validated:
在用户类中,假设我只需要验证电子邮件和姓名:
//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;
}
I tested this with phpunit and works fine.
我用 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 = '[email protected]';
$user->save();
$this->assertTrue($user->isValid($user->id), 'Expected to pass');
}
I hope will help someone, even if for getting a better idea. Thanks for sharing yours as well. (tested on Laravel 5.0)
我希望能帮助某人,即使是为了得到更好的主意。也谢谢你分享你的。(在 Laravel 5.0 上测试)
回答by DaShInG Sid
or what you could do in your Form Request is (for Laravel 5.3+)
或者你可以在你的表单请求中做的是(对于 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
];
}
i've done it in Laravel 5.6 and it worked.
我已经在 Laravel 5.6 中完成了它并且它有效。
回答by Rick
Laravel 5.8 simple and easy
Laravel 5.8 简单易用
you can do this all in a form request with quite nicely. . .
你可以在一个表单请求中很好地完成这一切。. .
first make a field by which you can pass the id (invisible) in the normal edit form. i.e.,
首先创建一个字段,您可以通过该字段在正常编辑表单中传递 id(不可见)。IE,
<div class="form-group d-none">
<input class="form-control" name="id" type="text" value="{{ $example->id }}" >
</div>
... Then be sure to add the Rule class to your form request like so:
...然后确保将 Rule 类添加到您的表单请求中,如下所示:
use Illuminate\Validation\Rule;
... Add the Unique rule ignoring the current id like so:
... 添加忽略当前 id 的 Unique 规则,如下所示:
public function rules()
{
return [
'example_field_1' => ['required', Rule::unique('example_table')->ignore($this->id)],
'example_field_2' => 'required',
];
... Finally type hint the form request in the update method the same as you would the store method, like so:
... 最后在 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);
}
This way you won't repeat code unnecessarily :-)
这样你就不会不必要地重复代码:-)
回答by JITEN CHY
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;
}

