【问题标题】:Laravel Middleware return variable to controllerLaravel 中间件将变量返回给控制器
【发布时间】:2015-07-24 14:19:57
【问题描述】:

我正在对用户进行权限检查,以确定他们是否可以查看页面。这涉及首先通过一些中间件传递请求。

我遇到的问题是在将数据返回到视图本身之前,我在中间件和控制器中复制了相同的数据库查询。

这是一个设置示例;

--routes.php

Route::get('pages/{id}', [
   'as' => 'pages',
   'middleware' => 'pageUser'
   'uses' => 'PagesController@view'
]);

-- PageUserMiddleware.php(PageUserMiddleware 类)

public function handle($request, Closure $next)
    {
        //get the page
        $pageId = $request->route('id');
        //find the page with users
        $page = Page::with('users')->where('id', $pageId)->first();
        //check if the logged in user exists for the page
        if(!$page->users()->wherePivot('user_id', Auth::user()->id)->exists()) {
            //redirect them if they don't exist
            return redirect()->route('redirectRoute');
        }
        return $next($request);
    }

-- PagesController.php

public function view($id)
{
    $page = Page::with('users')->where('id', $id)->first();
    return view('pages.view', ['page' => $page]);
}

如您所见,Page::with('users')->where('id', $id)->first() 在中间件和控制器中重复出现。我需要将数据从一个传递到另一个,以免重复。

【问题讨论】:

  • 我正要问同样的问题,我花了很长时间才找到这个答案。这是我的问题。出于 SEO/可查找性的原因,我会在此处添加它,希望没问题:Laravel 5.0 - 在中间件和控制器中加载模型。如何加载用户模型的实例,以便在中间件和控制器中都可以使用相同的实例(只有一个数据库查询)?因为在中间件中我想检查用户是否被授权,而在控制器中我可能想显示有关用户的信息或以某种方式操纵用户。

标签: php laravel laravel-5 laravel-middleware


【解决方案1】:

我相信正确的方法(在 Laravel 5.x 中)是将您的自定义字段添加到 attributes 属性。

从源代码cmets中,我们可以看到属性是用于自定义参数的:

 /**
 * Custom parameters.
 *
 * @var \Symfony\Component\HttpFoundation\ParameterBag
 *
 * @api
 */
public $attributes;

所以你可以按如下方式实现它;

$request->attributes->add(['myAttribute' => 'myValue']);

然后您可以通过调用来检索属性:

\Request::get('myAttribute');

或者来自 laravel 5.5+ 中的请求对象

 $request->get('myAttribute');

【讨论】:

  • 你如何访问接收控制器中的属性?
  • 将请求类添加到控制器方法参数(IoC 容器)或调用静态类\Request
  • $myAttribute = \Request::get('myAttribute');
  • 哇,这个解决方案看起来很干净!
  • 你也可以使用$request->request->add(['myAttribute' => 'myValue']);来使用magic getter的简写$request->myAttribute
【解决方案2】:

您可以遵循控制反转模式并使用依赖注入来代替自定义请求参数。

在您的中间件中,注册您的 Page 实例:

app()->instance(Page::class, $page);

然后声明你的控制器需要一个Page 实例:

class PagesController 
{
    protected $page;

    function __construct(Page $page) 
    {
        $this->page = $page;
    }
}

Laravel 将自动解析依赖关系并使用您在中间件中绑定的 Page 实例实例化您的控制器。

【讨论】:

  • 这真是个好主意,我继续创建了一个服务提供者,然后注册了一个服务容器。这样,当需要一些属性时,我只需注入依赖项。更加干净和透明。谢谢!
  • @ArianAcosta 请您用您的方式详细说明答案吗?我的意思是,如何使用依赖注入以及它如何与中间件关联。
  • @JCarlos 当然!这个想法是有一个自定义的服务容器类,它作为内部属性保存你需要在中间件和控制器之间传递的数据。如果您使用 $this->app->singleton(...) 将该服务容器注册为单例,那么每次注入它时它始终是同一个实例。所以,基本上你会首先将它注入中间件(只需将其作为参数),然后将数据放入其中,最后将其放入可以访问数据的控制器中。见laravel.com/docs/5.4/container祝你好运
  • 这是一个很好的答案......整洁! :)
  • 备注:在 __constructor 中不起作用,因为中间件是在控制器的构造函数之后加载的。但是您可以在控制器的任何操作中使用 DI。
【解决方案3】:

Laravel 5.7

// in Middleware register instance
app()->instance('myObj', $myObj);

// to get in controller just use the resolve helper
$myObj = resolve('myObj');

【讨论】:

    【解决方案4】:

    在 laravel >= 5 中你可以在中间件中使用$request->merge

    public function handle($request, Closure $next)
    {
    
        $request->merge(array("myVar" => "1234"));
    
        return $next($request);
    }
    

    在控制器中:

    public function index(Request $request)
    {
    
        $myVar = $request->instance()->query('myVar');
        ...
    }
    

    【讨论】:

    • 为什么要静态访问Request::instance(),而不是使用$request
    【解决方案5】:

    正如上面针对 laravel 5.3.x 的 cmets 之一所述

    $request->attributes->add(['key => 'value'] ); 
    

    不起作用。但是在中间件中设置这样的变量是可行的

    $request->attributes->set('key', 'value');
    

    我可以在我的控制器中使用它来获取数据

    $request->get('key');
    

    【讨论】:

      【解决方案6】:

      很简单:

      这是中间件代码:

      public function handle($request, Closure $next)
      {
      
          $request->merge(array("customVar" => "abcde"));
      
          return $next($request);
      }
      

      这是控制器代码:

      $request->customVar;
      

      【讨论】:

      • 这工作,谢谢兄弟
      【解决方案7】:

      我确定是否可以将数据从中间件传递到控制器,然后它会在 Laravel 文档中。

      看看thisthis,它可能会有所帮助。

      简而言之,您可以在传递给中间件的请求对象上捎带您的数据。 Laravel 身份验证外观也是这样做的。

      因此,在您的中间件中,您可以:

      $request->myAttribute = "myValue";
      

      【讨论】:

      • 谢谢@norman - 这是一个很好的解决方案,我不知道你能做到......!我在质疑我是否应该在这一点上使用中间件,但似乎我应该。该文档没有提及任何此类内容。再次感谢
      • @Alex 是的,我认为如果它是在每个控制器操作中执行的通用代码,那么将其实现为中间件并不是一个坏主意。
      【解决方案8】:

      如果您的网站有从数据库中获取的 cms 页面,并且希望在 laravel 应用程序的所有页面的页眉和页脚块中显示其标题,则使用中间件。在中间件中编写以下代码:

      namespace App\Http\Middleware;
      
      use Closure;
      
      use Illuminate\Support\Facades\DB;
      
      public function handle($request, Closure $next)
      {    
      
      $data = DB::table('pages')->select('pages.id','pages.title')->where('pages.status', '1')->get();
      
      \Illuminate\Support\Facades\View::share('cms_pages', $data);
      
      return $next($request);
      
      }
      

      然后转到您的 header.blade.php 和 footer.blade.php 并编写以下代码以添加 cms 页面的链接:

      <a href="{{ url('/') }}">Home</a> | 
      
      @foreach ($cms_pages as $page) 
      
      <a href="{{ url('page/show/'.$page->id) }}">{{ $page->title }}</a> | 
      
      @endforeach
      
      <a href="{{ url('contactus') }}">Contact Us</a>
      

      非常感谢大家,享受代码:)

      【讨论】:

        【解决方案9】:

        $request 是数组,因此我们可以在数组中添加值和键,并在控制器中使用此键获取$request

        $request['id'] = $id;

        【讨论】:

          【解决方案10】:

          我不会说英语,所以...抱歉可能出现的错误。

          您可以为此使用 IoC 绑定。在您的中间件中,您可以这样做来绑定 $page 实例:

          \App::instance('mi_page_var', $page);
          

          之后,在您的控制器中调用该实例:

          $page = \App::make('mi_page_var');
          

          App::instance 不会重新实例化类,而是返回先前绑定的实例。

          【讨论】:

            【解决方案11】:

            我能够通过以下方式向请求对象添加值:

            $request->attributes->set('key', 'value');
            

            并在稍后将它们取回:

            $request->attributes->get('key');
            

            这是可能的,因为laravels Request 扩展了symfonys Request,它具有ParameterBag 类型的属性“$attributes”,旨在容纳custom parameters

            我认为这应该是将数据传递到后续中间件、控制器或任何其他可能访问请求对象的地方的最佳实践。

            使用 Laravel 5.6 进行测试,但可能也适用于其他版本。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2022-07-28
              • 2018-01-06
              • 2018-10-22
              • 2015-01-06
              • 2014-10-02
              • 2021-07-12
              相关资源
              最近更新 更多