详解Laravel设置多态关系模型别名的方式


Posted in PHP onOctober 17, 2019

作为 Laravel 的重度使用者肯定都对多态关系不默生,以官方文档为例,文章有标签,视频有标签,那么文章和视频这些模型与标签模型的关系就是 多态多对多(Many To Many (Polymorphic))

如果我们给 ID 为 1 的文章打上两个标签,数据库标签关系表的的存储结果就是这样子:

> select * from taggables;
+--------+-------------+---------------+
| tag_id | taggable_id | taggable_type |
+--------+-------------+---------------+
|  1 |   1 | App\Post  |
|  2 |   1 | App\Post  |
+--------+-------------+---------------+

相信有不少人和我一样希望 taggable_type 的值不要直接用模型类名,而是使用表名: posts 。官方文档的建议是:

use Illuminate\Database\Eloquent\Relations\Relation;

Relation::morphMap([
 'posts' => 'App\Post',
 'videos' => 'App\Video',
]);

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;
}

那么,只要我们在模型中覆盖这个方法便可以方便的实现目标了。

实现目标

我们有两个选择去实现它:

  1. 创建一个模型基类覆盖这个方法,所有的模型都来集成它即可;
  2. 创建一个 trait,在需要的模型中引入它。

我当然会选择 trait 方式来实现,不管从定义还是代码耦合度上,使用 trait 来解决这类特性需求都是再适合不过了,如果你对 trait 还不太熟悉,可以阅读我之前的文章: 《我所理解的 PHP Trait》

我们的目标是使用表名来做为关系类别名,那么在模型中如何获取表名呢,直接使用模型的 getTable 即可,那么整个 trait 的实现如下:

app/Traits/UseTableNameAsMorphClass.php
<?php
namespace App\Traits;
trait UseTableNameAsMorphClass
{
 public function getMorphClass()
 {
  return $this->getTable();
 }
}

然后在我们需要用到关系类型的模型中引入它即可:

<?php
namespace App;
use App\Traits\UseTableNameAsMorphClass;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
 use UseTableNameAsMorphClass;

 //...
}

友情提示

当然,如果你习惯给表名加前缀,或者你的表名与模型名不太一致,那么,你只需要修改 trait 中 getMorphClass 的实现即可,我个人的习惯是模型名就是表名的单数,不带前缀。

总结

以上所述是小编给大家介绍的Laravel设置多态关系模型别名的方式,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

PHP 相关文章推荐
php+mysql分页代码详解
Mar 27 PHP
PHP教程之PHP中shell脚本的使用方法分享
Feb 23 PHP
php-cli简介(不会Shell语言一样用Shell)
Jun 03 PHP
php中的四舍五入函数代码(floor函数、ceil函数、round与intval)
Jul 14 PHP
PHP会话处理的10个函数
Aug 11 PHP
php 问卷调查结果统计
Oct 08 PHP
PHP+Mysql+jQuery文件下载次数统计实例讲解
Oct 10 PHP
Yii开启片段缓存的方法
Mar 28 PHP
PHP控制前台弹出对话框的实现方法
Aug 21 PHP
php微信公众平台交互与接口详解
Nov 28 PHP
Zend Framework入门教程之Zend_Db数据库操作详解
Dec 08 PHP
解决laravel上传图片之后,目录有图片,但是访问不到(404)的问题
Oct 14 PHP
Laravel 5.5 异常处理 &amp; 错误日志的解决
Oct 17 #PHP
PHP封装请求类实例分析【基于Yii框架】
Oct 17 #PHP
使用laravel指定日志文件记录任意日志
Oct 17 #PHP
Laravel 修改默认日志文件名称和位置的例子
Oct 17 #PHP
thinkPHP事务操作简单案例分析
Oct 17 #PHP
使用laravel根据用户类型来显示或隐藏字段
Oct 17 #PHP
laravel model模型定义实现开启自动管理时间created_at,updated_at
Oct 17 #PHP
You might like
PHP运行出现Notice : Use of undefined constant 的完美解决方案分享
2012/03/05 PHP
php生成N个不重复的随机数实例
2013/11/12 PHP
php文件上传类完整实例
2016/05/14 PHP
常用PHP封装分页工具类
2017/01/14 PHP
php微信公众号开发之快递查询
2018/10/20 PHP
JavaScript弹簧振子超简洁版 完全符合能量守恒,胡克定理
2009/10/25 Javascript
用js判断页面刷新或关闭的方法(onbeforeunload与onunload事件)
2012/06/22 Javascript
原生js实现shift/ctrl/alt按键的获取
2013/04/08 Javascript
Javascript中设置默认参数值示例
2014/09/11 Javascript
bootstrap改变按钮加载状态
2014/12/01 Javascript
JavaScript中获取Radio被选中的值
2015/11/11 Javascript
Easyui笔记2:实现datagrid多行删除的示例代码
2017/01/14 Javascript
JS仿JQuery选择器功能
2017/03/08 Javascript
vuejs2.0子组件改变父组件的数据实例
2017/05/10 Javascript
使用JavaScript实现alert的实例代码
2017/07/06 Javascript
shiro授权的实现原理
2017/09/21 Javascript
jquery实现联想词搜索框和搜索结果分页的示例
2018/10/10 jQuery
Vue使用lodop实现打印小结
2019/07/06 Javascript
如何在Express4.x中愉快地使用async的方法
2020/11/18 Javascript
python 制作自定义包并安装到系统目录的方法
2018/10/27 Python
Python3爬取英雄联盟英雄皮肤大图实例代码
2018/11/14 Python
Python 窗体(tkinter)按钮 位置实例
2019/06/13 Python
python实现BP神经网络回归预测模型
2019/08/09 Python
python定间隔取点(np.linspace)的实现
2019/11/27 Python
解决Python二维数组赋值问题
2019/11/28 Python
Python实现投影法分割图像示例(一)
2020/01/17 Python
Python中if有多个条件处理方法
2020/02/26 Python
Python3自定义http/https请求拦截mitmproxy脚本实例
2020/05/11 Python
python中not、and和or的优先级与详细用法介绍
2020/11/03 Python
印尼综合在线预订网站:Tiket.com(机票、酒店、火车、租车和娱乐)
2018/10/11 全球购物
英国水族馆和池塘用品购物网站:Warehouse Aquatics
2019/08/29 全球购物
监理员的岗位职责
2013/11/13 职场文书
高中体育教学反思
2014/01/29 职场文书
债务纠纷起诉书
2015/05/20 职场文书
2015年库房管理工作总结
2015/10/14 职场文书
浅谈Redis存储数据类型及存取值方法
2021/05/08 Redis