如何在Laravel中定义三对多关系的方式?

时间:2018-01-27 22:35:04

标签: php mysql laravel eloquent many-to-many

我很难在Laravel 5中创建三个表/模型之间的三对多关系。到目前为止,从网上查找并没有给我任何可行的解决方案。

我有三种模式:用户角色论文

我想要实现的是将三者相互连接起来。例如,用户可以与许多这些相关联,而用户可以在一个特定<上具有许多不同的角色强>论文即可。

因此用户可以在一个特定的论文上拥有多个角色(例如讲师和评论者),同样用户也可以关联另一个论文并且还有另一个角色(仅限教师)。

到目前为止,我已经尝试了一种方法,这意味着创建另一个可以处理数据透视表的模型。所以我创建了一个模型关系

我目前的表格:

用户

id 
name

论文

id 
topic

角色

id 
name

关系

id
role_id (references id on roles) 
thesis_id (references id on theses)
user_id (references id on users)

我现在有代码

user.php的

class User extends Authenticatable
{
    public function relations(){
        return $this->hasMany('App\Relation', 'relations');
    }
}

Thesis.php

class Thesis extends Model
{
    public function relations(){
        return $this->hasMany('App\Relation', 'relations');
    }
}

Role.php

class Role extends Model
{
    public function relations(){
        return $this->hasMany('App\Relation', 'relations');
    }
}

Relation.php

class Relation extends Model
{
    public function user(){
    return $this->belongsToMany('App\User');
    }

    public function thesis(){
        return $this->belongsToMany('App\Thesis');
    }

    public function role(){
        return $this->belongsToMany('App\Role');
    }
}

现在我在插入数据透视表时使用 $ relation = new Relation; 方法。

我不知道如何从数据透视表中获取数据。例如,获取用户论文以及用户对该特定论文<具有哪种角色 / strong>即可。

我尝试过像 $ user-&gt; thesis() $ user-&gt; role() $ user-&gt ;论文() - &gt;角色(),但没有一个不起作用。我只得到一个未定义的方法错误。

如果我能够得到一些帮助或至少某种方向,即使我在这里展示的内容有些正确,我也会非常感激。

谢谢。

2 个答案:

答案 0 :(得分:5)

您对通过中间表存储关系的Many to Many relationship感兴趣。中间表可以在其上存储其他属性,因此,您可以创建具有附加thesis_users属性的role_id中间表。该文档涵盖了“检索中间表列”标题下的此用例。您不需要其他模型来表示这些关系。

如果您需要确定哪个pivot table用户具有特定Thesis,则可以查询中间表(也称为roles),例如:

return $this->belongsToMany('App\Thesis')->wherePivot('role_id', 1);

您的用户模型关系看起来像这样:

public function theses()
{
    return $this->belongsToMany('App\Thesis');
}

你的论文模型关系看起来像这样:

public function users()
{
    return $this->belongsToMany('App\User');
}

然后你可以对论文模型做另外的关系约束,如下所示:

public function authors()
{
    return $this->belongsToMany('App\User')->wherePivot('role_id', 1);
}


public function reviewers()
{
    return $this->belongsToMany('App\User')->wherePivot('role_id', 2);
}


public function instructors()
{
    return $this->belongsToMany('App\User')->wherePivot('role_id', 3);
}

在您的用户模型上:

public function authored()
{
    return $this->belongsToMany('App\Thesis')->wherePivot('role_id', 1);
}

public function reviewer()
{
    return $this->belongsToMany('App\Thesis')->wherePivot('role_id', 2);
}

Thesis::find(1)->reviewers(); // returns every App\User with the role_id 2 on App\Thesis with ID 1
Thesis::find(1)->instructors(); // returns every App\User with the role_id 3 on App\Thesis with ID 1

User::find(1)->theses(); // returns each App\Thesis that the user has any role on 
User::find(1)->authored(); // returns each App\Thesis that the user has the author role on

答案 1 :(得分:0)

我做了一些工作。建立了新的关系。 This可能会对您有所帮助。我在这里复制了相同的代码。

  

它可能不是最好的表现。

第一种情景 - 属于许多人

实施例

用户属于多个角色

角色属于许多用户

角色属于许多权限

权限属于许多角色

users → user-role → roles → role-permission→ permissions

5个表(2个支点)

所以,让我们说我们想要获取用户权限,这些权限通过角色连接

 //attach roles to user
$user->roles()->attach($admin->id);

//attach permissions to user
$admin->permissions()->attach($permission->id);

//get users' permissions using HasManyThroughMany relationship

$userPermissions = $user->permissions();

user.php的

use App\Extensions\Eloquent\Model as Model;

class User extends Model
{
    public function roles()
    {
        return $this->belongsToMany(Role::class, 'user_role', 'user_id', 'role_id');
    }

    public function permissions()
    {        
        return $this->hasManyThroughMany(Permission::class,
           Role::class,
           'user_role',
           'role_permission',
           'permission_id',
           'role_id');
    }
}

Role.php

class Role extends Model
{ 
    public function users()
    {
        return $this->belongsToMany(User::class, 'user_role', 'role_id', 'user_id');
    }

    public function permissions()
    {
        return $this->belongsToMany(Permission::class, 'role_permission', 'role_id', 'permission_id');
    }
}

Permission.php

class Permission extends Model
{  
    public function users()
    {
        return $this->belongsToMany(User::class ,'user_permission', 'permission_id', 'user_id');
    }

    public function roles()
    {
        return $this->belongsToMany(Role::class, 'role_permission', 'permission_id', 'role_id');
    }
}

第二种情景 - 有很多次

实施例

学生有很多报名

每个报名都有很多科目

每个主题属于注册

每个注册都属于学生

student→ enrollment → subject

3桌

所以,让我们说我们想要取一个学生科目,这些科目是通过报名连接的

//save students enrollment
$student->enrollments()->save($enrollment);

//save enrollments subject
$enrollment->subjects()->save($subject);

//get student's subjects using HasManyThroughMany relationship
$student->subjects();

Student.php

use App\Extensions\Eloquent\Model as Model;

class Student extends Model
{
    public function enrollments()
    {
     return $this->hasMany(Enrollment::class);
    }

    public function subjects()
    {
     return $this->hasManyThroughMany(Subject::class, Enrollment::class);
    }
}

Enrollment.php

class Enrollment extends Model
{
    public function subjects()
    {
     return $this->hasMany(Subject::class);
    }

    public function student()
    {
     return $this->belongsTo(Student::class);
    }
}

Subject.php

class Subject extends Model
{
    public function enrollment()
    {
     return $this->belongsTo(Enrollment::class);
    }
}

新的HasManyThroughMany关系文件。

HasManyThroughMany.php

namespace App\Extensions\Eloquent;

use Illuminate\Database\Eloquent\Model as EloquentModel;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Query\Expression;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\Relation;

class HasManyThroughMany extends Relation
{
    public function __construct(
  Builder $query,
  EloquentModel $farParent,
  EloquentModel $parent,
  $firstKey, $secondKey,
  $localKey,
  $throughKey)
    {
        $this->localKey = $localKey;
        $this->firstKey = $firstKey;
        $this->secondKey = $secondKey;
        $this->farParent = $farParent;
        $this->throughKey = $throughKey;
        $this->farParentRelatedKey = $this->getModelRelatedKey($this->farParent);
        parent::__construct($query, $parent);
    }

    public function addConstraints()
    {
        $parentTable = $this->parent->getTable();

        $this->setJoin();
        if (static::$constraints && !$this->throughKey) {
            $localValue = $this->farParent[$this->localKey];
            $this->query->where($parentTable.'.'.$this->firstKey, '=', $localValue);
        } else {
            $localValue = $this->farParent['id'];
            $this->query->where($this->firstKey . '.' . $this->farParentRelatedKey, '=', $localValue);
        }

    }

    protected function setJoin(Builder $query = null)
    {

        $query = $query ?: $this->query;

        $foreignKey = $this->related->getTable().'.'.$this->secondKey;
        $farParentTable = $this->farParent->getTable();
        $farParentTableKey = $farParentTable.'.'.$this->localKey;
        $firstKey = $this->parent->getTable().'.'.$this->firstKey;

        $id = $this->related->getTable() . '.id as id';
        $all = $this->related->getTable() . '.*';
        $columns = [$id, $all];
        if(!$this->throughKey){
            $query->addSelect($columns)
   ->join($this->parent->getTable(),
     $this->getQualifiedParentKeyName(),
     '=',
     $foreignKey)
            ->join($farParentTable,
     $farParentTableKey,
     '=',
     $firstKey);
        } else {
            $query->addSelect($columns)
            ->join($this->secondKey,
     $this->secondKey . '.' . $this->localKey,
     '=',
     $this->related->getTable() . '.id')
            ->join($this->firstKey,
     $this->firstKey . '.' . $this->throughKey,
     '=',
     $this->secondKey . '.' . $this->throughKey)
            ->join($farParentTable,
     $farParentTable . '.id',
     '=',
     $this->firstKey . '.' . $this->farParentRelatedKey);
        }
        if ($this->parentSoftDeletes()) {
            $query->whereNull($this->parent->getQualifiedDeletedAtColumn());
        }

    }

    public function getModelRelatedKey($model)
    {
        return strtolower(class_basename($model)) . '_id';
    }

    public function getForeignKey()
    {
        return $this->related->getTable().'.'.$this->secondKey;
    }

    public function parentSoftDeletes()
    {
        return in_array('Illuminate\Database\Eloquent\SoftDeletes',
      class_uses_recursive(get_class($this->parent)));
    }

    public function addEagerConstraints(array $models){}
    public function initRelation(array $models, $relation)
    {
        foreach ($models as $model) {
            $model->setRelation($relation, $this->related->newCollection());
        }

        return $models;
    }
    public function match(array $models, Collection $results, $relation){}
    public function getResults()
    {
        return $this->get();
    }    
}

新模型文件 Model.php

namespace Hello\Extensions\Eloquent;

use Illuminate\Database\Eloquent\Model AS EloquentModel;
use App\Extensions\Eloquent\HasManyThroughMany;

class Model extends EloquentModel
{
    public function hasManyThroughMany($related,
            $through,
            $firstKey = null,
            $secondKey = null,
            $localKey = null,
            $throughKey = null)
    {
        $through = new $through;

        $firstKey = $firstKey ?: $this->getForeignKey();

        $secondKey = $secondKey ?: $through->getForeignKey();

        $localKey = $localKey ?: $this->getKeyName();

        return new HasManyThroughMany((new $related)->newQuery(),
          $this,
          $through,
          $firstKey,
          $secondKey,
          $localKey,
          $throughKey);

    }

}