Symfony Doctrine Readonly Entity с данными, управляемыми с помощью миграций - PullRequest
0 голосов
/ 04 декабря 2018

Мне нужен совет о том, какие могут быть лучшие практики для сценария, приведенного ниже.

Сценарий

У меня есть некоторые объекты, которые используют то, что я называю "данными как частью схемы":их данные являются частью программного обеспечения и не должны создаваться / редактироваться / удаляться программным обеспечением во время нормальной работы.

Я использую их для предоставления фиксированных списков вариантов для других объектов без использования полей enum - потому чтоони действительно являются частью определения столбца, и если мне нужно изменить столбец любым другим способом, кроме добавления нового значения, это приводит к полной копии таблицы.

Такая сущность определяется следующим образом - readOnly =истинный параметр, назначенный вручную идентификатор, уникальный слаг, уникальное видимое пользователю имя и приватный конструктор.Это не является хорошим кандидатом для осветителей, потому что это не тестовые данные (разговор о том, как Doctrine Fixtures хочет удалить мои «данные как схему», относится к другому вопросу SO)

/**
 * @ORM\Entity(readOnly=true)
 */
class SubmissionStatus
{
    /**
     * @var int
     * @ORM\Column(type="integer")
     * @ORM\Id()
     */
    protected $id;

    /**
     * @var string
     * @ORM\Column(type="string", length=191, unique=true)
     */
    protected $slug;

    /**
     * @var string
     * @ORM\Column(type="string", length=191, unique=true)
     */
    protected $name;

    private __construct() {}

    // ... other fields
}

Я управляю значениями с помощью DoctrineМиграции:

final class Version20181023132831 extends AbstractMigration
{
    public function up(Schema $schema) : void
    {
        $statuses = [
            ["id" => 1, "name" => "Pending", "slug" => "pending"],
            ["id" => 2, "name" => "Reported", "slug" => "reported"],
            ["id" => 3, "name" => "Rejected", "slug" => "rejected"],
            ["id" => 4, "name" => "Accepted", "slug" => "accepted"],
        ];

        foreach ($statuses as $status) {
            $this->addSql("INSERT INTO submission_status (id, name, slug) VALUES (:id, :name, :slug WHERE id = :id", [
                "id" => $status['id'],
                "name" => $status['name'],
                "slug" => $status['slug'],
            ]);
        }
    }
}

Я делаю UPDATE и DELETE в будущих миграциях, если мне нужно обновить эти значения - также массируя существующие внешние ключи, ссылаясь на эти строки, если необходимо.

Другоесущности имеют @ORM\ManyToOne отношения к этой сущности.

Проблема

Каков наилучший способ ссылаться на них в коде?

Не все эти сущности будут выбраныпользователями в ChoiceType полях в формах или через вызовы API.Некоторые из них будут использоваться только в коде, подобном $otherEntity->setStatus(...)

Текущее решение

В настоящее время мы решили сделать это:

Мы храним константы в сущностикласс для идентификаторов и слагов.

class SubmissionStatus
{
    const PENDING_ID = 1;
    const PENDING_SLUG = 'pending';
    const REPORTED_ID = 2;
    const REPORTED_SLUG = 'reported';
    const REJECTED_ID = 3;
    const REJECTED_SLUG = 'rejected';
    const ACCEPTED_ID = 4;
    const ACCEPTED_SLUG = 'accepted';
}

Когда нам нужно setStatus, мы делаем поиск в базе данных:

$status = $em->getRepository(SubmissionStatus::class)->findOneBy(['slug' => SubmissionStatus::ACCEPTED_SLUG])
$otherEntity->setStatus($status);

Вопрос

Есть ли лучший способчтобы сделать это?

Я не большой поклонник написания всего этого getRepository->findOneBy стандартного шаблона все время, особенно если мне нужно сослаться на несколько таких сущностей.Я хотел бы написать что-то короткое, легкое и быстрое, если делать это несколько раз.

Я бы также предпочел не менять слишком много мест, когда я вносил изменения в значения.Одного в миграции и одного в константах класса вполне достаточно.

То, что я до сих пор думал

Я не могу добавить вспомогательную функцию к самой сущности (например, setStatusAccepted() или setStatus(SubmissionStatus::ACCEPTED_SLUG)), потому что я не могу отыскать оттуда упомянутую сущность.

Внедренная служба, которая выполняет поиск при создании и хранит ссылки.Его использование будет, например, $entity->setStatus($statusRef->accepted), $entity->setStatus($statusRef->get(SubmissionStatus::ACCEPTED_SLUG)).Первый вариант нарушает завершение кода IDE.Второй слишком длинный, хотя и короче $em->getRepository->find

1 Ответ

0 голосов
/ 04 декабря 2018

Существует аннотация свойства, которая поможет сохранить IDE счастливым.

/**
 * One entry for each status 
 * @property-read SubmissionStatus $accepted 
 */
class SubmissionStatusReference
{
    public function __get($slug) {
        switch($slug) {
            // blah blah blah
            case 'accepted': 
                return $this->entityManager->getReference(etc...

Я думаю, что это самый чистый способ ответить на ваш вопрос.

Но сказав это, яв конечном счете, прекратил делать подобные вещи, и вместо создания сущностей с текущим статусом я просто использую слаг.Первоначально я был обеспокоен тем, что могу изменить ценности, а что нет, но с практической точки зрения мне вряд ли когда-нибудь понадобится это сделать.Я использую преобразователи представления, чтобы преобразовать слагов в то, что вы называете именами.И вообще без идентификатора.

...