php - Laravel - 模型自引用 belongsToMany 与其他关系和具有多个限制的查询

标签 php mysql laravel model relationship

我有 3 个表:

建筑:

+-----+-------------+-----------+--------------------------+------------+---------------+----------------------+---------------------+
| id  | order_flag  |   type    |           key            | unit_cost  | unit_produce  |     created_at       |     updated_at      |
+-----+-------------+-----------+--------------------------+------------+---------------+----------------------+---------------------+
|  1  |         10  | resource  | building1                |        10  |            0  | 2015-01-30 08:54:44  | 2015-01-30 08:54:44 |
|  2  |         20  | resource  | building2                |         5  |            0  | 2015-01-30 08:54:44  | 2015-01-30 08:54:44 |
|  3  |         30  | resource  | building3                |        10  |            0  | 2015-01-30 08:54:44  | 2015-01-30 08:54:44 |
|  4  |         10  | basic     | building4                |         0  |           25  | 2015-01-30 08:54:44  | 2015-01-30 08:54:44 |
+-----+-------------+-----------+--------------------------+------------+---------------+----------------------+---------------------+

建筑用户:

+-----+--------------+----------+--------+----------------------+---------------------+
| id  | building_id  | user_id  | level  |     created_at       |     updated_at      |
+-----+--------------+----------+--------+----------------------+---------------------+
|  1  |           2  |      12  |     3  | 2015-01-30 08:52:57  | 2015-01-30 08:55:37 |
|  2  |           4  |      12  |     1  | 2015-01-30 08:53:53  | 2015-01-30 08:53:53 |
|  3  |           1  |      12  |     2  | 2015-01-30 08:54:08  | 2015-01-30 08:55:10 |
+-----+--------------+----------+--------+----------------------+---------------------+

建筑要求:

+-----+--------------+-------------+--------+----------------------+---------------------+
| id  | building_id  | require_id  | level  |     created_at       |     updated_at      |
+-----+--------------+-------------+--------+----------------------+---------------------+
|  1  |           1  |          4  |     1  | 2015-01-30 08:54:44  | 2015-01-30 08:54:44 |
|  2  |           3  |          1  |     5  | 2015-01-30 08:54:44  | 2015-01-30 08:54:44 |
+-----+--------------+-------------+--------+----------------------+---------------------+

我在建筑模型中写下这个关系:

    # Building Require another Building(s)
    public function requires() {
        return $this->belongsToMany('Building', 'building_require', 'building_id', 'require_id')->withPivot(array(
            'level',
            'updated_at',
            'created_at'
        ));
    }

    public function users() {
        return $this->belongsToMany('User')->withPivot(array('level'));
    }

Now I want select ALL the buildings from table buildings.. with following restrictions:

  1. 如果 building_require 表中没有建筑物的条目,则该建筑物可能在结果中。

  2. 如果此建筑物在 building_require 表中有条目,则必须检查 building_user 表中是否有条目,其中 building_id 与 building_required 表中的 required_id 相同。

(例如 building_id 1 需要 building_id 4,而 building_id 3 需要 building_id 1 的条目。)

除此之外(这是困难的部分),必须检查 building_user 表中的条目是否具有级别值 >= 为 building_require 表中定义的级别。

所以总结:

In this case building_id 1 needs an entry in building_user where building_id is 4 and the level is at least 1. building_id 3 needs an entry in building_user where building_id is 1 and the level is at least 5. So - building_id 1 and 3 has a required building. building with id 2 and 4 are in the result without restrictions. In this case the only the building_id 3 is not allowed. because the level of building_id 1 in the building_user table is only 2 and not at least 5.

对我来说这很困难,我认为这不是最好的解决方案,遗憾的是没有检查级别值:

# all buildings there has a required building:
$allRequiredBuildingIds = DB::table('building_require')->lists('building_id');

# if user has buildings, this buildings must remove from $allRequiredBuildingIds
if(Sentry::getUser()->buildings()->count() > 0) {
    # list all building_id 's of the user_building table
    $userBuildingIds = Sentry::getUser()->buildings()->lists('building_id');
    # list all building_id's of the buildings there are required and already stored in the building_user table
    $userBuildingRequiredIds = DB::table('building_require')->whereIn('require_id', $userBuildingIds)->lists('building_id');
    # there are all the building_id's which are not allowed to display
    $allRequiredBuildingIds = array_values(array_diff($allRequiredBuildingIds,$userBuildingRequiredIds));
}

# if there are buildings there are not allowed to display?
if(count($allRequiredBuildingIds) > 0) {
    $buildings = Building::whereType($type)->whereNotIn('id', $allRequiredBuildingIds)->paginate(10);
}else{
    $buildings = Building::whereType($type)->paginate(10);
}

有人可以帮助我优化它,并集成级别检查吗? 我的头在跳。

最佳答案

我有一个理论认为这可能有效,但我尚未对其进行测试。我认为关键是仅在 whereHas 闭包中使用 Join ,从而使 Eloquent 构建器保持事件状态。

Building::doesntHave('requires')
    ->orWhereHas('users', function($q) {
        $q->join('building_require', 'building_user.building_id', '=', 'building_require.required_id')
          ->where('building_user.level', '>=', 'building_require.level');
    })->get();

它将生成如下查询:

select * from `buildings` where (
  select count(*) from `building_require` as `x` where `x`.`building_id` = `buildings`.`id`
) < 1 or (
  select count(*) from `users` 
  inner join `building_user` on `users`.`id` = `building_user`.`user_id` 
  inner join `building_require` on `building_user`.`building_id` = `building_require`.`required_id` 
  where `building_user`.`building_id` = `buildings`.`id` 
  and `building_user`.`level` >= building_require.level
) >= 1

不幸的是,这不会成功。它将返回 building_require.required_id 建筑物而不是 building_require.building_id 建筑物。我设法在原始 SQL 中找出正确的查询,但我不确定如何在 Eloquent 中修复它:

SQLFiddle

select * from `buildings` where (
  select count(*) from `building_require` as `x` where `x`.`building_id` = `buildings`.`id`
) < 1 or (
  select count(*) from `users` 
  inner join `building_user` on `users`.`id` = `building_user`.`user_id` 
  inner join `building_require` on `building_user`.`building_id` = `building_require`.`required_id` 
  where building_require.building_id = buildings.id
  and `building_user`.`level` >= building_require.level
) >= 1;

关于php - Laravel - 模型自引用 belongsToMany 与其他关系和具有多个限制的查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28232084/

相关文章:

php - Zend Framework 2 结果集按条件排序?

mysql - 如何在 jasperreports 中聚合(总和)整个月的值(每个月应该是之前所有月份的总和)

laravel - Laravel 5.7.9 中 Yajra 数据表中的删除按钮

php - 自动从mysql数据库更新php代码中的数据

php - 在 PHP 中聚合数据集以获得最佳性能

PHP:将唯一的随机数写入数据库

MySQL 到 Solr 导入

Laravel - 在 Blade View 中使用过多可重用组件是否会减慢页面访问速度或增加服务器负载?

php - 在 docker 中运行 laravel 队列 worker

PHP 间接修改重载属性 - 使用 ARRAYS