有个表,是角色表。有角色id,淘宝购买帐号id是什么,淘宝购买帐号id是什么和角色是一对多的关系,我现在想查一下这个表里超过两个角色的

[ Laravel 5.1 文档 ] Eloquent ORM —— 关联关系
数据表经常要与其它表做关联,比如一篇博客文章可能有很多评论,或者一个订单会被关联到下单用户,Eloquent使得组织和处理这些关联关系变得简单,并且支持多种不同类型的关联关系:
2、定义关联关系
Eloquent关联关系以Eloquent模型类方法的形式被定义。和Eloquent模型本身一样,关联关系也是强大的,定义关联关系为函数能够提供功能强大的方法链和查询能力。例如:
$user-&posts()-&where('active', 1)-&get();
但是,在深入使用关联关系之前,让我们先学习如何定义每种关联类型:
2.1 一对一
一对一关联是一个非常简单的关联关系,例如,一个User模型有一个与之对应的Phone模型。要定义这种模型,我们需要将phone方法置于User模型中,phone方法应该返回Eloquent模型基类上hasOne方法的结果:
namespace A
use Illuminate\Database\Eloquent\M
class User extends Model{
* 获取关联到用户的手机
public function phone()
return $this-&hasOne('App\Phone');
传递给hasOne方法的第一个参数是关联模型的名称,关联关系被定义后,我们可以使用Eloquent的动态属性获取关联记录。动态属性允许我们访问关联函数就像它们是定义在模型上的属性一样:
$phone = User::find(1)-&
Eloquent默认关联关系的外键基于模型名称,在本例中,Phone模型默认有一个user_id外键,如果你希望重写这种约定,可以传递第二个参数到hasOne方法:
return $this-&hasOne('App\Phone', 'foreign_key');
此外,Eloquent假设外键应该在父级上有一个与之匹配的id,换句话说,Eloquent将会通过user表的id值去phone表中查询user_id与之匹配的Phone记录。如果你想要关联关系使用其他值而不是id,可以传递第三个参数到hasOne来指定自定义的主键:
return $this-&hasOne('App\Phone', 'foreign_key', 'local_key');
2.1.1 定义相对的关联
我们可以从User中访问Phone模型,相应的,我们也可以在Phone模型中定义关联关系从而让我们可以拥有该phone的User。我们可以使用belongsTo方法定义与hasOne关联关系相对的关联:
namespace A
use Illuminate\Database\Eloquent\M
class Phone extends Model{
* 获取手机对应的用户
public function user()
return $this-&belongsTo('App\User');
在上面的例子中,Eloquent将会尝试通过Phone模型的user_id去User模型查找与之匹配的记录。Eloquent通过关联关系方法名并在方法名后加_id后缀来生成默认的外键名。然而,如果Phone模型上的外键不是user_id,也可以将自定义的键名作为第二个参数传递到belongsTo方法:
* 获取手机对应的用户
public function user(){
return $this-&belongsTo('App\User', 'foreign_key');
如果父模型不使用id作为主键,或者你希望使用别的列来连接子模型,可以将父表自定义键作为第三个参数传递给belongsTo方法:
* 获取手机对应的用户
public function user(){
return $this-&belongsTo('App\User', 'foreign_key', 'other_key');
2.2 一对多
“一对多”是用于定义单个模型拥有多个其它模型的关联关系。例如,一篇博客文章拥有无数评论,和其他关联关系一样,一对多关联通过在Eloquent模型中定义方法来定义:
namespace A
use Illuminate\Database\Eloquent\M
class Post extends Model{
* 获取博客文章的评论
public function comments()
return $this-&hasMany('App\Comment');
记住,Eloquent会自动判断Comment模型的外键,为方便起见,Eloquent将拥有者模型名称加上id后缀作为外键。因此,在本例中,Eloquent假设Comment模型上的外键是post_id。
关联关系被定义后,我们就可以通过访问comments属性来访问评论集合。记住,由于Eloquent提供“动态属性”,我们可以像访问模型的属性一样访问关联方法:
$comments = App\Post::find(1)-&
foreach ($comments as $comment) {
当然,由于所有关联同时也是查询构建器,我们可以添加更多的条件约束到通过调用comments方法获取到的评论上:
$comments = App\Post::find(1)-&comments()-&where('title', 'foo')-&first();
和hasOne方法一样,你还可以通过传递额外参数到hasMany方法来重新设置外键和本地主键:
return $this-&hasMany('App\Comment', 'foreign_key');
return $this-&hasMany('App\Comment', 'foreign_key', 'local_key');
2.2.1 定义相对的关联
现在我们可以访问文章的所有评论了,接下来让我们定义一个关联关系允许通过评论访问所属文章。要定义与hasMany相对的关联关系,需要在子模型中定义一个关联方法去调用belongsTo方法:
namespace A
use Illuminate\Database\Eloquent\M
class Comment extends Model{
* 获取评论对应的博客文章
public function post()
return $this-&belongsTo('App\Post');
关联关系定义好之后,我们可以通过访问动态属性post来获取一条Comment对应的Post:
$comment = App\Comment::find(1);
echo $comment-&post-&
在上面这个例子中,Eloquent尝试匹配Comment模型的post_id与Post模型的id,Eloquent通过关联方法名加上_id后缀生成默认外键,当然,你也可以通过传递自定义外键名作为第二个参数传递到belongsTo方法,如果你的外键不是post_id,或者你想自定义的话:
* 获取评论对应的博客文章
public function post(){
return $this-&belongsTo('App\Post', 'foreign_key');
如果你的父模型不使用id作为主键,或者你希望通过其他列来连接子模型,可以将自定义键名作为第三个参数传递给belongsTo方法:
* 获取评论对应的博客文章
public function post(){
return $this-&belongsTo('App\Post', 'foreign_key', 'other_key');
2.3 多对多
多对多关系比hasOne和hasMany关联关系要稍微复杂一些。这种关联关系的一个例子就是一个用户有多个角色,同时一个角色被多个用户共用。例如,很多用户可能都有一个“Admin”角色。要定义这样的关联关系,需要三个数据表:users、roles和role_user,role_user表按照关联模型名的字母顺序命名,并且包含user_id和role_id两个列。
多对多关联通过编写一个调用Eloquent基类上的belongsToMany方法的函数来定义:
namespace A
use Illuminate\Database\Eloquent\M
class User extends Model{
* 用户角色
public function roles()
return $this-&belongsToMany('App\Role');
关联关系被定义之后,可以使用动态属性roles来访问用户的角色:
$user = App\User::find(1);
foreach ($user-&roles as $role) {
当然,和所有其它关联关系类型一样,你可以调用roles方法来添加条件约束到关联查询上:
$roles = App\User::find(1)-&roles()-&orderBy('name')-&get();
正如前面所提到的,为了决定关联关系连接表的表名,Eloquent以字母顺序连接两个关联模型的名字。然而,你可以重写这种约定——通过传递第二个参数到belongsToMany方法:
return $this-&belongsToMany('App\Role', 'user_roles');
除了自定义连接表的表名,你还可以通过传递额外参数到belongsToMany方法来自定义该表中字段的列名。第三个参数是你定义的关系模型的外键名称,第四个参数你要连接到的模型的外键名称:
return $this-&belongsToMany('App\Role', 'user_roles', 'user_id', 'role_id');
2.3.1 定义相对的关联关系
要定义与多对多关联相对的关联关系,只需在关联模型中在调用一下belongsToMany方法即可。让我们在Role模型中定义users方法:
namespace A
use Illuminate\Database\Eloquent\M
class Role extends Model{
* 角色用户
public function users()
return $this-&belongsToMany('App\User');
正如你所看到的,定义的关联关系和与其对应的User中定义的一模一样,只是前者引用App\Role,后者引用App\User,由于我们再次使用了belongsToMany方法,所有的常用表和键自定义选项在定义与多对多相对的关联关系时都是可用的。
2.3.2 获取中间表的列
正如你已经学习到的,处理多对多关联要求一个中间表。Eloquent提供了一些有用的方法来与其进行交互,例如,我们假设User对象有很多与之关联的Role对象,访问这些关联关系之后,我们可以使用模型上的pivot属性访问中间表:
$user = App\User::find(1);
foreach ($user-&roles as $role) {
echo $role-&pivot-&created_
注意我们获取到的每一个Role模型都被自动赋上了pivot属性。该属性包含一个代表中间表的模型,并且可以像其它Eloquent模型一样使用。
默认情况下,只有模型键才能用在pivot对象上,如果你的pivot表包含额外的属性,必须在定义关联关系时进行指定:
return $this-&belongsToMany('App\Role')-&withPivot('column1', 'column2');
如果你想要你的pivot表自动包含created_at和updated_at时间戳,在关联关系定义时使用withTimestamps方法:
return $this-&belongsToMany('App\Role')-&withTimestamps();
2.4 远层的一对多
“远层一对多”关联为通过中间关联访问远层的关联关系提供了一个便利之道。例如,Country模型通过中间的User模型可能拥有多个Post模型。在这个例子中,你可以轻易的聚合给定国家的所有文章,让我们看看定义这个关联关系需要哪些表:
id - integer
name - string
id - integer
country_id - integer
name - string
id - integer
user_id - integer
title - string
尽管posts表不包含country_id列,hasManyThrough关联提供了通过$country-&posts来访问一个国家的所有文章。要执行该查询,Eloquent在中间表$users上检查country_id,查找到相匹配的用户ID后,通过用户ID来查询posts表。
既然我们已经查看了该关联关系的数据表结构,接下来让我们在Country模型上进行定义:
namespace A
use Illuminate\Database\Eloquent\M
class Country extends Model{
* 获取指定国家的所有文章
public function posts()
return $this-&hasManyThrough('App\Post', 'App\User');
第一个传递到hasManyThrough方法的参数是最终我们希望访问的模型的名称,第二个参数是中间模型名称。
当执行这种关联查询时通常Eloquent外键规则会被使用,如果你想要自定义该关联关系的外键,可以将它们作为第三个、第四个参数传递给hasManyThrough方法。第三个参数是中间模型的外键名,第四个参数是最终模型的外键名。
class Country extends Model{
public function posts()
return $this-&hasManyThrough('App\Post', 'App\User', 'country_id', 'user_id');
2.5 多态关联
2.5.1 表结构
多态关联允许一个模型在单个关联下属于多个不同模型。例如,假如你想要为产品和职工存储照片,使用多态关联,你可以在这两种场景下使用单个photos表,首先,让我们看看构建这种关联关系需要的表结构:
id - integer
name - string
id - integer
price - integer
id - integer
path - string
imageable_id - integer
imageable_type - string
两个重要的列需要注意的是photos表上的imageable_id和imageable_type。imageable_id列包含staff或product的ID值,而imageable_type列包含所属模型的类名。当访问imageable关联时,ORM根据imageable_type列来判断所属模型的类型并返回相应模型实例。
接下来,让我们看看构建这种关联关系需要在模型中定义什么:
namespace A
use Illuminate\Database\Eloquent\M
class Photo extends Model{
* 获取所有拥有的imageable模型
public function imageable()
return $this-&morphTo();
class Staff extends Model{
* 获取所有职员照片
public function photos()
return $this-&morphMany('App\Photo', 'imageable');
class Product extends Model{
* 获取所有产品照片
public function photos()
return $this-&morphMany('App\Photo', 'imageable');
2.5.3 获取多态关联
数据表和模型定义好以后,可以通过模型访问关联关系。例如,要访问一个职员的所有照片,可以通过使用photos的动态属性:
$staff = App\Staff::find(1);
foreach ($staff-&photos as $photo) {
你还可以通过访问调用morphTo方法名来从多态模型中获取多态关联的所属对象。在本例中,就是Photo模型中的imageable方法。因此,我们可以用动态属性的方式访问该方法:
$photo = App\Photo::find(1);
$imageable = $photo-&
Photo模型上的imageable关联返回Staff或Product实例,这取决于那个类型的模型拥有该照片。
2.6 多对多多态关联
2.6.1 表结构
除了传统的多态关联,还可以定义“多对多”的多态关联,例如,一个博客的Post和Video模型可能共享一个Tag模型的多态关联。使用对多对的多态关联允许你在博客文章和视频之间有唯一的标签列表。首先,让我们看看表结构:
id - integer
name - string
id - integer
name - string
id - integer
name - string
tag_id - integer
taggable_id - integer
taggable_type - string
2.6.2 模型结构
接下来,我们准备在模型中定义该关联关系。Post和Video模型都有一个tags方法调用Eloquent基类的morphToMany方法:
namespace A
use Illuminate\Database\Eloquent\M
class Post extends Model{
* 获取指定文章所有标签
public function tags()
return $this-&morphToMany('App\Tag', 'taggable');
2.6.3 定义相对的关联关系
接下来,在Tag模型中,应该为每一个关联模型定义一个方法,例如,我们定义一个posts方法和videos方法:
namespace A
use Illuminate\Database\Eloquent\M
class Tag extends Model{
* 获取所有分配该标签的文章
public function posts()
return $this-&morphedByMany('App\Post', 'taggable');
* 获取分配该标签的所有视频
public function videos()
return $this-&morphedByMany('App\Video', 'taggable');
2.6.4 获取关联关系
定义好数据库和模型后可以通过模型访问关联关系。例如,要访问一篇文章的所有标签,可以使用动态属性tags:
$post = App\Post::find(1);
foreach ($post-&tags as $tag) {
还可以通过访问调用morphedByMany的方法名从多态模型中获取多态关联的所属对象。在本例中,就是Tag模型中的posts或者videos方法:
$tag = App\Tag::find(1);
foreach ($tag-&videos as $video) {
3、关联查询
由于Eloquent所有关联关系都是通过函数定义,你可以调用这些方法来获取关联关系的实例而不需要再去手动执行关联查询。此外,所有Eloquent关联关系类型同时也是查询构建器,允许你在最终在数据库执行SQL之前继续添加条件约束到关联查询上。
例如,假定在一个博客系统中一个User模型有很多相关的Post模型:
namespace A
use Illuminate\Database\Eloquent\M
class User extends Model{
* 获取指定用户的所有文章
public function posts()
return $this-&hasMany('App\Post');
你可以像这样查询posts关联并添加额外的条件约束到该关联关系上:
$user = App\User::find(1);
$user-&posts()-&where('active', 1)-&get();
你可以在关联关系上使用任何!
关联关系方法 VS 动态属性
如果你不需要添加额外的条件约束到Eloquent关联查询,你可以简单通过动态属性来访问关联对象,例如,还是拿User和Post模型作为例子,你可以像这样访问所有用户的文章:
$user = App\User::find(1);
foreach ($user-&posts as $post) {
动态属性就是”懒惰式加载“,意味着当你真正访问它们的时候才会加载关联数据。正因为如此,开发者经常使用渴求式加载来预加载他们知道在加载模型时要被访问的关联关系。渴求式加载有效减少了必须要被执以加载模型关联的SQL查询。
查询已存在的关联关系
访问一个模型的记录的时候,你可能希望基于关联关系是否存在来限制查询结果的数目。例如,假设你想要获取所有至少有一个评论的博客文章,要实现这个,可以传递关联关系的名称到has方法:
// 获取所有至少有一条评论的文章...
$posts = App\Post::has('comments')-&get();
你还可以指定操作符和大小来自定义查询:
// 获取所有至少有三条评论的文章...
$posts = Post::has('comments', '&=', 3)-&get();
还可以使用”.“来构造嵌套has语句,例如,你要获取所有至少有一条评论及投票的所有文章:
// 获取所有至少有一条评论获得投票的文章...
$posts = Post::has('comments.votes')-&get();
如果你需要更强大的功能,可以使用whereHas和orWhereHas方法将where条件放到has查询上,这些方法允许你添加自定义条件约束到关联关系条件约束,例如检查一条评论的内容:
// 获取所有至少有一条评论包含foo字样的文章
$posts = Post::whereHas('comments', function ($query) {
$query-&where('content', 'like', 'foo%');
})-&get();
3.1 渴求式加载
当以属性方式访问数据库关联关系的时候,关联关系数据时”懒惰式加载“的,这意味着关联关系数据直到第一次访问的时候才被加载。然而,Eloquent可以在查询父级模型的同时”渴求式加载“关联关系。渴求式加载缓解了N+1查询问题,要阐明N+1查询问题,考虑下关联到Author的Book模型:
namespace A
use Illuminate\Database\Eloquent\M
class Book extends Model{
* 获取写这本书的作者
public function author()
return $this-&belongsTo('App\Author');
现在,让我们获取所有书及其作者:
$books = App\Book::all();
foreach ($books as $book) {
echo $book-&author-&
该循环先执行1次查询获取表中的所有书,然后另一个查询获取每一本书的作者,因此,如果有25本书,要执行26次查询:1次是获取书本身,剩下的25次查询是为每一本书获取其作者。
谢天谢地,我们可以使用渴求式加载来减少该操作到2次查询。当查询的时候,可以使用with方法指定应该被渴求式加载的关联关系:
$books = App\Book::with('author')-&get();
foreach ($books as $book) {
echo $book-&author-&
在该操作中,只执行两次查询即可:
select * from books
select * from authors where id in (1, 2, 3, 4, 5, ...)
3.1.1 渴求式加载多个关联关系
有时候你需要在单个操作中渴求式加载几个不同的关联关系。要实现这个,只需要添加额外的参数到with方法即可:
$books = App\Book::with('author', 'publisher')-&get();
3.1.2 嵌套的渴求式加载
要渴求式加载嵌套的关联关系,可以使用”.“语法。例如,让我们在一个Eloquent语句中渴求式加载所有书的作者及所有作者的个人联系方式:
$books = App\Book::with('author.contacts')-&get();
3.2 带条件约束的渴求式加载
有时候我们希望渴求式加载一个关联关系,但还想为渴求式加载指定更多的查询条件:
$users = App\User::with(['posts' =& function ($query) {
$query-&where('title', 'like', '%first%');
}])-&get();
在这个例子中,Eloquent只渴求式加载title包含first的文章。当然,你可以调用其它查询构建器来自定义渴求式加载操作:
$users = App\User::with(['posts' =& function ($query) {
$query-&orderBy('created_at', 'desc');
}])-&get();
3.3 懒惰渴求式加载
有时候你需要在父模型已经被获取后渴求式加载一个关联关系。例如,这在你需要动态决定是否加载关联模型时可能很有用:
$books = App\Book::all();
if ($someCondition) {
$books-&load('author', 'publisher');
如果你需要设置更多的查询条件到渴求式加载查询上,可以传递一个闭包到load方法:
$books-&load(['author' =& function ($query) {
$query-&orderBy('published_date', 'asc');
4、插入关联模型
4.1 基本使用
4.1.1 save方法
Eloquent提供了便利的方法来添加新模型到关联关系。例如,也许你需要插入新的Comment到Post模型,你可以从关联关系的save方法直接插入Comment而不是手动设置Comment的post_id属性:
$comment = new App\Comment(['message' =& 'A new comment.']);
$post = App\Post::find(1);
$comment = $post-&comments()-&save($comment);
注意我们没有用动态属性方式访问comments,而是调用comments方法获取关联关系实例。save方法会自动添加post_id值到新的Comment模型。
如果你需要保存多个关联模型,可以使用saveMany方法:
$post = App\Post::find(1);
$post-&comments()-&saveMany([
new App\Comment(['message' =& 'A new comment.']),
new App\Comment(['message' =& 'Another comment.']),
4.1.2 save & 多对多关联
当处理多对多关联的时候,save方法以数组形式接收额外的中间表属性作为第二个参数:
App\User::find(1)-&roles()-&save($role, ['expires' =& $expires]);
4.1.3 create方法
除了save和saveMany方法外,还可以使用create方法,该方法接收属性数组、创建模型、然后插入数据库。save和create的不同之处在于save接收整个Eloquent模型实例而create接收原生PHP数组:
$post = App\Post::find(1);
$comment = $post-&comments()-&create([
'message' =& 'A new comment.',
使用create方法之前确保先浏览属性文档。
4.1.4 更新”属于“关联
更新belongsTo关联的时候,可以使用associate方法,该方法会在子模型设置外键:
$account = App\Account::find(10);
$user-&account()-&associate($account);
$user-&save();
移除belongsTo关联的时候,可以使用dissociate方法。该方法在子模型上取消外键和关联:
$user-&account()-&dissociate();
$user-&save();
4.2 多对多关联
4.2.1 附加/分离
处理多对多关联的时候,Eloquent提供了一些额外的帮助函数来使得处理关联模型变得更加方便。例如,让我们假定一个用户可能有多个角色同时一个角色属于多个用户,要通过在连接模型的中间表中插入记录附加角色到用户上,可以使用attach方法:
$user = App\User::find(1);
$user-&roles()-&attach($roleId);
附加关联关系到模型,还可以以数组形式传递额外被插入数据到中间表:
$user-&roles()-&attach($roleId, ['expires' =& $expires]);
当然,有时候有必要从用户中移除角色,要移除一个多对多关联记录,使用detach方法。detach方法将会从中间表中移除相应的记录;然而,两个模型在数据库中都保持不变:
// 从指定用户中移除角色...
$user-&roles()-&detach($roleId);
// 从指定用户移除所有角色...
$user-&roles()-&detach();
为了方便,attach和detach还接收数组形式的ID作为输入:
$user = App\User::find(1);
$user-&roles()-&detach([1, 2, 3]);
$user-&roles()-&attach([1 =& ['expires' =& $expires], 2, 3]);
4.2.2 同步
你还可以使用sync方法构建多对多关联。sync方法接收数组形式的ID并将其放置到中间表。任何不在该数组中的ID对应记录将会从中间表中移除。因此,该操作完成后,只有在数组中的ID对应记录还存在于中间表:
$user-&roles()-&sync([1, 2, 3]);
你还可以和ID一起传递额外的中间表值:
$user-&roles()-&sync([1 =& ['expires' =& true], 2, 3]);
4.3 触发父级时间戳
当一个模型属于另外一个时,例如Comment属于Post,子模型更新时父模型的时间戳也被更新将很有用,例如,当Comment模型被更新时,你可能想要”触发“创建其所属模型Post的updated_at时间戳。Eloquent使得这项操作变得简单,只需要添加包含关联关系名称的touches属性到子模型中即可:
namespace A
use Illuminate\Database\Eloquent\M
class Comment extends Model{
* 要触发的所有关联关系
* @var array
protected $touches = ['post'];
* 评论所属文章
public function post()
return $this-&belongsTo('App\Post');
现在,当你更新Comment时,所属模型Post将也会更新其updated_at值:
$comment = App\Comment::find(1);
$comment-&text = 'Edit to this comment!';
$comment-&save();
扩展阅读1:
扩展阅读2:
声明: 原创文章,未经允许,禁止转载!
这篇文章对我很有帮助
这篇文章对我很有帮助
学院君 has written
Laravel学院院长,终身学习者
积分:95752
职业:码农
城市:杭州
支持 Markdown 语法,提交之前可通过预览查看效果问一个基础问题? 多对多表是否需要自增id? - ITeye问答
例如
有用户表: user&& 字段 id,name,xxx
有角色表: role&& 字段 id,name,xxx
用户角色表 :userrole&& 字段 :& userid,roleid
1方案. roleid加userid 作为主键,无其他字段
2方案. userrole增加id字段,id做主键, roleid加userid 做UNIQUE索引
大家在实际项目中是如何选择的?
采纳的答案
事实证明 加一个非业务主键 绝对是正确的。我做过的项目基本都属于类似情况。
第一种方案足以
这种情况,我会选择方案1.
这个根本就不需要主键的,要它有何用呢?你在实际中不可能给同一个人同一个role给多次的
利用Hibernate生成的表结构就是只有它们两个的id作为外键的
引用roleid加userid 作为主键,无其他字段
一般都采用非业务键做主键,如果使用ORM的工具,建议不要使用联合主键。
一个表的ID是否需要自增,与它是不是和别的表存在多对多关系应该是没有必然联系的,它只是一个主键的生成策略而已。
已解决问题
未解决问题现在位置:
上文http://www.jxtobo.com/kf/972.html给大家讲解了使用循环输出九九乘法表,逻辑上还是相对简单一些,重在给大家提供一种看程序,解析代码的方法和思路,有什么意见或者建议可以跟帖批斗....
好了,不多说了,本文来给大家介绍一下&基于角色的访问控制 &,
说到权限,大家就很头疼,怎么样能灵活把控好一个用户的权限,
有些同学会在用户表中加字段或者是在角色表中加相应的权限字段,
这样会有一个问题,做起权限来会感觉特别的蹩脚,而且很不灵活,每增加一种权限就要在数据库中增加一个字段,很不利于项目的迭代开发
那么我们就需要一种非常灵活的设计模式RBAC,即基于角色的访问控制;
我来给大家说下这种设计思想:
首先,我们的需求是判断某一个用户对当前操作的控制器或控制器的方法是否有权限访问,
如果多个用户同时拥有同样的权限,那我们就需要给这些用户指定同一个用户角色,然后只需要通过角色来对操作的访问进行权限控制,
那我们表结构需要这样来设计,这个很重要,如下:
第一张数据表(用户表):
用户ID(主键自增)
第二张数据表(角色表):
用户角色ID(主键自增)
用户角色名称
第三张数据表(节点表):
操作节点ID(主键自增)
操作节点的名称
节点的中文说明
我们使用第三范式来设计关联表,这样做的好处是,避免数据冗余,并且对于一对多,多对一的关系都可以清晰的记录,条理清晰
第四张数据表(节点对应角色表):
用户角色ID(外键,关联角色表中的主键ID)
操作节点ID(外键,关联节点表中的主键ID)
第五张数据表(用户对应角色表):
用户角色ID(外键,关联角色表中的主键ID)
用户ID(外键,关联用户表中的主键ID)
通过这五张表就可以对权限进行访问控制,它的具体操作步骤如下:
用户输入用户名密码登录,
通过用户表判断,如果输入的用户名密码不合法,跳回重新登录
如果合法,在用户表中返回用户的ID号,
通过此用户ID号,到用户与角色的关联表中查询出用户的角色ID号,
拿到角色ID号,通过此ID号到角色与节点的关联表中查询出此角色拥有的节点访问权限,
将此权限节点全部存入SESSION中,当用户访问某一个模块的时候,
例如:http://www.lampbroher.net/index.php/stu/index
我们用session中的权限与$_GET['m']与$_GET['a']去对比,
如果$_GET['m']或者$_GET['a']在SESSION中不存在,说明该用户没有此权限,作出处理即可。
参考代码:
RBAC类文件:
/* ---------------------------------------------------------------------------------------
| RBAC权限控制类
class Rbac{
private $node_ //定义私有属性节点表名称
private $group_auth_ //定义私有属性组权限表名称
private $group_ //定义私有属性用户组表名称
private $group_user_ //定义私有属性用户归属组表名称
private $user_ //定义私有属性用户表名称
@param1 string 节点表名称
@param2 string 用户权限表名称
@param3 string 用户组表名称
@param4 string 用户归属组表名称
@param5 string 用户表名称
public function __construct($node_tablename='node',$group_auth_tablename='group_auth',$group_tablename='group',$group_user_tablename='group_member',$user_tablename='member'){
$this-&node_tablename = $node_ //获取节点表名称
$this-&group_auth_tablename = $group_auth_ //获取用户权限表名称
$this-&group_tablename = $group_ //获取用户组表名称
$this-&group_user_tablename = $group_user_ //获取用户归属组表名称
$this-&user_tablename = $user_ //获取用户表名称
设置节点方法
@param1 string 节点名称
@param2 string 节点父ID
@param2 string 节点中文说明
@return int 插入节点记录成功以后的ID
public function set_node($name,$pid,$zh_name=''){
if(!empty($name) && !empty($pid)){
$node = D($this-&node_tablename)-&insert(array(&name&=&$name,&pid&=&$pid,&zh_name&=&$zh_name));
设置权限方法
@param1 int 组ID
@param2 int 节点ID
@return int 插入权限记录成功以后的ID
public function set_auth($gid,$nid){
if(!empty($gid) && !empty($nid)){
$auth = D($this-&group_auth_tablename)-&insert(array(&gid&=&$gid,&nid&=&$nid));
获取节点方法
@param1 int 节点ID
@return array 获取到节点表的相关信息
public function get_node($id){
if(!empty($id)){
$data = http://www.bkjia.com/PHPjc/D($this-&node_tablename)-&field("id,name,pid")-&where(array('id'=&$id))-&find();
获取组权限方法
@param1 int 用户组ID
@return array 获取到组权限表的相关信息
public function get_auth($gid){
if(!empty($gid)){
$data = http://www.bkjia.com/PHPjc/D($this-&group_auth_tablename)-&field("nid")-&where(array('gid'=&$gid))-&select();
获取用户组方法
@param1 int 用户ID
@return array 获取该用户所对应的用户组id
public function get_group($uid){
if(!empty($uid)){
$data = http://www.bkjia.com/PHPjc/D($this-&group_user_tablename)-&field("gid")-&where(array('uid'=&$uid))-&select();
获取节点的子节点方法
@param1 int 节点ID
@return array 获取该节点所对应的全部子节点
public function get_cnode($nid){
if(!empty($nid)){
$cnode = D($this-&node_tablename)-&field(&name&)-&where(array('pid'=&$nid))-&select();
获取权限方法
@param1 int 用户ID
@return array 得到权限列表
public function get_access($uid){
if(!empty($uid)){
//调用获取组信息方法
$group = $this-&get_group($uid);
//遍历组信息
foreach($group as $v){
//将组ID传入获取权限的方法
$auth = $this-&get_auth($v['gid']); //获取该组的权限
//遍历该组的权限数组
foreach($auth as $val){
//将节点的ID传入获取节点信息方法
$node[] = $this-&get_node($val['nid']); //获取节点的相关信息
//遍历节点数组,并拼装
foreach($node as $nval){
if($nval['pid']==0){
$fnode[] = $ //将控制器压入fnode数组
//$cnode = $this-&get_cnode($nval['id']);
$cnode[] = $ //将控制器的方法压入cnode数组
//将控制器数组和控制器数组拼装成一个数组
foreach($fnode as $fval){
foreach($cnode as $cval){
if($cval['pid'] == $fval['id']){
$access[$fval['name']][] = $cval['name'];
//返回权限列表数组
检测权限方法
@param1 int 用户ID
@return boolean 权限禁止与否
public function check($uid){
if(!empty($uid)){
//将权限存入到$_SESSION['Access_List']中
$_SESSION['Access_List'] = $this-&get_access($uid);
if(!empty($_GET['m'])){
//判断此控制器是否被允许
if(array_key_exists($_GET['m'],$_SESSION['Access_List'])){
//判断此控制器的方法是否被允许
if(in_array($_GET['a'],$_SESSION['Access_List'][$_GET['m']])){
//允许的话返回真
//否则返回假
//$_SESSION['user_'.$uid]['Access_List'] = 0;
public function show_node(){
$path = APP_PATH.'/controls/';
$handle = opendir($path);
while(false!==($data = http://www.bkjia.com/PHPjc/readdir($handle))){
if(is_file($path.$data) && $data!='common.class.php' && $data!='pub.class.php'){
$controller = str_replace(&.class.php&,'',$data);
$res = fopen($path.$data,'r');
$str = fread($res,filesize($path.$data));
$pattern = '/function(.*)()/iU';
preg_match_all($pattern, $str, $matches);
foreach($matches[1] as $v){
$v = trim($v);
$arr[$controller][] = $v;
closedir($handle);
初始化类:
/* ---------------------------------------------------------------------------------------
| 初始化控制器
class Common extends Action {
初始化方法
public function init(){
//如果SESSION为空,则跳转
if(empty($_SESSION['user_login'])){
$this-&redirect(&pub/index&);
$a = new rbac();
if(!$a-&check($_SESSION['user_info']['id'])){
echo &&script&alert('您没有此权限!')&/script&&;
exit(&&script&document.write('&span style='font-size:40font-weight:bold'&Access Forbidden');alert('您没有此权限!');&/script&&);
$this-&redirect(&pub/index&);
这里给大家写了一个简单的RBAC类,仅供大家学习参考此思想,如有问题可以跟帖回复....
作者 zdrjlamp}

我要回帖

更多关于 TT帐号id怎么查询 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信