Laravel-Backpack: 组合 hasMany 和 hasManyThrough 以在列表中添加子句

Laravel-Backpack: combine hasMany and hasManyThrough to add clauses in list

这是我的:

用户table

实例 table 将“project_id”作为列之一

项目table

instance_user table 与“user_id”和“instance_id”

project_user table 与“user_id”和“project_id”

当我创建用户时,我希望能够通过 select2_multiple 将项目 and/or 实例关联到用户,将条目添加到数据透视 tables。到目前为止,一切正常。

然后,当用户登录时,在实例列表中,我希望他们只看到他们在“instance_user”table 中关联的实例以及属于的实例他们在“project_user”table 中关联的项目。所以,例如:

用户:

id name
1 Example1
2 Example2

实例:

id name project_id
1 Instance1 1
2 Instance2 1
3 Instance3 2
4 Instance4 2
5 Instance5 2

instance_user:

instance_id user_id
4 1

project_user:

project_id user_id
1 1

此处,id=1 的用户将在实例列表中看到 = Instance1、Instance2、Instance4

我尝试在 InstanceCrudController 中添加这个:

CRUD::addClause('has', 'users');
CRUD::addClause('has', 'instances_through');

这些是我的用户和实例模型:

//USER MODEL
    public function instances()
    {
        return $this->belongsToMany(Instance::class);
    }

    public function projects()
    {
        return $this->belongsToMany(Project::class);
    }

//INSTANCE MODEL
    public function users()
    {
        return $this->belongsToMany(User::class);
    }

    public function instances_through()
    {
        return $this->hasManyThrough(
            User::class,
            ProjectUser::class,
            'project_id',
            'id',
            'id', 
            'user_id' 
        );        
    }

但这显然是不正确的,因为它没有显示预期的结果,而且我认为我不太了解如何在这种情况下使用 hasManyThrough。

有什么方法可以做到这一点,其中一个函数可以 return 具有给定限制的组合结果?或者有关如何处理此问题的任何提示。

非常感谢。

Even my answer get the expected result this is not a good way to get instances when there are millions of records. So you better find a different way to achieve this. Most probably try to have db table modification where you can get all the instances for a certain user.

这是您可以根据您的 table 结构使用的方法。

  1. 通过instance_user
  2. 获取实例ID
  3. 通过project_user
  4. 获取实例ID
  5. 合并 ID
  6. 通过合并 ID 查找实例

示例代码。我已经在 github/nipunTharuksha/Laravel-Backpack-answer 上测试了这个和演示项目,我在其中还定义了其他关系。

class InstanceCrudController extends Controller
{
    public function userInstances()
    {
        $user = User::find(1);

        $instance_ids_via_instance_user = (clone $user)->instances()->pluck('instance_id')->toArray(); //Instance id 4
        $instance_ids_via_project_user = Instance::whereIn('project_id', (clone $user)->projects()->pluck('project_id')->toArray())->get()->pluck('id')->toArray(); // Instance is 1,2

        $instance_ids = array_merge($instance_ids_via_instance_user,$instance_ids_via_project_user);

        $instances = Instance::find($instance_ids);

        return response()->json($instances);

    }
}

结果

[
  {
    "id": 1,
    "name": "Prof. Raphaelle Robel DVM",
    "project_id": 1,
    "created_at": "2021-08-22T17:26:54.000000Z",
    "updated_at": "2021-08-22T17:26:54.000000Z"
  },
  {
    "id": 2,
    "name": "Tianna Glover",
    "project_id": 1,
    "created_at": "2021-08-22T17:26:54.000000Z",
    "updated_at": "2021-08-22T17:26:54.000000Z"
  },
  {
    "id": 4,
    "name": "Abigale Cummings",
    "project_id": 2,
    "created_at": "2021-08-22T17:26:54.000000Z",
    "updated_at": "2021-08-22T17:26:54.000000Z"
  }
]

性能

这就是我最终所做的。很高兴看到不同的方法。

//InstanceCrudController

    public function get_instance_ids($user_id)
    {
        $user = User::find($user_id);

        $instance_ids_via_instance_user = $user->instances->pluck('id')->toArray(); 
        $instance_ids_via_project_user = Instance::whereIn('project_id', $user->projects->pluck('id')->toArray())->pluck('id')->toArray();

        $instance_ids = array_merge($instance_ids_via_instance_user,$instance_ids_via_project_user);                                                                 

        return $instance_ids;
    }

CRUD::addClause('whereIn', 'id', $this->get_instance_ids(backpack_user()->id));