ZF2:带有嵌套字段集的表单-Doctrine Hydrator试图为所有对象添加新的实体



我有以下设置:

我有一个Product条令对象和一些相关的条令实体。

/**
* Product
*
* @ORMTable(name="products")
* @ORMEntity(repositoryClass="EntitiesProductRepository")
*/
class Product
{
/**
 * @var integer
 *
 * @ORMColumn(name="id", type="integer", precision=0, scale=0, nullable=false, unique=false)
 * @ORMId
 * @ORMGeneratedValue(strategy="IDENTITY")
 */
private $id;
/**
 * @var string
 *
 * @ORMColumn(name="artist", type="string", length=100, precision=0, scale=0, nullable=false, unique=false)
 */
private $artist;
/**
 * @var string
 *
 * @ORMColumn(name="title", type="string", length=100, precision=0, scale=0, nullable=false, unique=false)
 */
private $title;
/**
 * @var string
 *
 * @ORMColumn(name="subtitle", type="string", length=100, precision=0, scale=0, nullable=true, unique=false)
 */
private $subtitle;
/**
 * @var string
 *
 * @ORMColumn(name="labelcode", type="string", length=100, precision=0, scale=0, nullable=false, unique=false)
 */
private $labelcode;
/**
 * @var string
 *
 * @ORMColumn(name="description", type="string", length=100, precision=0, scale=0, nullable=true, unique=false)
 */
private $description;
/**
 * @var string
 *
 * @ORMColumn(name="hints", type="text", precision=0, scale=0, nullable=true, unique=false)
 */
private $hints;
/**
 * @var string
 *
 * @ORMColumn(name="price", type="decimal", precision=0, scale=2, nullable=false, unique=false)
 */
private $price;
/**
 * @var integer
 *
 * @ORMColumn(name="amount", type="integer", precision=0, scale=0, nullable=true, options={"default" = 0}, unique=false)
 */
private $amount;
/**
 * @var string
 *
 * @ORMColumn(name="image", type="string", length=100, precision=0, scale=0, nullable=true, unique=false)
 */
private $image;
/**
 * @var DateTime
 *
 * @ORMColumn(name="instockdate", type="date", precision=0, scale=0, nullable=true, unique=false)
 */
private $instockdate;
/**
 * @var boolean
 *
 * @ORMColumn(name="ownrelease", type="boolean", precision=0, scale=0, nullable=true, columnDefinition="BOOLEAN DEFAULT FALSE", unique=false)
 */
private $ownrelease;
/**
 * @var EntitiesLabel
 *
 * @ORMManyToOne(targetEntity="EntitiesLabel", inversedBy="products")
 * @ORMJoinColumns({
 *   @ORMJoinColumn(name="label_id", referencedColumnName="id", nullable=false)
 * })
 */
private $label;
/**
 * @var EntitiesGenre
 *
 * @ORMManyToOne(targetEntity="EntitiesGenre", inversedBy="products"))
 * @ORMJoinColumns({
 *   @ORMJoinColumn(name="genre_id", referencedColumnName="id", nullable=false)
 * })
 */
private $genre;
/**
 * @var EntitiesType
 *
 * @ORMManyToOne(targetEntity="EntitiesType")
 * @ORMJoinColumns({
 *   @ORMJoinColumn(name="type_id", referencedColumnName="id", nullable=false)
 * })
 */
private $type;
/**
 * @var EntitiesWebshop
 *
 * @ORMManyToOne(targetEntity="EntitiesWebshop", inversedBy="products")
 * @ORMJoinColumns({
 *   @ORMJoinColumn(name="webshop_id", referencedColumnName="id", nullable=true)
 * })
 */
private $webshop;
/**
 * @var EntitiesSupplier
 *
 * @ORMManyToOne(targetEntity="EntitiesSupplier")
 * @ORMJoinColumns({
 *   @ORMJoinColumn(name="supplier_id", referencedColumnName="id", nullable=true)
 * })
 */
private $supplier;
/**  Getters and Setters **/
}

我有一个CreateProductForm:

class CreateProductForm extends Form implements InputFilterProviderInterface
{
protected $objectManager;
public function __construct(ObjectManager $objectManager)
{
    parent::__construct('create-product-form');
    $this->setObjectManager($objectManager);
    $this->setHydrator(new DoctrineHydrator($this->getObjectManager()));
    $this->addElements();
}
public function addElements()
{
    // Add the product fieldset, and set it as the base fieldset
    $productFieldset = new ProductFieldSet($this->getObjectManager());
    $productFieldset->setUseAsBaseFieldset(true);
    $this->add($productFieldset);
    // Add a checkbox allowing creation of another EntitiesProduct
    $this->add(array(
        'type' => 'ZendFormElementCheckbox',
        'name' => 'create_another_product',
        'attributes' => array(
            'required' => FALSE,
            'allow_empty' => TRUE,
        ),
        'options' => array(
            'label' => 'Create another',
            'use_hidden_element' => TRUE,
            'checked_value' => TRUE,
            'unchecked_value' => FALSE,
            'label_attributes' => array(
                'class' => 'control-label'
            ),
        ),
    ));
    // … add CSRF and submit elements …
    $this->add(array(
        'type' => 'ZendFormElementCsrf',
        'name' => 'create_product_csrf',
        'options' => array(
            'csrf_options' => array(
                'timeout' => 600
            )
        )
    ));
    $this->add(array(
        'name' => 'submit',
        'type' => 'Submit',
        'attributes' => array(
            'value' => 'Go',
            'id' => 'submitbutton',
            'class' => 'btn btn-primary'
        ),
    ));
}
/**
 * Get objectManager
 * 
 * @return type 
 */
public function getObjectManager()
{
    return $this->objectManager;
}
/**
 * Set objectManager
 * 
 * @param ObjectManager $objectManager
 * @return CmsFormProductForm
 */
public function setObjectManager(ObjectManager $objectManager)
{
    $this->objectManager = $objectManager;
    return $this;
}
/**
 * Should return an array specification compatible with
 * {@link ZendInputFilterFactory::createInputFilter()}.
 *
 * @return array
 */
public function getInputFilterSpecification()
{
    return array(
        'create_another_product' => array(
            'required' => FALSE,
            'allow_empty' => TRUE,
    ));
}
}

我将向您展示两个字段集,一个用于产品,另一个用于相关实体:

class ProductFieldSet extends Fieldset implements InputFilterProviderInterface
{
/**
 * @var ObjectManager
 *
 */
protected $objectManager;
/**
 * @var InputFilter
 *
 */
protected $inputFilter;
public function __construct(ObjectManager $objectManager)
{
    parent::__construct('product');
    $this->setObjectManager($objectManager);

    $this->setHydrator(new DoctrineEntity($this->getObjectManager()))->setObject(new Product());
    $this->addElements();
}
public function addElements()
{
    $this->add(array(
        'name' => 'id',
        'type' => 'Hidden',
    ));
    $this->addLabelCode();
    $this->addArtist();
    $this->addTitle();
    $this->addDescription();
    $this->addPrice();
    $this->addHints();
    $this->add(array(
        'name' => 'subtitle',
        'type' => 'Text',
        'options' => array(
            'label' => 'Subtitle',
        ),
        'attributes' => array(
            'class' => 'form-control',
        ),
    ));

    $this->add(array(
        'name' => 'amount',
        'type' => 'Text',
        'options' => array(
            'label' => 'Amount',
        ),
    ));
    $date = new Date('instockdate');
    $date
            ->setLabel('In Stock Date')
            ->setAttributes(array(
                'min' => '2012-01-01',
                'max' => '2200-01-01',
                'step' => '1', // days; default step interval is 1 day
    ));

    $this->addGenre();
    $this->addLabel();
    $this->addType();
}
// A lot of add methods
 /**
 * Add Type to the CmsFormProductFieldSet
 */
private function addType()
{
    $typeFieldset = new TypeFieldSet($this->getObjectManager());
    $typeFieldset->setName('type');
   //$labelFieldset->setAttribute('required', TRUE);
   //$labelFieldset->setAttribute('class', 'form-control');
    $typeFieldset->setLabel('Type');
   //$labelFieldset->setLabelAttributes(array('class' => 'control-label'));
    $this->add($typeFieldset);
}
}

现在TypeFieldSet:

class TypeFieldSet extends Fieldset implements InputFilterProviderInterface
{
/**
 * @var ObjectManager
 *
 */
protected $objectManager;
/**
 * @var InputFilter
 *
 */
protected $inputFilter;
/**
 * Construct CmsFormGenreFieldSet.
 * 
 * @param ObjectManager $objectManager
 */
public function __construct(ObjectManager $objectManager)
{
    parent::__construct('type');
    $this->setObjectManager($objectManager);
    $this->setHydrator(new DoctrineEntity($this->getObjectManager()))->setObject(new Type());
    $this->addElements();
}
/**
 * Method responsible for adding elements to CmsFormFieldset.
 */
public function addElements()
{
    $this->add(array(
        'name' => 'name',
        'type' => 'ZendFormElementText',
        'attributes' => array(
            'required' => true,
            'id' => 'name',
            'class' => 'form-control',
            'placeholder' => 'Enter type name'
        ),
        'options' => array(
            'label' => 'Name',
            'label_attributes' => array(
                'class' => 'control-label'
            ),
        ),
    ));
}
// Additional methods
}

不知何故,Doctrine试图将所有相关实体添加为新实体,而不是根据我输入的名称找到要关联的现有实体。

有人能帮我吗?

--编辑

所以实际上我没有相关实体的ID。控制器代码如下:

嗨,所以ID不见了,因为我用这个名字来识别相关的对象。我的控制器看起来像这样:

// Get your ObjectManager from the ServiceManager
  $objectManager = $this->getServiceLocator()->get('DoctrineORM 
  EntityManager');
    // Create the form and inject the ObjectManager
    $form = new CreateProductForm($objectManager);
    // Create a new, empty entity and bind it to the form
    $product = new Product();
    $form->bind($product);
    if ($this->request->isPost())
    {
        $form->setData($this->request->getPost());
        if ($form->isValid())
        {
            $this->getProductService()->saveProduct($product);
            $this->flashMessenger()->addSuccessMessage('Product ' . $product->getName() . ' saved');
                return $this->redirect()->toRoute('product');
        }
        else
        {
            $this->flashMessenger()->addErrorMessage($form->getMessages());
        }
    }
    return new ViewModel(array(
        'product' => $product,
        'form' => $form
    ));
}

我应该在控制器中获取相关ID吗?或者有更微妙的方法吗?在官方示例中https://github.com/doctrine/DoctrineModule/blob/master/docs/hydrator.md#a-使用zendform的完整示例控制器代码中没有获得id。

我无法完全弄清楚您在这里发布的大量代码中传递了哪些字段/数据,但要使DoctrineObject水合器从数据库中找到并使用现有实体,并随后将这些实体用于新对象的水合,您需要传递与关联对象的标识符相对应的字段。

假设您想用现有的Genre创建一个新的Product,这意味着要在数据中传递genre_id。这样的东西:

$hydrator = new DoctrineObject($objectManager);
$data = array(
    "genre" => array(
        "genre_id" => 1
    )
);
$product = new Product();
$hydrator->hydrate($data, $product);

在这个非常基本的代码示例中,hydrator将识别来自Genre实体的标识符字段,并在对新的Product进行水合之前使用它来收集它。因此,如果您在数据集中传递标识符字段,它应该会起作用。

DoctrineObject不会使用标识符字段以外的其他字段收集任何实体。因此,如果您要传递除标识符字段之外的任何字段,它会假设您想与新实体建立新的关联,并将使用您传递的数据来水合新的相关实体。

如果传递标识符字段是您正在做的事情,但它不起作用,那么请详细解释您正在传递的数据

相关内容

  • 没有找到相关文章

最新更新