详解Laravel设置多态关系模型别名的方式
作为 Laravel 的重度使用者肯定都对多态关系不默生,以官方文档为例,文章有标签,视频有标签,那么文章和视频这些模型与标签模型的关系就是 多态多对多(Many To Many (Polymorphic))
如果我们给 ID 为 1 的文章打上两个标签,数据库标签关系表的的存储结果就是这样子:
select * from taggables;
+--------+-------------+---------------+
| tag_id | taggable_id | taggable_type |
+--------+-------------+---------------+
| 1 | 1 | AppPost |
| 2 | 1 | AppPost |
+--------+-------------+---------------+
相信有不少人和我一样希望 taggable_type 的值不要直接用模型类名,而是使用表名: posts 。官方文档的建议是:
use IlluminateDatabaseEloquentRelationsRelation;
Relation::morphMap([
'posts' = 'AppPost',
'videos' = 'AppVideo',
]);
https://laravel.com/docs/6.x/eloquent-relationships#custom-polymorphic-types
我们可以将这个定义写到 AppServiceProvider 中,但是有一个非常严重的问题: 我们在新增或者删除模型的时候,会很容易忘记去更新这个定义 。我已经至少出现这个问题 3 次了,所以我一直在纠结有没有更好的方法,今天突然灵机一动,实现了一个看起来似乎是一个不错的方式,分享给大家。
思路来源
我尝试跟踪了一遍源码,发现模型中有一个方法 getMorphClass ,多态关联的时候,就是用它来取目标对象的类型名称的,默认返回类名:
public function getMorphClass()
{
$morphMap = Relation::morphMap();
if (! empty($morphMap) && in_array(static::class, $morphMap)) {
return array_search(static::class, $morphMap, true);
}
return static::class;
}
那么,只要我们在模型中覆盖这个方法便可以方便的实现目标了。
实现目标
我们有两个选择去实现它:
- 创建一个模型基类覆盖这个方法,所有的模型都来集成它即可;
- 创建一个 trait,在需要的模型中引入它。
我当然会选择 trait 方式来实现,不管从定义还是代码耦合度上,使用 trait 来解决这类特性需求都是再适合不过了,如果你对 trait 还不太熟悉,可以阅读我之前的文章: 《我所理解的 PHP Trait》
我们的目标是使用表名来做为关系类别名,那么在模型中如何获取表名呢,直接使用模型的 getTable 即可,那么整个 trait 的实现如下:
app/Traits/UseTableNameAsMorphClass.php
<?php
namespace AppTraits;
trait UseTableNameAsMorphClass
{
public function getMorphClass()
{
return $this- getTable();
}
}
然后在我们需要用到关系类型的模型中引入它即可:
<?php
namespace App;
use AppTraitsUseTableNameAsMorphClass;
use IlluminateDatabaseEloquentModel;
class Post extends Model
{
use UseTableNameAsMorphClass;
//...
}
友情提示
当然,如果你习惯给表名加前缀,或者你的表名与模型名不太一致,那么,你只需要修改 trait 中 getMorphClass
的实现即可,我个人的习惯是模型名就是表名的单数,不带前缀。
总结
以上所述是小编给大家介绍的Laravel设置多态关系模型别名的方式,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对ZaLou.Cn网站的支持!如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!
- 上传文件的陷阱
- BZOJ4872: [Shoi2017]分手是祝愿
- JSONP挖掘与高级利用
- CTF---隐写术入门第二题 小苹果
- 隐含层权重参数的初始化方式的对比实验
- BZOJ4868: [Shoi2017]期末考试
- namespace用法
- 全站缓存时代
- 洛谷P1962 斐波那契数列(矩阵快速幂)
- 负载均衡https转发会让服务器误判
- 凯撒加密之一个神奇的Python的API
- 10分钟搞懂TensorBoard用法
- 【最新TensorFlow1.4.0教程02】利用Eager Execution 自定义操作和梯度 (可在 GPU 运行)
- 清北集训Day1T3 LYK loves jumping(期望DP)
- php概述
- php教程
- php环境搭建
- PHP书写格式
- php变量
- php常量
- PHP注释
- php数组
- php字符串 string
- PHP整型 integer
- PHP浮点型 float
- php布尔型
- php数据类型之数组
- php数据类型之对象
- php数据类型之null
- php数据类型之间的转换
- php运算符
- php表达式
- PHP循环控制
- PHP流程控制
- php函数
- php全局变量
- PHP魔术变量
- php命名空间
- php 日期
- PHP包含文件
- php文件
- PHP 文件上传
- php Cookies
- php Sessions
- php email
- php安全email
- php错误处理
- PHP异常处理
- php过滤器
- PHP 高级过滤器
- php json
- php 表单
- PHP MySQL 简介
- PHP 连接 MySQL
- php创建数据库
- php 创建表
- php mysq 插入数据
- PHP MySQL 插入多条数据
- PHP MySQL 预处理语句
- php mysql 读取数据
- php mysql where
- PHP MySQL Order By
- PHP MySQL Update
- PHP MySQL Delete
- php ODBC
- wecenter反序列化造成任意SQL语句执行
- SAP Spartacus 读取payment detail数据的API
- SRCMS 多处越权+权限提升管理员漏洞
- SAP Spartacus把指定产品添加到购物车的API
- MyBatis源码解析之基础模块—Plugin
- php框架slim架构上存在XXE漏洞(XXE的典型存在形式)
- 个人博客搭建
- 安全箱子的秘密
- Linux 机器 CPU 毛刺问题排查
- phpwind 利用哈希长度扩展攻击进行getshell
- dotnet 构建 SourceRoot items must include at least one top-level item when DeterministicSourcePaths is
- Magicodes.IE 2.4版本发布
- EC2磁盘扩容-DiskPressure
- 谈一谈php://filter的妙用
- 新型php漏洞挖掘之debug导致的安全漏洞(Edusoho)