在 Laravel 中强制执行 Morph Maps
发布于 作者 Aaron Francis
Oliver Nybroe 为 Laravel (8.59.0) 贡献了一个 拉取请求,允许开发人员要求设置 morph maps,而不是默认使用完全限定的类名。
通过使用 enforceMorphMap
方法而不是传统的 morphMap
方法,Laravel 将确保所有 morphs 都映射到别名,如果一个 morph 未映射,则会抛出 ClassMorphViolationException
异常。
// If any other models are morphed but not mapped, Laravel// will throw a `ClassMorphViolationException` exception.Relation::enforceMorphMap([ 'user' => User::class,]);
您可以使用上面显示的单个调用强制执行 morph map,也可以在 Relation
类上使用独立的 requireMorphMap
方法。
// Turn morph map enforcement on (new in 8.59.0).Relation::requireMorphMap(); // And then map your morphs in the standard way.Relation::morphMap([ 'user' => User::class,]);
Morph Map 背景
在 Laravel 中创建多态关系时,默认行为始终是在数据库中存储相关模型的类名。从 Laravel 文档
默认情况下,Laravel 将使用完全限定的类名来存储相关模型的“类型”。例如,给定上面的示例,其中 Comment 模型可能属于 Post 或 Video 模型,默认的
commentable_type
将分别为App\Models\Post
或App\Models\Video
。
使用此默认方法意味着您的数据库最终将填充您的模型的类名,这将您的数据库中的数据紧密地耦合到您的类的名称。
Laravel 一直以来都赋予我们通过 注册 MorphMap 来将类名与数据库分离的能力,该 MorphMap 为类提供别名,从而打破这种关联。
// Store `user` in the database, instead of `App\User`Relation::morphMap([ 'user' => User::class,]);
虽然此行为已经存在一段时间了,但始终无法严格要求它。
Morph Maps 的优势
首先拥有 morph map 的好处是将您的应用程序逻辑与存储的数据分离。在数据库中存储类名可能会导致难以调试的错误。
如果您更改了已进行 morph 的其中一个类的名称,则数据库中的所有引用将不再与您的应用程序相符。关于这一点的棘手之处在于,开发或测试中可能没有任何东西会失败!除非您的测试套件以某种方式用先前的类名填充了您的数据库,否则您的所有测试都将是绿色的。只有当您部署到生产环境时,才会出现类和数据不匹配的问题。
上述情况可以通过编写迁移来更新存储的数据来解决,但不能保证您(或下一个用户,或下一个用户)会记得这是必需的。
与其依赖您公司的机构记忆,morph map 打破了这种关联,让您摆脱了这种潜在的错误。
强制执行 Morph Map 的优势
正如 morph map 使您不必记住在重构类时更新存储的数据一样,强制要求 morph map 使您不必记住您需要首先注册一个类。
在 morph map 可强制执行之前,开发人员或团队有责任记住首先映射 morph。
例如,一个开发人员可以像这样设置 morph map
Relation::morphMap([ 'image' => Image::class, 'post' => Post::class,]);
然后另一个开发人员可以开始使用 App\Video
作为 morph 关系,而无需将其添加到映射中!
现在,在数据库中,您将看到以下类型
-
image
- 来自 morph map -
post
- 来自 morph map -
App\Video
- 来自 Laravel 默认实现
因为开发人员不知道设置了 morph map,所以他们没有注册新的 Video
模型。对于足够旧的应用程序或足够大的团队来说,这将是不可避免的。
现在通过强制执行 morph map,除非设置了别名,否则无法在 morph 中使用 App\Video
。将抛出 ClassMorphViolationException
。
// All future morphs *must* be mapped!Relation::enforceMorphMap([ 'image' => Image::class, 'post' => Post::class,]);
此新功能允许您将隐式知识变为显式代码要求。
我们可以使应用程序的要求越明确,随着时间的推移维护它就越容易,招募新开发人员也越容易。