检查用户是否“拥有”另一个用户的最佳方法

时间:2018-07-18 07:34:17

标签: laravel laravel-5 eloquent

我在Laravel中实现了一个系统,用户可以是多个“商店”的管理员。一个商店可以有多个属于该商店的用户。这是我的简化表结构-

用户

  • id(int)
  • 名称(字符串)
  • 电子邮件(字符串)

user_stores

  • user_id(int)
  • store_id(int)
  • 经理(布尔值/ tinyint)

商店

  • id(int)
  • 名称(字符串)

我的问题是检查具有经理数据透视标记的user可以管理谁。我有一个解决方案,但不确定是否最佳。我希望查询尽可能精简。这是我当前的解决方案-

protected $manageable_users;

public function getManageableUserIds () {

    if(!is_array($this->manageable_users)) {

        // get our store id's that we manage
        $manages = DB::table('user_stores')
            ->where('user_id', $this->id)
            ->where('manager', true)
            ->select('store_id');

        // make a join so we can get our data
        $this->manageable_users = DB::table('user_stores AS d2')
            ->joinSub($manages, 'stores', function ($join) {
                $join->on('d2.store_id', '=', 'stores.dealership_id');
            })->distinct()->pluck('d2.user_id')->toArray();
    }

    return $this->manageable_users;
}

因此,我在这里要做的是获取经理可能管理的所有用户ID的数组。然后,我将其存储为一个受保护的变量,以便在同一请求上可以在同一请求中多次执行此检查,而无需进行多次查询。

然后我有一个名为canManage的单独方法,该方法检查当前用户对象是否可以实际管理传递的用户-

public function canManage(User $user) {
    // check if our user is manageable
    return in_array($user->id, $this->getManageableUserIds(), true);
}

现在我知道Laravel非常聪明,由于某种原因,我觉得这不是最好的解决方案。再加上我不希望它在数据库上过于密集,因为最终会出现很多{{ 1}}和users

如果没有别的,也许这可能是其他人的解决方案!

谢谢。

2 个答案:

答案 0 :(得分:0)

因此,基本上,您想建立一个枢轴关系。相对于您的情况,这是您可以采取的方法:

app / User.php

<?php
    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class User extends Model {
        public $table = 'user';
        protected $primaryKey 'id';
        protected $foreignKey = 'user_id';

        public function stores() {
            return $this->belongsToMany('App\Store', 'user_stores', 'user_id', 'store_id')->withPivot('manager');
        }
    }
?>

app / Store.php

<?php
    namespace App;

    use Illuminate\Database\Eloquent\Model;
    use App\Store;

    class Store extends Model {
        public $table = 'store';
        protected $primaryKey 'id';
        protected $foreignKey = 'store_id';

        public function users() {
            return $this->belongsToMany('App\User', 'user_stores', 'store_id', 'user_id')->withPivot('manager');
        }
    }
?>

现在,让我们说您预先知道ID为4的用户是管理员,并且您希望获得该管理员可以管理的所有用户。

我假设我们在一个控制器中,因为在大多数情况下,这是您所有业务逻辑所在的位置,因此您正在浏览路线/user/4/store/1,并且我们将显示所有用户列表用户(经理)进行管理。

我还要在路线中添加商店(1,以明确表明我们希望该商店的所有用户加入,因为您的模型不会禁止经理来管理多个商店。版本发布后,假设经理仅管理一家商店。

app / Http / Controllers / UserStoreController.php

<?php

namespace App\Http\Controllers;

use App\User;
use App\Http\Controllers\Controller;

class UserStoreController extends Controller {
    public function show(User $user, Store $store) {
        // Grab all the users that are in the store and that are not manager
        $managed_users = User::whereHas('stores', function($query) use($store) {
            $query->where('manager', false)->where('store_id', $store->id);
        })->get();

        return view('user.store.index')
            ->withStore($store)
            ->withUser($user)
            ->withManagedUsers($managed_users);
    }
}

(注意,访问具有ID的路由可以让我们使用模型注入的功能,这就是为什么我不放置public function show($user_id, $store_id)的原因,因为Laravel将自动使用User::find($user_id)和{{ 1}})。

假设经理只能管理一个商店的版本:

app / Http / Controllers / UserController.php

Store::find($store_id)

希望有帮助。

答案 1 :(得分:0)

这是原始的SQL解决方案:

SELECT
    a.userid FROM user_stores a
INNER JOIN
    user_stores b ON a.store_id = b.store_id
WHERE
    a.manager=0 AND b.manager=1;

要将其转换为雄辩的,可以尝试使用DB :: select和/或DB :: raw

数据库表视图也值得考虑。然后,您只需要查询视图即可获得自定义的定制结果,而不是直接获取表。这种解决方案可以促进干净的代码,使您可以继续使用ORM,不需要在应用程序中运行原始SQL,并且可以将所有操作作为原始SQL来获得所有的速度优势。主要的缺点是必须编写这样一个视图并确保它得到维护。与使用触发器几乎一样的缺点。

另一个想法是通过ORM一次拉动整个数据库,然后使用laravel collections过滤数据。在这种情况下,我可能会减少。也可以使用过滤器或列表中的其他任何内容进行流水线处理。当然这是多余的循环,但是与ORM相比,性能折衷真的不好吗?

最后,还值得考虑“任何可行且最易读的”解决方案,然后使用例如redis对其进行缓存。