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教程 基本语法
Oct 23 PHP
win2003服务器使用WPS的COM组件的一些问题解决方法
Jan 11 PHP
在win7中搭建Linux+PHP 开发环境
Oct 08 PHP
PHP使用feof()函数读文件的方法
Nov 07 PHP
PHP使用递归方式列出当前目录下所有文件的方法
Jun 02 PHP
thinkphp微信开之安全模式消息加密解密不成功的解决办法
Dec 02 PHP
php htmlentities()函数的定义和用法
May 13 PHP
php pdo oracle中文乱码的快速解决方法
May 16 PHP
完美解决php 导出excle的.csv格式的数据时乱码问题
Feb 18 PHP
PHP闭包定义与使用简单示例
Apr 13 PHP
PHP去除空数组且数组键名重置的讲解
Feb 28 PHP
PHP常用字符串函数用法实例总结
Jun 04 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
全国FM电台频率大全 - 17 湖北省
2020/03/11 无线电
php实现网站插件机制的方法
2009/11/10 PHP
php smarty 二级分类代码和模版循环例子
2011/06/01 PHP
php学习笔记之 函数声明(二)
2011/06/09 PHP
通达OA公共代码 php常用检测函数
2011/12/14 PHP
Yii2.0预定义的别名功能小结
2016/07/04 PHP
PHP基于session.upload_progress 实现文件上传进度显示功能详解
2019/08/09 PHP
JavaScript的Module模式编程深入分析
2013/08/13 Javascript
node.js实现逐行读取文件内容的代码
2014/06/27 Javascript
sails框架的学习指南
2014/12/22 Javascript
jquery中用函数来设置css样式
2016/12/22 Javascript
javascript ASCII和Hex互转的实现方法
2016/12/27 Javascript
vue2.0的contextmenu右键弹出菜单的实例代码
2017/07/24 Javascript
AngularJS 应用模块化的使用
2018/04/04 Javascript
Vue隐藏显示、只读实例代码
2018/07/18 Javascript
vue框架制作购物车小球动画效果实例代码
2019/09/26 Javascript
使用Karma做vue组件单元测试的实现
2020/01/16 Javascript
VSCode launch.json配置详细教程
2020/06/18 Javascript
Python的SQLalchemy模块连接与操作MySQL的基础示例
2016/07/11 Python
不管你的Python报什么错,用这个模块就能正常运行
2018/09/14 Python
解决django后台样式丢失,css资源加载失败的问题
2019/06/11 Python
Python和Anaconda和Pycharm安装教程图文详解
2020/02/04 Python
使用python爬取抖音app视频的实例代码
2020/12/01 Python
css3遮罩层镂空效果的多种实现方法
2020/05/11 HTML / CSS
Jacadi Paris美国官方网站:法国童装品牌
2017/10/15 全球购物
一组SQL面试题
2016/02/15 面试题
一些.net面试题
2014/10/06 面试题
实习单位推荐信范文
2013/11/27 职场文书
元旦促销方案
2014/03/15 职场文书
2014组织生活会方案
2014/05/19 职场文书
白酒营销策划方案
2014/08/17 职场文书
2014年英语工作总结
2014/12/20 职场文书
教代会开幕词
2015/01/28 职场文书
法定代表人免职证明
2015/06/24 职场文书
python如何在word中存储本地图片
2021/04/07 Python
python 常用的异步框架汇总整理
2021/06/18 Python