【问题标题】:Laravel 4: How to add more data to Auth::user() without extra queries?Laravel 4:如何在没有额外查询的情况下向 Auth::user() 添加更多数据?
【发布时间】:2014-06-27 06:29:04
【问题描述】:

我对 Laravel 4 比较陌生,似乎找不到正确的答案,也许你可以帮忙:

我们应用程序中的一个用户可以有多个帐户,所有数据都与一个帐户相关,而不是一个用户。用户当前登录的帐户由子域定义,即 accountname.mydomain.com。

我们在 User 模型中添加了一个方法 account():

/**
 * Get the account the user is currently logged in to
 */
public function account()
{
    $server = explode('.', Request::server('HTTP_HOST'));
    $subdomain = $server[0];
    return Account::where('subdomain', $subdomain)->first();
}

问题是,当我们现在在视图或控制器中使用类似这样的东西时,总会有一个额外的查询:

Auth::user()->account()->accountname

当我们想要获取与帐户相关的“产品”时,我们可以使用:

$products = Product::where('account_id', Auth::user()->account()->id)->get();

又是一个额外的查询...

我们需要以某种方式扩展 Auth::user() 对象,以便帐户数据始终在其中……或者我们可以创建一个新的 Auth::account() 对象,并在那里获取数据。 .

对此最好的解决方案是什么? 提前致谢

【问题讨论】:

  • 如何将模型存储到会话中
  • 这也是我们的第一个想法,但我认为如果我们必须在任何地方都使用 Session::get('account_id') 会很丑。此外,用户可以将子域更改为另一个帐户,因此必须在每次请求时检查/更新会话。
  • 从你写的来看,account()方法和User没有关系,所以你不应该把它放在User模型中,你可以在bootstrap/start.php的末尾添加它并调用@987654324 @(这不是最佳做法,请尝试让我们知道它是否有效)

标签: laravel laravel-4 eloquent


【解决方案1】:

我认为这是 Repositories 的一个很好的例子。

您不应直接查询(涉及的)模型,而应将它们包装到处理所有查询的ProductRepository(或一般的存储库)中。

例如:

<?php

class ProductRepository
{
    protected $accountId;

    public function __construct($accountId)
    {
         $this->accountId = $accountId;
    }

    public function all()
    {
        return Product::where('account_id', $this->accountId)->get();
    }
}

//now bind it to the app container to make it globaly available
App::bind('ProductRepository', function() {
    return new ProductRepository(Auth::user()->account()->id);
});

// and whenever you need it:
$productRepository = App::make('ProductRepository');
$userProducts = $productRepository->all();

您可以 group the relevant routesapply a filter on them 在每个请求上绑定它,这样每个存储库实例只会查询一次帐户 ID,而不是每次查询。

Scopes 在这种情况下也可能很有趣:

// app/models/Product.php
public function scopeCurrentAccount($query)
{
    return $query->where('account_id', Auth::user()->account()->id);
}

现在你可以简单地调用

$products = Product::currentAccount()->get();

【讨论】:

    【解决方案2】:

    只需将其设置为会话变量即可。这样,您可以在调用数据库之前检查该会话变量,看看您是否已经拥有它。

    或者不使用-&gt;get(),您可以使用-&gt;remember($minutes),其中$minutes 是您希望缓存查询结果的时间。

    【讨论】:

      【解决方案3】:

      你应该看看 Eloquent 关系:http://laravel.com/docs/eloquent#relationships

      它提供了获取用户帐户及其产品的简单方法。您说一个用户可以拥有多个帐户,但您在函数中使用了first(),我在这里使用了hasOne

      使用 Eloquent 关系,您可以在用户模型中编写:

      <?php
      public function account()
      {
          // I assume here 'username' is the local key for your User model
          return $this->hasOne('Account', 'subdomain', 'username');
      }
      
      public function products()
      {
          // You should really have a user_id in your User Model 
          // so that you will not have to use information from the
          // user's account
          return $this->hasMany('Product', 'account_id', 'user_id');
      }
      

      您应该在 Account 模型和 Product 模型中定义 belongsTo

      使用 Eager Loading,您不会运行大量 SQL 查询:http://laravel.com/docs/eloquent#eager-loading

      你将能够使用类似的东西

      $users = User::with('account', 'products')->get();
      

      让所有用户了解他们的帐户和产品。

      【讨论】:

      • 我不能使用 hasOne,因为用户可以有很多帐户。有一个 users_accounts 表可以将用户连接到他们的帐户,反之亦然。我们有一个 belongsToMany 关系,它获取用户有权访问的所有帐户,但问题是用户当前正在查看的帐户(仅由子域定义)。我们需要 Auth::user() 对象中可用的信息,而无需执行数据库查询。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-27
      • 2017-04-13
      • 1970-01-01
      • 1970-01-01
      • 2012-08-08
      • 2019-10-01
      • 1970-01-01
      相关资源
      最近更新 更多