0

I am pretty new to Zend Framework 2 and Doctrine 2, so I am not even sure how to search or debug my problem.

I have 3 database tables

1. advert
id
adverttitle ...

2. category
id
categoryname ...

3. advert_category
advert_id
category_id

I have created 2 Entities, Advert and Category. I have now got a Form where I show the Categories to choose from. I use jQuery to display the categories as a list instead of a dropdown, together with a selectable function. So when you click on a category, the value of this listelement gets entered into a hidden input field called categories.

Everything works fine, besides that when I display the form, the hidden categories input field got a value of Doctrine\Common\Collections\ArrayCollection@000000000..... instead of being empty. What am I doing wrong here? I have tried to find a solution, but unsuccessfully.

I have chosen a ManyToMany Relationship because I want to be able to save more then 1 category in the end. Currently it is only working with 1, but this way I should be able to change this at a later time.

Here my Advert entity:

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);
    }

  }

Is there an Error in the Advert Entity which causes this? I hope someone can help. I have this problems since weeks and can not get it to work correctly.

UPDATE -- added my Form and part in controller to call form

The below Form displays 2 Dropdown Elements and 2 Hidden Input Fields. The 2 Dropdown Fields get turned into a selectable List via jQuery. When you click on a List Element from the Maincategory, the Subcategories show up for that chosen Maincategory again as a selectable list. The MaincategoryID gets then entered into the hidden categoryID Field. As soon you choose the Subcategory from the List, the id of that category gets written in the hidden categories field. A click on the "next" button saves the value of $_POST['categories'] together with the advertID in my linking table.

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;
}

}

In my Controller I call my form the following way:

    $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);
4

1 回答 1

0

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

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

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 ,你也应该在实体中实现addCategories(Collection $categories)andremoveCategories(Collection $categories)方法。(我假设您正在使用DoctrineORMModule)。Advert

此时,您的Category实体不应该知道任何相关信息Advert,并且您无法通过实体方法(如$category->getAdverts(). 但是,当需要时,您可以轻松地getAdvertsByCategoryId($categoryId)在 AdvertRepository 中编写一个方法。

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

例如:

$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();
            ),
        )
    );

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

希望能帮助到你。

于 2014-11-29T10:45:15.143 回答