99

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

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

这是设置的示例;

-- 路由.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()在中间件和控制器中都重复了 。我需要将数据从一个传递到另一个,以免重复。

4

11 回答 11

153

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

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

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

因此,您将按如下方式实现它;

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

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

\Request::get('myAttribute');

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

 $request->get('myAttribute');
于 2015-07-16T12:22:45.210 回答
36

您可以遵循控制反转模式并使用依赖注入,而不是自定义请求参数。

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

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

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

class PagesController 
{
    protected $page;

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

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

于 2015-10-23T08:15:21.203 回答
22

在 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');
    ...
}
于 2015-11-07T13:50:49.810 回答
22

拉拉维尔 5.7

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

// to get in controller just use the resolve helper
$myObj = resolve('myObj');
于 2018-10-12T19:29:29.327 回答
9

正如上面对 laravel 5.3.x 的评论之一所述

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

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

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

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

$request->get('key');
于 2017-09-27T15:30:11.777 回答
7

这很简单:

这是中间件代码:

public function handle($request, Closure $next)
{

    $request->merge(array("customVar" => "abcde"));

    return $next($request);
}

这是控制器代码:

$request->customVar;
于 2018-08-07T07:56:04.390 回答
6

我确信是否可以将数据从中间件传递到控制器,那么它将在 Laravel 文档中。

看看这个这个,它可能会有所帮助。

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

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

$request->myAttribute = "myValue";
于 2015-05-13T12:33:59.057 回答
2

$request是数组,这样我们就可以将值和键添加到数组中,并$request在控制器中使用此键获取。

$request['id'] = $id;

于 2017-11-15T10:54:24.340 回答
2

如果您的网站有从数据库中获取的 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>

非常感谢所有人并享受代码:)

于 2019-01-19T15:18:10.677 回答
1

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

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

并在稍后将它们取回:

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

这是可能的,因为laravel 请求扩展了 symfonys 请求,它具有ParameterBag类型的属性“ $attributes ”,用于保存自定义参数

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

使用Laravel 5.6测试,但也可能与其他版本一起使用。

于 2018-07-06T10:57:08.750 回答
1

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

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

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

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

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

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

于 2015-08-18T10:03:11.720 回答