2015-05-13 17 views
46

Ich führe eine Berechtigungsprüfung für einen Benutzer durch, um festzustellen, ob er eine Seite anzeigen kann oder nicht. Dies beinhaltet, dass die Anforderung zuerst durch eine Middleware geleitet wird.Laravel Middleware Rückgabevariable zum Controller

Das Problem, das ich habe, ist, dass ich die gleiche Datenbankabfrage in der Middleware und im Controller dupliziere, bevor ich die Daten zur Ansicht selbst zurückgebe.

Hier ist ein Beispiel für das Setup;

- routes.php

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

- PageUserMiddleware.php (Klasse 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]); 
} 

Wie Sie, die sehen können Page::with('users')->where('id', $id)->first() wird sowohl in der Middleware als auch im Controller wiederholt. Ich muss die Daten von einem zum anderen weitergeben, um nicht zu duplizieren.

+0

Ich wollte etwas ähnliches fragen, brauchte lange, um diese Antwort zu finden. Hier ist meine Frage. Ich werde es hier für SEO/Auffindbarkeit Gründe hinzufügen, hoffe, dass das in Ordnung ist: Laravel 5.0 - Laden Sie das Modell in Middleware UND Controller. Wie lade ich eine Instanz des Benutzermodells, sodass dieselbe Instanz (nur eine Datenbankabfrage) sowohl in der Middleware als auch im Controller verfügbar ist? Weil ich in der Middleware überprüfen möchte, ob der Benutzer autorisiert ist und in dem Controller möchte ich Informationen über den Benutzer präsentieren oder den Benutzer irgendwie manipulieren. – alieninlondon

Antwort

64

Ich glaube, der richtige Weg, dies zu tun (in Laravel 5.x) ist Ihre benutzerdefinierte Felder auf die Attribute Eigenschaft hinzufügen.

aus dem Quellcode Kommentare können wir für benutzerdefinierte Parameter Attribute gebraucht wird:

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

So würden Sie dies wie folgt implementieren;

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

können Sie abgerufene dann das Attribut durch den Aufruf:

\Request::get('myAttribute'); 
+0

Ich habe dies auf die richtige Antwort geändert. Während Norman Recht hatte, scheint dies Laravels Best Practices zu entsprechen. Danke – Alex

+0

Wie greifen Sie dann auf die Attribute im empfangenden Controller zu? – user985366

+0

Hinzufügen von Request-Klasse zu Controller-Methodenargumenten (IoC-Container) oder Aufruf der statischen Klasse \ Request –

6

Ich bin sicher, wenn es möglich wäre, Daten von einer Middleware zu einem Controller zu übertragen, dann wäre es in der Laravel-Dokumentation.

Werfen Sie einen Blick auf this und this, könnte es helfen.

Kurz gesagt, können Sie Ihre Daten auf das Anfrageobjekt, das an die Middleware übergeben wird, piggyback. Die Laravel Authentifizierungsfassade macht das auch.

Also, in Ihrer Middleware, können Sie haben:

$request->myAttribute = "myValue"; 
+0

Dank @norman - das ist eine gute Lösung und ich wusste nicht, dass Sie es tun könnten ...! Ich habe mich gefragt, ob ich an dieser Stelle überhaupt Middleware verwenden sollte, aber es scheint, ich sollte es tun. Die Dokumentation erwähnt nichts dergleichen. Nochmals vielen Dank – Alex

+1

@Alex Ja, ich denke, wenn es ein gemeinsames Stück Code ist, der in jeder Controller-Aktion ausgeführt wird, ist es keine schlechte Idee, es als Middleware zu implementieren. –

1

ich nicht Englisch sprechen, so ... für mögliche Fehler sorry.

Sie können die IoC-Bindung dafür verwenden. In Ihrer Middleware können Sie diese für die Bindung $ page Beispiel tun:

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

Nach, in dem Controller Sie diese Instanz anrufen:

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

Die App :: Instanz nicht die Klasse neu beispielsweise statt Die Instanz wird vorher verbindlich zurückgeliefert.

8

Anstelle von benutzerdefinierten Anforderungsparametern können Sie dem Inversion-of-Control-Muster folgen und Dependency Injection verwenden.

In Middleware, registrieren Sie Ihr Page Beispiel:

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

Dann erklären, dass die Steuerung über eine Page Instanz benötigt:

Laravel wird die Abhängigkeit und instanziiert den Controller automatisch

class PagesController 
{ 
    protected $page; 

    function __construct(Page $page) 
    { 
     $this->page = $page; 
    } 
} 
löst mit die Page Instanz, die Sie in Ihrer Middleware eingebunden haben.

+0

Das ist ein wirklich gutes Idee, ich ging voran und schuf einen Service Provider, dann einen Service-Container registriert. Auf diese Weise würde ich bei einigen Attributen nur die Abhängigkeiten einspeisen. Viel sauberer und transparenter. Vielen Dank! –

+0

@ArianAcosta Bitte, können Sie eine Antwort mit Ihrem Weg erarbeiten? Ich meine, wie Dependency-Injection und wie es mit der Middleware verbunden ist. – JCarlos

+2

@JCarlos Sicher! Die Idee wäre eine benutzerdefinierte Service-Container-Klasse, die als interne Eigenschaften die Daten enthält, die zwischen der Middleware und dem Controller ausgetauscht werden müssen. Wenn Sie diesen Service Container als Singleton mit $ this-> app-> singleton (...) registrieren, wird es immer dieselbe Instanz sein, wenn Sie es injizieren. Also, im Wesentlichen würden Sie es zuerst in die Middleware injizieren (indem Sie es einfach als Argument verwenden), dann legen Sie die Daten darin, und schließlich benötigen Sie es in der Steuerung, wo Sie auf die Daten zugreifen können. Siehe https://laravel.com/docs/5.4/container viel Glück –

11

In Laravel> = 5 Sie $request->merge in der Middleware verwenden:

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

    $request->merge(array("myVar" => "1234")); 

    return $next($request); 
} 

Und in der Steuerung:

public function index(Request $request) 
{ 

    $myVar = Request::instance()->query('myVar'); 
    ... 
} 
+0

Dieser Ansatz des gesunden Menschenverstandes funktioniert für mich. –

+4

Warum sollten Sie statisch auf 'Request :: instance()' zugreifen, anstatt '$ request' zu verwenden? – jjok

0

Was Laravel 5.3.x in einer der Kommentare oben genannten

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

Funktioniert nicht. Aber Setzen der Variable wie dies in der Middleware arbeitet

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

Ich konnte die Daten holen mit diesem in meinem Controller

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

$ request das Array ist so, dass wir nur Wert und Schlüssel zum hinzufügen Array und erhalten Sie die $ Anfrage mit diesem Schlüssel in der Steuerung.

$ anfrage ['id'] = $ id;

Verwandte Themen