Laravelミドルウェアが変数をコントローラーに返す


87

ユーザーがページを表示できるかどうかを判断するために、ユーザーのアクセス許可チェックを実行しています。これには、最初にいくつかのミドルウェアを介して要求を渡すことが含まれます。

私が抱えている問題は、データをビュー自体に返す前に、ミドルウェアとコントローラーで同じデータベースクエリを複製していることです。

セットアップの例を次に示します。

--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 /ファインダビリティの理由からここに追加します。問題がないことを願っています:Laravel5.0-ミドルウェアとコントローラーにモデルをロードします。ミドルウェアとコントローラーの両方で同じインスタンス(1つのデータベースクエリのみ)を使用できるように、Usersモデルのインスタンスをロードするにはどうすればよいですか?ミドルウェアではユーザーが承認されているかどうかを確認したいので、コントローラーではユーザーに関する情報を表示したり、何らかの方法でユーザーを操作したりしたい場合があります。
alieninlondon 2015年

回答:


136

これを行う正しい方法(Laravel 5.x)は、カスタムフィールドをattributesプロパティに追加することだと思います。

ソースコードのコメントから、属性がカスタムパラメータに使用されていることがわかります。

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

したがって、これを次のように実装します。

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

次に、次の呼び出しによって属性を取得できます。

\Request::get('myAttribute');

またはlaravel5.5 +のリクエストオブジェクトから

 $request->get('myAttribute');

1
次に、受信コントローラー内の属性にどのようにアクセスしますか?
user985366 2016

1
コントローラメソッドの引数(IOCコンテナ)またはコール静的クラス\リクエストにリクエストクラスを追加
Gaz_Edge

8
$ myAttribute = \ Request :: get( 'myAttribute');
Shawn C.

4
うわー、このソリューションはとてもきれいに見えます!
schellingerht 2016年

3
また$request->request->add(['myAttribute' => 'myValue']);、マジックゲッターの速記を使用できるようにするために使用することもできます$request->myAttribute
jonan.pineda 2017年

29

カスタムリクエストパラメータの代わりに、制御の反転パターンに従い、依存性注入を使用できます。

ミドルウェアで、Pageインスタンスを登録します。

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

次に、コントローラーにPageインスタンスが必要であることを宣言します。

class PagesController 
{
    protected $page;

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

Laravelは依存関係を自動的に解決Pageし、ミドルウェアにバインドしたインスタンスを使用してコントローラーをインスタンス化します。


1
これは本当に良い考えです。先に進んでサービスプロバイダーを作成し、サービスコンテナーを登録しました。そうすれば、いくつかの属性が必要になったときに、依存関係を挿入するだけです。はるかにきれいで透明です。ありがとう!
Arian Acosta

1
@ArianAcostaお願いです、あなたのやり方で答えを詳しく説明していただけますか?つまり、依存性注入の使用方法と、それがミドルウェアにどのように関連付けられているかを意味します。
JCarlosR 2017

4
@JCarlosもちろんです!アイデアは、ミドルウェアとコントローラーの間で渡す必要のあるデータを内部プロパティとして保持するカスタムサービスコンテナークラスを持つことです。そのサービスコンテナを$ this-> app-> singleton(...)でシングルトンとして登録すると、注入するたびに常に同じインスタンスになります。したがって、基本的には、最初にミドルウェアに挿入し(単に引数として要求することにより)、次にデータをその中に配置し、最後にデータにアクセスできるコントローラーに要求します。laravel.com/docs/5.4/containerの幸運をご覧ください
Arian Acosta

2
これは素晴らしい答えです...きちんと!:)
ピエトロ

5
備考:__ constructorでは、ミドルウェアがコントローラーのコンストラクターの後にロードされるため、機能しません。ただし、コントローラーの任意のアクションでDIを使用できます。
SerhiiTopolnytskyi19年

18

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');
    ...
}

11
Request::instance()使用するのではなく、静的にアクセスするのはなぜ$requestですか?
jjok 2017

17

Laravel 5.7

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

そして

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

7

上記のlaravel5.3.xに関するコメントの1つで述べたように

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

動作しません。しかし、ミドルウェアでこのような変数を設定することは機能します

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

これを使用してコントローラーでデータをフェッチできます

$request->get('key');

6

ミドルウェアからコントローラーにデータを渡すことが可能であれば、それはLaravelのドキュメントにあると確信しています。

これこれを見てください、それは役立つかもしれません。

つまり、ミドルウェアに渡されるリクエストオブジェクトにデータを便乗させることができます。Laravel認証ファサードもそれを行います。

したがって、ミドルウェアでは、次のことができます。

$request->myAttribute = "myValue";

ありがとう@ norman-それは良い解決策であり、私はあなたがそれを行うことができるとは知りませんでした...!この時点でミドルウェアを使うべきかどうか疑問に思っていましたが、そうすべきだと思われます。ドキュメントには、そのようなことは何も記載されていません。もう一度ありがとう
アレックス

1
@Alexはい、すべてのコントローラーアクションで実行される共通のコードであれば、ミドルウェアとして実装することは悪い考えではないと思います。
Noman Ur Rehman 2015年

5

それは非常に簡単です:

ミドルウェアコードは次のとおりです。

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

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

    return $next($request);
}

そしてここにコントローラーコードがあります:

$request->customVar;

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>

みんなに感謝し、コードを楽しんでください:)


1

私は英語を話せないので...エラーの可能性をお詫びします。

これにはIoCバインディングを使用できます。ミドルウェアでは、$ pageインスタンスをバインドするためにこれを行うことができます。

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

その後、コントローラーでそのインスタンスを呼び出します。

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

App :: instanceはクラスを再インスタンス化せず、代わりに以前にバインドされたインスタンスを返します。


1

次の方法でRequest-objectに値を追加できました。

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

そして、後でそれらを取り戻す:

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

これが可能なのは、laravelsRequestカスタムパラメータを保持することを目的としたParameterBagタイプの属性 " $ attributes "を持つsymfonysRequestを拡張しているためです。

これは、後続のミドルウェア、コントローラー、またはRequestオブジェクトにアクセスできるその他の場所にデータを渡すためのベストプラクティスであると思います。

Laravel 5.6でテストされていますが、おそらく他のバージョンでも動作します。


1

$requestは配列であるため、値とキーを配列に追加$requestし、コントローラーでこのキーを使用してを取得できます。

$request['id'] = $id;

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.