PHP laravel中的多对多关系实例详解


Posted in PHP onJune 07, 2017

数据表之间是纵横交叉、相互关联的,laravel的一对一,一对多比较好理解,官网介绍滴很详细了,在此我就不赘述啦,重点我记下多对多的关系

一种常见的关联关系是多对多,即表A的某条记录通过中间表C与表B的多条记录关联,反之亦然。比如一个用户有多种角色,反之一个角色对应多个用户。

为了测试该关联关系,我们沿用官网的用户角色示例:

需要三张数据表:users、roles 和 role_user,role_user 表按照关联模型名的字母顺序命名(这里role_user是中间表),并且包含 user_id 和 role_id两个列。

多对多关联通过编写返回 belongsToMany 方法返回结果的方法来定义。废话不说多,直接上数据结构:

1:创建一个角色表roles,并添加一些初始化数据:

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`password` varchar(60) COLLATE utf8_unicode_ci NOT NULL,
`remember_token` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
UNIQUE KEY `users_email_unique` (`email`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES ('1', 'admin', 'admin@163.com', '$2y$10$J/yXqscucanrHAGZp9G6..Tu1Md.SOljX3M8WrHsUdrgat4zeSuhC', 'ilocXtjZJwhrmIdLG1cKOYegeCwQCkuyx1pYAOLuzY2PpScQFT5Ss7lBCi7i', '2016-04-21 16:26:23', '2016-12-14 09:29:59');
INSERT INTO `users` VALUES ('2', 'baidu', '10940370@qq.com', '$2y$10$2A5zJ4pnJ5uCp1DN3NX.5uj/Ap7P6O4nP2BaA55aFra8/rti1K6I2', null, '2016-04-22 06:48:10', '2016-04-22 06:48:10');
INSERT INTO `users` VALUES ('3', 'fantasy', '1009@qq.com', '', null, '2017-06-14 10:38:57', '2017-06-15 10:39:01');

2:创建一个角色表roles,并添加一些初始化数据:

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for roles
-- ----------------------------
DROP TABLE IF EXISTS `roles`;
CREATE TABLE `roles` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-- ----------------------------
-- Records of roles
-- ----------------------------
INSERT INTO `roles` VALUES ('1', '超级版主', '2016-04-21 16:26:23', '2016-12-14 09:29:59');
INSERT INTO `roles` VALUES ('2', '司令', '2016-04-22 06:48:10', '2016-04-22 06:48:10');
INSERT INTO `roles` VALUES ('3', '军长', '2017-06-14 10:38:57', '2017-06-15 10:39:01');
INSERT INTO `roles` VALUES ('4', '司长', '2017-06-07 10:41:41', '2017-06-15 10:41:51');
INSERT INTO `roles` VALUES ('5', '团战', '2017-06-22 10:41:44', '2017-06-28 10:41:54');
INSERT INTO `roles` VALUES ('6', '小兵', '2017-06-22 10:41:47', '2017-06-22 10:41:56');

3:创建一个中间表role_user用于记录users表与roles表的对应关系,并添加一些初始化数据:

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for role_user
-- ----------------------------
DROP TABLE IF EXISTS `role_user`;
CREATE TABLE `role_user` (
 `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `user_id` int(11) DEFAULT NULL,
 `role_id` int(11) DEFAULT NULL,
 `created_at` datetime DEFAULT NULL,
 `updated_at` datetime DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=latin1;
-- ----------------------------
-- Records of role_user
-- ----------------------------
INSERT INTO `role_user` VALUES ('1', '1', '2', '2017-06-07 11:42:13', '2017-06-21 11:32:16');
INSERT INTO `role_user` VALUES ('2', '1', '3', '2017-06-07 11:32:13', '2017-06-07 11:22:13');
INSERT INTO `role_user` VALUES ('3', '2', '4', '2017-06-07 11:32:13', '2017-06-07 11:12:13');
INSERT INTO `role_user` VALUES ('4', '1', '5', '2017-06-07 11:32:13', '2017-06-07 11:22:13');
INSERT INTO `role_user` VALUES ('5', '3', '6', '2017-06-07 11:32:13', '2017-06-07 11:52:13');
INSERT INTO `role_user` VALUES ('6', '3', '2', '2017-06-07 11:32:13', '2017-06-07 11:42:13');
INSERT INTO `role_user` VALUES ('7', '2', '2', '2017-06-07 11:42:13', '2017-06-07 11:52:13');

注意我们定义中间表的时候没有在结尾加s并且命名规则是按照字母表顺序,将role放在前面,user放在后面,并且用_分隔,这一切都是为了适应Eloquent模型关联的默认设置:在定义多对多关联的时候如果没有指定中间表,Eloquent默认的中间表使用这种规则拼接出来。

创建一个Role模型:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
/**
 * Class Role
 * @package App\Models
 * @mixin \Eloquent
 */
class Role extends Model
{
}

然后我们在 User 模型上定义 roles 方法:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
/**
 * Class User
 * @package App\Models
 * @mixin \Eloquent
 */
class User extends Model
{
  /**
   * 用户角色
   */
  public function roles()
  {
    return $this->belongsToMany('App\Models\Role');
  }
}

注:正如我们上面提到的,如果中间表不是role_user,那么需要将中间表作为第二个参数传入belongsToMany方法,如果中间表中的字段不是user_id和role_id,这里我们姑且将其命名为$user_id和$role_id,那么需要将$user_id作为第三个参数传入该方法,$role_id作为第四个参数传入该方法,如果关联方法名不是roles还可以将对应的关联方法名作为第五个参数传入该方法。

接下来我们在控制器中编写测试代码:

<?php
$user = User::find(1);
$roles = $user->roles;
echo '用户'.$user->name.'所拥有的角色:';
foreach($roles as $role)
  echo $role->name.' '; //对应输出为:用户admin所拥有的角色:司令 军长 团战

当然,和所有其它关联关系类型一样,你可以调用roles 方法来添加条件约束到关联查询上:

User::find(1)->roles()->orderBy('name')->get();

正如前面所提到的,为了确定关联关系连接表的表名,Eloquent 以字母顺序连接两个关联模型的名字。不过,你可以重写这种约定 —— 通过传递第二个参数到 belongsToMany 方法:

return $this->belongsToMany('App\Models\Role', 'user_roles');

除了自定义连接表的表名,你还可以通过传递额外参数到 belongsToMany 方法来自定义该表中字段的列名。第三个参数是你定义关联关系模型的外键名称,第四个参数你要连接到的模型的外键名称:

return $this->belongsToMany('App\Models\Role', 'user_roles', 'user_id', 'role_id');

定义相对的关联关系

要定义与多对多关联相对的关联关系,只需在关联模型中调用一下 belongsToMany 方法即可。我们在 Role 模型中定义 users 方法:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
/**
 * Class Role
 * @package App\Models
 * @mixin \Eloquent
 */
class Role extends Model
{
  /**
   * 角色用户
   */
  public function users()
  {
    return $this->belongsToMany('App\Models\User');
  }
}

 正如你所看到的,定义的关联关系和与其对应的User 中定义的一模一样,只是前者引用 App\Models\Role,后者引用App\Models\User,由于我们再次使用了 belongsToMany 方法,所有的常用表和键自定义选项在定义与多对多相对的关联关系时都是可用的。

测试代码如下:

$role = Role::find(2);
$users = $role->users;
echo '角色#'.$role->name.'下面的用户:';
foreach ($users as $user) 
echo $user->name.' ';//对应输出为:角色#司令下面的用户:admin fantasy baidu

正如你看到的,处理多对多关联要求一个中间表。Eloquent 提供了一些有用的方法来与这个中间表进行交互,例如,我们假设 User 对象有很多与之关联的 Role 对象,访问这些关联关系之后,我们可以使用这些模型上的pivot 属性访问中间表字段:

$roles = User::find(1)->roles;
foreach ($roles as $role) 
  echo $role->pivot->role_id.'<br>';//对应输出为:2 3 5

注意我们获取到的每一个 Role 模型都被自动赋上了 pivot 属性。该属性包含一个代表中间表的模型,并且可以像其它 Eloquent 模型一样使用。

默认情况下,只有模型主键才能用在 pivot 对象上,如果你的 pivot 表包含额外的属性,必须在定义关联关系时进行指定:

return $this->belongsToMany('App\Models\Role')->withPivot('column1', 'column2');

比如我们修改role_user表增加一个字段 username 数据如下:

PHP laravel中的多对多关系实例详解

修改模型User:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
/**
 * Class User
 * @package App\Models
 * @mixin \Eloquent
 */
class User extends Model
{
  /**
   * 用户角色
   */
  public function roles()
  {
    //return $this->belongsToMany('App\Models\Role');
    return $this->belongsToMany('App\Models\Role')->withPivot('username');
  }
}

 测试代码如下:

$user = User::find(1);
foreach ($user->roles as $role) 
echo $role->pivot->username;//对应输出为:马特马特2马特3

如果你想要你的 pivot 表自动包含created_at 和 updated_at 时间戳,在关联关系定义时使用 withTimestamps 方法:

return $this->belongsToMany('App\Models\Role')->withTimestamps();

通过中间表字段过滤关联关系

你还可以在定义关联关系的时候使用 wherePivot 和 wherePivotIn 方法过滤belongsToMany 返回的结果集:

return $this->belongsToMany('App\Models\Role')->withPivot('username')->wherePivot('username', '马特2');
//return $this->belongsToMany('App\Models\Role')->wherePivotIn('role_id', [1, 2]);

测试代码如下:

$user = User::find(1);
print_r($user->roles->toArray());

以上对应输出:

Array
(
  [0] => Array
    (
      [id] => 3
      [name] => 军长
      [created_at] => 2017-06-14 10:38:57
      [updated_at] => 2017-06-15 10:39:01
      [pivot] => Array
        (
          [user_id] => 1
          [role_id] => 3
          [username] => 马特2
        )
    )
)

如果你想要你的pivot表自动包含created_at和updated_at时间戳,在关联关系定义时使用withTimestamps方法:

return $this->belongsToMany('App\Models\Role')->withTimestamps();

以上所述是小编给大家介绍的PHP laravel中的多对多关系实例详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

PHP 相关文章推荐
利用PHP实现与ASP Banner组件相似的类
Oct 09 PHP
php木马攻击防御之道
Mar 24 PHP
php仿ZOL分页类代码
Oct 02 PHP
php win下Socket方式发邮件类
Aug 21 PHP
深入PHP与浏览器缓存的分析
Jun 03 PHP
PHP CURL获取返回值的方法
May 04 PHP
php通过记录IP来防止表单重复提交方法分析
Dec 16 PHP
Laravel 5 学习笔记
Mar 06 PHP
PHP 中 Orientation 属性判断上传图片是否需要旋转
Oct 16 PHP
php 从一个数组中随机的取出若干个不同的数实例
Dec 31 PHP
php json相关函数用法示例
Mar 28 PHP
PHP实现考试倒计时功能代码
Apr 16 PHP
PHP基于正则批量替换Img中src内容实现获取缩略图的功能示例
Jun 07 #PHP
PHP框架laravel的.env文件配置教程
Jun 07 #PHP
理清PHP在Linxu下执行时的文件权限方法
Jun 07 #PHP
Laravel如何友好的修改.env配置文件详解
Jun 07 #PHP
PHP面向对象之事务脚本模式(详解)
Jun 07 #PHP
PHP框架自动加载类文件原理详解
Jun 06 #PHP
Yii输入正确验证码却验证失败的解决方法
Jun 06 #PHP
You might like
PHP header()函数使用详细(301、404等错误设置)
2013/04/17 PHP
PHP获取youku视频真实flv文件地址的方法
2014/12/23 PHP
自己写的php curl库实现整站克隆功能
2015/02/12 PHP
PHP实现可自定义样式的分页类
2016/03/29 PHP
PHP 将数组打乱 shuffle函数的用法及简单实例
2016/06/17 PHP
PHP中Array相关函数简介
2016/07/03 PHP
PHP hex2bin()函数用法讲解
2019/02/25 PHP
12个非常有创意的JavaScript小游戏
2010/03/18 Javascript
JavaScript中数组的排序、乱序和搜索实现代码
2011/11/30 Javascript
Prototype源码浅析 String部分(一)之有关indexOf优化
2012/01/15 Javascript
通过AJAX的JS、JQuery两种方式解析XML示例介绍
2013/09/23 Javascript
js设置文本框中焦点位置在最后的示例代码(简单实用)
2014/03/04 Javascript
深入解析JavaScript中的立即执行函数
2016/05/21 Javascript
浅谈mint-ui loadmore组件注意的问题
2017/11/08 Javascript
Node.js爬取豆瓣数据实例分析
2018/03/05 Javascript
JS点击动态添加标签、删除指定标签的代码
2018/04/18 Javascript
JavaScript工具库之Lodash详解
2019/06/15 Javascript
关于angular引入ng-zorro的问题浅析
2020/09/09 Javascript
JS数据类型分类及常用判断方法
2020/11/19 Javascript
使用Python下载歌词并嵌入歌曲文件中的实现代码
2015/11/13 Python
在python3环境下的Django中使用MySQL数据库的实例
2017/08/29 Python
对变量赋值的理解--Pyton中让两个值互换的实现方法
2017/11/29 Python
对python捕获ctrl+c手工中断程序的两种方法详解
2018/12/26 Python
python调用matplotlib模块绘制柱状图
2019/10/18 Python
python TCP包注入方式
2020/05/05 Python
Python判断远程服务器上Excel文件是否被人打开的方法
2020/07/13 Python
python 爬取英雄联盟皮肤并下载的示例
2020/12/04 Python
HTML5 canvas绘制的玫瑰花效果
2014/05/29 HTML / CSS
美国班级戒指、帽子和礼服、毕业产品、年鉴:Balfour
2018/11/01 全球购物
印尼值得信赖的在线交易网站:Bukalapak
2019/03/11 全球购物
怎样有效的进行自我评价
2013/10/06 职场文书
法人授权委托书
2014/04/03 职场文书
库房保管员岗位职责
2014/04/07 职场文书
习近平在党的群众路线教育实践活动总结大会上的讲话全文
2014/10/25 职场文书
学生不参加考试检讨书
2015/02/19 职场文书
名人传读书笔记
2015/06/26 职场文书