symfony - 使用迁移管理数据的 Symfony Doctrine 只读实体
问题描述
我正在寻找有关以下场景的最佳实践的建议。
设想
我有一些实体使用我所说的“数据作为架构的一部分”:它们的数据是软件的一部分,在正常操作期间不会由软件创建/编辑/删除。
我正在使用这些为其他实体提供固定的选择列表,而不使用枚举字段 - 因为它们实际上是列定义的一部分,如果我需要以任何其他方式更改列而不是附加一个新值,它会导致全表副本。
这样的实体是这样定义的——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
解决方案
有一个属性注释可以帮助您的 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...
我认为这是实际回答您的问题的最干净的方法。
但话虽如此,我最终停止做这种事情,而不是制作实际的状态实体,我只使用 slug。最初我担心能够改变价值观,但实际上我几乎不需要这样做。我使用视图转换器将蛞蝓转换为您所称的名称。而且根本没有身份证。
推荐阅读
- firebase - Firestore 查询两个集合
- rest - 在 Put Body 中发送模型 id 而不是在 url 中
- reactjs - 如何使用 redux 获得以前的状态?
- gnuplot - 如何在 gnuplot 中使用 `set term push` 和 `set term pop`
- google-apps-script - 列出云端硬盘的内容(不超过配额)
- amazon-dynamodb - Botocore 引发 OSError: [errno 14] 错误地址
- reactjs - React-admin 在创建视图提交后保留表单数据
- python - 我正在尝试通过使用分隔符拆分列值来获取第 n 个空间值
- sql - Oracle查询以获取数据类型的最小值或最大值
- android - 如何在 AOSP 构建中隐藏已安装的应用程序?