cuyz / valinor-bundle
`cuyz/valinor`的Symfony集成——一个帮助将任何输入映射到强类型值对象结构的库。
Requires
- php: ~8.1.0 || ~8.2.0 || ~8.3.0
- cuyz/valinor: ^1.0
- symfony/config: ^5.4 || ^6.4 || ^7.0
- symfony/dependency-injection: ^5.4 || ^6.4 || ^7.0
- symfony/http-kernel: ^5.4 || ^6.4 || ^7.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.21
- infection/infection: ^0.27.0
- marcocesarato/php-conventional-changelog: ^1.17
- phpstan/phpstan: ^1.10
- phpstan/phpstan-phpunit: ^1.3
- phpstan/phpstan-strict-rules: ^1.5
- phpstan/phpstan-symfony: ^1.3
- phpunit/phpunit: ^10.2
- symfony/console: ^5.4 || ^6.4 || ^7.0
- symfony/framework-bundle: ^5.4 || ^6.4 || ^7.0
- symfony/runtime: ^5.4 || ^6.4 || ^7.0
README
Valinor库的Symfony集成。
Valinor负责将原始输入(JSON、普通数组等)构建和验证为对象,确保其处于完全有效状态。它允许在整个应用程序生命周期中使用这些对象,而不必担心其完整性。
验证系统将检测任何不正确的值,并通过提供精确且易于理解的错误消息来帮助开发者。
映射器可以处理原生PHP类型以及PHPStan和Psalm支持的其它高级类型,如形状数组、泛型、整数范围等。
安装
composer require cuyz/valinor-bundle
// config/bundles.php return [ // … CuyZ\ValinorBundle\ValinorBundle::class => ['all' => true], ];
映射器注入
可以将映射器实例注入任何带有类型TreeMapper
的自定义服务。
use CuyZ\Valinor\Mapper\TreeMapper; final class SomeAutowiredService { public function __construct( private TreeMapper $mapper, ) {} public function someMethod(): void { $this->mapper->map(SomeDto::class, /* … */); // … } }
它还可以手动注入到服务中...
...使用PHP文件
// config/services.php use CuyZ\Valinor\Mapper\TreeMapper; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; return static function (ContainerConfigurator $container): void { $container ->services() ->set(\Acme\SomeService::class) ->args([ service(TreeMapper::class), ]); };
...使用YAML文件
services: Acme\SomeService: arguments: - '@CuyZ\Valinor\Mapper\TreeMapper'
为了更精细的控制,可以注入一个MapperBuilder
实例。
use CuyZ\Valinor\Mapper\MapperBuilder; final class SomeAutowiredService { public function __construct( private MapperBuilder $mapperBuilder, ) {} public function someMethod(): void { $this->mapperBuilder // … // Some mapper configuration // … ->mapper() ->map(SomeDto::class, /* … */); // … } }
包配置
包的全球配置可以在配置文件中完成...
...使用PHP文件
// config/packages/valinor.php return static function (Symfony\Config\ValinorConfig $config): void { // Date formats that will be supported by the mapper by default. $config->mapper()->dateFormatsSupported(['Y-m-d', 'Y-m-d H:i:s']); // For security reasons, exceptions thrown in a constructor will not be // caught by the mapper unless they are specifically allowed by giving their // class names to the configuration below. $config->mapper()->allowedExceptions([ \Webmozart\Assert\InvalidArgumentException::class, \App\CustomException::class, ]); // When a mapping error occurs during a console command, the output will // automatically be enhanced to show information about errors. The maximum // number of errors that will be displayed can be configured below, or set // to 0 to disable this feature entirely. $config->console()->mappingErrorsToOutput(15); // By default, mapper cache entries are stored in the filesystem. This can // be changed by setting the name of a PSR-16 cache service below. $config->cache()->service('app.custom_cache'); // Cache entries representing class definitions won't be cleared when files // are modified during development of the application. This can be changed // by setting in which environments cache entries will be unvalidated. $config->cache()->envWhereFilesAreWatched(['dev', 'custom_env']); };
...使用YAML文件
# config/packages/valinor.yaml valinor: mapper: # Date formats that will be supported by the mapper by default. date_formats_supported: - 'Y-m-d' - 'Y-m-d H:i:s' # For security reasons, exceptions thrown in a constructor will not be # caught by the mapper unless they are specifically allowed by giving # their class names to the configuration below. allowed_exceptions: - \Webmozart\Assert\InvalidArgumentException - \App\CustomException, console: # When a mapping error occurs during a console command, the output will # automatically be enhanced to show information about errors. The # maximum number of errors that will be displayed can be configured # below, or set to 0 to disable this feature entirely. mapping_errors_to_output: 15 cache: # By default, mapper cache entries are stored in the filesystem. This # can be changed by setting the name of a PSR-16 cache service below. service: app.custom_cache # Cache entries representing class definitions won't be cleared when # files are modified during development of the application. This can be # changed by setting in which environments cache entries will be # unvalidated. env_where_files_are_watched: [ 'dev', 'custom_env' ]
其他功能
自定义映射器构建器
可以通过实现接口MapperBuilderConfigurator
来自定义服务映射器构建器。
注意
如果此服务自动配置,它将自动使用,否则需要使用标签valinor.mapper_builder_configurator
标记。
use CuyZ\Valinor\MapperBuilder; use CuyZ\ValinorBundle\Configurator\MapperBuilderConfigurator final class ConstructorRegistrationConfigurator implements MapperBuilderConfigurator { public function configure(MapperBuilder $builder): MapperBuilder { return $builder ->registerConstructor(SomeDTO::create(...)) ->registerConstructor(SomeOtherDTO::new(...)); } }
使用属性配置映射器行为
可以使用属性自动自定义映射器行为。
警告
此功能仅适用于自动注入的服务。
-
EnableFlexibleCasting
—— 改变了映射器关于类型灵活性的几个行为。有关更多信息,请阅读文档。 -
AllowSuperfluousKeys
—— 允许在源数组中有冗余键,防止在值未绑定到任何对象属性/参数或形状数组元素时出错。有关更多信息,请阅读文档。 -
AllowPermissiveTypes
—— 允许在映射时使用宽泛的类型mixed
和object
。 -
SupportDateFormats
—— 配置映射器支持的日期格式。
use CuyZ\Valinor\Mapper\TreeMapper; use CuyZ\ValinorBundle\Configurator\Attributes\AllowPermissiveTypes; use CuyZ\ValinorBundle\Configurator\Attributes\AllowSuperfluousKeys; use CuyZ\ValinorBundle\Configurator\Attributes\EnableFlexibleCasting; use CuyZ\ValinorBundle\Configurator\Attributes\SupportDateFormats; final class SomeService { public function __construct( #[EnableFlexibleCasting] private TreeMapper $mapperWithFlexibleCasting, // or… #[AllowSuperfluousKeys] private TreeMapper $mapperWithSuperfluousKeys, // or… #[AllowPermissiveTypes] private TreeMapper $mapperWithPermissiveTypes, // or… #[SupportDateFormats('Y-m-d', 'Y/m/d')] private TreeMapper $mapperWithCustomDateFormat, // or a combination of the above… #[EnableFlexibleCasting, AllowSuperfluousKeys, …] private TreeMapper $mapperWithSeveralAttributes, ) {} }
还可以通过使用接口MapperBuilderConfiguratorAttribute
声明自定义配置器属性。
use Attribute; use CuyZ\Valinor\MapperBuilder; use CuyZ\ValinorBundle\Configurator\Attributes\MapperBuilderConfiguratorAttribute; #[Attribute(Attribute::TARGET_PARAMETER)] final class SomeCustomConfigurator implements MapperBuilderConfiguratorAttribute { public function configure(MapperBuilder $builder): MapperBuilder { return $builder ->enableFlexibleCasting() ->allowSuperfluousKeys() ->supportDateFormats('Y/m/d'); } }
然后可以在服务中使用它
use CuyZ\Valinor\Mapper\TreeMapper; use CuyZ\ValinorBundle\Configurator\Attributes\SomeCustomConfigurator; final class SomeService { public function __construct( #[SomeCustomConfigurator] private TreeMapper $mapperWithCustomConfig ) {} }
控制台命令中的映射错误
当使用Symfony Console运行命令时,将捕获映射错误以增强输出,并提供更好的错误原因。
注意
可以配置将在包配置中显示的最大错误数在这里。
输出示例
$ bin/console some:command Mapping errors -------------- A total of 3 errors were found while trying to map to `Acme\Customer` -------- ------------------------------------------------------------------------- path message -------- ------------------------------------------------------------------------- id Value 'John' is not a valid integer. name Value 42 is not a valid string. email Cannot be empty and must be filled with a value matching type `string`. -------- ------------------------------------------------------------------------- [INFO] The above message was generated by the Valinor Bundle, it can be disabled in the configuration of the bundle.
缓存预热
当使用Symfony的缓存预热功能——通常是bin/console cache:warmup
——映射器缓存将自动为所有带有标签valinor.warmup
的类进行预热。
此标签可以通过服务配置手动添加,或者使用WarmupForMapper
属性自动为autoconfigured classes
添加。
#[\CuyZ\ValinorBundle\Cache\WarmupForMapper] final readonly class ClassThatWillBeWarmedUp { public function __construct( public string $foo, public int $bar, ) {} }
注意
WarmupForMapper
属性会禁用分配给类的依赖注入自动绑定。尽管在大多数情况下,为将被映射器实例化的类进行自动绑定没有意义,但在某些情况下可能仍然需要,这时可以将属性的$autowire
参数设置为true
。