Symfony2 将自定义字段添加到表单构建器

Posted

技术标签:

【中文标题】Symfony2 将自定义字段添加到表单构建器【英文标题】:Symfony2 add custom field to form builder 【发布时间】:2014-11-10 18:53:59 【问题描述】:

我有一个实体事件,它有一个字段关键字,它是一对多映射到另一个实体事件关键字。我还有一个表单类型类 CreateEventFormType。我使用以下代码在我的控制器中创建表单:

$event = new Event();
$form = $this->createForm(new CreateEventFormType(), $event);

但我还需要用于创建对象 EventKeywords 的关键字的附加输入字段。我尝试将其添加到我的 formBuilderInterface:

        ->add('keywords', 'text', [
                'constraints' =>[
                    new Assert\NotBlank([
                        'message' => "Renginio raktažodžiai negali būti tušti"
                    ]),
                    new Assert\Length([
                        'min' => "2",
                        'max' => "255",
                        'minMessage' => "Renginio raktažodžiai negali būti trumpesni nei  limit  simboliai",
                        'maxMessage' => "Renginio raktažodžiai negali būti ilgesni nei  limit  simboliai"
                    ])
                ]
            ])

然后我得到错误

Neither the property "keywords" nor one of the methods "addKeyword()"/"removeKeyword()", "setKeywords()", "keywords()", "__set()" or "__call()" exist and have public access in class "Atotrukis\MainBundle\Entity\Event".

完整的实体和FormType代码:

createEventFormType.php

<?php
namespace Atotrukis\MainBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\ORM\EntityRepository;
use Symfony\Component\Validator\Constraints as Assert;
class CreateEventFormType extends AbstractType

    public function buildForm(FormBuilderInterface $builder, array $options)
    
        $builder
            ->add('name', 'text', [
                'constraints' =>[
                    new Assert\NotBlank([
                        'message' => "Renginio pavadinimas negali būti tuščias"
                    ]),
                    new Assert\Length([
                        'min' => "2",
                        'max' => "255",
                        'minMessage' => "Renginio pavadinimas negali būti trumpesnis nei  limit  simboliai",
                        'maxMessage' => "Renginio pavadinimas negali būti ilgesnis nei  limit  simboliai"
                    ])
                ]
            ])
            ->add('description', 'textarea', [
                'constraints' =>[
                    new Assert\NotBlank([
                        'message' => "Renginio aprašymas negali būti tuščias"
                    ]),
                    new Assert\Length([
                        'min' => "10",
                        'max' => "5000",
                        'minMessage' => "Renginio aprašymas negali būti trumpesnis nei  limit  simbolių",
                        'maxMessage' => "Renginio aprašymas negali būti ilgesnis nei  limit  simbolių"
                    ])
                ]
            ])
            ->add('startDate', 'datetime', [
                'constraints' =>[
                    new \Atotrukis\MainBundle\Validator\Constraints\FutureDateTime([
                        'message' => "Pradžios laikas negali būti ankstesnis už dabartinį laiką."
                    ])
                ]
            ])
            ->add('endDate', 'datetime', [
                'constraints' =>[
                    new \Atotrukis\MainBundle\Validator\Constraints\FutureDateTime([
                        'message' => "Pabaigos laikas negali būti ankstesnis už dabartinį laiką."
                    ])
                ]
            ])
            ->add('keywords', 'text', [
                'constraints' =>[
                    new Assert\NotBlank([
                        'message' => "Renginio raktažodžiai negali būti tušti"
                    ]),
                    new Assert\Length([
                        'min' => "2",
                        'max' => "255",
                        'minMessage' => "Renginio raktažodžiai negali būti trumpesni nei  limit  simboliai",
                        'maxMessage' => "Renginio raktažodžiai negali būti ilgesni nei  limit  simboliai"
                    ])
                ]
            ])
            ->add('map', 'hidden')
            ->add('city', 'entity', array(
                'class' => 'AtotrukisMainBundle:City',
                'property' => 'name',
                'constraints' =>[
                    new Assert\NotBlank([
                        'message' => "Privalote pasirinkti miestą"
                    ])
                ],
                'empty_value' => 'Pasirinkite miestą',
                'query_builder' => function(EntityRepository $er) 
                    return $er->createQueryBuilder('c')
                        ->addOrderBy('c.priority', 'ASC')
                        ->addOrderBy('c.name', 'ASC');
                ,
            ));
//            ->add('save', 'submit', array('label' => 'Sukurti'));
    
    public function getName()
    
        return 'createEventForm';
    


事件.php

<?php
namespace Atotrukis\MainBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Atotrukis\MainBundle\Validator\Constraints as CustomAssert;


/**
 * @ORM\Entity
 * @ORM\Table(name="events")
 * @CustomAssert\DateRange
 */
class Event

    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;
    /**
     * @ORM\Column(type="string", length=255)
     */
    protected $name;

    /**
     * @ORM\Column(type="text")
     */
    protected $description;

    /**
     * @ORM\Column(type="datetime")
     */
    protected $startDate;

    /**
     * @ORM\Column(type="datetime")
     */
    protected $endDate;

    /**
     * @ORM\ManyToOne(targetEntity="User", inversedBy="events")
     * @ORM\JoinColumn(name="createdBy", referencedColumnName="id")
     */
    protected $createdBy;

    /**
     * @ORM\Column(type="datetime")
     */
    protected $createdOn;

    /**
     * @ORM\Column(type="string", length=2083)
     */
    protected $map;


    /**
     * @ORM\OneToMany(targetEntity="EventPhoto", mappedBy="eventId")
     */
    protected $photos;

    /**
     * @ORM\OneToMany(targetEntity="UserAttending", mappedBy="eventId")
     */
    protected $usersAttending;

    /**
     * @ORM\OneToMany(targetEntity="EventKeywords", mappedBy="eventId")
     */
    protected $keywords;

    /**
     * @ORM\ManyToOne(targetEntity="City", inversedBy="eventId")
     * @ORM\JoinColumn(name="city", referencedColumnName="id")
     */
    protected $city;


    public function __construct()
    
        $this->createdOn = new \DateTime();
        $this->keywords = new ArrayCollection();
        //parent::__construct();
    

    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    
        return $this->id;
    

    /**
     * Set name
     *
     * @param string $name
     * @return Event
     */
    public function setName($name)
    
        $this->name = $name;

        return $this;
    

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    
        return $this->name;
    

    /**
     * Set description
     *
     * @param string $description
     * @return Event
     */
    public function setDescription($description)
    
        $this->description = $description;

        return $this;
    

    /**
     * Get description
     *
     * @return string 
     */
    public function getDescription()
    
        return $this->description;
    

    /**
     * Set startDate
     *
     * @param \DateTime $startDate
     * @return Event
     */
    public function setStartDate($startDate)
    
        $this->startDate = $startDate;

        return $this;
    

    /**
     * Get startDate
     *
     * @return \DateTime 
     */
    public function getStartDate()
    
        return $this->startDate;
    

    /**
     * Set endDate
     *
     * @param \DateTime $endDate
     * @return Event
     */
    public function setEndDate($endDate)
    
        $this->endDate = $endDate;

        return $this;
    

    /**
     * Get endDate
     *
     * @return \DateTime 
     */
    public function getEndDate()
    
        return $this->endDate;
    

    /**
     * Set createdBy
     *
     * @param integer $createdBy
     * @return Event
     */
    public function setCreatedBy($createdBy)
    
        $this->createdBy = $createdBy;

        return $this;
    

    /**
     * Get createdBy
     *
     * @return integer 
     */
    public function getCreatedBy()
    
        return $this->createdBy;
    

    /**
     * Set createdOn
     *
     * @param \DateTime $createdOn
     * @return Event
     */
    public function setCreatedOn($createdOn)
    
        $this->createdOn = $createdOn;

        return $this;
    

    /**
     * Get createdOn
     *
     * @return \DateTime 
     */
    public function getCreatedOn()
    
        return $this->createdOn;
    

    /**
     * Add photos
     *
     * @param \Atotrukis\MainBundle\Entity\EventPhoto $photos
     * @return Event
     */
    public function addPhoto(\Atotrukis\MainBundle\Entity\EventPhoto $photos)
    
        $this->photos[] = $photos;

        return $this;
    

    /**
     * Remove photos
     *
     * @param \Atotrukis\MainBundle\Entity\EventPhoto $photos
     */
    public function removePhoto(\Atotrukis\MainBundle\Entity\EventPhoto $photos)
    
        $this->photos->removeElement($photos);
    

    /**
     * Get photos
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getPhotos()
    
        return $this->photos;
    

    /**
     * Set map
     *
     * @param string $map
     * @return Event
     */
    public function setMap($map)
    
        $this->map = $map;

        return $this;
    

    /**
     * Get map
     *
     * @return string 
     */
    public function getMap()
    
        return $this->map;
    

    /**
     * Set city
     *
     * @param \Atotrukis\MainBundle\Entity\City $city
     * @return Event
     */
    public function setCity(\Atotrukis\MainBundle\Entity\City $city = null)
    
        $this->city = $city;

        return $this;
    

    /**
     * Get city
     *
     * @return \Atotrukis\MainBundle\Entity\City 
     */
    public function getCity()
    
        return $this->city;
    

    /**
     * Add usersAttending
     *
     * @param \Atotrukis\MainBundle\Entity\UserAttending $usersAttending
     * @return Event
     */
    public function addUsersAttending(\Atotrukis\MainBundle\Entity\UserAttending $usersAttending)
    
        $this->usersAttending[] = $usersAttending;

        return $this;
    

    /**
     * Remove usersAttending
     *
     * @param \Atotrukis\MainBundle\Entity\UserAttending $usersAttending
     */
    public function removeUsersAttending(\Atotrukis\MainBundle\Entity\UserAttending $usersAttending)
    
        $this->usersAttending->removeElement($usersAttending);
    

    /**
     * Get usersAttending
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getUsersAttending()
    
        return $this->usersAttending;
    


    /**
     * Add keywords
     *
     * @param \Atotrukis\MainBundle\Entity\EventKeywords $keywords
     * @return Event
     */
    public function addKeyword(\Atotrukis\MainBundle\Entity\EventKeywords $keywords)
    
        $this->keywords[] = $keywords;

        return $this;
    

    /**
     * Remove keywords
     *
     * @param \Atotrukis\MainBundle\Entity\EventKeywords $keywords
     */
    public function removeKeyword(\Atotrukis\MainBundle\Entity\EventKeywords $keywords)
    
        $this->keywords->removeElement($keywords);
    

    /**
     * Get keywords
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getKeywords()
    
        return $this->keywords;
    

    /**
     * Set keywords
     *
     * @param \Atotrukis\MainBundle\Entity\EventKeywords $keywords
     * @return Event
     */
     public function setKeywords(\Atotrukis\MainBundle\Entity\EventKeywords $keywords = null)
     
        $this->keywords = $keywords;

        return $this;
     

EventKeywords.php

<?php
namespace Atotrukis\MainBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="event_keywords")
 */
class EventKeywords

    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\Column(type="string", length=255)
     */
    protected $keyword;

    /**
     * @ORM\ManyToOne(targetEntity="Event", inversedBy="keywords")
     * @ORM\JoinColumn(name="eventId", referencedColumnName="id")
     */
    protected $eventId;

    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    
        return $this->id;
    

    /**
     * Set eventId
     *
     * @param \Atotrukis\MainBundle\Entity\Event $eventId
     * @return UserAttending
     */
    public function setEventId(\Atotrukis\MainBundle\Entity\Event $eventId = null)
    
        $this->eventId = $eventId;

        return $this;
    

    /**
     * Get eventId
     *
     * @return \Atotrukis\MainBundle\Entity\Event
     */
    public function getEventId()
    
        return $this->eventId;
    

    /**
     * Set keyword
     *
     * @param string $keyword
     * @return EventKeywords
     */
    public function setKeyword($keyword)
    
        $this->keyword = $keyword;

        return $this;
    

    /**
     * Get keyword
     *
     * @return string 
     */
    public function getKeyword()
    
        return $this->keyword;
    

【问题讨论】:

事件实体中的关键字设置器在哪里?我找不到它.. 你也应该初始化keywords集合(在__constructArrayCollection中) 我已将关键字设置器添加到事件实体。还尝试将 $this-&gt;keywords = new ArrayCollection(); 添加到 __construct 但现在出现错误:Catchable Fatal Error: Argument 1 passed to Atotrukis\MainBundle\Entity\Event::setKeywords() must be an instance of Atotrukis\MainBundle\Entity\EventKeywords, string given, called in /var/www/vendor/symfony/symfony/src/Symfony/Component/PropertyAccess/PropertyAccessor.php on line 438 and defined in /var/www/src/Atotrukis/MainBundle/Entity/Event.php line 389 1.我看到您添加了setKeyWords,但没有看到集合初始化。 2. 由于您设置了 OneToMany 关联,该字段应该包含对象集合,而不是单个 EventKeywords 对象 我该怎么做?我对 Symfony 和 OOP 都很陌生。 【参考方案1】:

你要做的是:

->add('yourfield', 'choice', array(
            'label' => 'Your Field',
            'required' => false,
            'choices'  => array(true => 'Yes', false => 'No'),
            'empty_value' => false,
            'mapped' => false                
        ))

注意 'mapped' => false 。这意味着该字段与您的 entity(object) 无关。它根本不存在于您的班级中。 这样做,您将能够添加任意数量的附加字段。

【讨论】:

以上是关于Symfony2 将自定义字段添加到表单构建器的主要内容,如果未能解决你的问题,请参考以下文章

将自定义参数传递给 Symfony2 中的自定义 ValidationConstraint

如何将自定义字段添加到 WooCommerce 注册表单

Drupal,Ubercart - 将自定义字段添加到结帐表单

Symfony2 表单 > 实体字段类型 > 查询构建器 > 可能的子选择?

php 将自定义字段添加到Popup Maker MailChimp集成表单。

如何将自定义字段添加到 devise_invitable 邀请表单