问题描述
我有带有字段 phones
的数据库表 phone_number
。我有一个模型电话。我想以固定格式(已清理)和填充的 phone_number
(已验证)
代码中有很多地方我或我的同事需要保存手机。我不相信,他们都会费心检查 phone_number
是否已填写且格式是否正确。而且我不想指望前端 JS 验证,或数据库 NOT NULL
检查,...
所以我认为清理和验证电话的最佳位置是模型本身。
我怎样才能在 Laravel 8.x 中以最干净的方式做到这一点?
我在互联网上发现了很多这样的问题,但提出的解决方案要么编写了大量代码并令人作呕地扭曲了框架,要么人们根本没有掌握问题。
Mabye 我应该补充一点,我希望这会自动发生。因此,任何尝试以错误格式发送 $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 中实现这一点?
解决方法
所以现在我用 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...']);
}
}
}
然后你必须在 “App/Providers/EventServiceProvider.php” 中的 “boot()” 方法中“注册”这个观察者:
*/ App/Providers/EventServiceProvider.php */
use App\Models\Phone;
use App\Observers\PhoneObserver.php
public function boot()
{
Phone::observe(PhoneObserver::class);
}
我不知道这是最好的地方还是最干净的方法,但它现在对我有用,我的手机会自动保护以免以错误格式保存。
希望这对某人有所帮助。我是 Laravel 的新手,我花了几周时间寻找答案。如果我找到更好的方法,我会在这里发布。
,在模型级别验证数据是一个坏主意,因为验证逻辑更多地与表单请求有关。
话虽如此,您可以使用 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 响应。