indexzer0 / laravel-validation-provider
简单的可重用可组合验证提供者
Requires
- php: ^8.2
- illuminate/contracts: ^11.0
- illuminate/support: ^11.0
Requires (Dev)
- larastan/larastan: ^2.0.1
- laravel/pint: ^1.0
- nunomaduro/collision: ^8.1
- orchestra/testbench: ^9.0
- pestphp/pest: ^2.34
- pestphp/pest-plugin-arch: ^2.7
- pestphp/pest-plugin-laravel: ^2.0
- phpstan/extension-installer: ^1.1
- phpstan/phpstan-deprecation-rules: ^1.0
- phpstan/phpstan-phpunit: ^1.0
- spatie/laravel-ray: ^1.26
This package is auto-updated.
Last update: 2024-09-17 05:59:11 UTC
README
- 在干净的、可重用的可组合提供者中编写所有验证规则。
- 标准化您在
表单请求
和其他地方定义和使用验证的方式。 - 轻松使用多个验证提供者组合验证规则。
- 方便从
ValidationProvider
直接创建和验证数据。
简单示例
- 在数组中嵌套域模型规则。
use IndexZer0\LaravelValidationProvider\Facades\ValidationProvider; class AuthorValidationProvider extends AbstractValidationProvider { protected array $rules = ['name' => ['required']]; } class BookValidationProvider extends AbstractValidationProvider { protected array $rules = ['title' => ['required']]; } $validationProvider = ValidationProvider::make([ 'author' => [ AuthorValidationProvider::class, new ArrayValidationProvider('books', new BookValidationProvider()), ], ]); $validationProvider->rules(); // [ // 'author.name' => ['required'], // 'author.books.*.title' => ['required'], // ]
要求
安装
您可以通过composer安装此包
composer require indexzer0/laravel-validation-provider
使用
定义验证提供者
- 在验证提供者类中创建域概念的细粒度表示。
- 应扩展
AbstractValidationProvider
。
- 应扩展
通过属性
$rules
,$messages
,$attributes
class AddressValidationProvider extends AbstractValidationProvider { protected array $rules = [ 'post_code' => ['required', 'string', 'between:1,20'], ]; protected array $messages = []; protected array $attributes = []; }
通过方法
class AddressValidationProvider extends AbstractValidationProvider { public function rules(): array { return [ 'post_code' => ['required', 'string', "regex:" . RegexHelper::getPostCodeRegex()], 'zip_code' => ["same:{$this->dependentField('post_code')}"] ]; } public function messages(): array { return []; } public function attributes(): array { return []; } }
创建验证提供者
创建验证提供者有3种方式。外观、手动创建和流畅API。
在所有3个示例中,我们将使用以下两个定义的验证提供者以及此包的核心验证提供者来实现验证规则。
class AuthorValidationProvider extends AbstractValidationProvider { protected array $rules = ['name' => ['required'],]; } class BookValidationProvider extends AbstractValidationProvider { protected array $rules = ['title' => ['required',],]; } // Desired validation rules: // [ // 'author.name' => ['required'], // 'author.books' => ['required', 'array', 'min:1', 'max:2'], // 'author.books.*.title' => ['required'], // ]
外观
use IndexZer0\LaravelValidationProvider\Facades\ValidationProvider; $validationProvider = ValidationProvider::make([ 'author' => [ AuthorValidationProvider::class, new CustomValidationProvider(['books' => ['required', 'array', 'min:1', 'max:2']]), new ArrayValidationProvider('books', new BookValidationProvider()), ], ]); $validationProvider->rules(); // [ // 'author.name' => ['required'], // 'author.books' => ['required', 'array', 'min:1', 'max:2'], // 'author.books.*.title' => ['required'], // ]
手动创建
$validationProvider = new NestedValidationProvider( 'author', new AggregateValidationProvider( new AuthorValidationProvider(), new CustomValidationProvider(['books' => ['required', 'array', 'min:1', 'max:2']]), new ArrayValidationProvider('books', new BookValidationProvider()) ) ); $validationProvider->rules(); // [ // 'author.name' => ['required'], // 'author.books' => ['required', 'array', 'min:1', 'max:2'], // 'author.books.*.title' => ['required'], // ]
流畅API
- 对于流畅API,您从下往上组合验证提供者。
$validationProvider = (new BookValidationProvider()) ->nestedArray('books') ->with(new CustomValidationProvider(['books' => ['required', 'array', 'min:1', 'max:2']])) ->with(AuthorValidationProvider::class) ->nested('author'); $validationProvider->rules(); // [ // 'author.name' => ['required'], // 'author.books' => ['required', 'array', 'min:1', 'max:2'], // 'author.books.*.title' => ['required'], // ]
服务/操作类使用
在您的服务和动作中,提供了->createValidator()
和->validate()
方法以方便使用。
$addressValidationProvider = new AddressValidationProvider(); /** @var Illuminate\Validation\Validator $validator */ $validator = $addressValidationProvider->createValidator($data); /** @var array $validated */ $validated = $addressValidationProvider->validate($data);
表单请求使用
您可以通过两种方法在表单请求中使用验证提供者。
扩展抽象
提供了ValidationProviderFormRequest
以扩展您的表单请求。
使用prepareForValidation
钩子实例化验证提供者。
class StoreAddressRequest extends ValidationProviderFormRequest { public function prepareForValidation() { $this->validationProvider = new AddressValidationProvider(); } }
或使用依赖注入。
// In a service provider. $this->app->when(StoreAddressRequest::class) ->needs(ValidationProvider::class) ->give(AddressValidationProvider::class); class StoreAddressRequest extends ValidationProviderFormRequest { public function __construct(ValidationProvider $validationProvider) { $this->validationProvider = $validationProvider; } }
使用特性装饰
提供了HasValidationProvider
以装饰您的现有表单请求。
有时您没有扩展ValidationProviderFormRequest
的能力。您可以在现有表单请求中使用HasValidationProvider
特性。
class StoreAddressRequest extends YourOwnExistingFormRequest { use HasValidationProvider; public function prepareForValidation() { $this->validationProvider = new AddressValidationProvider(); } }
可用的验证提供者
此包提供了核心类,使您能够组合验证提供者。
聚合验证提供者
- 在相邻组合验证提供者时使用。
class AggregateValidationProvider extends AbstractValidationProvider {} $validationProvider = new AggregateValidationProvider( new AuthorValidationProvider(), new BookValidationProvider(), ); $validationProvider->rules(); // [ // 'name' => ['required'], // From AuthorValidationProvider. // 'title' => ['required'], // From BookValidationProvider. // ]
嵌套验证提供者
- 在想要在数组中嵌套验证提供者时使用。
class NestedValidationProvider extends AbstractValidationProvider {} $validationProvider = new NestedValidationProvider( 'author', new AuthorValidationProvider(), ); $validationProvider->rules(); // [ // 'author.name' => ['required'], // From AuthorValidationProvider. // ]
数组验证提供者
class ArrayValidationProvider extends NestedValidationProvider {} $validationProvider = new ArrayValidationProvider('books', new BookValidationProvider()); $validationProvider->rules(); // [ // 'books.*.title' => ['required'], // From BookValidationProvider. // ]
自定义验证提供者
- 当需要验证数据而不创建专门的ValidationProvider类时使用。
class CustomValidationProvider extends AbstractValidationProvider {} $customRules = [ 'books' => ['required', 'array', 'min:1', 'max:2'], ]; $customMessages = [ 'books.required' => 'Provide :attribute' ]; $customAttributes = [ 'books' => 'BOOKS' ]; $validationProvider = new CustomValidationProvider($customRules, $customMessages, $customAttributes); $validationProvider->rules(); // [ // 'books' => ['required', 'array', 'min:1', 'max:2'], // ]
排除属性验证提供者
- 有时你可能想要从验证提供者中移除某些属性。
class ExcludeAttributesValidationProvider extends AbstractValidationProvider {} $validationProvider = new ExcludeAttributesValidationProvider( ['one'], new CustomValidationProvider([ 'one' => ['required'], 'two' => ['required'] ]) ); $validationProvider->rules(); // [ // 'two' => ['required'], // ]
映射属性验证提供者
- 有时你可能想要重命名一个属性。
class MapAttributesValidationProvider extends AbstractValidationProvider {} $validationProvider = new MapAttributesValidationProvider( ['one' => 'two'], new CustomValidationProvider([ 'one' => ['required'], ]) ); $validationProvider->rules(); // [ // 'two' => ['required'], // ]
深入了解
使用流畅API
使用外观
ValidationProvider::make(ValidationProviderInterface|string|array $config): ValidationProviderInterface
- 可以使用完全限定的类名字符串。
// Returns AuthorValidationProvider $validationProvider = ValidationProvider::make(AuthorValidationProvider::class);
- 无效的类名字符串会抛出异常。
// throws ValidationProviderExceptionInterface try { $validationProvider = ValidationProvider::make('This is an invalid fqcn string'); } catch (\IndexZer0\LaravelValidationProvider\Contracts\ValidationProviderExceptionInterface $exception) { $exception->getMessage(); // Class must be a ValidationProvider }
- 可以使用验证提供者对象。本质上不起作用。
// Returns AuthorValidationProvider (same object) $validationProvider = ValidationProvider::make(new AuthorValidationProvider());
- 可以使用数组(完全限定的类名字符串和对象)。
// Returns AuthorValidationProvider $validationProvider = ValidationProvider::make([ AuthorValidationProvider::class, ]); // Returns AggregateValidationProvider $validationProvider = ValidationProvider::make([ AuthorValidationProvider::class, new BookValidationProvider() ]);
- 数组字符串键创建
NestedValidationProvider
。
// Returns NestedValidationProvider $validationProvider = ValidationProvider::make([ 'author' => [ AuthorValidationProvider::class, ], ]);
- 空数组是无效的。
// throws ValidationProviderExceptionInterface try { $validationProvider = ValidationProvider::make([]); } catch (\IndexZer0\LaravelValidationProvider\Contracts\ValidationProviderExceptionInterface $exception) { $exception->getMessage(); // Empty array provided }
组合验证提供者
用例
- 你可能有一些需要为多个域概念验证数据的应用程序部分。
- 你可能希望在嵌套数组中验证数据,而不在规则定义中引入重复。
示例
让我们看看3个路由示例以及如何重用你的Validation Providers。
- 路由:address
- 存储地址信息
- 使用
AddressValidationProvider
/* * ------------------ * Address * ------------------ */ Route::post('address', StoreAddress::class); class StoreAddress extends Controller { public function __invoke(StoreAddressRequest $request) {} } class StoreAddressRequest extends ValidationProviderFormRequest { public function prepareForValidation() { $this->validationProvider = new AddressValidationProvider(); } }
- 路由:contact-details
- 存储联系信息
- 使用
ContactValidationProvider
/* * ------------------ * Contact * ------------------ */ Route::post('contact-details', StoreContactDetails::class); class StoreContactDetails extends Controller { public function __invoke(StoreContactDetailsRequest $request) {} } class StoreContactDetailsRequest extends ValidationProviderFormRequest { public function prepareForValidation() { $this->validationProvider = new ContactValidationProvider(); } }
- 路由:profile
- 存储地址和联系信息。
- 使用
AddressValidationProvider
ContactValidationProvider
NestedValidationProvider
(底层由Facade实现)AggregateValidationProvider
(底层由Facade实现)
/* * ------------------ * Profile * ------------------ */ Route::post('profile', StoreProfile::class); class StoreProfile extends Controller { public function __invoke(StoreProfileRequest $request) {} } class StoreProfileRequest extends ValidationProviderFormRequest { public function prepareForValidation() { $this->validationProvider = ValidationProvider::make([ 'profile' => [ 'address' => AddressValidationProvider::class 'contact' => ContactValidationProvider::class ] ]); } }
依赖规则
- 当使用任何相关规则时,应使用
$this->dependentField()
辅助函数。- 这确保了在使用
NestedValidationProvider
和ArrayValidationProvider
时,相关字段将具有正确的嵌套。
- 这确保了在使用
class PriceRangeValidationProvider extends AbstractValidationProvider { public function rules(): array { return [ 'min_price' => ["lt:{$this->dependentField('max_price')}"], 'max_price' => ["gt:{$this->dependentField('min_price')}"], ]; } } $validationProvider = new NestedValidationProvider( 'product', new PriceRangeValidationProvider() ); $validationProvider->rules(); // [ // "product.min_price" => [ // "lt:product.max_price" // ] // "product.max_price" => [ // "gt:product.min_price" // ] // ]
错误处理
该包抛出的所有异常都实现了\IndexZer0\LaravelValidationProvider\Contracts\ValidationProviderExceptionInterface
。
然而,也捕获\Throwable
不会造成伤害。
try { $validationProvider = ValidationProvider::make('This is an invalid fqcn string'); } catch (\IndexZer0\LaravelValidationProvider\Contracts\ValidationProviderExceptionInterface $exception) { $exception->getMessage(); // Class must be a ValidationProvider } catch (\Throwable $t) { // Shouldn't happen - but failsafe. }
包提供
// Interface interface ValidationProvider {} // Validation Providers abstract class AbstractValidationProvider implements ValidationProvider {} class AggregateValidationProvider extends AbstractValidationProvider {} class NestedValidationProvider extends AbstractValidationProvider {} class ArrayValidationProvider extends NestedValidationProvider {} class CustomValidationProvider extends AbstractValidationProvider {} class ExcludeAttributesValidationProvider extends AbstractValidationProvider {} class MapAttributesValidationProvider extends AbstractValidationProvider {} // Form Request class ValidationProviderFormRequest extends \Illuminate\Foundation\Http\FormRequest {} trait HasValidationProvider {} // Facade class ValidationProvider extends \Illuminate\Support\Facades\Facade {}
测试
composer test
变更日志
请参阅变更日志以获取有关最近更改的更多信息。
贡献
请参阅贡献指南以获取详细信息。
致谢
许可
MIT许可证(MIT)。请参阅许可文件以获取更多信息。