如何使用数据转换器
编辑本页警告:您正在浏览的文档欧宝官网下载appob娱乐下载Symfony 6.0,现已不再维护。
读本页的更新版本用于Syob娱乐下载mfony 6.2(当前稳定版本)。
如何使用数据转换器
数据转换器用于将字段的数据转换为可以在表单中显示的格式(并在提交时返回)。它们已经在内部用于许多字段类型。例如,DateType字段可以呈现为yyyy-MM-dd
格式的输入文本框。在内部,数据转换器转换DateTime
字段的值yyyy-MM-dd
在呈现表单时格式化字符串,然后返回到DateTime
对象在提交时。
谨慎
属性时inherit_data
选项设置为真正的
,数据转换器并不应用于该领域。
另请参阅
如果不是转换值的表示形式,而是需要将值映射到表单字段并返回,则应该使用数据映射器。看看何时以及如何使用数据映射器.
示例#1:将字符串从用户输入的数据标签转换为数组
假设您有一个带有标记的Task表单文本
类型:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/ / src /形式/类型/ TaskType.php名称空间应用程序\形式\类型;使用应用程序\实体\任务;使用ob娱乐下载\组件\形式\扩展\核心\类型\TextType;使用ob娱乐下载\组件\形式\FormBuilderInterface;使用ob娱乐下载\组件\OptionsResolver\OptionsResolver;/ /……类TaskType扩展AbstractType{公共函数buildForm(FormBuilderInterface$构建器数组,$选项):无效{$构建器->add (“标签”, TextType::类);}公共函数configureOptions(OptionsResolver$解析器):无效{$解析器->setDefaults ([“data_class”= >任务::类,]);}/ /……}
在内部的标签
存储为数组,但显示给用户为逗号分隔的普通字符串,以便于编辑。
这是一个完美的对象上附加自定义数据转换器的时间到了标签
字段。最简单的方法是用CallbackTransformer类:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/ / src /形式/类型/ TaskType.php名称空间应用程序\形式\类型;使用ob娱乐下载\组件\形式\CallbackTransformer;使用ob娱乐下载\组件\形式\扩展\核心\类型\TextType;使用ob娱乐下载\组件\形式\FormBuilderInterface;/ /……类TaskType扩展AbstractType{公共函数buildForm(FormBuilderInterface$构建器数组,$选项):无效{$构建器->add (“标签”, TextType::类);$构建器->get (“标签”)->addModelTransformer (新CallbackTransformer (函数($tagsAsArray){//将数组转换为字符串返回内爆(”、“,$tagsAsArray);},函数($tagsAsString){//将字符串转换回数组返回爆炸(”、“,$tagsAsString);}));}/ /……}
的CallbackTransformer
接受两个回调函数作为参数。第一个函数将原始值转换为用于呈现字段的格式。第二种则相反:它将提交的值转换回您将在代码中使用的格式。
提示
的addModelTransformer ()
方法接受任何实现的对象DataTransformerInterface-所以你可以创建自己的类,而不是把所有的逻辑都放在表单中(见下一节)。
你也可以添加转换器,在添加字段时稍微改变格式:
1 2 3 4 5 6 7
使用ob娱乐下载\组件\形式\扩展\核心\类型\TextType;$构建器->add ($构建器->创建(“标签”, TextType::类)->addModelTransformer (/ *……* /));
示例#2:将问题编号转换为问题实体
假设你有一个从任务实体到问题实体的多对一关系(即每个任务都有一个可选的外键指向其相关的问题)。添加一个包含所有可能问题的列表框最终会得到真的时间长,加载时间长。相反,您决定添加一个文本框,用户可以在其中输入问题编号。
首先像往常一样设置文本字段:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/ / src /形式/类型/ TaskType.php名称空间应用程序\形式\类型;使用应用程序\实体\任务;使用ob娱乐下载\组件\形式\扩展\核心\类型\TextareaType;使用ob娱乐下载\组件\形式\扩展\核心\类型\TextType;/ /……类TaskType扩展AbstractType{公共函数buildForm(FormBuilderInterface$构建器数组,$选项):无效{$构建器->add (“描述”, TextareaType::类)->add (“问题”, TextType::类);}公共函数configureOptions(OptionsResolver$解析器):无效{$解析器->setDefaults ([“data_class”= >任务::类,]);}/ /……}
好的开始!但如果你停在这里,提交表单,任务问题
属性将是一个字符串(例如:“55”)。你怎么把这个转化成问题
实体提交?
创建变压器
你可以使用CallbackTransformer
就像早些时候。但是由于这有点复杂,因此创建一个新的转换器类将保留TaskType
形式类更简单。
创建一个IssueToNumberTransformer
类:它将负责从发行号和问题
对象:
12 34 56 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
/ / src /形式/ DataTransformer / IssueToNumberTransformer.php名称空间应用程序\形式\DataTransformer;使用应用程序\实体\问题;使用学说\ORM\EntityManagerInterface;使用ob娱乐下载\组件\形式\DataTransformerInterface;使用ob娱乐下载\组件\形式\异常\TransformationFailedException;类IssueToNumberTransformer实现了DataTransformerInterface{公共函数__construct(私人EntityManagerInterface$entityManager){}/** *将对象(issue)转换为字符串(number)。* *@paramIssue|null $ Issue */公共函数变换($问题):字符串{如果(零= = =$问题) {返回”;}返回$问题->getId ();}/** *将字符串(数字)转换为对象(问题)。* *@param字符串$issueNumber *@throws如果object (issue)未找到,TransformationFailedException异常。* /公共函数reverseTransform($issueNumber): ?问题{//没有发行号?这是可选的,所以没关系如果(!$issueNumber) {返回零;}$问题=$这->entityManager->getRepository(问题::类)//查询带有此id的问题->找到($issueNumber);如果(零= = =$问题) {//导致验证错误//该消息不显示给用户//查看invalid_message选项扔新TransformationFailedException (sprintf (“数字“%s”不存在问题!”,$issueNumber));}返回$问题;}}
与第一个示例一样,转换器有两个方向。的变换()
方法负责将代码中使用的数据转换为可以在您的表单中呈现的格式(例如问题
其对象id
,一个字符串)。的reverseTransform ()
方法执行相反的操作:它将提交的值转换回您想要的格式(例如,将id
回到问题
对象)。
若要导致验证错误,抛出TransformationFailedException.但是传递给这个异常的消息不会显示给用户。设置该消息invalid_message
选项(见下文)。
请注意
当零
传递给变换()
方法,您的转换器应该返回它要转换到的类型的等效值(例如,空字符串,整数为0或浮点数为0.0)。
使用变压器
接下来,您需要使用IssueToNumberTransformer
的内部对象TaskType
把它加到问题
字段。没问题!添加一个__construct ()
方法和类型提示新类:
12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
/ / src /形式/类型/ TaskType.php名称空间应用程序\形式\类型;使用应用程序\形式\DataTransformer\IssueToNumberTransformer;使用ob娱乐下载\组件\形式\扩展\核心\类型\TextareaType;使用ob娱乐下载\组件\形式\扩展\核心\类型\TextType;/ /……类TaskType扩展AbstractType{私人$变压器;公共函数__construct(IssueToNumberTransformer$变压器){$这->变压器=$变压器;}公共函数buildForm(FormBuilderInterface$构建器数组,$选项):无效{$构建器->add (“描述”, TextareaType::类)->add (“问题”, TextType::类,如果数据转换器失败,则发送验证消息“invalid_message”= >“这不是有效的发行号”]);/ /……$构建器->get (“问题”)->addModelTransformer ($这->变压器);}/ /……}
每当转换器抛出异常时,invalid_message
显示给用户。方法在数据转换器中设置最终用户错误消息,而不是每次都显示相同的消息setInvalidMessage ()
方法。它还允许你包含用户价值:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/ / src /形式/ DataTransformer / IssueToNumberTransformer.php名称空间应用程序\形式\DataTransformer;使用ob娱乐下载\组件\形式\DataTransformerInterface;使用ob娱乐下载\组件\形式\异常\TransformationFailedException;类IssueToNumberTransformer实现了DataTransformerInterface{/ /……公共函数reverseTransform($issueNumber): ?问题{/ /……如果(零= = =$问题) {$privateErrorMessage= sprintf (“数字“%s”不存在问题!”,$issueNumber);$publicErrorMessage=“给定的“{{value}}”值不是有效的发行号。”;$失败=新TransformationFailedException ($privateErrorMessage);$失败->setInvalidMessage ($publicErrorMessage, (“{{value}}”= >$issueNumber]);扔$失败;}返回$问题;}}
就是这样!如果你在用默认的服务。yaml的配置, ob娱乐下载Symfony将自动知道通过您的TaskType
的实例IssueToNumberTransformer
多亏了自动装配而且可以使用autoconfigure.否则,将表单类注册为服务而且标记它与form.type
标签。
现在你可以用你的TaskType
:
1 2 3 4
//例如,在控制器的某个地方$形式=$这->createForm (TaskType::类,$任务);/ /……
酷,你完成了!您的用户将能够在文本字段中输入一个问题编号,该数字将被转换回issue对象。这意味着,在成功提交之后,Form组件将传递一个实问题
对象任务::setIssue ()
而不是发行号。
方法将为该字段创建一个表单错误,并且其错误消息可以用invalid_message
场的选择。
谨慎
在添加变压器时要小心。例如,下面是错误的,因为转换器将被应用到整个表单,而不仅仅是这个字段:
1 2 3 4
//这是错误的- transformer将被应用到整个表单//查看上面的示例以获得正确的代码$构建器->add (“问题”, TextType::类)->addModelTransformer ($变压器);
创建一个可重用的issue_selector字段
在上面的示例中,您将变压器应用到法线上文本
字段。但如果你经常做这个变换,可能会更好创建自定义字段类型.这是自动的。
首先,创建自定义字段类型类:
12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/ / src /形式/ IssueSelectorType.php名称空间应用程序\形式;使用应用程序\形式\DataTransformer\IssueToNumberTransformer;使用ob娱乐下载\组件\形式\AbstractType;使用ob娱乐下载\组件\形式\扩展\核心\类型\TextType;使用ob娱乐下载\组件\形式\FormBuilderInterface;使用ob娱乐下载\组件\OptionsResolver\OptionsResolver;类IssueSelectorType扩展AbstractType{私人$变压器;公共函数__construct(IssueToNumberTransformer$变压器){$这->变压器=$变压器;}公共函数buildForm(FormBuilderInterface$构建器数组,$选项):无效{$构建器->addModelTransformer ($这->变压器);}公共函数configureOptions(OptionsResolver$解析器):无效{$解析器->setDefaults ([“invalid_message”= >“所选问题不存在”]);}公共函数getParent():字符串{返回TextType::类;}}
太棒了!这将像文本字段(getParent ()
),但会自动拥有数据转换器而且的良好默认值invalid_message
选择。
只要你在用自动装配而且可以使用autoconfigure,你可以立即开始使用此表格:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/ / src /形式/类型/ TaskType.php名称空间应用程序\形式\类型;使用应用程序\形式\DataTransformer\IssueToNumberTransformer;使用ob娱乐下载\组件\形式\扩展\核心\类型\TextareaType;/ /……类TaskType扩展AbstractType{公共函数buildForm(FormBuilderInterface$构建器数组,$选项):无效{$构建器->add (“描述”, TextareaType::类)->add (“问题”, IssueSelectorType::类);}/ /……}
提示
如果你不吸毒的话自动装配
而且可以使用autoconfigure
,请参阅如何创建自定义表单字段类型如何配置您的新IssueSelectorType
.
关于模型和视图变形金刚
在上面的例子中,变压器被用作“模型”变压器。事实上,有两种不同类型的变压器和三种不同类型的底层数据。
在任何形式下,三种不同类型的数据是:
- 模型数据-这是在您的应用程序中使用的格式的数据(例如
问题
对象)。如果你打电话形式::getData ()
或形式::setData ()
,您正在处理“模型”数据。 - 规范数据-这是数据的规范化版本,通常与“模型”数据相同(尽管在我们的例子中不是这样)。通常不直接使用。
- 视图数据-这是用来填写表单字段本身的格式。它也是用户提交数据的格式。当你打电话时
形式:提交(元数据)
,元数据
是“视图”数据格式。
两种不同类型的变压器帮助转换这些类型的数据:
- 变形金刚模型:
-
变换()
: "model data" => "norm data"reverseTransform ()
: "norm data" => "model data"
- 看变形金刚:
-
变换()
: "norm data" => "view data"reverseTransform ()
: "view data" => "norm data"
您需要哪种变压器取决于您的情况。
要使用视图转换器,请调用addViewTransformer ()
.
谨慎
小心模型变压器和集合字段类型。集合的子节点是在PRE_SET_DATA
由其ResizeFormListener
它们的数据稍后从规范化的数据中填充。因此,您的模型转换器不能减少集合中的项的数量(即过滤掉一些项),因为在这种情况下,集合最终会有一些空的子项。
对于这种限制,一种可能的解决方法是不直接使用底层对象,而是使用DTO(数据传输对象)来实现这种不兼容数据结构的转换。
那么为什么要使用模型转换器呢?
在本例中,字段为a文本
字段,而文本字段总是被期望是“norm”和“view”格式中的简单标量格式。由于这个原因,最合适的变压器是“模型”变压器(它转换为/从规范格式-字符串发行号-到模型format -发布对象)。
转换器之间的差异是微妙的,您应该始终考虑一个字段的“规范”数据应该是什么。例如,a的“规范”数据文本
字段是一个字符串,但是是DateTime
对象的日期
字段。
提示
作为一般规则,规范化的数据应该包含尽可能多的信息。