Biến trả về Laravel Middleware cho bộ điều khiển


87

Tôi đang thực hiện kiểm tra quyền đối với người dùng để xác định xem họ có thể xem một trang hay không. Điều này liên quan đến việc chuyển yêu cầu qua một số phần mềm trung gian trước.

Vấn đề tôi gặp phải là tôi đang sao chép cùng một truy vấn cơ sở dữ liệu trong phần mềm trung gian và trong bộ điều khiển trước khi trả lại dữ liệu về chính chế độ xem.

Đây là một ví dụ về thiết lập;

- route.php

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

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

Như bạn có thể thấy, điều Page::with('users')->where('id', $id)->first()này được lặp lại trong cả phần mềm trung gian và bộ điều khiển. Tôi cần chuyển dữ liệu từ cái này sang cái kia để không bị trùng lặp.


Tôi cũng định hỏi như vậy, tôi đã mất nhiều thời gian để tìm ra câu trả lời này. Đây là câu hỏi của tôi. Tôi sẽ thêm nó vào đây vì lý do SEO / khả năng tìm thấy, hy vọng điều đó ổn: Laravel 5.0 - Tải mô hình trong phần mềm trung gian VÀ bộ điều khiển. Làm cách nào để tải một phiên bản của mô hình Users để cùng một phiên bản (chỉ một truy vấn cơ sở dữ liệu) có sẵn trong cả Middleware và Controller? Bởi vì trong phần mềm trung gian, tôi muốn kiểm tra xem người dùng có được Ủy quyền hay không và trong Bộ điều khiển, tôi có thể muốn trình bày thông tin về Người dùng hoặc thao tác Người dùng bằng cách nào đó.
alieninlondon

Câu trả lời:


136

Tôi tin rằng cách chính xác để làm điều này (trong Laravel 5.x) là thêm các trường tùy chỉnh của bạn vào thuộc tính thuộc tính.

Từ các nhận xét mã nguồn, chúng ta có thể thấy các thuộc tính được sử dụng cho các thông số tùy chỉnh:

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

Vì vậy, bạn sẽ thực hiện điều này như sau;

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

Sau đó, bạn có thể truy xuất thuộc tính bằng cách gọi:

\Request::get('myAttribute');

Hoặc từ đối tượng yêu cầu trong laravel 5.5+

 $request->get('myAttribute');

1
Làm thế nào để bạn truy cập các thuộc tính trong bộ điều khiển nhận?
user985366

1
thêm lớp yêu cầu đối số phương pháp điều khiển (IoC container) hoặc gọi tĩnh lớp \ Yêu cầu
Gaz_Edge

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

4
Wow, dung dịch này trông rất sạch!
schellingerht

3
Bạn cũng có thể sử dụng $request->request->add(['myAttribute' => 'myValue']);để có thể sử dụng viết tắt diệu getter$request->myAttribute
jonan.pineda

29

Thay vì các tham số yêu cầu tùy chỉnh, bạn có thể thực hiện theo mô hình đảo ngược điều khiển và sử dụng chèn phụ thuộc.

Trong phần mềm trung gian của bạn, hãy đăng ký Pagephiên bản của bạn :

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

Sau đó, khai báo rằng bộ điều khiển của bạn cần một Pagephiên bản:

class PagesController 
{
    protected $page;

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

Laravel sẽ tự động giải quyết sự phụ thuộc và khởi tạo bộ điều khiển của bạn với Pagephiên bản mà bạn đã ràng buộc trong phần mềm trung gian của mình.


1
Đây thực sự là một ý tưởng hay, tôi đã tiếp tục và tạo Nhà cung cấp dịch vụ sau đó đăng ký Vùng chứa dịch vụ. Bằng cách đó, khi cần một số thuộc tính, tôi sẽ chỉ đưa các phụ thuộc vào. Trong suốt và sạch hơn nhiều. Cảm ơn!
Arian Acosta

1
@ArianAcosta Xin vui lòng, bạn có thể giải thích một câu trả lời theo cách của bạn? Ý tôi là, cách sử dụng phương thức tiêm phụ thuộc và cách nó được liên kết với phần mềm trung gian.
JCarlosR

4
@JCarlos Chắc chắn rồi! Ý tưởng sẽ là có một lớp Service Container tùy chỉnh chứa dữ liệu thuộc tính bên trong mà bạn cần chuyển giữa phần mềm trung gian và bộ điều khiển. Nếu bạn đăng ký Vùng chứa dịch vụ đó là một singleton với $ this-> app-> singleton (...) thì nó sẽ luôn giống nhau mỗi khi bạn đưa nó vào. Vì vậy, về cơ bản, trước tiên bạn sẽ đưa nó vào phần mềm trung gian (bằng cách chỉ cần yêu cầu nó như một đối số), sau đó đưa dữ liệu vào bên trong nó và cuối cùng yêu cầu nó trong bộ điều khiển nơi bạn có thể truy cập dữ liệu. Xem laravel.com/docs/5.4/container chúc may mắn
Arian Acosta

2
Đây là một câu trả lời TUYỆT VỜI ... gọn gàng! :)
Pietro

5
Lưu ý: trong __constructor, nó không hoạt động, bởi vì phần mềm trung gian được tải sau hàm tạo của bộ điều khiển. Nhưng bạn có thể sử dụng DI trong bất kỳ hành động nào của bộ điều khiển.
Serhii Topolnytskyi

18

Trong laravel> = 5, bạn có thể sử dụng $request->mergephần mềm trung gian:

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

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

    return $next($request);
}

Và trong bộ điều khiển:

public function index(Request $request)
{

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

11
Tại sao bạn truy cập Request::instance()tĩnh thay vì sử dụng $request?
jjok

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

Như đã đề cập trong một trong các nhận xét ở trên cho laravel 5.3.x

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

Không hoạt động. Nhưng đặt biến như thế này trong phần mềm trung gian hoạt động

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

Tôi có thể tìm nạp dữ liệu bằng cách sử dụng cái này trong bộ điều khiển của mình

$request->get('key');

6

Tôi chắc chắn nếu có thể truyền dữ liệu từ phần mềm trung gian đến bộ điều khiển thì nó sẽ có trong tài liệu Laravel.

Hãy xem cái nàycái này , nó có thể hữu ích.

Tóm lại, bạn có thể thu thập dữ liệu của mình trên đối tượng yêu cầu đang được chuyển đến phần mềm trung gian. Mặt tiền xác thực Laravel cũng làm điều đó.

Vì vậy, trong phần mềm trung gian của bạn, bạn có thể có:

$request->myAttribute = "myValue";

Cảm ơn @norman - đó là một giải pháp tốt và tôi không biết bạn có thể làm được ...! Tôi đã tự hỏi liệu tôi có nên sử dụng phần mềm trung gian vào thời điểm này hay không, nhưng có vẻ như tôi nên làm vậy. Tài liệu không đề cập đến bất cứ điều gì thuộc loại này. Cảm ơn một lần nữa
Alex

1
@Alex Có, tôi nghĩ nếu nó là một đoạn mã chung thực thi trong mọi hành động của bộ điều khiển, thì việc triển khai nó như một phần mềm trung gian là một ý tưởng không tồi.
Noman Ur Rehman

5

Nó rất đơn giản:

Đây là mã phần mềm trung gian:

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

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

    return $next($request);
}

và đây là mã bộ điều khiển:

$request->customVar;

2

Nếu trang web của bạn có các trang cms đang được tìm nạp từ cơ sở dữ liệu và muốn hiển thị tiêu đề của chúng trong khối đầu trang và chân trang trên tất cả các trang của ứng dụng laravel thì hãy sử dụng phần mềm trung gian. Viết mã dưới đây vào phần mềm trung gian của bạ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);

}

Sau đó, truy cập header.blade.php và footer.blade.php của bạn và viết mã bên dưới để thêm liên kết của các trang 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>

Cảm ơn rất nhiều cho tất cả và tận hưởng mã :)


1

Tôi không nói được tiếng Anh, vì vậy ... xin lỗi vì những sai sót có thể xảy ra.

Bạn có thể sử dụng ràng buộc IoC cho việc này. Trong phần mềm trung gian của mình, bạn có thể thực hiện việc này để ràng buộc phiên bản $ page:

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

Sau đó, trong bộ điều khiển của bạn, bạn gọi phiên bản đó:

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

Ứng dụng :: instance không tái hiện lớp, thay vào đó trả về thể hiện ràng buộc trước đó.


1

Tôi đã có thể thêm các giá trị vào đối tượng Yêu cầu bằng:

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

và lấy lại chúng sau đó với:

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

Điều này có thể thực hiện được vì laravels Request mở rộng symfonys Request có thuộc tính " $ thuộc tính " của loại ParameterBag nhằm giữ các thông số tùy chỉnh .

Tôi nghĩ rằng đây nên là Phương pháp hay nhất để chuyển dữ liệu đến Phần mềm trung gian, Bộ điều khiển tiếp theo hoặc bất kỳ nơi nào khác nơi có thể truy cập đối tượng Yêu cầu.

Đã thử nghiệm với Laravel 5.6 , nhưng có lẽ cũng hoạt động với các phiên bản khác.


1

$requestlà mảng để chúng ta có thể thêm giá trị và khóa vào mảng và lấy $requestbằng khóa này trong bộ điều khiển.

$request['id'] = $id;

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.