【发布时间】:2018-12-04 13:00:35
【问题描述】:
我正在就以下场景的最佳做法寻求建议。
场景
我有一些实体使用我所说的“数据作为架构的一部分”:它们的数据是软件的一部分,在正常操作期间不能由软件创建/编辑/删除。
我使用这些来为其他实体提供固定的选择列表,而不使用枚举字段 - 因为它们实际上是列定义的一部分,如果我需要以任何其他方式更改列而不是附加一个新值生成完整的表副本。
这样的实体定义如下 - readOnly=true 参数、手动分配的 ID、唯一的 slug、唯一的用户可见名称和私有构造函数。这不是夹具的好候选,因为它不是测试数据(谈论 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 Migrations 管理价值观:
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(...)之类的代码中使用
当前解决方案
目前我们已经决定这样做:
我们在实体类中存储 ID 和 slug 的常量。
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短了点
【问题讨论】:
标签: symfony doctrine-orm