symfony2:一个表单的多个实体
|
我有2个实体:
ADSLinkBundleEntityLink:
type: entity
table: null
repositoryClass: ADSLinkBundleEntityLinkRepository
id:
id:
type: integer
id: true
generator:
strategy: AUTO
fields:
dateAdded:
type: datetime
expirationDate:
type: datetime
nullable: true
designator:
type: string
length: 255
nullable: false
unique: true
slug:
type: string
length: 255
nullable: true
unique: true
manyToOne:
company:
targetEntity: ADSUserBundleEntityCompany
inversedBy: link
joinColumn:
name: company_id
referencedColumnName: id
nullable: true
createdBy:
targetEntity: ADSUserBundleEntityUser
inversedBy: link
joinColumn:
name: createdBy_id
referencedColumnName: id
domain:
targetEntity: ADSDomainBundleEntityDomain
inversedBy: link
joinColumn:
name: domain_id
referencedColumnNames: id
oneToMany:
paths:
targetEntity: ADSLinkBundleEntityPath
mappedBy: link
cascade: [persist]
lifecycleCallbacks: { }
和 ADSLinkBundleEntityPath:
type: entity
table: null
repositoryClass: ADSLinkBundleEntityPathRepository
id:
id:
type: integer
id: true
generator:
strategy: AUTO
fields:
pathAddress:
type: string
length: 255
pathWeight:
type: string
length: 255
manyToOne:
link:
targetEntity: ADSLinkBundleEntityLink
inversedBy: paths
joinColumn:
name: link_id
referencedColumnName: id
lifecycleCallbacks: { }
除了实体的路径部分,我已经弄明白了.这是用于A / B分割测试,因此每个链接可以有2个路径.每个路径将包含一个网址和一个数字(0 – 100) 这是我目前状态的形式: <?php
namespace ADSLinkBundleForm;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolverInterface;
class PathType extends AbstractType {
public function buildForm(FormBuilderInterface $builder,array $options) {
$builder
->add('pathAddress')
->add('pathWeight')
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array('data_class' => 'ADSLinkBundleEntityPath'));
}
public function getName() { return 'ads_linkbundle_link'; }
}
和 <?php
namespace ADSLinkBundleForm;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolverInterface;
class LinkType extends AbstractType {
public function buildForm(FormBuilderInterface $builder,array $options) {
$builder
->add('designator')
->add('domain','entity',array(
'class' => 'ADSDomainBundleEntityDomain','property' => 'domainAddress'
))
->add('paths','collection',array('type' => new PathType(),'allow_add' => true))
->add('Submit','submit')
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array('data_class' => 'ADSLinkBundleEntityLink'));
}
public function getName() { return 'ads_linkbundle_link'; }
}
我需要弄清楚的是,在创建链接时,我还需要能够创建正确的路径和权重.在创建链接之前,路径不在数据库中. 这是我对我的控制器所拥有的: public function newAction(Request $request) {
$entity = new Link();
$form = $this->createForm(new LinkType(),$entity);
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isValid()) {
$code = $this->get('ads.default');
$em = $this->getDoctrine()->getManager();
$user = $this->getUser();
$entity->setDateAdded(new DateTime("now"));
$entity->setCreatedBy($user);
$entity->setSlug($code->generateToken(5));
$entity->setCompany($user->getParentCompany());
$em->persist($entity);
$em->flush();
return new Response(json_encode(array('error' => '0','success' => '1')));
}
return new Response(json_encode(array('error' => count($form->getErrors()),'success' => '0')));
}
return $this->render('ADSLinkBundle:Default:form.html.twig',array(
'entity' => $entity,'saction' => $this->generateUrl('ads.link.new'),'form' => $form->createView()
));
}
解决方法
感谢@Onema(阅读上面的评论),我已经想到了这一点.通过阅读
http://symfony.com/doc/current/cookbook/form/form_collections.html的文档它给了我完成这项工作所需的信息.
做我需要做的第一步是创建一个名为PathsType.php的新表单类型,其中包含与Paths Entity关联的字段 <?php
namespace ADSLinkBundleForm;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolverInterface;
class PathType extends AbstractType {
public function buildForm(FormBuilderInterface $builder,array $options) {
$builder
->add('pathAddress')
->add('pathWeight')
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array('data_class' => 'ADSLinkBundleEntityPath'));
}
public function getName() { return 'ads_linkbundle_path'; }
}
然后修改LinkType.php以使用此新表单 <?php
namespace ADSLinkBundleForm;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolverInterface;
class LinkType extends AbstractType {
public function buildForm(FormBuilderInterface $builder,array(
'type' => new PathType(),'allow_add' => true,))
->add('Submit','submit')
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array('data_class' => 'ADSLinkBundleEntityLink'));
}
public function getName() { return 'ads_linkbundle_link'; }
}
添加allow_add使得您可以添加该表单的多个实例. 在视图中,我现在使用data-prototype属性.在文档中,它有一个使用列表项的示例 – 这就是我开始的地方. < ul class =“tags”data-prototype =“{{form_widget(form.paths.vars.prototype)| e}}”>< / ul> 然后是jQuery函数(在上面的文档链接中列出,简单的复制/粘贴将起作用) 这使得系统工作,有一个小问题,并且在我的路径实体中,我与Link实体有关系,但它没有注意到这种关系并且将link_id字段设为null 为了解决这个问题,我们再次编辑LinkType.php,并将by_reference = false添加到集合定义中.然后我们在实体中编辑addPath方法,如下所示: public function addPath(ADSLinkBundleEntityPath $paths)
{
$paths->setLink($this);
$this->paths->add($paths);
}
这将当前链接对象设置为与路径关联的链接. 此时,系统运行正常.它创造了它所需要的一切,只需稍微调整一下显示.我个人选择使用twig宏来修改data-prototype中包含的html输出 我现在坐的宏(不完整 – 但工作),我添加到我的form.html.twig的开头 {% macro path_prototype(paths) %}
<div class="form-group col-md-10">
<div class="col-md-3">
<label class="control-label">Address</label>
</div>
<div class="col-md-9">
{{ form_widget(paths.pathAddress,{ 'attr' : { 'class' : 'form-control required' }}) }}
</div>
</div>
{% endmacro %}
在表单本身的HTML中,我删除了列表创建,并将其替换为: <div class="form-group">
{{ form_label(form.paths,'Destination(s)',{ 'label_attr' : {'class' : 'col-md-12 control-label align-left text-left' }}) }}
<div class="tags" data-prototype="{{ _self.path_prototype(form.paths.vars.prototype)|e }}">
</div>
</div>
然后我修改了我的javascript以使用div作为起点,而不是示例中的ul. <script type="text/javascript">
var $collectionHolder;
// setup an "add a tag" link
var $addTagLink = $('<a href="#" class="add_tag_link btn btn-xs btn-success">Add Another Destination</a>');
var $newLinkLi = $('<div></div>').append($addTagLink);
jQuery(document).ready(function() {
// Get the ul that holds the collection of tags
$collectionHolder = $('div.tags');
// add the "add a tag" anchor and li to the tags ul
$collectionHolder.append($newLinkLi);
// count the current form inputs we have (e.g. 2),use that as the new
// index when inserting a new item (e.g. 2)
$collectionHolder.data('index',$collectionHolder.find(':input').length);
addTagForm($collectionHolder,$newLinkLi);
$addTagLink.on('click',function(e) {
// prevent the link from creating a "#" on the URL
e.preventDefault();
// add a new tag form (see next code block)
addTagForm($collectionHolder,$newLinkLi);
});
});
function addTagForm($collectionHolder,$newLinkLi) {
// Get the data-prototype explained earlier
var prototype = $collectionHolder.data('prototype');
// get the new index
var index = $collectionHolder.data('index');
// Replace '__name__' in the prototype's HTML to
// instead be a number based on how many items we have
var newForm = prototype.replace(/__name__/g,index);
// increase the index with one for the next item
$collectionHolder.data('index',index + 1);
console.log(index);
if (index == 1) {
console.log('something');
$('a.add_tag_link').remove();
}
// Display the form in the page in an li,before the "Add a tag" link li
var $newFormLi = newForm;
$newLinkLi.before($newFormLi);
}
</script>
由于这些路径是我的营销应用程序中的A / B拆分测试的目标地址,因此我选择将路径限制为每个链接2个.有了这个,我已经成功设置了一个表单来使用集合类型. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
