如何嵌入一个集合的形式
编辑本页警告:您正在浏览的文档欧宝官网下载appob娱乐下载Symfony 2.3,现已不再维护。
读本页的更新版本用于Syob娱乐下载mfony 6.2(当前稳定版本)。
任务类,并且您想编辑/创建/删除许多标签
与该任务相关的对象,就在同一个表单中。
请注意
在本条目中,我们粗略地假设您使用Doctrine作为数据库存储。但如果你不使用Doctrine(例如,Propel或只是一个数据库连接),这是非常相似的。本教程中只有少数部分真正关心“持久性”。
如果你是使用Doctrine时,您将需要添加Doctrine元数据,包括多
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 26 27 28 29 30 31
/ / src / AppBundle /实体/ Task.php名称空间AppBundle\实体;使用学说\常见的\集合\ArrayCollection;类任务{受保护的$描述;受保护的$标签;公共函数__construct(){$这->标签=新ArrayCollection ();}公共函数getDescription(){返回$这->描述;}公共函数setDescription($描述){$这->描述=$描述;}公共函数getTags(){返回$这->标签;}}
请注意
的ArrayCollection
是教义所特有的,基本上与使用数组
(但它必须是一个ArrayCollection
如果你使用的是Doctrine)。
现在,创建一个标签
类。正如你在上面看到的,a任务
可以有很多标签
对象:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/ / src / AppBundle /实体/ Tag.php名称空间AppBundle\实体;类标签{私人$的名字;公共函数getName(){返回$这->名称;}公共函数setName($的名字){$这->name =$的名字;}}
然后,创建一个表单类,以便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 / AppBundle / /类型/ TagType.php形式名称空间AppBundle\形式\类型;使用ob娱乐下载\组件\形式\AbstractType;使用ob娱乐下载\组件\形式\FormBuilderInterface;使用ob娱乐下载\组件\OptionsResolver\OptionsResolverInterface;类TagType扩展AbstractType{公共函数buildForm(FormBuilderInterface$构建器数组,$选项){$构建器->add (“名字”);}公共函数setDefaultOptions(OptionsResolverInterface$解析器){$解析器->setDefaults (数组(“data_class”= >“AppBundle \实体\标签”));}公共函数getName(){返回“标签”;}}
有了这些,您就足够单独呈现一个标签表单了。但由于最终目标是允许a的标记任务
控件的窗体中进行修改,请为任务
类。
的集合TagType
使用集合字段类型:
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
/ / src / AppBundle / /类型/ TaskType.php形式名称空间AppBundle\形式\类型;使用ob娱乐下载\组件\形式\AbstractType;使用ob娱乐下载\组件\形式\FormBuilderInterface;使用ob娱乐下载\组件\OptionsResolver\OptionsResolverInterface;类TaskType扩展AbstractType{公共函数buildForm(FormBuilderInterface$构建器数组,$选项){$构建器->add (“描述”);$构建器->add (“标签”,“收集”,数组(“类型”= >新TagType ()));}公共函数setDefaultOptions(OptionsResolverInterface$解析器){$解析器->setDefaults (数组(“data_class”= >“实体AppBundle \ \任务”));}公共函数getName(){返回“任务”;}}
的一个新实例TaskType
:
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 36 37 38
/ / src / AppBundle /控制器/ TaskController.php名称空间AppBundle\控制器;使用AppBundle\实体\任务;使用AppBundle\实体\标签;使用AppBundle\形式\类型\TaskType;使用ob娱乐下载\组件\HttpFoundation\请求;使用ob娱乐下载\包\FrameworkBundle\控制器\控制器;类TaskController扩展控制器{公共函数newAction(请求$请求){$任务=新任务();//伪代码-这里只是为了任务有一些标签//否则,这不是一个有趣的例子$标签1=新标签();$标签1->setName (“标签1”);$任务->getTags ()->add ($标签1);$标签2=新标签();$标签2->setName (标签2的);$任务->getTags ()->add ($标签2);//结束虚拟代码$形式=$这->createForm (新TaskType (),$任务);$形式->handleRequest ($请求);如果($形式->isValid ()) {/ /……可能会做一些表单处理,比如保存Task和Tag对象}返回$这->呈现(“AppBundle:任务:new.html.twig”,数组(“形式”= >$形式->createView ()));}}
对应的模板现在能够同时呈现描述
字段的TagType
已经与此相关的任何标记的表单任务
.在上面的控制器中,我添加了一些虚拟代码,这样你就可以看到它的作用(因为a任务
第一次创建时没有标记)。
- 嫩枝
- PHP
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
{# src / AppBundle /资源/视图/任务/ new.html。树枝#}{#……#}{{form_start(form)}}{#渲染任务的唯一字段:description #}{{form_row(form.description)}}<h3>标签h3><ul类=“标签”>{#遍历每个现有标签并呈现其唯一字段:name #}{%为形式上的标签。标签%}<李>{{form_row(tag.name)}}李>{%endfor%}ul>{{form_end(form)}}{#……#}
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
<!——src/AppBundle/Resources/views/Task/new.html.php——> .php<!——……--><?php回声$视图[“形式”]->开始($形式)? ><!——渲染任务的唯一字段:description——><?php回声$视图[“形式”]->行($形式[“描述”])? ><h3>标签h3><ul类=“标签”><?phpforeach($形式[“标签”]作为$标签):? ><李><?php回声$视图[“形式”]->行($标签[“名字”])? >李><?phpendforeach? >ul><?php回声$视图[“形式”]->结束($形式)? ><!——……-->
当用户提交表单时,提交的数据为标签
字段用于构造一个ArrayCollection
的标签
对象,然后在标签
字段任务
实例。
的标签
收集自然是通过任务- > getTags ()
并且可以持久化到数据库中,或者根据需要任意使用。
到目前为止,这工作得很好,但不允许动态添加新标记或删除现有标记。因此,虽然编辑现有的标签会工作得很好,但用户实际上还不能添加任何新标签。
谨慎
在这个条目中,您只嵌入了一个集合,但不限于此。您还可以将嵌套集合嵌入到您喜欢的任意级别。但是,如果在开发设置中使用Xdebug,则可能会收到一个错误已达到'100'的最大函数嵌套级别,中止!
错误。这是由于xdebug.max_nesting_level
PHP设置,默认为One hundred.
.
这个指令将递归限制在100个调用,如果你一次呈现整个表单,这可能还不够form_widget(形式)
).要解决这个问题,你可以将这个指令设置为一个更高的值(通过aphp . ini
档案或经由报错,例如在app / autoload.php
)或手动渲染每个表单字段form_row
.
此表单不应包含额外字段.要使其更加灵活,可以添加allow_add
选择您的收集字段:
12 3 4 5 6 7 8 9 10 11 12 13 14
/ / src / AppBundle / /类型/ TaskType.php形式/ /……使用ob娱乐下载\组件\形式\FormBuilderInterface;公共函数buildForm(FormBuilderInterface$构建器数组,$选项){$构建器->add (“描述”);$构建器->add (“标签”,“收集”,数组(“类型”= >新TagType (),“allow_add”= >真正的));}
除了告诉字段接受任意数量的提交对象之外,allow_add
也会产生“原型”变量可供您选择。这个“原型”是一个小的“模板”,它包含了能够呈现任何新“标签”表单的所有HTML。要渲染它,请对模板进行以下更改:
- 嫩枝
- PHP
1 2 3
<ul类=“标签”data-prototype="{{form_widget(form.tags.vars.prototype)|e('html_attr')}}">...ul>
1 2 3 4 5
<ul类=“标签”data-prototype=“< ?php echo $视图- >逃脱(视图(“形式”)- >行美元(美元形式['标签']- > var[‘原型’]))? > ">...ul>
请注意
如果你渲染你的整个“标签”子表单一次(例如。form_row (form.tags)
),则原型自动可在外部使用div
随着data-prototype
属性,类似于上面所看到的。
提示
的form.tags.vars.prototype
表单元素看起来和感觉起来就像个体吗form_widget(标签)
您的为
循环。这意味着你可以打电话form_widget
,form_row
或了form_label
在上面。你甚至可以选择只呈现它的一个字段(例如的名字
字段):
1
{{form_widget(form.tags.vars.prototype.name)|e}}
在渲染的页面上,结果看起来像这样:
1
<ul类=“标签”data-prototype="& lt;div比;& lt;标签类=“;要求“;比;__name__& lt;/标签比;& lt;div id =“;task_tags___name__“;比;& lt;div比;& lt;标签=“;task_tags___name___name“;类=“;要求“;比;的名字& lt;/标签比;& lt;输入类型=“;文本“;id =“;task_tags___name___name“;name =“;任务[标记][__name__][名称]“;要求=“;要求“;最大长度=“;255“;/比;& lt;/ div比;& lt;/ div比;& lt;/ div比;">
本节的目标是使用JavaScript读取该属性,并在用户单击“添加标记”链接时动态添加新的标记表单。为了简单起见,本示例使用jQuery,并假设您已经将它包含在页面的某个地方。
添加一个脚本
标签,这样您就可以开始编写JavaScript了。
首先,通过JavaScript将一个链接添加到“tags”列表的底部。其次,绑定到该链接的“click”事件,这样您就可以添加一个新的标记表单(addTagForm
将在下一页显示):
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
varcollectionHolder美元;//设置一个“添加标签”链接var$addTagLink = $('添加标签');var$newLinkLi = $李李' < > < / > ') .append (addTagLink美元);jQuery (文档时(函数(){//获取包含标签集合的ul$collectionHolder = $(“ul.tags”);//添加“添加标签”锚和li到标签ul(collectionHolder.append美元newLinkLi);//计算当前的表单输入(例如2),使用它作为新的//当插入一个新项时(例如2)collectionHolder.data美元(“指数”collectionHolder.find美元(:输入) . length);addTagLink.on美元(“点击”,函数(e){//阻止链接在URL上创建“#e.preventDefault ();//添加一个新的标签表单(见下一个代码块)addTagForm (collectionHolder, newLinkLi美元);});});
的addTagForm
函数的工作是使用data-prototype
属性在单击此链接时动态添加新表单。的data-prototype
HTML包含标签文本
输入名称为的元素任务[标记][__name__][名称]
的idtask_tags___name___name
.的__name__
是一个小的“占位符”,您将用一个唯一的递增数字(例如。任务[标记][3][名称]
).
实现这一切所需的实际代码可能会有很大的不同,但这里有一个例子:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
函数addTagForm(collectionHolder, newLinkLi美元){//获取前面解释的数据原型var$collectionHolder.data(“原型”);//获取新的索引var$collectionHolder.data(“指数”);//将原型HTML中的__name__替换为//而是一个基于我们有多少项的数字varnewForm = prototype.replace(/ __name__ / g、指数);//为下一项增加索引collectionHolder.data美元(“指数”, index +1);//在“添加标签”链接之前,以一里的单位显示页面中的表单var$newFormLi = $(李李' < > < / > ') .append (newForm中将);(newLinkLi.before美元newFormLi);}
请注意
最好将JavaScript分离到真正的JavaScript文件中,而不是像这里这样在HTML中编写。
现在,每当用户单击添加标签
链接,一个新的子表单将出现在页面上。当表单提交时,任何新的标签表单都将转换为新的标签
对象,并添加到标签
的属性任务
对象。
另请参阅
您可以在这里找到一个工作示例JSFiddle.
另请参阅
如果您想自定义原型中的HTML代码,请阅读如何自定义表单渲染.
控件中的标记添加一个“加法器”和一个“移除器”方法,使处理这些新标记更加容易任务
类:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/ / src / AppBundle /实体/ Task.php名称空间AppBundle\实体;/ /……类任务{/ /……公共函数addTag(标签$标签){$这->标签->add ($标签);}公共函数removeTag(标签$标签){/ /……}}
接下来,添加一个by_reference
选项。标签
字段并设置为假
:
12 3 4 5 6 7 8 9 10 11 12
/ / src / AppBundle / /类型/ TaskType.php形式/ /……公共函数buildForm(FormBuilderInterface$构建器数组,$选项){/ /……$构建器->add (“标签”,“收集”,数组(/ /……“by_reference”= >假));}
通过这两个更改,当表单提交时,每个更改都是新的标签
对象添加到任务
类,通过调用addTag
方法。在此更改之前,它们是通过调用在表单内部添加的任务- > getTags() - >添加标签($)
.这很好,但是强制使用“加法器”方法使得处理这些问题变得很新鲜标签
对象更容易(特别是如果你使用Doctrine,你将在接下来学习!)。
谨慎
你必须创造这两个addTag
而且removeTag
方法,否则表单仍将使用setTag
即使by_reference
是假
.你会学到更多关于removeTag
方法。
原则:级联关系和保存“逆”面
为了保存Doctrine的新标签,您需要考虑更多的事情。首先,除非遍历所有的new标签
对象和调用(em - >坚持美元标签)
在每一个,你会收到一个来自Doctrine的错误:
通过这种关系发现了一个新的实体实体AppBundle \ \任务#标签
没有配置为级联实体的持久化操作…
方法自动“级联”持久化操作任务
对象到任何相关标记。要做到这一点,请添加级联
选择您的多
元数据:
- 注释
- YAML
- XML
1 2 3 4 5 6 7 8
/ / src / AppBundle /实体/ Task.php/ /……/ * * *@ORM\ManyToMany(targetEntity="Tag", cascade={"persist"}) */受保护的$标签;
1 2 3 4 5 6 7 8
# src / AppBundle /资源/ config /理论/ Task.orm.yml实体AppBundle \ \任务:类型:实体#……对:标签:targetEntity:标签级联:(持续)
12 3 4 5 6 7 8 9 10 11 12 13 14 15
<!——src/AppBundle/Resources/config/doctrine/Task.orm.xml——> .xml<doctrine-mappingxmlns=“http://doctrine-project.org/schemas/orm/doctrine-mapping”xmlns: xsi=“http://www.w3.org/2001/XMLSchema-instance”xsi: schemaLocation=“http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd”><实体的名字=“实体AppBundle \ \任务”><!——……--><一对多场=“标签”目标实体=“标签”><级联><层叠persist/>级联>一对多>实体>doctrine-mapping>
第二个潜在的问题涉及拥有侧和反向侧教义关系。在这个例子中,如果关系的“拥有”方是“Task”,那么持久化将很好地工作,因为标记被正确地添加到Task中。但是,如果所属方在“Tag”上,那么您将需要做更多的工作,以确保修改关系的正确一方。
诀窍是确保每个“标签”上都设置了单个“任务”。做到这一点的一个简单方法是添加一些额外的逻辑addTag ()
,由表单类型since调用by_reference
设置为假
:
1 2 3 4 5 6 7 8 9
/ / src / AppBundle /实体/ Task.php/ /……公共函数addTag(标签$标签){$标签->addTask ($这);$这->标签->add ($标签);}
内部标签
,只要确保你有一个addTask
方法:
1 2 3 4 5 6 7 8 9
/ / src / AppBundle /实体/ Tag.php/ /……公共函数addTask(任务$任务){如果(!$这->任务->包含($任务)) {$这->任务->add ($任务);}}
如果您有一对多关系,那么除了可以简单地调用之外,解决方法也类似setTask
从内addTag
.
allow_delete类型:
12 3 4 5 6 7 8 9 10 11 12
/ / src / AppBundle / /类型/ TaskType.php形式/ /……公共函数buildForm(FormBuilderInterface$构建器数组,$选项){/ /……$构建器->add (“标签”,“收集”,数组(/ /……“allow_delete”= >真正的));}
现在,需要将一些代码放入removeTag
的方法任务
:
12 3 4 5 6 7 8 9 10 11 12
/ / src / AppBundle /实体/ Task.php/ /……类任务{/ /……公共函数removeTag(标签$标签){$这->标签->removeElement ($标签);}}
allow_delete选项有一个后果:如果集合的项在提交时没有发送,则相关数据将从服务器上的集合中删除。因此,解决方案是从DOM中删除表单元素。
首先,在每个标签表单中添加一个“delete this tag”链接:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
jQuery (文档时(函数(){//获取包含标签集合的ul$collectionHolder = $(“ul.tags”);//添加一个删除链接到所有现有的标签形式li元素collectionHolder.find美元(“李”) . each (函数(){addTagFormDeleteLink ($ (这));});/ /……从上面看剩下的街区});函数addTagForm(){/ /……//添加一个删除链接到新表单addTagFormDeleteLink ($ newFormLi);}
的addTagFormDeleteLink
函数看起来是这样的:
12 3 4 5 6 7 8 9 10 11 12
函数addTagFormDeleteLink(tagFormLi美元){var$removeFormA = $('delete this tag');(tagFormLi.append美元removeFormA);removeFormA.on美元(“点击”,函数(e){//阻止链接在URL上创建“#e.preventDefault ();//删除标签表单的li美元tagFormLi.remove ();});}
当一个标签表单从DOM中删除并提交时,被删除的标签
对象将不包含在传递给的集合中setTags
.根据您的持久性层,这可能不足以实际删除被删除对象之间的关系标签
而且任务
对象。
原则:确保数据库持久性
当以这种方式删除对象时,您可能需要多做一点工作,以确保对象之间的关系任务
被移除的标签
被正确移除。
在《主义》中,你有关系的两个方面:拥有的一面和相反的一面。通常在这种情况下,您将拥有一个多对多的关系,删除的标记将消失并正确地保存(添加新标记也很容易)。
但是如果你有一对多的关系或者多对多的关系的mappedBy
在Task实体上(意味着Task是“逆”面),您将需要做更多的工作来正确地保存已删除的标记。
在这种情况下,您可以修改控制器以删除已删除标记上的关系。假设你有一些editAction
它正在处理任务的“更新”:
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
/ / src / AppBundle /控制器/ TaskController.php使用学说\常见的\集合\ArrayCollection;/ /……公共函数editAction($id,请求$请求){$新兴市场=$这->getDoctrine ()->getManager ();$任务=$新兴市场->getRepository (“AppBundle:任务”)->找到($id);如果(!$任务) {扔$这->createNotFoundException (“没有找到任务”.$id);}$originalTags=新ArrayCollection ();//创建数据库中当前Tag对象的ArrayCollectionforeach($任务->getTags ()作为$标签) {$originalTags->add ($标签);}$editForm=$这->createForm (新TaskType (),$任务);$editForm->handleRequest ($请求);如果($editForm->isValid ()) {//删除标签和任务之间的关系foreach($originalTags作为$标签) {如果(假= = =$任务->getTags ()->包含($标签)) {//从标签中删除任务$标签->getTasks ()->removeElement ($任务);//如果它是一个多对一关系,像这样删除关系/ /标签- > setTask(空);$新兴市场->persist ($标签);//如果你想完全删除标签,你也可以这样做/ / em - >删除美元($标签);}}$新兴市场->persist ($任务);$新兴市场->冲洗();//重定向到某个编辑页面返回$这->重定向($这->generateUrl (“task_edit”,数组(“id”= >$id)));}//渲染一些表单模板}
如您所见,正确地添加和删除元素可能很棘手。除非您有一个Task是“拥有”方的多对多关系,否则您将需要做额外的工作,以确保在每个Tag对象本身上正确地更新关系(无论是添加新标记还是删除现有标记)。
请注意
在本条目中,我们粗略地假设您使用Doctrine作为数据库存储。但如果你不使用Doctrine(例如,Propel或只是一个数据库连接),这是非常相似的。本教程中只有少数部分真正关心“持久性”。
如果你是使用Doctrine时,您将需要添加Doctrine元数据,包括多
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 26 27 28 29 30 31
/ / src / AppBundle /实体/ Task.php名称空间AppBundle\实体;使用学说\常见的\集合\ArrayCollection;类任务{受保护的$描述;受保护的$标签;公共函数__construct(){$这->标签=新ArrayCollection ();}公共函数getDescription(){返回$这->描述;}公共函数setDescription($描述){$这->描述=$描述;}公共函数getTags(){返回$这->标签;}}
请注意
的ArrayCollection
是教义所特有的,基本上与使用数组
(但它必须是一个ArrayCollection
如果你使用的是Doctrine)。
标签
类。正如你在上面看到的,a任务
可以有很多标签
对象:12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/ / src / AppBundle /实体/ Tag.php名称空间AppBundle\实体;类标签{私人$的名字;公共函数getName(){返回$这->名称;}公共函数setName($的名字){$这->name =$的名字;}}
标签
对象可以被用户修改: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 / AppBundle / /类型/ TagType.php形式名称空间AppBundle\形式\类型;使用ob娱乐下载\组件\形式\AbstractType;使用ob娱乐下载\组件\形式\FormBuilderInterface;使用ob娱乐下载\组件\OptionsResolver\OptionsResolverInterface;类TagType扩展AbstractType{公共函数buildForm(FormBuilderInterface$构建器数组,$选项){$构建器->add (“名字”);}公共函数setDefaultOptions(OptionsResolverInterface$解析器){$解析器->setDefaults (数组(“data_class”= >“AppBundle \实体\标签”));}公共函数getName(){返回“标签”;}}
任务
控件的窗体中进行修改,请为任务
类。TagType
使用集合字段类型: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
/ / src / AppBundle / /类型/ TaskType.php形式名称空间AppBundle\形式\类型;使用ob娱乐下载\组件\形式\AbstractType;使用ob娱乐下载\组件\形式\FormBuilderInterface;使用ob娱乐下载\组件\OptionsResolver\OptionsResolverInterface;类TaskType扩展AbstractType{公共函数buildForm(FormBuilderInterface$构建器数组,$选项){$构建器->add (“描述”);$构建器->add (“标签”,“收集”,数组(“类型”= >新TagType ()));}公共函数setDefaultOptions(OptionsResolverInterface$解析器){$解析器->setDefaults (数组(“data_class”= >“实体AppBundle \ \任务”));}公共函数getName(){返回“任务”;}}
TaskType
: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 36 37 38
/ / src / AppBundle /控制器/ TaskController.php名称空间AppBundle\控制器;使用AppBundle\实体\任务;使用AppBundle\实体\标签;使用AppBundle\形式\类型\TaskType;使用ob娱乐下载\组件\HttpFoundation\请求;使用ob娱乐下载\包\FrameworkBundle\控制器\控制器;类TaskController扩展控制器{公共函数newAction(请求$请求){$任务=新任务();//伪代码-这里只是为了任务有一些标签//否则,这不是一个有趣的例子$标签1=新标签();$标签1->setName (“标签1”);$任务->getTags ()->add ($标签1);$标签2=新标签();$标签2->setName (标签2的);$任务->getTags ()->add ($标签2);//结束虚拟代码$形式=$这->createForm (新TaskType (),$任务);$形式->handleRequest ($请求);如果($形式->isValid ()) {/ /……可能会做一些表单处理,比如保存Task和Tag对象}返回$这->呈现(“AppBundle:任务:new.html.twig”,数组(“形式”= >$形式->createView ()));}}
描述
字段的TagType
已经与此相关的任何标记的表单任务
.在上面的控制器中,我添加了一些虚拟代码,这样你就可以看到它的作用(因为a任务
第一次创建时没有标记)。- 嫩枝
- PHP
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
{# src / AppBundle /资源/视图/任务/ new.html。树枝#}{#……#}{{form_start(form)}}{#渲染任务的唯一字段:description #}{{form_row(form.description)}}<h3>标签h3><ul类=“标签”>{#遍历每个现有标签并呈现其唯一字段:name #}{%为形式上的标签。标签%}<李>{{form_row(tag.name)}}李>{%endfor%}ul>{{form_end(form)}}{#……#}
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
<!——src/AppBundle/Resources/views/Task/new.html.php——> .php<!——……--><?php回声$视图[“形式”]->开始($形式)? ><!——渲染任务的唯一字段:description——><?php回声$视图[“形式”]->行($形式[“描述”])? ><h3>标签h3><ul类=“标签”><?phpforeach($形式[“标签”]作为$标签):? ><李><?php回声$视图[“形式”]->行($标签[“名字”])? >李><?phpendforeach? >ul><?php回声$视图[“形式”]->结束($形式)? ><!——……-->
标签
字段用于构造一个ArrayCollection
的标签
对象,然后在标签
字段任务
实例。标签
收集自然是通过任务- > getTags ()
并且可以持久化到数据库中,或者根据需要任意使用。谨慎
在这个条目中,您只嵌入了一个集合,但不限于此。您还可以将嵌套集合嵌入到您喜欢的任意级别。但是,如果在开发设置中使用Xdebug,则可能会收到一个错误已达到'100'的最大函数嵌套级别,中止!
错误。这是由于xdebug.max_nesting_level
PHP设置,默认为One hundred.
.
这个指令将递归限制在100个调用,如果你一次呈现整个表单,这可能还不够form_widget(形式)
).要解决这个问题,你可以将这个指令设置为一个更高的值(通过aphp . ini
档案或经由报错,例如在app / autoload.php
)或手动渲染每个表单字段form_row
.
此表单不应包含额外字段.要使其更加灵活,可以添加allow_add
选择您的收集字段:
12 3 4 5 6 7 8 9 10 11 12 13 14
/ / src / AppBundle / /类型/ TaskType.php形式/ /……使用ob娱乐下载\组件\形式\FormBuilderInterface;公共函数buildForm(FormBuilderInterface$构建器数组,$选项){$构建器->add (“描述”);$构建器->add (“标签”,“收集”,数组(“类型”= >新TagType (),“allow_add”= >真正的));}
除了告诉字段接受任意数量的提交对象之外,allow_add
也会产生“原型”变量可供您选择。这个“原型”是一个小的“模板”,它包含了能够呈现任何新“标签”表单的所有HTML。要渲染它,请对模板进行以下更改:
- 嫩枝
- PHP
1 2 3
<ul类=“标签”data-prototype="{{form_widget(form.tags.vars.prototype)|e('html_attr')}}">...ul>
1 2 3 4 5
<ul类=“标签”data-prototype=“< ?php echo $视图- >逃脱(视图(“形式”)- >行美元(美元形式['标签']- > var[‘原型’]))? > ">...ul>
请注意
如果你渲染你的整个“标签”子表单一次(例如。form_row (form.tags)
),则原型自动可在外部使用div
随着data-prototype
属性,类似于上面所看到的。
提示
的form.tags.vars.prototype
表单元素看起来和感觉起来就像个体吗form_widget(标签)
您的为
循环。这意味着你可以打电话form_widget
,form_row
或了form_label
在上面。你甚至可以选择只呈现它的一个字段(例如的名字
字段):
1
{{form_widget(form.tags.vars.prototype.name)|e}}
在渲染的页面上,结果看起来像这样:
1
<ul类=“标签”data-prototype="& lt;div比;& lt;标签类=“;要求“;比;__name__& lt;/标签比;& lt;div id =“;task_tags___name__“;比;& lt;div比;& lt;标签=“;task_tags___name___name“;类=“;要求“;比;的名字& lt;/标签比;& lt;输入类型=“;文本“;id =“;task_tags___name___name“;name =“;任务[标记][__name__][名称]“;要求=“;要求“;最大长度=“;255“;/比;& lt;/ div比;& lt;/ div比;& lt;/ div比;">
本节的目标是使用JavaScript读取该属性,并在用户单击“添加标记”链接时动态添加新的标记表单。为了简单起见,本示例使用jQuery,并假设您已经将它包含在页面的某个地方。
添加一个脚本
标签,这样您就可以开始编写JavaScript了。
首先,通过JavaScript将一个链接添加到“tags”列表的底部。其次,绑定到该链接的“click”事件,这样您就可以添加一个新的标记表单(addTagForm
将在下一页显示):
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
varcollectionHolder美元;//设置一个“添加标签”链接var$addTagLink = $('添加标签');var$newLinkLi = $李李' < > < / > ') .append (addTagLink美元);jQuery (文档时(函数(){//获取包含标签集合的ul$collectionHolder = $(“ul.tags”);//添加“添加标签”锚和li到标签ul(collectionHolder.append美元newLinkLi);//计算当前的表单输入(例如2),使用它作为新的//当插入一个新项时(例如2)collectionHolder.data美元(“指数”collectionHolder.find美元(:输入) . length);addTagLink.on美元(“点击”,函数(e){//阻止链接在URL上创建“#e.preventDefault ();//添加一个新的标签表单(见下一个代码块)addTagForm (collectionHolder, newLinkLi美元);});});
的addTagForm
函数的工作是使用data-prototype
属性在单击此链接时动态添加新表单。的data-prototype
HTML包含标签文本
输入名称为的元素任务[标记][__name__][名称]
的idtask_tags___name___name
.的__name__
是一个小的“占位符”,您将用一个唯一的递增数字(例如。任务[标记][3][名称]
).
实现这一切所需的实际代码可能会有很大的不同,但这里有一个例子:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
函数addTagForm(collectionHolder, newLinkLi美元){//获取前面解释的数据原型var$collectionHolder.data(“原型”);//获取新的索引var$collectionHolder.data(“指数”);//将原型HTML中的__name__替换为//而是一个基于我们有多少项的数字varnewForm = prototype.replace(/ __name__ / g、指数);//为下一项增加索引collectionHolder.data美元(“指数”, index +1);//在“添加标签”链接之前,以一里的单位显示页面中的表单var$newFormLi = $(李李' < > < / > ') .append (newForm中将);(newLinkLi.before美元newFormLi);}
请注意
最好将JavaScript分离到真正的JavaScript文件中,而不是像这里这样在HTML中编写。
现在,每当用户单击添加标签
链接,一个新的子表单将出现在页面上。当表单提交时,任何新的标签表单都将转换为新的标签
对象,并添加到标签
的属性任务
对象。
另请参阅
您可以在这里找到一个工作示例JSFiddle.
另请参阅
如果您想自定义原型中的HTML代码,请阅读如何自定义表单渲染.
控件中的标记添加一个“加法器”和一个“移除器”方法,使处理这些新标记更加容易任务
类:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/ / src / AppBundle /实体/ Task.php名称空间AppBundle\实体;/ /……类任务{/ /……公共函数addTag(标签$标签){$这->标签->add ($标签);}公共函数removeTag(标签$标签){/ /……}}
接下来,添加一个by_reference
选项。标签
字段并设置为假
:
12 3 4 5 6 7 8 9 10 11 12
/ / src / AppBundle / /类型/ TaskType.php形式/ /……公共函数buildForm(FormBuilderInterface$构建器数组,$选项){/ /……$构建器->add (“标签”,“收集”,数组(/ /……“by_reference”= >假));}
通过这两个更改,当表单提交时,每个更改都是新的标签
对象添加到任务
类,通过调用addTag
方法。在此更改之前,它们是通过调用在表单内部添加的任务- > getTags() - >添加标签($)
.这很好,但是强制使用“加法器”方法使得处理这些问题变得很新鲜标签
对象更容易(特别是如果你使用Doctrine,你将在接下来学习!)。
谨慎
你必须创造这两个addTag
而且removeTag
方法,否则表单仍将使用setTag
即使by_reference
是假
.你会学到更多关于removeTag
方法。
原则:级联关系和保存“逆”面
为了保存Doctrine的新标签,您需要考虑更多的事情。首先,除非遍历所有的new标签
对象和调用(em - >坚持美元标签)
在每一个,你会收到一个来自Doctrine的错误:
通过这种关系发现了一个新的实体实体AppBundle \ \任务#标签
没有配置为级联实体的持久化操作…
方法自动“级联”持久化操作任务
对象到任何相关标记。要做到这一点,请添加级联
选择您的多
元数据:
- 注释
- YAML
- XML
1 2 3 4 5 6 7 8
/ / src / AppBundle /实体/ Task.php/ /……/ * * *@ORM\ManyToMany(targetEntity="Tag", cascade={"persist"}) */受保护的$标签;
1 2 3 4 5 6 7 8
# src / AppBundle /资源/ config /理论/ Task.orm.yml实体AppBundle \ \任务:类型:实体#……对:标签:targetEntity:标签级联:(持续)
12 3 4 5 6 7 8 9 10 11 12 13 14 15
<!——src/AppBundle/Resources/config/doctrine/Task.orm.xml——> .xml<doctrine-mappingxmlns=“http://doctrine-project.org/schemas/orm/doctrine-mapping”xmlns: xsi=“http://www.w3.org/2001/XMLSchema-instance”xsi: schemaLocation=“http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd”><实体的名字=“实体AppBundle \ \任务”><!——……--><一对多场=“标签”目标实体=“标签”><级联><层叠persist/>级联>一对多>实体>doctrine-mapping>
第二个潜在的问题涉及拥有侧和反向侧教义关系。在这个例子中,如果关系的“拥有”方是“Task”,那么持久化将很好地工作,因为标记被正确地添加到Task中。但是,如果所属方在“Tag”上,那么您将需要做更多的工作,以确保修改关系的正确一方。
诀窍是确保每个“标签”上都设置了单个“任务”。做到这一点的一个简单方法是添加一些额外的逻辑addTag ()
,由表单类型since调用by_reference
设置为假
:
1 2 3 4 5 6 7 8 9
/ / src / AppBundle /实体/ Task.php/ /……公共函数addTag(标签$标签){$标签->addTask ($这);$这->标签->add ($标签);}
内部标签
,只要确保你有一个addTask
方法:
1 2 3 4 5 6 7 8 9
/ / src / AppBundle /实体/ Tag.php/ /……公共函数addTask(任务$任务){如果(!$这->任务->包含($任务)) {$这->任务->add ($任务);}}
如果您有一对多关系,那么除了可以简单地调用之外,解决方法也类似setTask
从内addTag
.
12 3 4 5 6 7 8 9 10 11 12 13 14
/ / src / AppBundle / /类型/ TaskType.php形式/ /……使用ob娱乐下载\组件\形式\FormBuilderInterface;公共函数buildForm(FormBuilderInterface$构建器数组,$选项){$构建器->add (“描述”);$构建器->add (“标签”,“收集”,数组(“类型”= >新TagType (),“allow_add”= >真正的));}
allow_add
也会产生“原型”变量可供您选择。这个“原型”是一个小的“模板”,它包含了能够呈现任何新“标签”表单的所有HTML。要渲染它,请对模板进行以下更改:- 嫩枝
- PHP
1 2 3
<ul类=“标签”data-prototype="{{form_widget(form.tags.vars.prototype)|e('html_attr')}}">...ul>
1 2 3 4 5
<ul类=“标签”data-prototype=“< ?php echo $视图- >逃脱(视图(“形式”)- >行美元(美元形式['标签']- > var[‘原型’]))? > ">...ul>
请注意
如果你渲染你的整个“标签”子表单一次(例如。form_row (form.tags)
),则原型自动可在外部使用div
随着data-prototype
属性,类似于上面所看到的。
提示
的form.tags.vars.prototype
表单元素看起来和感觉起来就像个体吗form_widget(标签)
您的为
循环。这意味着你可以打电话form_widget
,form_row
或了form_label
在上面。你甚至可以选择只呈现它的一个字段(例如的名字
字段):
1
{{form_widget(form.tags.vars.prototype.name)|e}}
1
<ul类=“标签”data-prototype="& lt;div比;& lt;标签类=“;要求“;比;__name__& lt;/标签比;& lt;div id =“;task_tags___name__“;比;& lt;div比;& lt;标签=“;task_tags___name___name“;类=“;要求“;比;的名字& lt;/标签比;& lt;输入类型=“;文本“;id =“;task_tags___name___name“;name =“;任务[标记][__name__][名称]“;要求=“;要求“;最大长度=“;255“;/比;& lt;/ div比;& lt;/ div比;& lt;/ div比;">
脚本
标签,这样您就可以开始编写JavaScript了。addTagForm
将在下一页显示):12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
varcollectionHolder美元;//设置一个“添加标签”链接var$addTagLink = $('添加标签');var$newLinkLi = $李李' < > < / > ') .append (addTagLink美元);jQuery (文档时(函数(){//获取包含标签集合的ul$collectionHolder = $(“ul.tags”);//添加“添加标签”锚和li到标签ul(collectionHolder.append美元newLinkLi);//计算当前的表单输入(例如2),使用它作为新的//当插入一个新项时(例如2)collectionHolder.data美元(“指数”collectionHolder.find美元(:输入) . length);addTagLink.on美元(“点击”,函数(e){//阻止链接在URL上创建“#e.preventDefault ();//添加一个新的标签表单(见下一个代码块)addTagForm (collectionHolder, newLinkLi美元);});});
addTagForm
函数的工作是使用data-prototype
属性在单击此链接时动态添加新表单。的data-prototype
HTML包含标签文本
输入名称为的元素任务[标记][__name__][名称]
的idtask_tags___name___name
.的__name__
是一个小的“占位符”,您将用一个唯一的递增数字(例如。任务[标记][3][名称]
).12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
函数addTagForm(collectionHolder, newLinkLi美元){//获取前面解释的数据原型var$collectionHolder.data(“原型”);//获取新的索引var$collectionHolder.data(“指数”);//将原型HTML中的__name__替换为//而是一个基于我们有多少项的数字varnewForm = prototype.replace(/ __name__ / g、指数);//为下一项增加索引collectionHolder.data美元(“指数”, index +1);//在“添加标签”链接之前,以一里的单位显示页面中的表单var$newFormLi = $(李李' < > < / > ') .append (newForm中将);(newLinkLi.before美元newFormLi);}
请注意
最好将JavaScript分离到真正的JavaScript文件中,而不是像这里这样在HTML中编写。
添加标签
链接,一个新的子表单将出现在页面上。当表单提交时,任何新的标签表单都将转换为新的标签
对象,并添加到标签
的属性任务
对象。另请参阅
您可以在这里找到一个工作示例JSFiddle.
另请参阅
如果您想自定义原型中的HTML代码,请阅读如何自定义表单渲染.
任务
类:12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/ / src / AppBundle /实体/ Task.php名称空间AppBundle\实体;/ /……类任务{/ /……公共函数addTag(标签$标签){$这->标签->add ($标签);}公共函数removeTag(标签$标签){/ /……}}
by_reference
选项。标签
字段并设置为假
:12 3 4 5 6 7 8 9 10 11 12
/ / src / AppBundle / /类型/ TaskType.php形式/ /……公共函数buildForm(FormBuilderInterface$构建器数组,$选项){/ /……$构建器->add (“标签”,“收集”,数组(/ /……“by_reference”= >假));}
标签
对象添加到任务
类,通过调用addTag
方法。在此更改之前,它们是通过调用在表单内部添加的任务- > getTags() - >添加标签($)
.这很好,但是强制使用“加法器”方法使得处理这些问题变得很新鲜标签
对象更容易(特别是如果你使用Doctrine,你将在接下来学习!)。谨慎
你必须创造这两个addTag
而且removeTag
方法,否则表单仍将使用setTag
即使by_reference
是假
.你会学到更多关于removeTag
方法。
原则:级联关系和保存“逆”面
为了保存Doctrine的新标签,您需要考虑更多的事情。首先,除非遍历所有的new标签
对象和调用(em - >坚持美元标签)
在每一个,你会收到一个来自Doctrine的错误:
通过这种关系发现了一个新的实体
实体AppBundle \ \任务#标签
没有配置为级联实体的持久化操作…
方法自动“级联”持久化操作任务
对象到任何相关标记。要做到这一点,请添加级联
选择您的多
元数据:
- 注释
- YAML
- XML
1 2 3 4 5 6 7 8
/ / src / AppBundle /实体/ Task.php/ /……/ * * *@ORM\ManyToMany(targetEntity="Tag", cascade={"persist"}) */受保护的$标签;
1 2 3 4 5 6 7 8
# src / AppBundle /资源/ config /理论/ Task.orm.yml实体AppBundle \ \任务:类型:实体#……对:标签:targetEntity:标签级联:(持续)
12 3 4 5 6 7 8 9 10 11 12 13 14 15
<!——src/AppBundle/Resources/config/doctrine/Task.orm.xml——> .xml<doctrine-mappingxmlns=“http://doctrine-project.org/schemas/orm/doctrine-mapping”xmlns: xsi=“http://www.w3.org/2001/XMLSchema-instance”xsi: schemaLocation=“http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd”><实体的名字=“实体AppBundle \ \任务”><!——……--><一对多场=“标签”目标实体=“标签”><级联><层叠persist/>级联>一对多>实体>doctrine-mapping>
第二个潜在的问题涉及拥有侧和反向侧教义关系。在这个例子中,如果关系的“拥有”方是“Task”,那么持久化将很好地工作,因为标记被正确地添加到Task中。但是,如果所属方在“Tag”上,那么您将需要做更多的工作,以确保修改关系的正确一方。
诀窍是确保每个“标签”上都设置了单个“任务”。做到这一点的一个简单方法是添加一些额外的逻辑addTag ()
,由表单类型since调用by_reference
设置为假
:
1 2 3 4 5 6 7 8 9
/ / src / AppBundle /实体/ Task.php/ /……公共函数addTag(标签$标签){$标签->addTask ($这);$这->标签->add ($标签);}
内部标签
,只要确保你有一个addTask
方法:
1 2 3 4 5 6 7 8 9
/ / src / AppBundle /实体/ Tag.php/ /……公共函数addTask(任务$任务){如果(!$这->任务->包含($任务)) {$这->任务->add ($任务);}}
如果您有一对多关系,那么除了可以简单地调用之外,解决方法也类似setTask
从内addTag
.
allow_delete类型:
12 3 4 5 6 7 8 9 10 11 12
/ / src / AppBundle / /类型/ TaskType.php形式/ /……公共函数buildForm(FormBuilderInterface$构建器数组,$选项){/ /……$构建器->add (“标签”,“收集”,数组(/ /……“allow_delete”= >真正的));}
现在,需要将一些代码放入removeTag
的方法任务
:
12 3 4 5 6 7 8 9 10 11 12
/ / src / AppBundle /实体/ Task.php/ /……类任务{/ /……公共函数removeTag(标签$标签){$这->标签->removeElement ($标签);}}
allow_delete选项有一个后果:如果集合的项在提交时没有发送,则相关数据将从服务器上的集合中删除。因此,解决方案是从DOM中删除表单元素。
首先,在每个标签表单中添加一个“delete this tag”链接:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
jQuery (文档时(函数(){//获取包含标签集合的ul$collectionHolder = $(“ul.tags”);//添加一个删除链接到所有现有的标签形式li元素collectionHolder.find美元(“李”) . each (函数(){addTagFormDeleteLink ($ (这));});/ /……从上面看剩下的街区});函数addTagForm(){/ /……//添加一个删除链接到新表单addTagFormDeleteLink ($ newFormLi);}
的addTagFormDeleteLink
函数看起来是这样的:
12 3 4 5 6 7 8 9 10 11 12
函数addTagFormDeleteLink(tagFormLi美元){var$removeFormA = $('delete this tag');(tagFormLi.append美元removeFormA);removeFormA.on美元(“点击”,函数(e){//阻止链接在URL上创建“#e.preventDefault ();//删除标签表单的li美元tagFormLi.remove ();});}
当一个标签表单从DOM中删除并提交时,被删除的标签
对象将不包含在传递给的集合中setTags
.根据您的持久性层,这可能不足以实际删除被删除对象之间的关系标签
而且任务
对象。
原则:确保数据库持久性
当以这种方式删除对象时,您可能需要多做一点工作,以确保对象之间的关系任务
被移除的标签
被正确移除。
在《主义》中,你有关系的两个方面:拥有的一面和相反的一面。通常在这种情况下,您将拥有一个多对多的关系,删除的标记将消失并正确地保存(添加新标记也很容易)。
但是如果你有一对多的关系或者多对多的关系的mappedBy
在Task实体上(意味着Task是“逆”面),您将需要做更多的工作来正确地保存已删除的标记。
在这种情况下,您可以修改控制器以删除已删除标记上的关系。假设你有一些editAction
它正在处理任务的“更新”:
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
/ / src / AppBundle /控制器/ TaskController.php使用学说\常见的\集合\ArrayCollection;/ /……公共函数editAction($id,请求$请求){$新兴市场=$这->getDoctrine ()->getManager ();$任务=$新兴市场->getRepository (“AppBundle:任务”)->找到($id);如果(!$任务) {扔$这->createNotFoundException (“没有找到任务”.$id);}$originalTags=新ArrayCollection ();//创建数据库中当前Tag对象的ArrayCollectionforeach($任务->getTags ()作为$标签) {$originalTags->add ($标签);}$editForm=$这->createForm (新TaskType (),$任务);$editForm->handleRequest ($请求);如果($editForm->isValid ()) {//删除标签和任务之间的关系foreach($originalTags作为$标签) {如果(假= = =$任务->getTags ()->包含($标签)) {//从标签中删除任务$标签->getTasks ()->removeElement ($任务);//如果它是一个多对一关系,像这样删除关系/ /标签- > setTask(空);$新兴市场->persist ($标签);//如果你想完全删除标签,你也可以这样做/ / em - >删除美元($标签);}}$新兴市场->persist ($任务);$新兴市场->冲洗();//重定向到某个编辑页面返回$这->重定向($这->generateUrl (“task_edit”,数组(“id”= >$id)));}//渲染一些表单模板}
如您所见,正确地添加和删除元素可能很棘手。除非您有一个Task是“拥有”方的多对多关系,否则您将需要做额外的工作,以确保在每个Tag对象本身上正确地更新关系(无论是添加新标记还是删除现有标记)。
12 3 4 5 6 7 8 9 10 11 12
/ / src / AppBundle / /类型/ TaskType.php形式/ /……公共函数buildForm(FormBuilderInterface$构建器数组,$选项){/ /……$构建器->add (“标签”,“收集”,数组(/ /……“allow_delete”= >真正的));}
removeTag
的方法任务
:12 3 4 5 6 7 8 9 10 11 12
/ / src / AppBundle /实体/ Task.php/ /……类任务{/ /……公共函数removeTag(标签$标签){$这->标签->removeElement ($标签);}}
allow_delete选项有一个后果:如果集合的项在提交时没有发送,则相关数据将从服务器上的集合中删除。因此,解决方案是从DOM中删除表单元素。
首先,在每个标签表单中添加一个“delete this tag”链接:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
jQuery (文档时(函数(){//获取包含标签集合的ul$collectionHolder = $(“ul.tags”);//添加一个删除链接到所有现有的标签形式li元素collectionHolder.find美元(“李”) . each (函数(){addTagFormDeleteLink ($ (这));});/ /……从上面看剩下的街区});函数addTagForm(){/ /……//添加一个删除链接到新表单addTagFormDeleteLink ($ newFormLi);}
的addTagFormDeleteLink
函数看起来是这样的:
12 3 4 5 6 7 8 9 10 11 12
函数addTagFormDeleteLink(tagFormLi美元){var$removeFormA = $('delete this tag');(tagFormLi.append美元removeFormA);removeFormA.on美元(“点击”,函数(e){//阻止链接在URL上创建“#e.preventDefault ();//删除标签表单的li美元tagFormLi.remove ();});}
当一个标签表单从DOM中删除并提交时,被删除的标签
对象将不包含在传递给的集合中setTags
.根据您的持久性层,这可能不足以实际删除被删除对象之间的关系标签
而且任务
对象。
原则:确保数据库持久性
当以这种方式删除对象时,您可能需要多做一点工作,以确保对象之间的关系任务
被移除的标签
被正确移除。
在《主义》中,你有关系的两个方面:拥有的一面和相反的一面。通常在这种情况下,您将拥有一个多对多的关系,删除的标记将消失并正确地保存(添加新标记也很容易)。
但是如果你有一对多的关系或者多对多的关系的mappedBy
在Task实体上(意味着Task是“逆”面),您将需要做更多的工作来正确地保存已删除的标记。
在这种情况下,您可以修改控制器以删除已删除标记上的关系。假设你有一些editAction
它正在处理任务的“更新”:
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
/ / src / AppBundle /控制器/ TaskController.php使用学说\常见的\集合\ArrayCollection;/ /……公共函数editAction($id,请求$请求){$新兴市场=$这->getDoctrine ()->getManager ();$任务=$新兴市场->getRepository (“AppBundle:任务”)->找到($id);如果(!$任务) {扔$这->createNotFoundException (“没有找到任务”.$id);}$originalTags=新ArrayCollection ();//创建数据库中当前Tag对象的ArrayCollectionforeach($任务->getTags ()作为$标签) {$originalTags->add ($标签);}$editForm=$这->createForm (新TaskType (),$任务);$editForm->handleRequest ($请求);如果($editForm->isValid ()) {//删除标签和任务之间的关系foreach($originalTags作为$标签) {如果(假= = =$任务->getTags ()->包含($标签)) {//从标签中删除任务$标签->getTasks ()->removeElement ($任务);//如果它是一个多对一关系,像这样删除关系/ /标签- > setTask(空);$新兴市场->persist ($标签);//如果你想完全删除标签,你也可以这样做/ / em - >删除美元($标签);}}$新兴市场->persist ($任务);$新兴市场->冲洗();//重定向到某个编辑页面返回$这->重定向($这->generateUrl (“task_edit”,数组(“id”= >$id)));}//渲染一些表单模板}
如您所见,正确地添加和删除元素可能很棘手。除非您有一个Task是“拥有”方的多对多关系,否则您将需要做额外的工作,以确保在每个Tag对象本身上正确地更新关系(无论是添加新标记还是删除现有标记)。
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
jQuery (文档时(函数(){//获取包含标签集合的ul$collectionHolder = $(“ul.tags”);//添加一个删除链接到所有现有的标签形式li元素collectionHolder.find美元(“李”) . each (函数(){addTagFormDeleteLink ($ (这));});/ /……从上面看剩下的街区});函数addTagForm(){/ /……//添加一个删除链接到新表单addTagFormDeleteLink ($ newFormLi);}
addTagFormDeleteLink
函数看起来是这样的:12 3 4 5 6 7 8 9 10 11 12
函数addTagFormDeleteLink(tagFormLi美元){var$removeFormA = $('delete this tag');(tagFormLi.append美元removeFormA);removeFormA.on美元(“点击”,函数(e){//阻止链接在URL上创建“#e.preventDefault ();//删除标签表单的li美元tagFormLi.remove ();});}
标签
对象将不包含在传递给的集合中setTags
.根据您的持久性层,这可能不足以实际删除被删除对象之间的关系标签
而且任务
对象。原则:确保数据库持久性
当以这种方式删除对象时,您可能需要多做一点工作,以确保对象之间的关系任务
被移除的标签
被正确移除。
在《主义》中,你有关系的两个方面:拥有的一面和相反的一面。通常在这种情况下,您将拥有一个多对多的关系,删除的标记将消失并正确地保存(添加新标记也很容易)。
但是如果你有一对多的关系或者多对多的关系的mappedBy
在Task实体上(意味着Task是“逆”面),您将需要做更多的工作来正确地保存已删除的标记。
在这种情况下,您可以修改控制器以删除已删除标记上的关系。假设你有一些editAction
它正在处理任务的“更新”:
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
/ / src / AppBundle /控制器/ TaskController.php使用学说\常见的\集合\ArrayCollection;/ /……公共函数editAction($id,请求$请求){$新兴市场=$这->getDoctrine ()->getManager ();$任务=$新兴市场->getRepository (“AppBundle:任务”)->找到($id);如果(!$任务) {扔$这->createNotFoundException (“没有找到任务”.$id);}$originalTags=新ArrayCollection ();//创建数据库中当前Tag对象的ArrayCollectionforeach($任务->getTags ()作为$标签) {$originalTags->add ($标签);}$editForm=$这->createForm (新TaskType (),$任务);$editForm->handleRequest ($请求);如果($editForm->isValid ()) {//删除标签和任务之间的关系foreach($originalTags作为$标签) {如果(假= = =$任务->getTags ()->包含($标签)) {//从标签中删除任务$标签->getTasks ()->removeElement ($任务);//如果它是一个多对一关系,像这样删除关系/ /标签- > setTask(空);$新兴市场->persist ($标签);//如果你想完全删除标签,你也可以这样做/ / em - >删除美元($标签);}}$新兴市场->persist ($任务);$新兴市场->冲洗();//重定向到某个编辑页面返回$这->重定向($这->generateUrl (“task_edit”,数组(“id”= >$id)));}//渲染一些表单模板}
如您所见,正确地添加和删除元素可能很棘手。除非您有一个Task是“拥有”方的多对多关系,否则您将需要做额外的工作,以确保在每个Tag对象本身上正确地更新关系(无论是添加新标记还是删除现有标记)。