Doctrine 2:表单字段显示 Doctrine\Common\Collections\ArrayCollection@00 作为值

Posted

技术标签:

【中文标题】Doctrine 2:表单字段显示 Doctrine\\Common\\Collections\\ArrayCollection@00 作为值【英文标题】:Doctrine 2: Form field shows Doctrine\Common\Collections\ArrayCollection@00 as valueDoctrine 2:表单字段显示 Doctrine\Common\Collections\ArrayCollection@00 作为值 【发布时间】:2015-01-27 09:36:41 【问题描述】:

我对 Zend Framework 2 和 Doctrine 2 还很陌生,所以我什至不知道如何搜索或调试我的问题。

我有 3 个数据库表

1.广告 身份证 广告标题 ...

2。类别 身份证 分类名称 ...

3.广告类别 advert_id category_id

我创建了 2 个实体,广告和类别。我现在有一个表格,可以在其中显示可供选择的类别。我使用 jQuery 将类别显示为列表而不是下拉列表,以及可选择的函数。因此,当您单击一个类别时,此列表元素的值将输入到一个名为类别的隐藏输入字段中。

一切正常,除了当我显示表单时,隐藏类别输入字段的值为 Doctrine\Common\Collections\ArrayCollection@000000000..... strong> 而不是空的。我在这里做错了什么?我试图找到解决方案,但没有成功。

我选择了多对多关系,因为我希望最终能够保存超过 1 个类别。目前它只适用于 1,但这样我应该可以在以后更改它。

这是我的广告实体:

namespace Advert\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use DateTime;

/** Advert
 * 
 * @ORM\Table(name="advert")
 * @ORM\Entity(repositoryClass="Advert\Repository\AdvertRepository")
 */

class Advert

 /**
  * @var integer
  *
  * @ORM\Column(name="id", type="integer", nullable=false)
  * @ORM\Id
  * @ORM\GeneratedValue(strategy="IDENTITY")
  */
  private $id;


 /**
  * @var string
  *
  * @ORM\Column(name="advert_title", type="string", length=255, nullable=true)
  */
  private $advertTitle; 

 /** 
  * @ORM\ManyToMany(targetEntity="Category", inversedBy="adverts", cascade="persist") 
  * @ORM\JoinTable(name="advert2category") 
  */
  private $categories;

  public function __construct() 
   
    $this->categories = new ArrayCollection();
  

 /**
  * Set categories
  *
  * @param ArrayCollection $category
  * @return Advert
  */
  public function setCategories($categories)
  
    $this->categories = $categories;
    return $this;
  


 /**
  * Get categories
  *
  * @return ArrayCollection
  */
  public function getCategories()
  
    return $this->categories;
  

  /**
   * @param Collection $categories
   */
  public function addCategories($categories)
  
    foreach ($categories as $category) 
        $this->categories->add($category);
    
  

  /**
   * @param Collection $categories
   */
  public function removeCategories($categories)
  
    foreach($categories as $category)
        $this->categories->removeElement($category);
    

  

广告实体中是否存在导致此问题的错误?我希望有人能帮帮忙。几周以来我就遇到了这个问题,无法让它正常工作。

更新——添加了我的表单和控制器中的一部分以调用表单

下面的表单显示 2 个下拉元素和 2 个隐藏输入字段。 2 个下拉字段通过 jQuery 变成一个可选择的列表。当您单击主类别中的列表元素时,子类别将再次显示为所选主类别的可选列表。然后将 MaincategoryID 输入到隐藏的 categoryID 字段中。一旦您从列表中选择子类别,该类别的 id 就会写入隐藏类别字段中。单击“下一步”按钮会将 $_POST['categories'] 的值与 advertID 一起保存在我的链接表中。

use Zend\Form\Form;
use DoctrineModule\Persistence\ObjectManagerAwareInterface;
use Doctrine\Common\Persistence\ObjectManager;

class CategoryForm extends Form implements ObjectManagerAwareInterface


protected $objectManager;


public function __construct()
       
    $this->setInputFilter(new AdvertFilter());
    parent::__construct('category');




public function init()

    $this->setAttribute('method', 'post');




    $this->add(array(
            'name' => 'categories',
            'attributes' => array(
                    'type' => 'hidden',
                    'id'    => 'categories',

            ),
            'options'=> array(
                    'label'=> 'categories',
                    ),


    ));


    $this->add(
            array(

                    'type' => 'DoctrineModule\Form\Element\ObjectSelect',
                    'name' => 'categoriesList',

                    'options' => array(

                            'object_manager' => $this->getObjectManager(),
                            'label' => 'Main Category',
                            'target_class'   => 'Advert\Entity\Category',
                            'property'       => 'name',
                            'is_method' => true,

                            'find_method'        => array(
                                    'name'   => 'getMainCategories',
                            ),
                    ),
                    'allow_empty'  => true,
                    'required'     => false,
                    'attributes' => array(
                            'id' => 'categoryList',
                            'multiple' => true,


                    )
            )
    );

    $this->add(
            array(
                    'type' => 'DoctrineModule\Form\Element\ObjectSelect',
                    'name' => 'subcategoryList',
                    'options' => array(
                            'object_manager' => $this->getObjectManager(),
                            'label' => 'Sub Category',


                            'target_class'   => 'Advert\Entity\Category',
                            'property'       => 'name',

                            'is_method' => true,
                            'find_method'        => array(
                                    'name'   => 'getSubCategories',
                            ),
                    ),
                    'allow_empty'  => true,
                    'required'     => false,
                    'attributes' => array(

                            'id' => 'subcategoryList',
                            'multiple' => true,
                            )
            )
    );


    $this->add(array(
            'type' => 'hidden',
            'name' => 'categoryID',
            'options'=> array(
                    'label'=> 'categoryID'),
            'attributes' => array(
                    'id' => 'categoryID',
                    'value' => '1',
            )
    ));

   $this->add(array(
            'name' => 'submit',
            'attributes' => array(
                    'type'  => 'submit',
                    'value' => 'Next',
                    'id' => 'submitbutton',
            ),
    ));





public function setObjectManager(ObjectManager $objectManager)

    $this->objectManager = $objectManager;


public function getObjectManager()

    return $this->objectManager;



在我的控制器中,我用以下方式调用我的表单:

    $sl = $this->getServiceLocator();
    $form = $sl->get('FormElementManager')->get('\Advert\Form\CreateForm');

    # create a new, empty entity
    $advert = new Advert();

    # set the hydrator to connect form and entity
    $form->setHydrator(new DoctrineHydrator($this->getEntityManager(),'Advert\Entity\Advert'));

    # connect form and entity
    $form->bind($advert);

【问题讨论】:

【参考方案1】:

首先,双向关系不使用连接表。您的映射似乎是双向的,但您尝试使用第三个表:advert_category

我建议将Advert 实体的$categories 属性映射更改为单向关系:

class Advert

     // ...

    /**
     * @ORM\ManyToMany(targetEntity="Category")
     * @ORM\JoinTable(name="advert_category",
     *      joinColumns=@ORM\JoinColumn(name="advert_id", referencedColumnName="id"),
     *      inverseJoinColumns=@ORM\JoinColumn(name="category_id", referencedColumnName="id")
     *      )
     **/
    protected $categories;

    // ...

如果您想利用DoctrineObject hydrator,您还应该在Advert 实体中实现addCategories(Collection $categories)removeCategories(Collection $categories) 方法。 (我假设您使用的是DoctrineORMModule)。

此时,您的Category 实体不应该知道任何关于Advert 的信息,并且您无法通过$category->getAdverts() 之类的实体方法直接访问来自类别实例的所有广告。但是,当需要时,您可以轻松地在 AdvertRepository 中编写 getAdvertsByCategoryId($categoryId) 方法。

最后一个细节是,您应该有一个CategoryFieldset(它还需要使用Category 实体作为对象)并且您必须使用target_elementconfiguration 键或直接将该字段集指向表单的categories 元素提供实例本身。

例如:

$formManager = $serviceLocator->get('FormElementManager');
$form = $formManager->get('your\form\name');
$form->add(
    array(
        'name' => 'categories',
        'type' => 'Zend\Form\Element\Collection',
        'options' => array(
            'target_element' => $formManager->get('your\fieldset\name');
            // or you can do this but probably you will also need $entityManager
            // inside the CategoryFieldset
            // 'target_element' => new CategoryFieldset();
            ),
        )
    );

我强烈建议使用FormElementManager 来获取表单和字段集实例,而不是通过new AdvertForm()new CategoryFieldset() 直接实例化它们。编写AbstractFormElementFactory 也是一种很好的做法,可以以正确的方式将$entityManager 之类的依赖项注入到您的字段集和表单中。

希望对你有帮助。

【讨论】:

感谢 foozy 的详细回答。 addCategories 和 removecategories 已经包含在内,我只是把它放在上面,因为我认为这对我的问题并不重要,它现在出现了。我很惊讶双向关系不使用连接表,因为我在网上到处都看到过,我会更详细地研究。我现在也将我的表单添加到帖子中,所以我想错误就在这里,但我看不到在哪里。也许你看到了?我会尽力了解您的建议并做出更改。 我绝对会将 Category 字段集分离到一个单独的类中。无需在 AdvertForm 中引入“categoryID”隐藏元素,因为类别字段集中将有一个 id 元素,并且 AdvertForm 应该有一个 categories 集合。我认为 SubCategories 问题也需要在 Category 字段集中处理,而不是 AdvertForm。

以上是关于Doctrine 2:表单字段显示 Doctrine\Common\Collections\ArrayCollection@00 作为值的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SonataAdminBundle 的上传字段上方显示当前图片?

Doctrine2 Mapping:2 个字段映射到一个字段(ManyToOne)

Doctrine 2 DQL CONCAT 字段和常量字符串

更新数据库中的表/字段 - Doctrine 2 和 Codeigniter 2

在 Doctrine 2 中加载/保存字段时透明地执行 SQL 函数

在 Doctrine 2 中指定十进制字段类型时,比例和精度是啥意思?