Мне нужен совет о том, какие могут быть лучшие практики для сценария, приведенного ниже.
Сценарий
У меня есть некоторые объекты, которые используют то, что я называю "данными как частью схемы":их данные являются частью программного обеспечения и не должны создаваться / редактироваться / удаляться программным обеспечением во время нормальной работы.
Я использую их для предоставления фиксированных списков вариантов для других объектов без использования полей 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