形式

编辑本页

警告:您正在浏览的文档欧宝体育电话欧宝娱乐app下载地址Symfony 2.4,现已不再维护。

本页的更新版本用于Sy欧宝娱乐app下载地址mfony 6.2(当前稳定版本)。

形式

处理HTML表单是web开发人员最常见也是最具挑战性的任务之一。欧宝娱乐app下载地址Symfony集成了一个Form组件,使处理表单变得容易。在本章中,您将从头开始构建一个复杂的表单,并在此过程中学习表单库的最重要特性。

请注意

Symf欧宝娱乐app下载地址ony Form组件是一个独立的库,可以在Symfony项目之外使用。有关更多信息,请参见欧宝娱乐app下载地址Symfony窗体组件在GitHub上。

创建简单表单

假设您正在构建一个简单的待办事项列表应用程序,需要显示“任务”。因为您的用户需要编辑和创建任务,所以您需要构建一个表单。但在你开始之前,首先关注一般任务表示和存储单个任务数据的类:

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 / Acme / / Task.php TaskBundle /实体名称空间AcmeTaskBundle实体任务受保护的任务受保护的dueDate公共函数getTask()返回->任务;}公共函数setTask任务->任务=任务;}公共函数getDueDate()返回->dueDate;}公共函数setDueDate(\ DateTimedueDate= null)->dueDate =dueDate;}}

请注意

如果您正在按照这个示例编写代码,请创建AcmeTaskBundle首先运行以下命令(并接受所有默认选项):

1
$ php app/控制台生成:bundle——namespace=Acme/TaskBundle

这个类是一个“普通的老php对象”,因为到目前为止,它与Symfony或任何其他库都没有关系。欧宝娱乐app下载地址它只是直接解决内部问题的普通PHP对象<新兴市场>你的应用程序(即需要在应用程序中表示任务)。当然,在本章结束时,您将能够向a提交数据任务实例(通过HTML表单),验证其数据,并将其持久化到数据库中。

构建表单

现在您已经创建了一个任务类,下一步是创建并呈现实际的HTML表单。在Sy欧宝娱乐app下载地址mfony中,这是通过构建一个表单对象,然后在模板中呈现它来完成的。现在,这一切都可以在控制器内部完成:

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 / Acme / TaskBundle /控制器/ DefaultController.php名称空间AcmeTaskBundle控制器使用欧宝娱乐app下载地址FrameworkBundle控制器控制器使用AcmeTaskBundle实体任务使用欧宝娱乐app下载地址组件HttpFoundation请求DefaultController扩展控制器公共函数newAction(请求请求//创建一个任务并为它提供一些虚拟数据任务任务();任务->setTask (“写一篇博客”);任务->setDueDate (\ DateTime (“明天”));形式->createFormBuilder (任务->add (“任务”“文本”->add (“dueDate”“日期”->add (“保存”“提交”数组“标签”= >“创建发布”))->getForm ();返回->呈现(“AcmeTaskBundle:违约:new.html.twig”数组“形式”= >形式->createView ()));}}

提示

这个示例向您展示了如何直接在控制器中构建表单。后来,在“形式部分,您将学习如何在一个独立的类中构建表单,当您的表单变得可重用时,建议您这样做。

创建表单只需要相对较少的代码,因为Symfony表单对象是用“表单构建器”构建的。欧宝娱乐app下载地址表单构建器的目的是允许您编写简单的表单“食谱”,并让它完成实际构建表单的所有繁重工作。

在本例中,您向表单中添加了两个字段-任务而且dueDate-对应任务而且dueDate的属性任务类。你还为每个人分配了一个“类型”(例如:文本日期),它决定为该字段呈现哪个HTML表单标记。

最后,您添加了一个带有自定义标签的提交按钮,用于向服务器提交表单。

2.3

在Symfony 2.3中引入了对提交按钮的支持。欧宝娱乐app下载地址在此之前,您必须手动向表单的HTML添加按钮。

欧宝娱乐app下载地址Symfony附带了许多内置类型,稍后将讨论这些类型(参见形式).

渲染表单

现在已经创建了表单,下一步是呈现它。这是通过向模板传递一个特殊的表单“view”对象来实现的(注意形式- > createView ()在上面的控制器中),并使用一组表单帮助函数:

  • 嫩枝
  • PHP
1 2 3
{# src / Acme / TaskBundle /资源/视图/ / new.html违约。树枝#}{{form(form)}}

请注意

本例假设您在“POST”请求中提交表单,并将其提交到显示表单的相同URL。稍后您将了解如何更改请求方法和表单的目标URL。

就是这样!通过印刷形式(形式),将呈现表单中的每个字段,以及标签和错误消息(如果有的话)。的形式函数还包含必要的HTML中的所有内容< >形式标签。尽管这很简单,但它(目前)还不是很灵活。通常,您希望单独呈现每个表单字段,以便可以控制表单的外观。你会在"形式”一节。

在继续之前,请注意如何渲染任务字段的值任务属性中的美元的任务对象(即。“写一篇博客”)。这是表单的第一项工作:从对象中获取数据,并将其转换为适合在HTML表单中呈现的格式。

提示

表单系统足够智能,可以访问受保护的值任务通过getTask ()而且setTask ()方法任务类。除非一个属性是公共的,否则它<新兴市场>必须有一个“getter”和“setter”方法,这样Form组件就可以获取数据并将数据放到属性上。对于一个布尔属性,你可以使用“isser”或“hasser”方法(例如:发表()hasReminder ())而不是getter(例如。个短篇()getReminder ()).

处理递交表格

表单的第二项工作是将用户提交的数据转换回对象的属性。要做到这一点,必须将用户提交的数据写入表单。添加以下功能到你的控制器:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/ /……使用欧宝娱乐app下载地址组件HttpFoundation请求公共函数newAction(请求请求//设置一个新的$task对象(删除虚拟数据)任务任务();形式->createFormBuilder (任务->add (“任务”“文本”->add (“dueDate”“日期”->add (“保存”“提交”数组“标签”= >“创建发布”))->getForm ();形式->handleRequest (请求);如果形式->isValid ()) {//执行一些操作,例如将任务保存到数据库返回->重定向(->generateUrl (“task_success”));}/ /……

2.3

handleRequest ()方法是在Symfony 2.3中引入的。欧宝娱乐app下载地址在此之前,美元的请求被传给了提交method——一个已弃用的策略,将在Symfony 3.0中被移除。欧宝娱乐app下载地址有关该方法的详细信息,请参见如何使用submit()函数来处理表单提交

该控制器遵循处理表单的通用模式,并有三种可能的路径:

  1. 最初在浏览器中加载页面时,只需创建并呈现表单。handleRequest ()确认表单未提交并且不执行任何操作。isValid ()返回如果没有提交表格。
  2. 当用户提交表单时,handleRequest ()识别此错误并立即将提交的数据写回任务而且dueDate的属性美元的任务对象。然后验证该对象。如果它无效(验证将在下一节中讨论),isValid ()返回同样,表单与所有验证错误一起呈现;

    请注意

    你可以使用这个方法isSubmitted ()检查表单是否已提交,而不管提交的数据是否实际有效。

  3. 当用户提交带有有效数据的表单时,再次将提交的数据写入表单,但这一次不同isValid ()返回真正的.方法执行一些操作美元的任务对象(例如将其持久化到数据库),然后将用户重定向到其他页面(例如“谢谢”或“成功”页面)。

    请注意

    在成功提交表单后重定向用户会阻止用户点击浏览器的“刷新”按钮并重新发布数据。

提交带有多个按钮的表单

2.3

在Symfony 2.3中引入了对表单中按钮的支持。欧宝娱乐app下载地址

当表单包含多个提交按钮时,您将希望检查单击了哪个按钮以适应控制器中的程序流。要做到这一点,添加第二个按钮,标题为“保存并添加”到您的表单:

1 2 3 4 5 6
形式->createFormBuilder (任务->add (“任务”“文本”->add (“dueDate”“日期”->add (“保存”“提交”数组“标签”= >“创建发布”))->add (“saveAndAdd”“提交”数组“标签”= >“保存并添加”))->getForm ();

在你的控制器中,使用按钮那么回事()查询是否点击“保存并添加”按钮的方法:

1 2 3 4 5 6 7 8 9
如果形式->isValid ()) {/ /……执行一些操作,例如将任务保存到数据库nextAction形式->get (“saveAndAdd”->那么回事()?“task_new”“task_success”返回->重定向(->generateUrl (nextAction));}

表单验证

在前一节中,您了解了如何提交带有有效或无效数据的表单。在Sy欧宝娱乐app下载地址mfony中,验证应用于底层对象(例如。任务).换句话说,问题不在于“形式”是否有效,而在于“形式”是否有效美元的任务对象在表单向其应用提交的数据后有效。调用美元形式- > isValid ()是问的快捷方式美元的任务对象,无论它是否具有有效数据。

验证是通过向类添加一组规则(称为约束)来完成的。要查看实际情况,请添加验证约束,以便任务字段不能为空,且dueDate字段不能为空,必须是有效的DateTime对象。

  • YAML
  • 注释
  • XML
  • PHP
1 2 3 4 5 6 7 8
# Acme / TaskBundle /资源/ config / validation.ymlAcme实体\ TaskBundle \ \任务:属性:任务:-NotBlank:dueDate:-NotBlank:-类型:\ DateTime

就是这样!如果您使用无效数据重新提交表单,您将看到表单打印出相应的错误。

对于HTML5,许多浏览器都可以在客户端本地强制执行某些验证约束。最常见的验证是通过呈现要求属性。对于支持HTML5的浏览器,如果用户试图提交该字段为空的表单,这将导致显示本机浏览器消息。

生成的表单通过添加触发验证的合理HTML属性,充分利用了这个新特性。方法来禁用客户端验证已经属性的形式标签或formnovalidate到提交标记。当您想要测试服务器端验证约束,但浏览器阻止您提交空白字段时,这尤其有用。

  • 嫩枝
  • PHP
1 2 3
{# src / Acme / DemoBundle /资源/视图/ / new.html违约。树枝#}{{形式(形式,{attr”:{“已经”:“已经”}})}}

验证是Symfony的一个非常强大的特性,它有自己的特性欧宝娱乐app下载地址专用的章

验证组

如果你的对象利用验证组,你需要指定你的表单应该使用哪个验证组:

1 2 3
形式->createFormBuilder (用户数组“validation_groups”= >数组“注册”)))->添加(…);

如果你在创作表单类(一个很好的实践),然后您需要将以下内容添加到setDefaultOptions ()方法:

1 2 3 4 5 6 7 8
使用欧宝娱乐app下载地址组件OptionsResolverOptionsResolverInterface公共函数setDefaultOptions(OptionsResolverInterface解析器解析器->setDefaults (数组“validation_groups”= >数组“注册”)));}

在这两种情况下,<新兴市场>只有登记验证组将用于验证基础对象。

禁用验证

2.3

设置的能力validation_groups到false是在Symfony 2.3中引入的。欧宝娱乐app下载地址

有时完全抑制表单的验证是有用的。对于这些情况,您可以设置validation_groups选项

1 2 3 4 5 6 7 8
使用欧宝娱乐app下载地址组件OptionsResolverOptionsResolverInterface公共函数setDefaultOptions(OptionsResolverInterface解析器解析器->setDefaults (数组“validation_groups”= >));}

注意,当您这样做时,表单仍然会运行基本的完整性检查,例如上传的文件是否太大,或者是否提交了不存在的字段。如果希望抑制验证,可以使用POST_SUBMIT事件

根据提交的数据进行分组

如果您需要一些高级逻辑来确定验证组(例如,基于提交的数据),您可以设置validation_groups数组回调的选项:

1 2 3 4 5 6 7 8 9 10 11
使用欧宝娱乐app下载地址组件OptionsResolverOptionsResolverInterface公共函数setDefaultOptions(OptionsResolverInterface解析器解析器->setDefaults (数组“validation_groups”= >数组“Acme \ \ AcmeBundle \实体客户端”“determineValidationGroups”,),));}

这将调用静态方法determineValidationGroups ()客户端在提交表单后,但在执行验证之前,初始化。Form对象作为参数传递给该方法(参见下一个示例)。您还可以使用关闭

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16
使用欧宝娱乐app下载地址组件形式FormInterface使用欧宝娱乐app下载地址组件OptionsResolverOptionsResolverInterface公共函数setDefaultOptions(OptionsResolverInterface解析器解析器->setDefaults (数组“validation_groups”= >函数(FormInterface形式数据形式->getData ();如果(实体\客户::TYPE_PERSON = =数据->方法()){返回数组“人”);}其他的返回数组“公司”);}},));}

根据所单击按钮进行分组

2.3

在Symfony 2.3中引入了对表单中按钮的支持。欧宝娱乐app下载地址

当您的表单包含多个提交按钮时,您可以根据用于提交表单的按钮更改验证组。例如,考虑向导中的表单,该表单允许您执行下一步或返回上一步。还要假设返回到上一步时,应该保存表单的数据,但不进行验证。

首先,我们需要向表单添加两个按钮:

1 2 3 4 5
形式->createFormBuilder (任务/ /……->add (nextStep的“提交”->add (“previousStep”“提交”->getForm ();

然后,我们配置返回到上一步的按钮,以运行特定的验证组。在本例中,我们希望它抑制验证,因此我们设置了它的validation_groups选项为false:

1 2 3 4 5 6
形式->createFormBuilder (任务/ /……->add (“previousStep”“提交”数组“validation_groups”= >,))->getForm ();

现在表单将跳过验证约束。它仍然会验证基本的完整性约束,例如检查上传的文件是否太大,或者您是否试图在数字字段中提交文本。

内置字段类型

欧宝娱乐app下载地址Symfony标准提供了一大组字段类型,涵盖了您将遇到的所有常见表单字段和数据类型:

基础领域

您还可以创建自己的自定义字段类型。此主题在“如何创建自定义表单字段类型食谱的文章。

字段类型选项

每个字段类型都有许多可用于配置它的选项。例如,dueDate字段目前被渲染为3个选择框。然而,日期字段可以配置为呈现为单个文本框(用户将在框中输入日期作为字符串):

1
->add (“dueDate”“日期”数组“部件”= >“single_text”))

每个字段类型都有许多可以传递给它的不同选项。其中许多是特定于字段类型的,可以在每种类型的文档中找到详细信息。欧宝体育电话

最常见的选项是要求选项,该选项可应用于任何字段。默认情况下,要求选项设置为真正的,这意味着如果该字段为空,支持html5的浏览器将应用客户端验证。如果不想要此行为,也可以设置要求选择你的领域禁用HTML5验证

还要注意设置要求选项真正的将应用服务器端验证的结果。换句话说,如果用户为字段提交了一个空白值(例如,使用旧的浏览器或web服务),它将被接受为有效值,除非您使用Symfony的欧宝娱乐app下载地址NotBlankNotNull验证约束。

换句话说,要求选项是“好”,但真正的服务器端验证应该<新兴市场>总是被使用。

属性可以设置表单字段的标签标签选项,可应用于任何字段:

1 2 3 4
->add (“dueDate”“日期”数组“部件”= >“single_text”“标签”= >“到期日”,))

字段的标签也可以在呈现表单的模板中设置,见下文。如果不需要与输入相关联的标签,可以通过将其值设置为来禁用它

字段类型猜测

方法中添加了验证元数据任务类,Symfo欧宝娱乐app下载地址ny已经知道一些关于你的领域。如果您允许,Symfony可以“猜欧宝娱乐app下载地址测”您的字段类型并为您设置。在本例中,Symfony可以从验证欧宝娱乐app下载地址规则中猜测任务场是正常的文本场和dueDate字段是日期字段:

1 2 3 4 5 6 7 8 9 10
公共函数newAction()任务任务();形式->createFormBuilder (任务->add (“任务”->add (“dueDate”数组“部件”= >“single_text”))->add (“保存”“提交”->getForm ();}

的第二个参数时,“猜测”将被激活add ()方法(或如果您通过它)。如果您传递一个选项数组作为第三个参数(done fordueDate),这些选项将应用于猜测的字段。

谨慎

如果您的表单使用特定的验证组,字段类型猜测器仍然会考虑<新兴市场>所有猜测字段类型时的验证约束(包括不属于正在使用的验证组的约束)。

字段类型选项猜测

除了猜测字段的“类型”之外,Symfony还可以尝试猜测许多字段选项的正确值。欧宝娱乐app下载地址

提示

设置了这些选项后,字段将呈现为HTML5客户端验证的特殊HTML属性。然而,它不会生成等效的服务器端约束(例如。维护\长度).尽管您需要手动添加服务器端验证,但这些字段类型选项可以从该信息中猜测出来。

  • 要求:要求选项可以根据验证规则(即是字段)来猜测NotBlankNotNull)或Doctrine元数据(即字段可以为空).这非常有用,因为您的客户端验证将自动匹配您的验证规则。
  • max_length:如果字段是某种文本字段,则max_length选项可以从验证约束(如果长度范围使用)或从Doctrine元数据(通过字段的长度)。

请注意

这些字段选项是<新兴市场>只有猜测是否使用Symfony来猜测字段类型(即省略欧宝娱乐app下载地址或传递)正如第二个论点add ()).

如果你想改变一个猜测值,你可以通过在options字段数组中传递选项来覆盖它:

1
->add (“任务”数组“max_length”= >4))

在模板中呈现表单

到目前为止,您已经看到了如何用一行代码呈现整个表单。当然,在渲染时你通常需要更大的灵活性:

  • 嫩枝
  • PHP
1 2 3 4 5 6 7
{# src / Acme / TaskBundle /资源/视图/ / new.html违约。树枝#}{{form_start(form)}}{{form_errors(form)}}{{form_row(form.task)}}{{form_row(form.dueDate)}}{{form_end(form)}}

看看每个部分:

  • form_start(形式)-渲染表单的开始标签。
  • form_errors(形式)-将所有错误呈现为整个表单的全局错误(字段特定的错误显示在每个字段旁边);
  • form_row (form.dueDate)-渲染标签,任何错误,和HTML表单小部件为给定的字段(例如。dueDate)内部,默认情况下,adiv元素;
  • form_end ()-呈现表单的结束标签和尚未呈现的任何字段。这对于渲染隐藏字段和利用自动属性非常有用CSRF保护

大部分的工作是由form_row类中每个字段的标签、错误和HTML表单小部件div标签。在形式部分,你将学习如何form_row可以在许多不同的级别上定制输出。

提示

您可以通过访问表单的当前数据form.vars.value

  • 嫩枝
  • PHP
1
{{form.vars.value.task}}

手工渲染每个字段

form_rowHelper非常有用,因为您可以非常快速地呈现表单的每个字段(用于“行”的标记也可以自定义)。但由于生活并不总是那么简单,您也可以完全手工渲染每个字段。的最终结果与使用form_row助手:

  • 嫩枝
  • PHP
12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20
{{form_start(form)}}{{form_errors(form)}}<div>{{form_label(form.task)}}{{form_errors(form.task)}}{{form_widget(form.task)}}div><div>{{form_label(form.dueDate)}}{{form_errors(form.dueDate)}}{{form_widget(form.dueDate)}}div><div>{{form_widget(form.save)}}div>{{form_end(form)}}

如果字段的自动生成标签不太正确,你可以显式地指定它:

  • 嫩枝
  • PHP
1
{{了form_label(形式。任务,“工作描述”)}}

某些字段类型具有可以传递给小部件的附加呈现选项。这些选项在每种类型中都有文档说明,但是一个常见的选项是attr,它允许您修改表单元素上的属性。下面将添加task_field类添加到呈现的输入文本字段:

  • 嫩枝
  • PHP
1
{{form_widget(形式。任务,{“attr”:{“类”:“task_field”}})}}

如果您需要“手动”呈现表单字段,那么您可以访问字段的单个值,例如id的名字而且标签.例如,得到id

  • 嫩枝
  • PHP
1
{{form.task.vars.id}}

要获取表单字段的name属性所使用的值,需要使用full_name值:

  • 嫩枝
  • PHP
1
{{form.task.vars。full_name}}

树枝模板函数参考

如果您正在使用Twig,则可以在参考手册.阅读本文,了解有关可用的helper的所有信息,以及每个helper可以使用的选项。

更改表单的动作和方法

目前为止,form_start ()helper已经用于呈现表单的开始标记,并且我们假设每个表单都在POST请求中提交到相同的URL。有时你想改变这些参数。您可以通过几种不同的方式来做到这一点。如果在控制器中构建表单,则可以使用setAction ()而且setMethod ()

1 2 3 4 5 6 7
形式->createFormBuilder (任务->setAction (->generateUrl (“target_route”))->setMethod (“得到”->add (“任务”“文本”->add (“dueDate”“日期”->add (“保存”“提交”->getForm ();

请注意

这个例子假设您已经创建了一个名为target_route它指向处理表单的控制器。

形式您将学习如何将表单构建代码移动到单独的类中。当在控制器中使用外部表单类时,你可以将动作和方法作为表单选项传递:

1 2 3 4
形式->createForm (TaskType (),任务数组“行动”= >->generateUrl (“target_route”),“方法”= >“得到”));

方法来重写模板中的操作和方法形式()或者是form_start ()助手:

  • 嫩枝
  • PHP
1 2 3 4
{# src / Acme / TaskBundle /资源/视图/ / new.html违约。树枝#}{{形式(形式,{“行动”:路径(“target_route”)、“法”:“得到”})}}{{form_start(形式,{“行动”:路径(“target_route”)、“法”:“得到”})}}

请注意

如果表单的方法不是GET或POST,而是PUT、PATCH或DELETE, Symfony将插入一个包含名称的隐藏字段欧宝娱乐app下载地址_method它存储这个方法。表单将在正常的POST请求中提交,但是Symfony的路由器能够检测到欧宝娱乐app下载地址_method参数,并将其解释为PUT, PATCH或DELETE请求。阅读烹饪书的章节如何在路由中使用GET和POST之外的HTTP方法获取更多信息。

创建表单类

如您所见,可以在控制器中直接创建和使用表单。但是,更好的做法是在单独的、独立的PHP类中构建表单,这样就可以在应用程序的任何地方重用它。创建一个新类,它将容纳构建任务表单的逻辑:

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21
/ / src / Acme / TaskBundle /形式/类型/ TaskType.php名称空间AcmeTaskBundle形式类型使用欧宝娱乐app下载地址组件形式AbstractType使用欧宝娱乐app下载地址组件形式FormBuilderInterfaceTaskType扩展AbstractType公共函数buildForm(FormBuilderInterface构建器数组,选项构建器->add (“任务”->add (“dueDate”数组“部件”= >“single_text”))->add (“保存”“提交”);}公共函数getName()返回“任务”;}}

这个新类包含创建任务表单所需的所有方向(注意getName ()方法应返回此表单“type”的唯一标识符)。它可以用于在控制器中快速构建一个表单对象:

12 3 4 5 6 7 8 9 10 11 12
/ / src / Acme / TaskBundle /控制器/ DefaultController.php//在类的顶部添加新的use语句使用AcmeTaskBundle形式类型TaskType公共函数newAction()任务=……;形式->createForm (TaskType (),任务);/ /……

将表单逻辑放入自己的类中意味着该表单可以轻松地在项目的其他地方重用。这是创建表单的最佳方式,但最终还是取决于您。

每个表单都需要知道保存底层数据的类的名称(例如。Acme实体\ TaskBundle \ \任务).通常,这只是基于传递给第二个参数的对象来猜测createForm(即。美元的任务).之后,当您开始嵌入表单时,这将不再足够。因此,虽然并不总是必要的,但显式地指定属性通常是个好主意data_class选项,将以下内容添加到您的表单类型类:

1 2 3 4 5 6 7 8
使用欧宝娱乐app下载地址组件OptionsResolverOptionsResolverInterface公共函数setDefaultOptions(OptionsResolverInterface解析器解析器->setDefaults (数组“data_class”= >“Acme实体\ TaskBundle \ \任务”));}

提示

将表单映射到对象时,将映射所有字段。表单上映射对象上不存在的任何字段都将导致抛出异常。

如果您需要表单中的额外字段(例如:“您是否同意这些术语”复选框)而不会映射到底层对象,则需要设置映射选项

1 2 3 4 5 6 7 8 9
使用欧宝娱乐app下载地址组件形式FormBuilderInterface公共函数buildForm(FormBuilderInterface构建器数组,选项构建器->add (“任务”->add (“dueDate”数组“映射”= >))->add (“保存”“提交”);}

此外,如果表单上有任何字段未包含在提交的数据中,这些字段将显式地设置为

在控制器中可以通过以下方式访问现场数据:

1
形式->get (“dueDate”->getData ();

此外,还可以直接修改未映射字段的数据:

1
形式->get (“dueDate”->setData (\ DateTime ());

将表单定义为服务

将表单类型定义为服务是一种很好的实践,可以使其在应用程序中非常容易使用。

请注意

服务和服务容器将被处理在这本书的后面.读完那一章,事情就会更清楚了。

  • YAML
  • XML
  • PHP
1 2 3 4 5 6
# src / Acme / TaskBundle /资源/ config / services.yml服务:acme_demo.form.type.task:类:Acme \ TaskBundle \ \ \ TaskType型形式标签:-名称:form.type,别名:任务

就是这样!现在你可以直接在控制器中使用你的表单类型:

1 2 3 4 5 6 7 8 9 10
/ / src / Acme / TaskBundle /控制器/ DefaultController.php/ /……公共函数newAction()任务=……;形式->createForm (“任务”任务);/ /……

甚至可以在另一个表单的表单类型中使用:

12 3 4 5 6 7 8 9 10 11 12
/ / src / Acme / TaskBundle /形式/类型/ ListType.php/ /……ListType扩展AbstractType公共函数buildForm(FormBuilderInterface构建器数组,选项/ /……构建器->add (“someTask”“任务”);}}

如何创建自定义表单字段类型获取更多信息。

形式与教义

表单的目标是将数据从对象(例如。任务)转换为HTML表单,然后将用户提交的数据转换回原始对象。因此,这个话题的坚持任务对象对数据库的影响与表单主题完全无关。但是,如果你配置了任务类通过Doctrine(即您已经添加了映射元数据对于它),然后在表单提交后持久化它可以在表单有效时完成:

1 2 3 4 5 6 7
如果形式->isValid ()) {新兴市场->getDoctrine ()->getManager ();新兴市场->persist (任务);新兴市场->冲洗();返回->重定向(->generateUrl (“task_success”));}

如果,出于某种原因,你无法接触到你的原作美元的任务对象,你可以从表单中获取它:

1
任务形式->getData ();

有关更多信息,请参见教义ORM章节

要理解的关键是,当提交表单时,提交的数据将立即传输到底层对象。如果希望持久化该数据,只需要持久化对象本身(它已经包含了提交的数据)。

嵌入的形式

通常,您会希望构建一个包含来自许多不同对象的字段的表单。例如,注册表单可以包含属于用户对象以及许多地址对象。幸运的是,这对于Form组件来说是简单而自然的。

嵌入单个对象

假设每一个任务属于简单的类别对象。当然,首先要创建类别对象:

12 3 4 5 6 7 8 9 10 11 12
/ / src / Acme / / Category.php TaskBundle /实体名称空间AcmeTaskBundle实体使用欧宝娱乐app下载地址组件验证器约束作为断言类别/ * * *@Assert\ NotBlank () * /公共的名字;}

接下来,添加一个new类别属性任务类:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/ /……任务/ /……/ * * *@Assert\类型(Type =“Acme \ \ TaskBundle \实体类别”)* /受保护的类别/ /……公共函数getCategory()返回->类别;}公共函数setCategory(类别类别= null)->类别=类别;}}

现在您的应用程序已经被更新以反映新的需求,创建一个表单类以便a类别对象可以被用户修改:

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
/ / src / Acme / TaskBundle /形式/类型/ CategoryType.php名称空间AcmeTaskBundle形式类型使用欧宝娱乐app下载地址组件形式AbstractType使用欧宝娱乐app下载地址组件形式FormBuilderInterface使用欧宝娱乐app下载地址组件OptionsResolverOptionsResolverInterfaceCategoryType扩展AbstractType公共函数buildForm(FormBuilderInterface构建器数组,选项构建器->add (“名字”);}公共函数setDefaultOptions(OptionsResolverInterface解析器解析器->setDefaults (数组“data_class”= >“Acme \ \ TaskBundle \实体类别”));}公共函数getName()返回“类别”;}}

最终目标是允许类别任务在任务表单本身内部进行修改。要完成此操作,请添加类别字段到TaskType对象,其类型为new的实例CategoryType类:

1 2 3 4 5 6 7 8
使用欧宝娱乐app下载地址组件形式FormBuilderInterface公共函数buildForm(FormBuilderInterface构建器数组,选项/ /……构建器->add (“类别”CategoryType ());}

田野从CategoryType现在可以和那些来自TaskType类。要激活对CategoryType的验证,请添加cascade_validation选项TaskType

1 2 3 4 5 6 7
公共函数setDefaultOptions(OptionsResolverInterface解析器解析器->setDefaults (数组“data_class”= >“Acme实体\ TaskBundle \ \任务”“cascade_validation”= >真正的));}

呈现类别与原字段相同任务字段:

  • 嫩枝
  • PHP
1 2 3 4 5 6 7 8
{#……#}<h3>类别h3><div“类别”>{{form_row(form.category.name)}}div>{#……#}

当用户提交表单时,提交的数据为类别字段用于构造的实例类别,然后设置在类别字段任务实例。

类别实例可以通过任务- > getCategory ()并且可以持久化到数据库中,或者根据需要任意使用。

嵌入一个表单集合

您还可以将一组表单嵌入到一个表单中(想象一个类别Form with many产品体)。这是通过使用集合字段类型。

有关更多信息,请参阅“如何嵌入一个集合的形式“食谱条目和集合字段类型引用。

形式主题

表单呈现方式的每个部分都可以自定义。您可以自由地更改每个表单“行”呈现的方式,更改用于呈现错误的标记,甚至自定义一个窗体的呈现方式文本区域标签应该被呈现。没有什么是禁止的,不同的定制可以在不同的地方使用。

欧宝娱乐app下载地址Symfony使用模板来呈现表单的每个部分,例如标签标签,输入标签、错误消息和其他一切。

在Twig中,每个表单“片段”都由一个Twig块表示。要自定义表单呈现方式的任何部分,只需覆盖适当的块。

在PHP中,每个表单“片段”都是通过一个单独的模板文件呈现的。要自定义表单呈现方式的任何部分,只需通过创建一个新模板来覆盖现有模板。

要了解这是如何工作的,请自定义form_row片段,并向div元素,用于围绕每一行。要做到这一点,创建一个新的模板文件来存储新的标记:

  • 嫩枝
  • PHP
1 2 3 4 5 6 7 8 9 10
{# src / Acme / TaskBundle /资源/视图/形式/ fields.html。树枝#}{%form_row %}{%没有余地的%}<div“form_row”>{{form_label(form)}}{{form_errors(form)}}{{form_widget(form)}}div>{%endspaceless%}{%endblockform_row %}

form_row控件呈现大多数字段时使用表单片段form_row函数。来告诉Form组件使用您的newform_row在上面定义的片段中,将以下内容添加到呈现表单的模板顶部:

  • 嫩枝
  • PHP
1 2 3 4 5 6
{# src / Acme / TaskBundle /资源/视图/ / new.html违约。树枝#}{%form_theme“AcmeTaskBundle:形式:fields.html形式。嫩枝' %}{%form_theme“AcmeTaskBundle:形式:fields.html形式。树枝“AcmeTaskBundle:形式:fields2.html。嫩枝' %}<!--...呈现表单——>

form_theme标签(Twig)“导入”给定模板中定义的片段,并在呈现表单时使用它们。也就是说,当form_row函数在此模板中稍后调用时,它将使用form_row从您的自定义主题(而不是默认form_rowSymfony)。欧宝娱乐app下载地址

您的自定义主题不必覆盖所有的块。当呈现一个在自定义主题中没有被覆盖的块时,主题引擎将退回到全局主题(在包级别定义)。

如果提供了几个自定义主题,则在返回到全局主题之前将按列出的顺序进行搜索。

要自定义表单的任何部分,只需覆盖适当的片段。确切地知道要覆盖哪个块或文件是下一节的主题。

1 2 3 4 5
{# src / Acme / TaskBundle /资源/视图/ / new.html违约。树枝#}{%form_theme使用'AcmeTaskBundle: form:fields.html。嫩枝' %}{%form_theme使用['AcmeTaskBundle: form:fields.html嫩枝”、“AcmeTaskBundle:形式:fields2.html。嫩枝']%}

有关更广泛的讨论,请参见如何自定义表单渲染

表单片段命名

在Sy欧宝娱乐app下载地址mfony中,所呈现的表单的每个部分——HTML表单元素、错误、标签等——都定义在基本主题中,基本主题是Twig中的块集合和PHP中的模板文件集合。

在Twig中,需要的每个块都定义在一个模板文件中(form_div_layout.html.twig),住在树枝桥.在这个文件中,您可以看到呈现表单所需的每个块和每个默认字段类型。

在PHP中,片段是单独的模板文件。默认情况下,它们位于资源/视图/形式框架包的目录(在GitHub上查看).

每个片段名称遵循相同的基本模式,并被分为两个部分,由单个下划线字符(_).一些例子是:

  • form_row-由form_row渲染大部分字段;
  • textarea_widget-由form_widget渲染文本区域字段类型;
  • form_errors-由form_errors显示错误:显示字段的错误;

每个片段都遵循相同的基本模式:type_part.的类型部分对应于字段<新兴市场>类型被渲染(例如:文本区域复选框日期,等),而部分部分对应于<新兴市场>什么正在被渲染(例如:标签小部件错误等等)。默认情况下,有4种可能<新兴市场>部分可呈现的形式的:

标签 (如。了form_label 呈现字段的标签
小部件 (如。form_widget 渲染字段的HTML表示
错误 (如。form_errors 呈现字段的错误
(如。form_row 渲染字段的整行(标签,小部件和错误)

请注意

实际上还有两个<新兴市场>部分-而且休息-但你几乎不需要担心重写它们。

通过了解字段类型(例如:文本区域)和你想自定义的部分(例如:小部件),您可以构造需要重写的片段名称(例如。textarea_widget).

模板片段继承

在某些情况下,您想要自定义的片段将会出现缺失。例如,没有textarea_errors片段在Symfony提供的默认主题中。欧宝娱乐app下载地址那么如何渲染textarea字段的错误呢?

答案是:通过form_errors片段。当Symf欧宝娱乐app下载地址ony呈现textarea类型的错误时,它首先查找textarea_errors碎片才落回form_errors片段。每个字段类型都有一个<新兴市场>父的父类型文本区域文本,其父节点为形式),如果基本片欧宝娱乐app下载地址段不存在,Symfony将使用该片段作为父类型。

为了重写错误<新兴市场>只有文本区域字段,复制form_errors片段,重命名为textarea_errors并自定义它。的默认错误呈现<新兴市场>所有字段,复制并自定义form_errors直接片段。

提示

每个字段类型的“父”类型可在表单类型引用对于每个字段类型。

全局表单主题

在上面的示例中,使用了form_themehelper(在Twig中)来“导入”自定义表单片段<新兴市场>只是这种形式。您还可以告诉Symfony在整个项目欧宝娱乐app下载地址中导入表单定制。

嫩枝

控件中自动包含自定义块fields.html.twig中创建的模板<新兴市场>所有模板,修改您的应用程序配置文件:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6
# app / config / config.yml枝:形式:资源:-“AcmeTaskBundle:形式:fields.html.twig”#……

中的任何块fields.html.twig模板现在用于全局定义表单输出。

在Twig中,你还可以在需要定制的模板中定制表单块:

12 3 4 5 6 7 8 9 10 11 12 13 14 15
{%扩展“::base.html。嫩枝' %}{#导入“_self”作为表单主题#}{%form_themeForm _self %}{#定制表单片段#}{%form_row %}{#自定义字段输出#}{%endblockform_row %}{%内容%}{#……#}{{form_row(form.task)}}{%endblock%}

{% form_theme form _self %}标记允许在将使用这些自定义的模板中直接自定义表单块。使用此方法可以快速进行表单输出定制,而这些定制只需要在单个模板中使用。

谨慎

{% form_theme form _self %}功能将<新兴市场>只有如果您的模板扩展了另一个模板,则可以工作。如果你的模板没有,你必须指向form_theme到一个单独的模板。

PHP

控件中自动包含自定义模板Acme / TaskBundle /资源/视图/形式中创建的目录<新兴市场>所有模板,修改您的应用程序配置文件:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7
# app / config / config.yml框架:模板:形式:资源:-“AcmeTaskBundle:形式”#……

中的任何片段Acme / TaskBundle /资源/视图/形式目录现在被全局地用于定义表单输出。

CSRF保护

CSRF -或跨站请求伪造-是一种恶意用户试图让合法用户在不知情的情况下提交他们不打算提交的数据的方法。幸运的是,可以通过在表单中使用CSRF令牌来防止CSRF攻击。

好消息是,默认情况欧宝app在哪里找下,Symfony会自动嵌入并验证CSRF令牌。欧宝娱乐app下载地址这意味着您不需要做任何事情就可以利用CSRF保护。事实上,本章中的每个表单都利用了CSRF的保护!

CSRF保护工作通过添加一个隐藏字段到您的表单-称为_token默认情况下-包含一个只有您和您的用户知道的值。这确保提交给定数据的是用户(而不是其他实体)。欧宝娱乐app下载地址Symfony自动验证这个令牌的存在和准确性。

_token字段是一个隐藏字段,如果包含form_end ()函数,该函数确保输出所有未呈现的字段。

可以逐个表单地定制CSRF令牌。例如:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
使用欧宝娱乐app下载地址组件OptionsResolverOptionsResolverInterfaceTaskType扩展AbstractType/ /……公共函数setDefaultOptions(OptionsResolverInterface解析器解析器->setDefaults (数组“data_class”= >“Acme实体\ TaskBundle \ \任务”“csrf_protection”= >真正的“csrf_field_name”= >“_token”//帮助生成秘密令牌的唯一密钥“意图”= >“task_item”));}/ /……

若要禁用CSRF保护,请设置csrf_protection选项为false。还可以在项目中进行全局自定义。有关更多信息,请参见表单配置参考部分。

请注意

意图Option是可选的,但通过使每个表单的令牌都不同,极大地增强了所生成令牌的安全性。

使用没有类的表单

在大多数情况下,表单被绑定到一个对象,表单的字段在该对象的属性上获取并存储它们的数据。这正是到目前为止你在本章中看到的“Task”类。

但有时,您可能只是想使用没有类的表单,并返回提交数据的数组。这其实很简单:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
//确保你已经在类上面导入了Request命名空间使用欧宝娱乐app下载地址组件HttpFoundation请求/ /……公共函数contactAction(请求请求defaultData数组“消息”= >“在这里输入您的信息”);形式->createFormBuilder (defaultData->add (“名字”“文本”->add (“电子邮件”“电子邮件”->add (“消息”“文本区域”->add (“发送”“提交”->getForm ();形式->handleRequest (请求);如果形式->isValid ()) {// data是一个包含"name", "email"和"message"键的数组数据形式->getData ();}/ /……渲染表单

默认情况下,表单实际上假定您要处理数据数组,而不是对象。有两种方法可以改变这种行为并将表单绑定到对象上:

  1. 在创建表单时传递一个对象(作为createFormBuilder或者第二个参数createForm);
  2. 声明data_class表格上的选项。

如果你<新兴市场>不执行其中任何一项操作,表单都将以数组的形式返回数据。在这个例子中,sincedefaultData美元不是一个对象(而且不是data_class选项已设置),形式- > getData ()最终返回一个数组。

提示

你也可以直接通过请求对象访问POST值(在本例中是“name”),如下所示:

1
->get (“请求”->请求->get (“名字”);

但是,建议在大多数情况下使用getData ()方法是更好的选择,因为它在表单框架转换数据后返回数据(通常是对象)。

添加验证

唯一缺少的部分是验证。通常是你打电话的时候美元形式- > isValid (),通过读取应用到该类的约束来验证对象。如果您的表单映射到一个对象(即您正在使用data_class选项或向表单传递对象),这几乎总是您想要使用的方法。看到验证欲知详情。

但是,如果表单没有映射到对象,而希望检索提交数据的简单数组,那么如何向表单数据添加约束呢?

答案是自己设置约束,并将它们附加到各个字段。方法中详细介绍了总体方法验证章,但这里有一个简短的例子:

12 3 4 5 6 7 8 9 10 11 12 13 14
使用欧宝娱乐app下载地址组件验证器约束长度使用欧宝娱乐app下载地址组件验证器约束NotBlank构建器->add (“firstName”“文本”数组“约束”= >长度(数组“最小值”= >3.))))->add (“姓”“文本”数组“约束”= >数组NotBlank (),长度(数组“最小值”= >3.)),),));

提示

如果使用验证组,则需要引用默认的组,或在添加的约束上设置正确的组。

1
NotBlank (数组“组织”= >数组“创建”“更新”))

最终的想法

现在您已经了解了为应用程序构建复杂的功能表单所需的所有构建块。在构建表单时,请记住表单的第一个目标是从对象转换数据(任务)转换为HTML表单,以便用户可以修改该数据。表单的第二个目标是获取用户提交的数据,并将其重新应用于对象。

关于表单的强大世界,还有很多东西需要学习,比如如何处理文件上传Doctrine或者如何创建一个可以添加动态数量子表单的表单(例如,在提交之前可以通过JavaScript添加更多字段的todo列表)。有关这些主题,请参阅烹饪书。另外,一定要靠在字段类型引用文档欧宝体育电话,其中包括如何使用每种字段类型及其选项的示例。

此工作,包括代码示例,是根据创作共用BY-SA 3.0许可证。
版本: