Laravel Middleware kontrolöre değişken dönüşü


90

Bir kullanıcının bir sayfayı görüntüleyip görüntüleyemeyeceğini belirlemek için bir izin kontrolü yapıyorum. Bu, önce isteğin bazı ara yazılımlardan geçirilmesini içerir.

Sahip olduğum sorun, verileri görünümün kendisine döndürmeden önce ara yazılımda ve denetleyicide aynı veritabanı sorgusunu kopyalıyorum.

İşte kurulumun bir örneği;

- route.php

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

- PageUserMiddleware.php (PageUserMiddleware sınıfı)

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]);
}

Gördüğünüz gibi Page::with('users')->where('id', $id)->first(), hem ara yazılımda hem de denetleyicide tekrarlanıyor. Verileri birinden diğerine geçirmem gerekiyor, böylece kopyalamamalıyım.


Ben de aynı şeyi soracaktım, bu cevabı bulmam uzun zaman aldı. İşte sorum şu. SEO / bulunabilirlik nedenleri için buraya ekleyeceğim, umarım sorun olmaz: Laravel 5.0 - Modeli ara yazılım VE denetleyiciye yükleyin. Aynı örnek (yalnızca bir veritabanı sorgusu) hem Middleware hem de Controller'da mevcut olacak şekilde Users modelinin bir örneğini nasıl yüklerim? Çünkü ara yazılımda kullanıcının Yetkili olup olmadığını kontrol etmek istiyorum ve Kontrolörde Kullanıcı hakkında bilgi sunmak veya Kullanıcıyı bir şekilde manipüle etmek isteyebilirim.
alieninlondon

Yanıtlar:


140

Bunu yapmanın doğru yolunun (Laravel 5.x'te) özel alanlarınızı attributes özelliğine eklemek olduğuna inanıyorum.

Kaynak kodu yorumlarından, özniteliklerin özel parametreler için kullanıldığını görebiliriz:

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

Yani bunu şu şekilde gerçekleştirirsiniz;

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

Daha sonra şu çağrı yaparak özniteliği alabilirsiniz:

\Request::get('myAttribute');

Veya laravel 5.5+ içindeki istek nesnesinden

 $request->get('myAttribute');

1
Daha sonra alıcı denetleyicideki özniteliklere nasıl erişirsiniz?
user985366

1
denetleyici yöntemi argümanlarına (IoC konteyner) istek sınıfı ekleyin veya statik sınıfı çağırın \ İstek
Gaz_Edge

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

4
Vay canına, bu çözüm çok temiz görünüyor!
schellingerht

3
$request->request->add(['myAttribute' => 'myValue']);Magic getter kısaltmasını kullanmak için de kullanabilirsiniz$request->myAttribute
jonan.pineda

33

Özel istek parametreleri yerine, kontrolün ters çevrilmesi modelini izleyebilir ve bağımlılık yerleştirmeyi kullanabilirsiniz.

Ara yazılımınızda Pageörneğinizi kaydedin :

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

Ardından, denetleyicinizin bir Pageörneğe ihtiyacı olduğunu bildirin:

class PagesController 
{
    protected $page;

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

Laravel, bağımlılığı otomatik olarak çözecek ve Pageara yazılımınıza bağladığınız örnek ile denetleyicinizi başlatacaktır .


1
Bu gerçekten iyi bir fikir, devam ettim ve bir Servis Sağlayıcı oluşturdum ve ardından bir Servis Konteyneri kaydettim. Bu şekilde, bazı niteliklere ihtiyaç duyulduğunda, sadece bağımlılıkları enjekte ederdim. Çok daha temiz ve şeffaf. Teşekkürler!
Arian Acosta

1
@ArianAcosta Lütfen, kendi yönteminizle bir cevap verebilir misiniz? Demek istediğim, bağımlılık enjeksiyonu nasıl kullanılır ve ara yazılım ile nasıl ilişkilendirilir.
JCarlosR

4
@JCarlos Tabii! Buradaki fikir, ara yazılım ile denetleyici arasında iletmeniz gereken verileri dahili özellikler olarak tutan özel bir Hizmet Kapsayıcı sınıfına sahip olmak olacaktır. Bu Hizmet Konteynırını $ this-> app-> singleton (...) ile tekli olarak kaydederseniz, her enjekte ettiğinizde her zaman aynı örnek olacaktır. Yani, esasen önce onu ara katman yazılımına enjekte edersiniz (basitçe bir argüman olarak isteyerek), sonra veriyi içine koyarsınız ve son olarak verilere erişebileceğiniz denetleyiciye ihtiyaç duyarsınız. Bkz. Laravel.com/docs/5.4/container iyi şanslar
Arian Acosta

2
Bu BÜYÜK bir cevap ... güzel! :)
Pietro

5
Açıklama: __constructor'da çalışmıyor, çünkü ara katman denetleyicinin yapıcısından sonra yüklendi. Ancak DI'yi herhangi bir kontrolör eyleminde kullanabilirsiniz.
Serhii Topolnytskyi

19

Laravel> = 5'de $request->mergeara yazılımda kullanabilirsiniz :

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

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

    return $next($request);
}

Ve kontrolörde:

public function index(Request $request)
{

    $myVar = $request->instance()->query('myVar');
    ...
}

11
Neden Request::instance()kullanmak yerine statik olarak erişiyorsunuz $request?
jjok

18

Laravel 5.7

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

ve

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

8

Laravel 5.3.x için yukarıdaki yorumlardan birinde belirtildiği gibi

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

Çalışmıyor. Ancak değişkeni ara yazılımda bu şekilde ayarlamak,

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

Kontrol cihazımda bunu kullanarak verileri getirebilirim

$request->get('key');

6

Bir ara yazılımdan bir denetleyiciye veri iletmek mümkün olsaydı, o zaman Laravel belgelerinde olurdu.

Göz at bu ve bu , bu yardımcı olabilir.

Kısacası, verilerinizi ara katman yazılımına iletilen istek nesnesine geri yükleyebilirsiniz. Laravel kimlik doğrulama cephesi de bunu yapıyor.

Yani, ara yazılımınızda şunları yapabilirsiniz:

$request->myAttribute = "myValue";

Teşekkürler @norman - bu iyi bir çözüm ve bunu yapabileceğini bilmiyordum ...! Bu noktada ara yazılım kullanmalı mıyım diye sorguluyordum ama öyle görünüyor ki yapmalıyım. Belgeler bu türden hiçbir şeyden bahsetmiyor. Tekrar teşekkürler
Alex

1
@Alex Evet, bence her denetleyici eyleminde çalışan ortak bir kod parçasıysa, onu bir ara katman olarak uygulamak kötü bir fikir değil.
Noman Ur Rehman

5

O çok basit:

İşte ara yazılım kodu:

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

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

    return $next($request);
}

ve işte kontrolör kodu:

$request->customVar;

2

Web sitenizde veritabanından getirilen cms sayfaları varsa ve başlıklarını laravel uygulamasının tüm sayfalarında üstbilgi ve altbilgi bloğunda göstermek istiyorsanız, ara yazılım kullanın. Ara yazılımınıza aşağıdaki kodu yazın:

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);

}

Ardından header.blade.php ve footer.blade.php dosyalarınıza gidin ve cms sayfalarının bağlantılarını eklemek için aşağıdaki kodu yazın:

<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>

Herkese çok teşekkürler ve kodun tadını çıkarın :)


1

İngilizce bilmiyorum, bu yüzden ... olası hatalar için özür dilerim.

Bunun için IoC bağlamayı kullanabilirsiniz. Ara yazılımınızda, $ page örneğini bağlamak için bunu yapabilirsiniz:

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

Ardından, denetleyicinizde bu örneği çağırırsınız:

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

App :: örneği sınıfı yeniden örneklemez, bunun yerine örneği önceden bağlamayı döndürür.


1

İstek nesnesine şu değerleri ekleyebildim:

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

ve bunları daha sonra geri alın:

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

Bu mümkündür çünkü laravels Request , özel parametreleri tutması amaçlanan ParameterBag türünde " $ öznitelikler " özniteliğine sahip symfonys Request'i genişletir .

Bence bu, verileri sonraki Ara Yazılımlara, Denetleyicilere veya İstek nesnesine erişmenin mümkün olduğu diğer herhangi bir yere iletmek için En İyi Uygulama olmalıdır.

Laravel 5.6 ile test edildi , ancak muhtemelen diğer sürümlerle de çalışıyor.


1

$requestdizidir, böylece diziye sadece değer ve anahtar ekleyebilir ve $requestdenetleyicideki bu anahtarla elde edebiliriz.

$request['id'] = $id;

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.