ChatGPT解决这个技术问题 Extra ChatGPT

Laravel 更新模型,具有唯一的属性验证规则

我有一个 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":["电子邮件已被占用。"]}

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


j
joshuamabina

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

传递您的实例的 id 以忽略唯一验证器。在验证器中,使用参数来检测您是否正在更新或创建资源。

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

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

如果创建,照常进行:

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

那么用户 ID 与电子邮件地址相关还是什么?
好的。假设,如果您正在更新已经存在的电子邮件地址,那么如何找到它?
请看这个问题需要帮助stackoverflow.com/questions/39591620/…
@xcy7e 웃:laravel.com/docs/5.3/validation unique:table,column,except,idColumn
这对我来说是最好的解决方案谢谢!
B
BaM

另一种优雅的方式...

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

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' => 'required|email|unique:member'. ($id ? ",id,$id" : '')
T
Tom Macdonald

在我的问题范围内工作:

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 传递给您的更新方法,并确保发布模型 ID。


你在哪里发布ID?
C
CoderPi

Laravel 中不同列 ID 的唯一验证

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

只有这个对我有用。因为在 MongoDB 的主列是 _id,其他答案对我不起作用。
E
Emtiaz Zahid

或者您可以在表单请求中执行的操作是(对于 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 中完成了它并且它有效。


这是最简单最容易的答案
c
cgross

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',
];

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

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()


A
Angel M.

我有 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 上测试)


R
Ricardo Canelas

角色更新的简单示例

// 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);
    }

}

D
Dan Lowe
'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 版本
您应该在答案中格式化代码(我已经为您完成了)。此外,一般来说,答案不应该只是没有备注的代码 - 您可能想要添加一个简短的解释,说明为什么这个特定代码对这种情况有帮助。
C
Chaudhry Waqas

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

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

O
Oat

我正在为 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();
    }
}

r
rink.attendant.6
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;
}

v
vlkrm

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

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

l
luongit

你可以试试下面的代码

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',
];

你能再解释一下吗?
R
Rick

Laravel 5.8 简单易上手

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

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

 <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);


}

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


J
JITENDRA CHOUDHARY
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;
}

s
steve

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

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

M
Makdous

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

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

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

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

因此,我使用要验证的同一 unique 字段从查询中获得了 $id

    /**
 * 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)],
    ];
}

K
Kaleemullah

它将 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),
                
            ]);

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅