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. Запись текста в таблице политик также облегчит чтение ваших таблиц данных или создание представления индекса из единого объекта, если вам когда-либо это понадобится.

Другие вопросы по тегам