@fattan
программист

Как организовать Doctrine One-To-One, Unidirectional with Join Table?

Нашел в документации Doctrine как сделать One-To-Many, Unidirectional with Join Table.
Но мне нужно One-To-One, Unidirectional with Join Table.
Никак не соображу как сделать.
Структура таблиц такая: у документа есть статус. Статус связан с документом через промежуточную таблицу exp_doc_status (где также хранится время перехода в статус и доп. информация о состоянии статуса)

SQL код таблиц
--
-- Структура таблицы `exp_document`
--

CREATE TABLE `exp_document` (
  `id` mediumint(8) UNSIGNED NOT NULL,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

--
-- Индексы таблицы `exp_document`
--
ALTER TABLE `exp_document`
  ADD PRIMARY KEY (`id`);

ALTER TABLE `exp_document`
  MODIFY `id` mediumint(8) UNSIGNED NOT NULL AUTO_INCREMENT;


--
-- Структура таблицы `exp_doc_status`
--

CREATE TABLE `exp_doc_status` (
  `id_doc` mediumint(8) UNSIGNED NOT NULL,
  `id_status` tinyint(2) UNSIGNED NOT NULL,
  `event_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `event_day` tinyint(2) UNSIGNED NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Индексы таблицы `exp_doc_status`
--
ALTER TABLE `exp_doc_status`
  ADD PRIMARY KEY (`id_doc`),
  ADD KEY `id_doc` (`id_doc`),
  ADD KEY `id_status` (`id_status`);

--
-- Ограничения внешнего ключа таблицы `exp_doc_status`
--
ALTER TABLE `exp_doc_status`
  ADD CONSTRAINT `exp_doc_status_ibfk_1` FOREIGN KEY (`id_status`) REFERENCES `exp_status` (`id`),
  ADD CONSTRAINT `exp_doc_status_ibfk_2` FOREIGN KEY (`id_doc`) REFERENCES `exp_document` (`id`);


--
-- Структура таблицы `exp_status`
--

CREATE TABLE `exp_status` (
  `id` tinyint(2) UNSIGNED NOT NULL,
  `name` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Индексы таблицы `exp_status`
--
ALTER TABLE `exp_status`
  ADD PRIMARY KEY (`id`);

--
-- AUTO_INCREMENT для таблицы `exp_status`
--
ALTER TABLE `exp_status`
  MODIFY `id` tinyint(2) UNSIGNED NOT NULL AUTO_INCREMENT;

  • Вопрос задан
  • 4896 просмотров
Решения вопроса 1
@fattan Автор вопроса
программист
Сделал как советовал Myroslav Berlad в комментарии.
Подробный результат:
документы связал с промежуточной таблицей двусторонней связью 1 к 1
Промежуточную таблицу (документ-статус) связал с таблицей статусов двусторонней связью 1 ко многим
Схема БД та же, см. шапку.

Создал 3 Entity.

Для документов:
спойлер
<?php

namespace Finance\ExpBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;

/**
 * Document
 *
 * @ORM\Table(name="exp_document", indexes={@ORM\Index(name="tasks_user_id_index", columns={"initiator_id"})})
 * @ORM\Entity(repositoryClass="Finance\ExpBundle\Repository\DocumentRepository")
 */
class Document
{
    /**
     * @var integer
     *
     * @ORM\Column(name="initiator_id", type="integer", nullable=false)
     */
    private $initiatorId;

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

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="created_at", type="datetime", nullable=true)
     */
    private $createdAt;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="updated_at", type="datetime", nullable=true)
     */
    private $updatedAt;

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;


    /**
     * One Customer has One Cart.
     * @var DocStatus
     * @ORM\OneToOne(targetEntity="DocStatus", mappedBy="document")
     */
    private $docStatus;


    /**
     * @return DocStatus
     */
    public function getDocStatus()
    {
        return $this->docStatus;
    }

    /**
     * @return Status
     */
    public function getStatus()
    {
        return $this->getDocStatus()->getStatus();
    }

    /**
     * Set initiatorId
     *
     * @param integer $initiatorId
     *
     * @return Document
     */
    public function setInitiatorId($initiatorId)
    {
        $this->initiatorId = $initiatorId;

        return $this;
    }

    /**
     * Get initiatorId
     *
     * @return integer
     */
    public function getInitiatorId()
    {
        return $this->initiatorId;
    }

    /**
     * Set name
     *
     * @param string $name
     *
     * @return Document
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set createdAt
     *
     * @param \DateTime $createdAt
     *
     * @return Document
     */
    public function setCreatedAt($createdAt)
    {
        $this->createdAt = $createdAt;

        return $this;
    }

    /**
     * Get createdAt
     *
     * @return \DateTime
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    /**
     * Set updatedAt
     *
     * @param \DateTime $updatedAt
     *
     * @return Document
     */
    public function setUpdatedAt($updatedAt)
    {
        $this->updatedAt = $updatedAt;

        return $this;
    }

    /**
     * Get updatedAt
     *
     * @return \DateTime
     */
    public function getUpdatedAt()
    {
        return $this->updatedAt;
    }

    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }
}



Для промежуточной таблицы (документ-статус):
Спойлер
<?php

namespace Finance\ExpBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;

/**
 * DocStatus
 *
 * @ORM\Table(name="exp_doc_status", indexes={@ORM\Index(name="id_doc", columns={"id_doc"}), @ORM\Index(name="id_status", columns={"id_status"})})
 * @ORM\Entity
 */
class DocStatus
{
    /**
     * @var \DateTime
     *
     * @ORM\Column(name="event_date", type="datetime", nullable=false)
     */
    private $eventDate = 'CURRENT_TIMESTAMP';

    /**
     * @var integer
     *
     * @ORM\Column(name="event_day", type="integer", nullable=false)
     */
    private $eventDay = '0';

    /**
     * @var integer
     *
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="NONE")
     */
    private $idDoc;


    /**
     * @ORM\OneToOne(targetEntity="Document", inversedBy="docStatus")
     * @ORM\JoinColumn(name="id_doc", referencedColumnName="id")
     */
    private $document;


    /**
     * @ORM\ManyToOne(targetEntity="Status", inversedBy="docStatus")
     * @ORM\JoinColumn(name="id_status", referencedColumnName="id")
     */
    private $status;


    public function getStatus()
    {
        return $this->status;
    }

    public function getDocument()
    {
        return $this->document;
    }

    /**
     * @var integer
     * @ORM\Id
     * @ORM\Column(name="id_status", type="integer", nullable=false)
     */
    private $idStatus;

    /**
     * Set eventDate
     *
     * @param \DateTime $eventDate
     *
     * @return DocStatus
     */
    public function setEventDate($eventDate)
    {
        $this->eventDate = $eventDate;

        return $this;
    }

    /**
     * Get eventDate
     *
     * @return \DateTime
     */
    public function getEventDate()
    {
        return $this->eventDate;
    }

    /**
     * Set eventDay
     *
     * @param integer $eventDay
     *
     * @return DocStatus
     */
    public function setEventDay($eventDay)
    {
        $this->eventDay = $eventDay;

        return $this;
    }

    /**
     * Get eventDay
     *
     * @return int
     */
    public function getEventDay()
    {
        return $this->eventDay;
    }

    /**
     * Get idDoc
     *
     * @return \Finance\ExpBundle\Entity\Document
     */
    public function getIdDoc()
    {
        return $this->idDoc;
    }

}



Для статусов:
Спойлер
<?php

namespace Finance\ExpBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Status
 *
 * @ORM\Table(name="exp_status")
 * @ORM\Entity
 */
class Status
{
    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255, nullable=false)
     */
    private $name;

    /**
     * @var integer
     *
     * @ORM\Column(name="day_by_reglament", type="integer", nullable=false)
     */
    private $dayByReglament = '0';

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;


    /**
     * @ORM\OneToMany(targetEntity="DocStatus", mappedBy="status")
     */
    private $docStatus;


    public function getDocStatus()
    {
        return $this->docStatus;
    }


    /**
     * Set name
     *
     * @param string $name
     *
     * @return Status
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set dayByReglament
     *
     * @param integer $dayByReglament
     *
     * @return Status
     */
    public function setDayByReglament($dayByReglament)
    {
        $this->dayByReglament = $dayByReglament;

        return $this;
    }

    /**
     * Get dayByReglament
     *
     * @return integer
     */
    public function getDayByReglament()
    {
        return $this->dayByReglament;
    }

    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }
}



В результате, получить информацию о статусе документа в Symfony3 можно таким образом:

В action контроллера:

$em = $this->getDoctrine();
$repoDoc = $em->getRepository(Document::class);
$doc = $repoDoc->find($id);

dump($doc->getStatus()->getName());
dump($doc->getStatus()->getDayByReglament());


В шаблонизаторе twig:

{{ dump(doc.status.name) }}
{{ dump(doc.status.dayByReglament) }}
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
myrkoxx
@myrkoxx
developer
Вот как описано в доке:
docs.doctrine-project.org/projects/doctrine-orm/en...

Маленький соевет. Всегда опишите мапинг в Entity через annotanions, xml или yml и пользуйтесь бандлом DoctrineMigrationsBundle

После добавлений изменений в мапинге делайте просто:

app/console (bin/console if symfony 3+) doctrine:migrations:diff

вам миграция нагенерит sql для приведения к актуальному состоянию.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы