【问题标题】:Protect model with validation in Laravel 8在 Laravel 8 中通过验证保护模型
【发布时间】:2021-04-08 17:45:34
【问题描述】:

我有数据库表phones,字段为phone_number。我有一个模型电话。我想以固定格式(已清理)和填充 phone_number(已验证)保存电话

代码中有很多地方需要我或我的同事保存手机。我不相信,他们都会费心检查phone_number 是否已填写且格式正确。而且我不想指望前端JS验证,或数据库NOT NULL检查,...

所以我认为清理和验证 Phone 的最佳位置是模型本身。

如何在 Laravel 8.x 中以最干净的方式做到这一点?

我在互联网上发现了很多类似的问题,但提出的解决方案要么编写大量代码并扭曲框架令人作呕,要么人们根本没有抓住问题。

也许我应该补充一点,我希望这会自动发生。因此,任何尝试以错误格式拨打$phone->save()Phone::create() 电话的人最终都会遇到ValidationException

编辑 2:提供者/观察者 - 我找对方向了吗?

编辑 3:事件?所以在我的模型中,我应该这样做:

use Notifiable;

protected $dispatchesEvents = [
    'validating' => PhoneSanitize::class,
    'saving'     => PhoneValidate::class,
];

编辑 4:或者您认为在模型级别验证数据是个坏主意?我读过这篇文章:

Nikola Poša - Self-validating domain model

在我看来这是个好主意。但是如何在 Laravel 中实现这一点呢?

【问题讨论】:

  • 您是否尝试过创建表单验证?你可以找到更多关于它here
  • 是的,我做到了。但我正在寻找如何在模型中进行验证的方法

标签: laravel validation sanitization laravel-8


【解决方案1】:

所以现在我用 Observer 解决了这个问题。

在 shell 中运行:

php artisan make:observer PhoneObserver --model=Phone

然后在“App/Observers”中你会发现“PhoneObserver”有一些方法。添加方法 "saving(Phone $phone)",您可以在其中清理和验证电话数据。 "saving()" 应该适用于创建和更新你的模型

如果您在此处抛出(特别是!)ValidationException 并带有错误消息,Laravel 将使用该消息将您重定向回您的表单:

/* App/Observers/PhoneObserver.php */

use App\Models\Phone;
use Illuminate\Validation\ValidationException;

class PhoneObserver
{
    public function saving(Phone $phone) 
    {
        /* Do your sanitisation */
        /* Do your validation */
        if (something wrong) {
            throw ValidationException::withMessage(['phone_number' => 'Phone number has wrong format...']);
        }
    }
}

那么你必须在“boot()”方法中的“App/Providers/EventServiceProvider.php”中“注册”这个Observer:

*/ App/Providers/EventServiceProvider.php */

use App\Models\Phone;
use App\Observers\PhoneObserver.php

public function boot()
{
    Phone::observe(PhoneObserver::class);
}

我不知道这是否是最好的地方或最干净的方法,但它现在对我有用,而且我的手机会自动受到保护,不会以错误的格式保存。

希望这对某人有所帮助。我是 Laravel 的新手,我花了数周时间寻找答案。如果我找到更好的方法,我会在这里发布。

【讨论】:

    【解决方案2】:

    在模型级别验证数据是个坏主意,因为验证逻辑更多的是关于表单请求。

    话虽如此,您可以使用Eloquent Mutators 来清理(甚至验证)您在模型中的输入。

    namespace App\Models;
    
    use Illuminate\Support\Facades\Validator;
    
    class Phone extends Model
    {
        // ...
    
        public function setPhoneNumberAttribute($value)
        {
            // Do your sanitization
            // ...
    
            // Do your validation
            Validator::make([
                'phone_number' => $value,
            ], [
                'phone_number' => ['required'], // Define your validation rules
            ])->validate();
    
            $this->attributes['phone_number'] = $value;
        }
    
        // ...
    }
    

    如果验证失败,Illuminate\Validation\ValidationException 将被抛出,用户将被自动重定向,或者在 AJAX 请求的情况下,将返回 JSON 响应。

    【讨论】:

    • 谢谢。但这真的是个坏主意吗?如果我不仅要通过 Web 表单,还要通过 API 或命令行来处理这些数据呢?
    • 如果您想使用命令行并创建自己的控制台命令,您可能需要使用类似Command Validator 的包来验证 Artisan 控制台命令中的输入。
    • 谢谢,我不知道那个包。但在这种情况下,我将不得不编写两次验证规则。那么 API 访问呢?是否有一些 API Validator 包,我将在其中第三次编写相同的验证规则?这不是违反 DRY 原则吗?
    • API 请求本质上是 HTTP 请求。因此,对表单和 API 请求应用相同的验证逻辑是非常好的。为避免重复验证规则,您可以将其存储在模型中的静态属性中,如下所示:public static $rules = [ 'phone_number' => ['required'] ];。然后在模型内部使用self::$rules 访问它,在模型外部使用Phone::$rules 访问它。
    猜你喜欢
    • 2020-05-10
    • 1970-01-01
    • 2013-08-27
    • 2013-03-27
    • 2021-10-25
    • 1970-01-01
    • 2019-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多