Zend \ Form与Doctrine 2和ManyToOne Relationships一起使用

时间:2012-07-17 13:09:02

标签: doctrine-orm zend-form relationship zend-framework2

今天我开始阅读Zend \ Form的功能。我找到了来自Michael Gallego的great tutorial,其中他解释了如何使用一些新的酷炫功能。

如果我们处理1-1关系,这个例子到目前为止工作正常。学说很好。

我想做的是

  • 我不想使用textarea作为相关值,而是选择一个选择框
  • 选择框应具有有效选项,具体取决于数据库中的内容
  • 以后进行编辑时,需要选择当前选择的值
  • Doctrine不应向One-Table添加新行

正如您在my github sources所见,我使用了教程中的示例,但将其缩短为“Product”和“Brand”。品牌 - 在我的例子中 - 是一个带有预定义品牌的数据库表(Nike,Adidas,Puma,等等),当您从表单中创建新产品时,您将这些品牌作为选择菜单。

现在,我添加选项的方式不起作用。我知道我可以使用像

这样的数组手动设置选项
$form->get('product')->get('brand')->setAttribute('options', array('Nike'=>'1', 'Adidas'=>'2', etc);

但我强烈认为有一种更自动化的方法可以做到这一点。我根本不理解Zend提供的所有这些Hydrator类。

问题是,即使我如上所述手动定义阵列,产品和品牌的映射也无法正常工作。现在转储$product看起来像这样

object(Application\Entity\Product)[210]
  protected 'id' => null
  protected 'name' => string 'asdasd' (length=6)
  protected 'price' => string '123123' (length=6)
  protected 'brand' => 
    object(Application\Entity\Brand)[215]
      protected 'id' => null
      protected 'name' => string '1' (length=1)

显然,品牌映射完全错误(对于我想要实现的目标,zend可能认为这是正确的,因为我的选择的值为1)。

问题如何告诉我的表单将select-value映射到映射的对象ID?虽然在这种情况下我设置产品模型的方式可能不对。

任何帮助将不胜感激:)

3 个答案:

答案 0 :(得分:1)

查看您的BrandFieldSet,您只为InputFilterProvider指定了名称,因此永远不会传递ID。

其次我建议您删除注册表。如果没有使用构造函数指定的话,使用ServiceManager创建的类可以/应该实现ServiceManagareAwareInterface,如果他们需要访问其他任何东西。

因此,在您的控制器中,而不是使用您的注册表,您将访问服务管理器

$this->getServiceLocator()
     ->get('FQCN_OR_ALIAS');

这个框架的贡献者写了一些很好的例子,并列出了一些github repos。

https://github.com/ZF-Commonshttps://github.com/EvanDotPro(由于我缺乏声誉,不能再发帖了)

如果您有任何其他问题,请加入irc.freenode.org上的#zftalk.2

答案 1 :(得分:1)

这是我的表单对象的代码 我希望它会有所帮助

class ProductForm extends Form
{
public function __construct($em)
{
    parent::__construct();

    $this->add(array(
        'name' => 'productGroupId',
        'attributes' => array(
            'type'  => 'select',
            'label' => 'Category',
            'options' => array(),
        ),
    ));

$this->setProductGropus($em->getRepository('Project\Entity\ProductGroup')->findAll());

public function setProductGropus($groups)
{
  $groupsForm = array('--Select--'=>'');
  foreach ($groups as $group) {
        $groupsForm[$group->name] = (string) $group->productGroupId;
    }
    $this->get('productGroupId')->setAttribute('options',$groupsForm);  
}
}
}

答案 2 :(得分:0)

虽然这是一个老问题,但我还是想回答。以前的答案不使用Doc ObjectSelect

你说要有一个OneToOne关系,并且不希望将记录添加到" One-table&#34 ;;我在这里假设你有Uni-directional OneToOne的关系。

然而,如果你得到了"产品"和"品牌"作为实体,OneToMany Bi-directional关系可能更合适;)

然而,使用OneToOne,您的实体应如下所示:

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

    /**
     * @var string
     * @ORM\Column(name="name", type="string", nullable=false, length=128)
     */
    protected $name;

    //Getters/Setters
}

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

    /**
     * @var string
     * @ORM\Column(name="name", type="string", nullable=false, length=128)
     */
    protected $name;

    //Change below "OneToOne" to "ManyToOne" for proper product + brand relationship. Just this change will leave it as uni-directional.
    /**
     * @var Brand
     * @ORM\OneToOne(targetEntity="Brand", fetch="EAGER")
     * @ORM\JoinColumn(name="brand", referencedColumnName="id")
     */
    protected $brand;

    //Getters/Setters
}

假设您的实体是正确的,那么您应该使用ObjectSelect构建到Doctrine中。

class ProductForm
{
    /** @var  ObjectManager */
    protected $objectManager;

    public function __construct($name = 'product-form', $options = [])
    {
        parent::__construct($name, $options);
    }

    public function init()
    {
        $this->add([
            'type' => 'DoctrineModule\\Form\\Element\\ObjectSelect',
            'name' => 'brand',
            'required' => true,
            'attributes' => [
                'id' => 'selectBrand',
                'multiple' => false,
                'value' => null,
            ],
            'options' => [
                'label' => 'Select brand',
                'object_manager' => $this->getObjectManager(),
                'target_class' => Brand::class,
                'property' => 'id',
                'is_method' => true,
                'find_method' => [
                    'name' => 'findBy',
                    'params' => [
                        'criteria' => [],
                        'orderBy' => ['name' => 'ASC'],
                    ],
                ],
                'empty_option' => '--- Select Brand ---',
                'label_generator' => function (Brand $entity) {
                    return $entity->getName();
                }
            ],
        ]);
    }

    /**
     * @return ObjectManager
     */
    public function getObjectManager()
    {
        return $this->objectManager;
    }

    /**
     * @param ObjectManager $objectManager
     */
    public function setObjectManager(ObjectManager $objectManager)
    {
        $this->objectManager = $objectManager;
    }
}

确保设置Module.php以便能够加载此表单。添加getServiceConfig()功能。

public function getServiceConfig()
    {
        /** @var ServiceManager $sm */
        return [
            'factories' => [
                'product_form' => function ($sm)
                {
                    $form = new ProductForm();
                    $form->setInputFilter(new ProductInputFilter());

                    /** @var EntityManager $entityManager */
                    $entityManager = $sm->get('doctrine.entitymanager.orm_default');

                    //Set Doctrine ObjectManager
                    $form->setObjectManager($entityManager);
                    //Set Doctrine Object as Hydrator
                    $form->setHydrator(new DoctrineObject($entityManager, Product::class));
                    //Set Doctrine Entity
                    $form->setObject(new Product());
                    //Initialize elements onto form
                    $form->init();

                    return $form;
                },
            ],
        ];
    }
}

接下来,在Controller中加载表单。

$form = $this->getServiceLocator()->get('product_form');

===========================

注意:这一直可用到Zend Framework 2.5.2