Как ссылаться на связь «многие-к-одному» в Учении 2 по неосновному ключу - PullRequest
0 голосов
/ 18 февраля 2019

Как я понимаю, Doctrine требует много-к-одному ассоциаций с ссылкой на первичный ключ с одной стороны.(См. здесь или здесь )

Как можно решить ассоциацию «многие к одному», на которую ссылается уникальный ключ в Доктрине 2?

Ниже я покажу, что я придумал до сих пор и столкнулся с вышеупомянутой проблемой.Какие изменения необходимо внести, чтобы он работал в моем контексте?

В моем случае:

Проект имеет среди прочих свойств snapshotId и cid.cid представляет внутренний номер проекта.При определенных изменениях снимок снимается и сохраняется с уникальным snapshotId (включая все зависимые записи в связанной таблице - здесь не показано).Запись с пустым (нулевым) snapshotId является текущим состоянием.

Изменения в проекте отслеживаются в ProjectHistory.Для демонстрации эта сущность имеет свойства function, modifyDate и modifyUserId.

. Проект имеет однозначную связь с ProjectHistory.ProjectHistory ассоциация «многие-к-одному» для Project.Первый работает, как и ожидалось, последний приносит ошибку, указанную в начале.

<?php

namespace App\Entity;

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

/**
 * @ORM\Entity()
 * @ORM\Table(
 *     indexes={
 *         @ORM\Index(
 *             name="cid",
 *             columns={"cid"}
 *         ),
 *     },
 *     uniqueConstraints={
 *         @ORM\UniqueConstraint(
 *             name="unique_snapshot_per_project",
 *             columns={"snapshot_id", "cid"}
 *         ),
 *     },
 * )
 */
class Project
{
    /**
     * @ORM\Id()
     * @ORM\Column(type="guid")
     * @ORM\GeneratedValue(strategy="UUID")
     * @var string
     */
    private $id;

    /**
     * @ORM\Column(type="guid", unique=true, nullable=true)
     * @var string|null
     */
    private $snapshotId;

    /**
     * @ORM\Column()
     * @var string
     */
    private $cid;

    /**
     * @ORM\OneToMany(targetEntity="ProjectHistory", mappedBy="projectCid", cascade={"persist"})
     * @var Collection|ProjectHistory[]
     */
    private $projectHistories;

    public function __construct()
    {
        $this->projectHistories = new ArrayCollection();
    }

    public function toArray(): array
    {
        return [
            'id'               => $this->getId(),
            'snapshotId'       => $this->getSnapshotId(),
            'cid'              => $this->getCid(),
            'projectHistories' => $this->getProjectHistoriesAsArray(),
        ];
    }

    public function getProjectHistoriesAsArray(): array
    {
        $projectHistories = [];
        foreach ($this->getProjectHistories() as $projectHistory) {
            $projectHistories[] = $projectHistory->toArray();
        }

        return $projectHistories;
    }

    public function getId(): ?string
    {
        return $this->id;
    }

    public function setId(string $id): void
    {
        $this->id = $id;
    }

    public function getSnapshotId(): ?string
    {
        return $this->snapshotId;
    }

    public function setSnapshotId(string $snapshotId): void
    {
        $this->snapshotId = $snapshotId;
    }

    public function getCid(): string
    {
        return $this->cid;
    }

    public function setCid(string $cid): void
    {
        $this->cid = $cid;
    }

    public function getProjectHistories(): Collection
    {
        return $this->projectHistories;
    }

    /**
     * @param ArrayCollection|ProjectHistory[] $projectHistories
     * @return Project
     */
    public function addProjectHistories(ArrayCollection $projectHistories): Project
    {
        foreach ($projectHistories as $projectHistory) {
            if (! $this->projectHistories->contains($projectHistory)) {
                $this->projectHistories->add($projectHistory);
                $projectHistory->setProject($this);
            }
        }

        return $this;
    }

    /**
     * @param ArrayCollection|ProjectHistory[] $projectHistories
     * @return Project
     */
    public function removeProjectHistories(ArrayCollection $projectHistories): Project
    {
        foreach ($projectHistories as $projectHistory) {
            if ($this->projectHistories->contains($projectHistory)) {
                $this->projectHistories->remove($projectHistory);
            }
        }

        return $this;
    }
}
<?php

namespace App\Entity;

use DateTime;
use DateTimeInterface;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 */
class ProjectHistory
{
    /**
     * @ORM\Id()
     * @ORM\Column(type="guid")
     * @ORM\GeneratedValue(strategy="UUID")
     * @var string
     */
    private $id;

    /**
     * @ORM\Column()
     * @var string
     */
    private $function;

    /**
     * @ORM\Column(type="datetime")
     * @var Datetime
     */
    private $modifyDate;

    /**
     * @ORM\Column(type="guid")
     * @var string
     */
    private $modifyUserId;

    /**
     * @ORM\ManyToOne(targetEntity="Project", inversedBy="projectHistories")
     * @ORM\JoinColumn(name="project_cid", referencedColumnName="cid")
     * @var Project
     */
    private $project;

    public function toArray(): array
    {
        return [
            'id'           => $this->getId(),
            'projectCid'   => $this->getProjectCid(),
            'function'     => $this->getFunction(),
            'modifyDate'   => $this->getModifyDateAsString(),
            'modifyUserId' => $this->getModifyUserId(),
        ];
    }

    public function getModifyDateAsString(): string
    {
        if (null === $this->getModifyDate()) {
            return '';
        }

        return $this->getModifyDate()->format(DateTimeInterface::ATOM);
    }

    public function getProjectCid(): ?string
    {
        if (null !== $this->getProject()) {
            return $this->getProject()->getCid();
        }

        return null;
    }

    public function getId(): ?string
    {
        return $this->id;
    }

    public function setId(string $id): void
    {
        $this->id = $id;
    }

    public function getFunction(): string
    {
        return $this->function;
    }

    public function setFunction($function): void
    {
        $this->function = $function;
    }

    public function getModifyDate(): DateTime
    {
        return $this->modifyDate;
    }

    public function setModifyDate(DateTime $modifyDate): void
    {
        $this->modifyDate = $modifyDate;
    }

    public function getModifyUserId(): string
    {
        return $this->modifyUserId;
    }

    public function setModifyUserId(string $modifyUserId): void
    {
        $this->modifyUserId = $modifyUserId;
    }

    public function getProject(): ?Project
    {
        return $this->project;
    }

    public function setProject(Project $project): void
    {
        $this->project = $project;
    }
}

Любая помощь очень ценится.Дайте мне знать, если вам нужна дополнительная информация.

1 Ответ

0 голосов
/ 18 февраля 2019

Обычно, если вам нужно сделать такие вещи, я имею в виду ссылку не первичным ключом, у вас есть проблемы с дизайном.Первое, о чем я подумал, читая ваш вопрос, это Event Soursing .Есть хорошая реализация ES для PHP - prooph .К сожалению, рефакторинг существующего проекта в ES не является тривиальным, но, возможно, он поможет вам лучше понять концепцию изменений в истории и моментальных снимков.

В соответствии с текущей ситуацией я могу сказать, что целью Project не является создание снимка.Вы можете изменить модель и создать объект ProjectSnapshot с отношением Project, тогда ProjectHistory будет связан с ProjectSnapshot.Также я не рекомендую хранить какие-либо ассоциации (и внешние ключи) в снимках, вместо этого сохраняйте только идентификаторы связанных объектов.Обратите внимание на регистрируемое расширение , возможно, оно будет полезным.

...