ADS\LinkBundle\Entity\Link: type: entity table: null repositoryClass: ADS\LinkBundle\Entity\LinkRepository 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: ADS\UserBundle\Entity\Company inversedBy: link joinColumn: name: company_id referencedColumnName: id nullable: true createdBy: targetEntity: ADS\UserBundle\Entity\User inversedBy: link joinColumn: name: createdBy_id referencedColumnName: id domain: targetEntity: ADS\DomainBundle\Entity\Domain inversedBy: link joinColumn: name: domain_id referencedColumnNames: id oneToMany: paths: targetEntity: ADS\LinkBundle\Entity\Path mappedBy: link cascade: [persist] lifecycleCallbacks: { }
和
ADS\LinkBundle\Entity\Path: type: entity table: null repositoryClass: ADS\LinkBundle\Entity\PathRepository id: id: type: integer id: true generator: strategy: AUTO fields: pathAddress: type: string length: 255 pathWeight: type: string length: 255 manyToOne: link: targetEntity: ADS\LinkBundle\Entity\Link inversedBy: paths joinColumn: name: link_id referencedColumnName: id lifecycleCallbacks: { }
除了实体的路径部分,我已经弄明白了.这是用于A / B分割测试,因此每个链接可以有2个路径.每个路径将包含一个网址和一个数字(0 – 100)
这是我目前状态的形式:
<?PHP namespace ADS\LinkBundle\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolverInterface; 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' => 'ADS\LinkBundle\Entity\Path')); } public function getName() { return 'ads_linkbundle_link'; } }
和
<?PHP namespace ADS\LinkBundle\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolverInterface; class LinkType extends AbstractType { public function buildForm(FormBuilderInterface $builder,array $options) { $builder ->add('designator') ->add('domain','entity',array( 'class' => 'ADS\DomainBundle\Entity\Domain','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' => 'ADS\LinkBundle\Entity\Link')); } 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() )); }
解决方法
做我需要做的第一步是创建一个名为PathsType.PHP的新表单类型,其中包含与Paths Entity关联的字段
<?PHP namespace ADS\LinkBundle\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolverInterface; 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' => 'ADS\LinkBundle\Entity\Path')); } public function getName() { return 'ads_linkbundle_path'; } }
<?PHP namespace ADS\LinkBundle\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolverInterface; 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' => 'ADS\LinkBundle\Entity\Link')); } public function getName() { return 'ads_linkbundle_link'; } }
在视图中,我现在使用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(\ADS\LinkBundle\Entity\Path $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个.有了这个,我已经成功设置了一个表单来使用集合类型.