ZF2 + Doctrine2 Class Inherritence Excression
У меня проблема с получением моей сущности доктрины для извлечения в мою форму ZF2. Я довольно новичок в ZF2 и Doctrine (а также в наследовании таблиц классов). Я прочитал практически всю документацию по ZF2 и Doctrine, но все еще не могу понять, как заставить это работать.
Чтобы кратко объяснить систему, существует основной объект, который называется Политика. Сущность Policy включает сущность Proposer и сущность PolicyProduct, а также несколько других столбцов.
Я использую наследование таблиц классов в сущности PolicyProduct, поскольку у меня есть 3 разных типа продуктов, каждый из которых требует разные данные. 3 продукта являются TouringCaravan, StaticCaravan и Parkhome.
Сущность Policy может иметь только 1 Proposer и 1 PolicyProduct.
Все сущности имеют методы получения и установки для каждого столбца.
Отображаемая форма включает в себя поля как объекта Policy, так и объекта PolicyProduct.
Чтобы отобразить форму, я сначала получаю сущность Policy и Policy Fieldset. А затем установите набор полей политики в качестве базы.
$policyEntity = $entityManager->getRepository('Policy\Entity\Policy')->find($policyId);
$policyFieldset = $formElementManager->get('policy_form_policy_fieldset');
$policyFieldset->setUseAsBaseFieldset(true);
Затем я получаю определенный набор полей PolicyProduct и добавляю его в policyFieldset.
eg
$productFieldset = $formElementManager->get('tourers_form_touring_fieldset');
$policyFieldset->add($productFieldset);
Затем я добавляю policyFieldset в форму, связываю его с сущностью Policy и возвращаю заполненную форму.
$productForm->add($policyFieldset);
$productForm->bind($policyEntity);
return $productForm;
К сведению, я использую DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator
как мой гидратор для каждого набора полей. Затем я называю следующее внутри init()
метод каждого набора полей.
// Example from PolicyFieldset
$hydrator = new DoctrineHydrator($this->objectManager,true);
$this->setHydrator($hydrator)
->setObject(new Policy());
Если я заполняю форму и сохраняю в базу данных, я вижу, что данные правильно хранятся в таблицах. Если я затем попытаюсь увлажнить ту же форму с объектом, ни одно из значений объекта PolicyProduct не будет сопоставлено. Значения в объекте политики, однако, правильно гидратированы.
Если я выброшу $policyEntity->getPolicyProduct()
я могу видеть все данные, что означает, что сущность правильно сохраняет и извлекает информацию, проблема заключается в том, что я пытаюсь извлечь данные сущности в набор полей формы.
Я надеюсь, что это имеет смысл, но дайте мне знать, если нет, и я постараюсь уточнить.
Спасибо
Вот основные объекты
политика
namespace Policy\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="policy")
*/
class Policy {
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\ManyToOne(targetEntity="Proposer\Entity\Proposer", inversedBy="policy")
* @ORM\JoinColumn(name="proposer_id", referencedColumnName="id")
*
protected $proposer;
/**
* @ORM\ManyToOne(targetEntity="Product")
* @ORM\JoinColumn(name="product_id", referencedColumnName="id", onDelete="RESTRICT")
*/
protected $product;
/**
* @ORM\OneToOne(targetEntity="Policy\Entity\PolicyProduct")
* @ORM\JoinColumn(name="policy_product_id", referencedColumnName="id")
*/
protected $policyProduct;
/**
* @ORM\ManyToOne(targetEntity="PolicyStatus")
* @ORM\JoinColumn(name="policy_status_id", referencedColumnName="id", onDelete="RESTRICT")
*/
protected $policyStatus;
/**
* @ORM\Column(name="policyInception", type="date", nullable=true)
*/
protected $policyInception;
// Omitted getters and setters
}
PolicyProduct
namespace Policy\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="policy_product")
* @ORM\InheritanceType("JOINED")
* @ORM\DiscriminatorColumn(name="productDiscriminator", type="integer")
* @ORM\DiscriminatorMap({1 = "Tourers\Entity\TouringCaravan", 2 = "Statics\Entity\StaticCaravan", 3 = "Parkhomes\Entity\Parkhome"})
*/
class PolicyProduct {
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
// Omitted getters and setters
}
TouringCaravan - пример наследуемой таблицы PolicyProduct
namespace Tourers\Entity;
use Doctrine\ORM\Mapping as ORM;
use Policy\Entity\PolicyProduct;
/**
* @ORM\Entity
* @ORM\Table(name="touring_caravan")
*/
class TouringCaravan extends PolicyProduct {
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\OneToOne(targetEntity="Policy\Entity\Policy")
* @ORM\JoinColumn(name="policy_id", referencedColumnName="id")
*/
protected $policy;
/**
* @ORM\ManyToOne(targetEntity="TouringCaravanMake")
* @ORM\JoinColumn(name="touring_caravan_make", referencedColumnName="id", onDelete="RESTRICT")
*/
protected $caravanMake;
/**
* @ORM\Column(name="caravanModel", type="string", length=128, unique=false, nullable=false)
*/
protected $caravanModel;
....
Lots more columns specific to the TouringCaravan Entity
// Omitted getters and setters
}
1 ответ
Похоже, у вас здесь слишком много сущностей. Если я понимаю, что вы пытаетесь сделать, каждая политика связана с одним "классом" продукта, который будет либо TouringCaravan, StaticCaravan или Parkhome. Если это так, то ваш столбец дискриминатора принадлежит вашей сущности Policy, и политика PolicyProduct может просто исчезнуть. Вот что вы хотите сделать:
1) Сделайте это изменение в Policy\Entity\Policy
:
// ... //
/**
* @ORM\Entity
* @ORM\Table(name="policy")
* @ORM\InheritanceType("JOINED")
* @ORM\DiscriminatorColumn(name="policyProduct", type="integer")
* @ORM\DiscriminatorMap({1 = "Tourers\Entity\TouringCaravan", 2 = "Statics\Entity\StaticCaravan", 3 = "Parkhomes\Entity\Parkhome"})
*/
class Policy {
// ... //
и удалите это:
/**
* @ORM\OneToOne(targetEntity="Policy\Entity\PolicyProduct")
* @ORM\JoinColumn(name="policy_product_id", referencedColumnName="id")
*/
protected $policyProduct;
1a) Пока вы здесь, вам нужно сбежать из DocBlock для $proposer
с */
,
2) Удалить Policy\Entity\PolicyProduct
,
3) Сделайте это изменение в Tourers\Entity\TouringCaravan
и все остальные дочерние объекты:
// ... //
class TouringCaravan extends Policy {
// ... //
4) Подумайте о переименовании ваших идентификаторов. Каждая из сущностей имеет свой собственный идентификатор, и легко забыть, какой из них, если они все называются $ id. Если идентификатор вашего продукта продукта $product_id
и идентификатор вашего объекта TouringCaravan $touring_caravan_id
и так далее, их легче идентифицировать. Я присваиваю уникальные описательные имена своим идентификаторам как в моих таблицах, так и в моих сущностях, и я обнаружил, что Doctrine иногда создает для меня соединение, если я забываю сделать некоторые из моих утверждений сопоставления.
5). Попробуйте удалить сгенерированные дочерние идентификаторы из Tourers\Entity\TouringCaravan
и другие дочерние объекты, и ваша база данных генерирует значения в таблице. Я обнаружил, что Doctrine не нравится, когда одна сущность расширяет другую, и в JOIN есть два столбца автономных номеров.
Здесь происходит гораздо больше, чем вы делитесь (сущность Proposer и сущность PolicyStatus), поэтому я не могу сказать, решат ли эти предложения все ваши проблемы, но это только начало.
Еще одно предложение, не связанное с вашим вопросом:
Возможно, вы захотите изменить столбец дискриминатора на строку, а не на целое число, и записать там текстовое описание продукта. В противном случае вам нужно будет создать еще одну сущность или жесткий код массива, чтобы указать, что 1 = TouringCaravan, 2 = StaticCaravan и 3 = Parkhome. Запись текста в таблице политик также облегчит чтение ваших таблиц данных или создание представления индекса из единого объекта, если вам когда-либо это понадобится.