У меня есть следующие настройки:
у меня есть Product
Объект Doctrine с некоторыми связанными сущностями Doctrine.
/**
* Product
*
* @ORM\Table(name="products")
* @ORM\Entity(repositoryClass="\Entities\ProductRepository")
*/
class Product
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer", precision=0, scale=0, nullable=false, unique=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="artist", type="string", length=100, precision=0, scale=0, nullable=false, unique=false)
*/
private $artist;
/**
* @var string
*
* @ORM\Column(name="title", type="string", length=100, precision=0, scale=0, nullable=false, unique=false)
*/
private $title;
/**
* @var string
*
* @ORM\Column(name="subtitle", type="string", length=100, precision=0, scale=0, nullable=true, unique=false)
*/
private $subtitle;
/**
* @var string
*
* @ORM\Column(name="labelcode", type="string", length=100, precision=0, scale=0, nullable=false, unique=false)
*/
private $labelcode;
/**
* @var string
*
* @ORM\Column(name="description", type="string", length=100, precision=0, scale=0, nullable=true, unique=false)
*/
private $description;
/**
* @var string
*
* @ORM\Column(name="hints", type="text", precision=0, scale=0, nullable=true, unique=false)
*/
private $hints;
/**
* @var string
*
* @ORM\Column(name="price", type="decimal", precision=0, scale=2, nullable=false, unique=false)
*/
private $price;
/**
* @var integer
*
* @ORM\Column(name="amount", type="integer", precision=0, scale=0, nullable=true, options={"default" = 0}, unique=false)
*/
private $amount;
/**
* @var string
*
* @ORM\Column(name="image", type="string", length=100, precision=0, scale=0, nullable=true, unique=false)
*/
private $image;
/**
* @var \DateTime
*
* @ORM\Column(name="instockdate", type="date", precision=0, scale=0, nullable=true, unique=false)
*/
private $instockdate;
/**
* @var boolean
*
* @ORM\Column(name="ownrelease", type="boolean", precision=0, scale=0, nullable=true, columnDefinition="BOOLEAN DEFAULT FALSE", unique=false)
*/
private $ownrelease;
/**
* @var \Entities\Label
*
* @ORM\ManyToOne(targetEntity="Entities\Label", inversedBy="products")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="label_id", referencedColumnName="id", nullable=false)
* })
*/
private $label;
/**
* @var \Entities\Genre
*
* @ORM\ManyToOne(targetEntity="Entities\Genre", inversedBy="products"))
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="genre_id", referencedColumnName="id", nullable=false)
* })
*/
private $genre;
/**
* @var \Entities\Type
*
* @ORM\ManyToOne(targetEntity="Entities\Type")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="type_id", referencedColumnName="id", nullable=false)
* })
*/
private $type;
/**
* @var \Entities\Webshop
*
* @ORM\ManyToOne(targetEntity="Entities\Webshop", inversedBy="products")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="webshop_id", referencedColumnName="id", nullable=true)
* })
*/
private $webshop;
/**
* @var \Entities\Supplier
*
* @ORM\ManyToOne(targetEntity="Entities\Supplier")
* @ORM\JoinColumns({
* @ORM\JoinColumn(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 \Entities\Product
$this->add(array(
'type' => 'Zend\Form\Element\Checkbox',
'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' => 'Zend\Form\Element\Csrf',
'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 \Cms\Form\ProductForm
*/
public function setObjectManager(ObjectManager $objectManager)
{
$this->objectManager = $objectManager;
return $this;
}
/**
* Should return an array specification compatible with
* {@link Zend\InputFilter\Factory::createInputFilter()}.
*
* @return array
*/
public function getInputFilterSpecification()
{
return array(
'create_another_product' => array(
'required' => FALSE,
'allow_empty' => TRUE,
));
}
}
Я покажу вам два FieldSets, один для продукта и один для связанной сущности:
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 Cms\Form\ProductFieldSet
*/
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 Cms\Form\GenreFieldSet.
*
* @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 \Cms\Form\Fieldset.
*/
public function addElements()
{
$this->add(array(
'name' => 'name',
'type' => 'Zend\Form\Element\Text',
'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 пытается добавить все связанные сущности в качестве новой сущности и не находит существующую сущность для связи на основе введенного мной имени.
Кто-нибудь может мне помочь?
— редактировать
Так что на самом деле у меня нет удостоверения личности связанных сущностей. Код контроллера выглядит так:
Привет, значит, идентификатор отсутствует, потому что я использую имя для идентификации связанного объекта. Мой контроллер выглядит так:
// Get your ObjectManager from the ServiceManager
$objectManager = $this->getServiceLocator()->get('Doctrine\ORM
\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
));
}
Должен ли я получить соответствующие идентификаторы в контроллере или есть более тонкий способ сделать это?
В официальном примере https://github.com/doctrine/DoctrineModule/blob/master/docs/hydrator.md#a-complete-example-using-zendform никакие идентификаторы не получены в коде контроллера.
Я не могу полностью выяснить, какие поля / данные вы передаете из огромного количества кода, который вы разместили здесь, но чтобы сделать DoctrineObject
Гидратор находит и использует существующие объекты из базы данных, а затем использует их для гидратации вашего нового объекта, вам необходимо передать поля, которые соответствуют идентификаторам ассоциированных объектов.
Допустим, вы хотите создать новый Product
с существующим Genre
это будет означать прохождение genre_id
в данных. Так что-то вроде этого:
$hydrator = new DoctrineObject($objectManager);
$data = array(
"genre" => array(
"genre_id" => 1
)
);
$product = new Product();
$hydrator->hydrate($data, $product);
В этом очень простом примере кода гидратор распознает поле идентификатора из Genre
юридическое лицо и использовать его, чтобы собрать его перед увлажнением вашего нового Product
, Поэтому, если вы передадите поля идентификаторов в своих наборах данных, это должно сработать.
DoctrineObject
не будет собирать никакие объекты, используя поля идентификатора. Поэтому, если вы передадите какие-либо поля, кроме идентификатора, это предполагает, что вы хотите создать новую ассоциацию с новой сущностью, и будет использовать данные, которые вы передаете, для гидратации новой связанной сущности.
Если передача полей идентификатора — это то, что вы делаете, и это не работает, то, пожалуйста, объясните подробно, какие данные вы точно передаете …
Других решений пока нет …