形式

编辑该页面

警告:你浏览的文档欧宝体育电话欧宝娱乐app下载地址Symfony 2.3,不再维护。

这个页面的更新版本Symf欧宝娱乐app下载地址ony 6.2(当前的稳定版本)。

形式

处理HTML表单是最常见的一种为web开发人员和具有挑战性的任务。欧宝娱乐app下载地址Symfony集成表单组件,简化处理形式。在本章中,您将构建一个复杂的形式,形式的学习最重要的特征库。

请注意

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

创建一个简单的形式

假设你正在构建一个简单的todo列表应用程序,它将需要显示“任务”。因为你的用户将需要编辑和创建任务,你需要建立一个形式。但在你开始之前,首先关注通用任务类表示并存储数据为单个任务:

1 2 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
/ / src / AppBundle /实体/ Task.php名称空间AppBundle\实体;任务{受保护的美元任务;受保护的美元dueDate;公共函数getTask(){返回美元- >任务;}公共函数setTask(美元任务){美元- >任务=美元任务;}公共函数getDueDate(){返回美元- >dueDate;}公共函数setDueDate(\ DateTime美元dueDate= null){美元- >dueDate =美元dueDate;}}

这个类是一个“plain-old-PHP-object”,因为,到目前为止,它已经与Symfony或任何其他图书馆。欧宝娱乐app下载地址很简单的一个正常的PHP对象里面直接解决问题<新兴市场>你的应用程序(例如,需要在应用程序中代表一个任务)。当然,在本章结束时,您将能够提交数据任务实例(通过HTML表单),验证其数据,并保存到数据库。

建筑的形式

现在,您已经创建了一个任务类,下一步是创建和渲染实际的HTML表单。在Sy欧宝娱乐app下载地址mfony中,这是通过构建一个form对象,然后呈现在一个模板。现在,从在一个控制器都可以做到这一点:

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

提示

这个例子展示了如何构建表单直接控制器。后,在“形式”部分中,您将学习如何构建表单在一个独立的类,这是推荐为表单变得可重用。

创建一个表单需要相对较少的代码,因为Symfony表单对象构建“形式构建器”。欧宝娱乐app下载地址表单生成器的目的是允许您编写简单的形式“食谱”,并让它做所有的重型起重建筑形式。

在这个示例中,您已经添加了形式——两个字段任务dueDate- - - - - -对应任务dueDate的属性任务类。你也分配每一个“类型”(如。文本,日期),除此之外,确定哪些HTML表单标签(s)呈现。

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

2.3

支持提交按钮是在Symfony 2.3中引入的。欧宝娱乐app下载地址在那之前,你必须手动将按钮添加到表单的HTML。

欧宝娱乐app下载地址Symfony提供了很多内建类型(见不久将讨论形式)。

呈现形式

既然已经创建了表单,下一步是呈现它。这样做是通过一种特殊的“视图”模板(注意对象$形式- > createView ()在上面的控制器),使用一组表单辅助函数:

  • 嫩枝
  • PHP
1 2 3 4
{# app /资源/视图/ / new.html违约。树枝#}{{form_start(形式)}}{{form_widget(形式)}}{{form_end(形式)}}

请注意

这个示例假设您提交表单的“后”请求和相同的URL,这是显示在。稍后您将了解如何更改请求方法和目标URL的形式。

就是这样!仅仅需要三行呈现完整的表单:

form_start(形式)
呈现表单的开始标记,包括当使用添加了正确的enctype属性文件上传。
form_widget(形式)
呈现的所有字段,包括字段元素本身,一个标签和任何验证错误消息的字段。
form_end(形式)
呈现表单的结束标记和尚未呈现的任何领域,以防你呈现的每个字段。这是用于呈现隐藏字段,利用自动CSRF保护

另请参阅

像这是那么容易,不是非常灵活的(还)。通常情况下,你要单独渲染每个表单字段,这样你就可以控制形式的样子。你将学习如何在“形式”一节。

在继续之前,请注意如何呈现任务输入字段的值任务财产的美元的任务对象(即。“写博客”)。这是第一份工作的一种形式:把数据从一个对象转换成适合的格式,会呈现在一个HTML表单。

提示

表单系统是足够聪明来访问受保护的价值任务属性通过getTask ()setTask ()方法任务类。除非一个属性是公共的,它<新兴市场>必须有“getter”和“setter”方法,以便表单组件可以get和put数据到财产。对于一个布尔属性,您可以使用一个“伊塞”或“有”的方法(如。发表()hasReminder ())而不是一个getter(如。个短篇()getReminder ())。

处理表单提交

一种形式的第二份工作是将用户提交的数据对象的属性。为了实现这一点,用户提交的数据必须写入表单对象。添加以下功能控制器:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21日22日23日24日25日26日
/ /……使用欧宝娱乐app下载地址\组件\HttpFoundation\请求;公共函数newAction(请求美元请求){/ /设置一个新的美元任务对象(删除虚拟数据)美元任务=任务();美元形式=美元- >createFormBuilder (美元任务)- >add (“任务”,“文本”)- >add (“dueDate”,“日期”)- >add (“保存”,“提交”,数组(“标签”= >“创建任务”))- >getForm ();美元形式- >handleRequest (美元请求);如果(美元形式- >isSubmitted () & &美元形式- >isValid ()) {/ /……执行一些操作,比如拯救任务到数据库返回美元- >重定向(美元- >generateUrl (“task_success”));}返回美元- >呈现(“违约/ new.html.twig”,数组(“形式”= >美元形式- >createView ()));}

谨慎

请注意,createView ()方法应该被称为<新兴市场>后handleRequest被称为。否则,所做的更改* _SUBMIT事件不应用于视图(如验证错误)。

2.3

handleRequest ()方法是在Symfony 2.3中引入的。欧宝娱乐app下载地址在此之前,美元的请求被传递到提交方法——即弃用策略和在Symfony 3.0将被删除。欧宝娱乐app下载地址对于方法的细节,明白了如何使用submit()函数来处理表单提交

这个控制器处理形式,遵循一个共同的模式,有三个可能的路径:

  1. 最初在浏览器中加载页面时,形式只是创建和渲染。handleRequest ()认识到表单没有提交,什么也不做。isSubmitted ()返回如果表单没有提交。
  2. 当用户提交表单时,handleRequest ()承认这一点,立即回写提交的数据任务dueDate的属性美元的任务对象。然后这个对象验证。如果它是无效的(验证将在下一节中讨论),isValid ()返回一起,所以形式呈现所有的验证错误;
  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 9 10 11 12 13 14 15 16 17 18
/ / src / AppBundle /实体/ Task.php名称空间AppBundle\实体;使用欧宝娱乐app下载地址\组件\验证器\约束作为断言;任务{/ * * *@Assert\ NotBlank () * /公共美元任务;/ * * *@Assert* \ NotBlank ()@Assert\类型(" \ DateTime ") * /受保护的美元dueDate;}

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

HTML5,许多本地浏览器可以在客户端上执行特定的验证约束。最常见的验证激活呈现要求属性字段是必需的。对于支持HTML5的浏览器,这将导致原生浏览器消息显示,如果用户试图提交表单字段空白。

生成的形式充分利用这个新特性添加合理的HTML属性触发验证。然而,客户端验证可以通过添加禁用已经属性的形式标签或formnovalidate提交标记。这是特别有用,当你想测试您的服务器端验证约束,但被浏览器阻止了,例如,提交空白领域。

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

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

验证组

如果你的对象利用验证组,您需要指定验证组(s)表单应该使用:

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

如果你创建表单类(一个好的实践),那么你需要添加以下setDefaultOptions ()方法:

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

在这两种情况下,<新兴市场>只有登记验证小组将被用来验证底层对象。

禁用验证

2.3

的能力集validation_groups错误是在Symfony 2.3中引入的。欧宝娱乐app下载地址

有时是有用的完全抑制一种形式的验证。这些情况下你可以设置validation_groups选项:

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

请注意,当您这样做,形式仍将运行基本的完整性检查,例如是否上传文件太大或不存在的字段是否提交。如果你想抑制验证,您可以使用POST_SUBMIT事件

组根据提交的数据

如果你需要一些先进的逻辑来确定验证组织(如根据提交的数据),可以设置validation_groups选项数组回调:

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

这将调用静态方法determineValidationGroups ()客户端类表单提交后,但在执行验证。表单对象作为参数传递给该方法(见下一个示例)。您还可以定义整个逻辑内联使用关闭:

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

使用validation_groups选择覆盖默认验证组被使用。如果你想验证默认约束实体的调整可以选择如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
使用AppBundle\实体\客户端;使用欧宝娱乐app下载地址\组件\形式\FormInterface;使用欧宝娱乐app下载地址\组件\OptionsResolver\OptionsResolverInterface;/ /……公共函数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选择错误的:

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

现在的形式将跳过验证约束。它仍然会验证基本完整性约束,如检查是否一个上传文件太大你是否试图提交文本在许多领域。

内置字段类型

欧宝娱乐app下载地址Symfony是标准与一大群字段类型,覆盖所有常见的表单字段和数据类型你会遇到:

基础领域

您还可以创建自己的自定义字段类型。这个话题覆盖在“如何创建一个自定义表单字段类型”文章的食谱。

字段类型选项

每种字段类型有很多选项可用于配置它。例如,dueDate领域目前正呈现为3选择框。然而,日期字段可以配置为显示为一个单一的文本框(用户输入的日期作为一个字符串在盒子里):

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

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

最常见的选项要求选项,它可以应用于任何领域。默认情况下,要求选项设置为真正的,这意味着准备好了支持html5技术的浏览器将客户端验证字段留空。如果你不希望这种行为禁用HTML5验证或设置要求选择在你的领域:

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

还要注意,设置要求选项真正的导致应用服务器端验证。换句话说,如果用户提交一个空白字段的值(用旧浏览器或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 ()方法(或者如果你通过它)。如果你通过选项数组作为第三个参数(完蛋了dueDate上图),这些选项应用到猜。

谨慎

如果你的表单使用一个特定的验证组,字段类型猜测者仍然会考虑<新兴市场>所有验证约束当猜测你的字段类型(包括验证组的约束不属于被使用)。

字段类型选项猜

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

提示

当设置这些选项时,该领域将呈现特殊的HTML属性为HTML5客户端验证。然而,它不产生相当于端约束(如。维护\长度)。虽然你需要手动添加服务器端验证,这些字段类型选项可以猜到的信息。

要求
要求选项可以猜测基于验证规则(即是NotBlankNotNull)或教义的元数据(即可以为空)。这是非常有用的,因为你的客户端验证将自动匹配您的验证规则。
max_length
如果字段是某种形式的文本字段,然后max_length选择从验证约束(如果可以猜到了长度范围使用)或教义的元数据(通过字段的长度)。

请注意

这些字段选项<新兴市场>只有猜如果你使用Symfony猜字段类型(即省略或通欧宝娱乐app下载地址过作为第二个参数add ())。

如果你想改变一个的猜测值,您可以重写它通过选项选项字段数组:

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

呈现一个表单模板

到目前为止,您已经看到了一个完整的呈现形式可以只有一行代码。当然,你通常会需要更多的灵活性在呈现:

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

你已经知道了form_start ()form_end ()函数,但其他功能做什么?

form_errors(形式)
全球整个形式呈现任何错误(每个字段旁边显示领域的错误)。
form_row (form.dueDate)
显示标签、任何错误和给定的字段的HTML表单小部件(如。dueDate)内,默认情况下,div元素。

大部分的工作是做的form_row辅助显示标签,错误和在每个字段的HTML表单小部件div默认的标签。在形式节中,您将了解如何form_row输出可以定制在许多不同的水平。

提示

你可以通过访问你的当前数据形式form.vars.value:

  • 嫩枝
  • PHP
1
{{form.vars.value。任务}}

渲染每个字段

form_row助手是伟大的,因为你可以很快呈现每个字段的表单(和标记用于“行”也可以定制)。但由于生活并不总是那么简单,你也可以完全由手工渲染每个字段。后的最终产品使用时是一样的form_row助手:

  • 嫩枝
  • PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
{{form_start(形式)}}{{form_errors(形式)}}<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(形式)}}

如果字段的自动生成的标签并不十分正确,可以显式地指定:

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

一些字段类型额外的渲染选项,可以传递到小部件。这些选项记录每种类型,但一个共同的选择attr,它允许您修改属性表单元素。以下将增加task_field类来呈现输入文本字段:

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

如果你需要渲染表单字段“手工”然后你可以访问个人价值观等领域id,的名字标签。例如获得id:

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

得到的值用于表单字段的名称属性需要使用full_name值:

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

树枝模板函数引用

如果你用树枝,一个完整的参考的形式呈现功能是可用的参考手册。读这篇文章了解可用的助手和可以使用的选项。

改变表单的动作和方法

到目前为止,form_start ()助手已经被用于呈现表单的开始标记,我们假定每个表单提交相同的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
{# app /资源/视图/ / new.html违约。树枝#}{{form_start(形式,{“行动”:路径(“target_route”)、“法”:“得到”})}}

请注意

如果表单的方法不是GET或POST,但把补丁或删除,Symfony会插入一个隐藏字段的名称欧宝娱乐app下载地址_method存储这个方法。表单将提交在一个正常的POST请求,但Symfony的路由器能够检测欧宝娱乐app下载地址_method参数,将它视为一个补丁或删除请求。阅读食谱”章如何使用HTTP方法除了GET和POST路线”的更多信息。

创建表单类

如您所见,一个表单可以直接创建和使用一个控制器。然而,更好的做法是建立在一个单独的形式,独立的PHP类,它可以在您的应用程序中重用。创建一个新类,它将构建任务的逻辑形式:

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

谨慎

getName ()方法返回此表单“类型”的标识符。这些标识符在应用程序中必须是惟一的。除非你想覆盖一个内置的类型,他们应该不同于默认的Symfony类型和从任何类型定义的第三方包安装在您的应用程序。欧宝娱乐app下载地址考虑类型前缀app_避免碰撞标识符。

这个新类包含所需的所有方向创建任务表单。它可以用于快速构建一个表单对象的控制器:

1 2 3 4 5 6 7 8 9 10 11 12
/ / src / AppBundle /控制器/ DefaultController.php/ /添加这个新的使用声明的类使用AppBundle\形式\类型\TaskType;公共函数newAction(){美元任务=……;美元形式=美元- >createForm (TaskType (),美元任务);/ /……}

把形式逻辑分类意味着形式可以很容易地在你的项目中重用。这是最好的方法来创建表单,但最终取决于你的选择。

每个表单需要知道类的名称,底层数据(例如实体AppBundle \ \任务)。通常情况下,这仅仅是猜测的基于对象传递给第二个参数createForm(即。美元的任务)。后来,当你开始嵌入形式,这将不再是足够的。所以,虽然并不总是必要的,通常是一个好主意来显式地指定data_class选择通过添加以下表单类型类:

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

提示

当映射对象的形式,所有字段映射。任何字段映射对象的形式,不存在会导致抛出一个异常。

在这种情况下,您需要额外的字段的形式(例如:“你同意这些条款”复选框),将不会被映射到底层对象,您需要设置映射选项:

1 2 3 4 5 6 7 8 9 10
使用欧宝娱乐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 / AppBundle /资源/ config / services.yml服务:app.form.type.task:类:AppBundle \ \ \ TaskType型形式标签:- - - - - -{名称:form.type,别名:app_task}

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

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

甚至从内部使用另一种形式的表单类型:

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

如何创建一个自定义表单字段类型为更多的信息。

形式和原则

一种形式的目的是将数据从一个对象(如任务)一个HTML表单,然后将用户提交的数据回到原来的对象。因此,坚持的主题任务对象到数据库是完全无关的主题形式。但是,如果你配置了任务类通过教义被持久化(即你补充道映射元数据),然后坚持它在表单提交时可以做形式是有效的:

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

如果出于某种原因,你没有访问你的原创美元的任务对象,您可以获取它的形式:

1
美元任务=美元形式- >getData ();

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

关键要理解的是,当提交表单,提交的数据立即转移到底层对象。如果你想保存这些数据,你只需要持久化对象本身(已经包含提交的数据)。

嵌入的形式

通常,您会希望构建一种包括来自许多不同的对象的字段。例如,一个属于一个注册表单可能包含数据用户对象以及许多地址对象。幸运的是,这很容易和自然与表单组件。

嵌入一个对象

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

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

接下来,添加一个新的类别财产任务类:

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

提示

有效的约束添加到属性类别。这瀑布验证相应的实体。如果您省略这个约束孩子不会验证实体。

现在,您的应用程序已经更新以反映新的需求,创建一个类,这样一个形式类别对象由用户可以修改:

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

最终目标是允许的类别任务在任务表单本身要修改的权利。为此,添加一个类别场的TaskType对象的类型的新实例CategoryType类:

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

的字段CategoryType现在可以一起呈现的TaskType类。

呈现类别字段一样原始任务字段:

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

当用户提交表单时,提交的数据类别字段是用于构造的一个实例类别,然后套上类别场的任务实例。

类别自然通过实例访问$任务- > getCategory ()并且可以但是你需要持久化到数据库或使用。

嵌入形式的集合

你也可以嵌入形式的集合到一个表单(想象一个类别有很多形式产品体)。这是通过使用集合字段类型。

更多信息见“如何嵌入一组形式和“食谱条目集合字段类型引用。

形式主题

的每一部分如何定制的形式呈现。你可以自由地改变每个形式呈现“行”,如何改变标记用于呈现错误,甚至定制如何文本区域标签应该呈现。没有限制,可以用在不同的地方和不同的定制。

欧宝娱乐app下载地址Symfony使用模板来呈现每一种形式的一部分,等标签标签,输入标签,和其他所有错误消息。

在小枝,每个表单“片段”是由一块树枝。定制任何部分的形式呈现,你只需要覆盖适当的块。

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

要理解这是如何工作的,定制的form_row片段和添加一个类属性div元素周围每一行。为此,创建一个新模板文件存储新的标记:

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

form_row表单片段是大多数字段通过渲染时使用form_row函数。告诉组件使用你的新形式form_row片段上面定义,添加以下的呈现形式的模板:

  • 嫩枝
  • PHP
1 2 3 4 5 6 7
{# app /资源/视图/ / new.html违约。树枝#}{%form_theme表单的表单/ fields.html。嫩枝' %}{#或如果你想使用多个主题#}{%form_theme表单的表单/ fields.html。/ fields2.html树枝的形式。嫩枝' %}{#……呈现形式#}

form_theme标签(嫩枝)“进口”定义的碎片在给定的模板,并使用它们在呈现表单。换句话说,当form_row在这个模板函数被调用后,它将使用form_row从自定义主题块(而不是默认的form_row附带Symfony的块)。欧宝娱乐app下载地址

自定义主题没有覆盖所有的块。在呈现一块不覆盖在您的自定义主题,主题引擎将回落到全球的主题(在包级别上定义)。

如果他们会提供了一些自定义主题搜索顺序列出之前回落全球主题。

定制表单的任何部分,你只需要覆盖适当的片段。知道哪些块或文件覆盖下一节的主题。

更广泛的讨论,请参阅如何自定义形式呈现

表单片段命名

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

在小枝,每一块需要被定义在一个模板文件(如form_div_layout.html.twig),生活在树枝桥。在这个文件中,您可以看到每一块需要呈现形式和每一个默认字段类型。

在PHP中,单个模板文件碎片。默认情况下它们位于资源/视图/形式FrameworkBundle目录(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) 渲染领域的整个行(标签、小部件和错误)

请注意

实际上有2<新兴市场>部分- - - - - -- - - - - -- - - - - -- - - - - -- - - - - -- - - - - -休息——但是你应该几乎从不需要担心覆盖它们。

通过了解字段类型(例如文本区域),哪个部分你想定制(如。小部件),您可以构建片段的名称需要覆盖(如。textarea_widget)。

模板片段继承

在某些情况下,您想要定制的片段将似乎失踪。例如,没有textarea_errors在Symfony提供的默认主题片段。欧宝娱乐app下载地址所以textarea字段显示的错误吗?

答案是:通过form_errors片段。当Symf欧宝娱乐app下载地址ony呈现文本区域的错误类型,它看起来第一的textarea_errors片段之前回下降form_errors片段。每个字段类型都有<新兴市场>父类型(父类型的文本区域文本,它的父形式),Symfo欧宝娱乐app下载地址ny的片段使用父类型如果基本片段不存在。

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

提示

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

全球形式主题

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

嫩枝

自动包括定制的街区fields.html.twig模板创建的早些时候<新兴市场>所有模板,修改应用程序配置文件:

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

任何一块内fields.html.twig模板现在在全球范围内用于定义形式输出。

在树枝,还可以定制一个表单内块正确的模板定制需要的地方:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
{%扩展“base.html。嫩枝' %}{#进口“_self”为形式的主题#}{%form_theme形式_self %}{#让表单片段定制#}{%form_row %}{#自定义字段行输出#}{%endblockform_row %}{%内容%}{#……#}{{form_row (form.task)}}{%endblock%}

{% form_theme形式_self %}标记允许自定义表单模块直接在模板将使用这些定制。使用这个方法快速使形式输出定制,只需要在一个模板。

谨慎

{% form_theme形式_self %}功能将<新兴市场>只有如果你的模板扩展另一个工作。如果你的模板不,你必须点form_theme到一个单独的模板。

PHP

从自动包括定制模板应用程序/资源/视图/形式目录之前创建<新兴市场>所有模板,修改应用程序配置文件:

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

任何片段里应用程序/资源/视图/形式目录目前全球用于定义形式输出。

CSRF保护

CSRF——或者跨站点请求伪造——是一个恶意用户的方法试图让你合法用户在不知情的情况下提交数据,他们不打算提交。幸运的是,可以阻止CSRF攻击使用CSRF令牌在你的形式。

好消息是,默认情况欧宝app在哪里找下,Symfony嵌入和验证CSRF令牌自动为你。欧宝娱乐app下载地址这意味着您可以利用CSRF保护什么事情都不做。事实上,每个表单在本章利用CSRF保护!

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

_token字段是一个隐藏字段,如果包括会自动呈现form_end ()函数模板,它确保所有un-rendered字段输出。

谨慎

因为令牌是存储在会话中,一个会话开始自动就呈现一种形式与CSRF保护。

CSRF令牌可以定制form-by-form基础上。例如:

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

禁用CSRF保护,设置csrf_protection选择错误的。也可以在您的项目在全球范围内的定制。有关更多信息,请参见形式配置参考部分。

请注意

意图选项是可选的但是,极大地增强了安全生成的令牌使它不同形式。

谨慎

CSRF标记是不同的对于每一个用户。这就是为什么你需要谨慎,如果你试图缓存页面形式包括这种保护。有关更多信息,请参见缓存的页面包含CSRF保护形式

使用一种形式没有一个类

在大多数情况下,一种形式是与一个对象,表单的字段获取和存储数据的属性对象。这正是你看到到目前为止在本章的“任务”类。

但有时,您可能想要使用一种形式没有一个类,然后重新提交数据的数组。这实际上是很简单:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21日22日23日
/ /确保你进口上述请求的名称空间使用欧宝娱乐app下载地址\组件\HttpFoundation\请求;/ /……公共函数contactAction(请求美元请求){美元defaultData=数组(“消息”= >这里输入您的消息的);美元形式=美元- >createFormBuilder (美元defaultData)- >add (“名字”,“文本”)- >add (“电子邮件”,“电子邮件”)- >add (“消息”,“文本区域”)- >add (“发送”,“提交”)- >getForm ();美元形式- >handleRequest (美元请求);如果(美元形式- >isValid ()) {/ /数据数组与“名称”、“电子邮件”,“信息”键美元数据=美元形式- >getData ();}/ /……呈现形式}

默认情况下,一种形式实际上假设您希望使用数组的数据,而不是一个对象。确切地说,有两种方法可以改变这一行为和领带表单对象而不是:

  1. 通过一个对象在创建表单(第一个参数createFormBuilder或第二个参数createForm);
  2. 声明data_class选择表单。

如果你<新兴市场>不做这两种,那么将返回一个数组的数据形式。在这个例子中,defaultData美元不是一个对象(和没有data_class选项设置),$形式- > getData ()最终返回一个数组。

提示

您还可以访问后值(在本例中“名字”)直接通过请求对象,如下所示:

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

建议,然而,在大多数情况下使用getData ()方法是一种更好的选择,因为它返回后的数据(通常是一个对象)转换的表单组件。

添加验证

唯一缺少的功能验证。通常,当你调用$ - > isValid形式(),对象是验证通过阅读的约束应用于该类。如果表单映射到一个对象(即你使用data_class选择表单或传递一个对象),这是几乎总是你想要使用的方法。看到验证为更多的细节。

但如果表单不是映射到一个对象,你不是想要检索一个简单的数组你提交的资料,如何约束添加到表单的数据吗?

答案是自己设置的约束,并附上个人领域。整体的方法是更多的覆盖验证章,但是这里有一个简单的例子:

2.1

约束选项,它接受一个单一的约束或一组约束(2.1之前,选择是validation_constraint,只有接受一个约束)是在Symfony 2.1中引入的。欧宝娱乐app下载地址

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

提示

如果您使用的是验证组,需要引用默认的集团在创建表单时,或一组正确的小组所添加的约束。

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

最终的想法

你现在知道所有的构件必须为应用程序构建复杂和功能形式。在构建形式时,记住,一个表单的第一个目标是将数据从一个对象(任务)HTML表单,以便用户可以修改该数据。一种形式的第二个目标是把用户提交的数据并重新应用到对象。

还有更多学习的强大的世界形式,比如如何处理文件上传或如何创建一个形式,一个动态的表单可以添加(例如一个todo列表,您可以继续添加更多的领域通过JavaScript之前提交)。看到这些主题的食谱。另外,一定要依靠字段类型参考文档欧宝体育电话,其中包括如何使用的例子,每个字段类型及其选择。

这项工作,包括代码示例,许可下Creative Commons冲锋队3.0许可证。
< /article>
< /div> 版本: