Laravel Middleware возвращает переменную в контроллер

58

Я выполняю проверку прав пользователя, чтобы определить, могут ли они просматривать страницу или нет. Это включает в себя передачу запроса через некоторое промежуточное ПО.

Проблема заключается в том, что я дублирую один и тот же запрос базы данных в промежуточном программном обеспечении и в контроллере, прежде чем возвращать данные самому представлению.

Вот пример настройки;

- 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() повторяется как в промежуточном программном обеспечении, так и в контроллере. Мне нужно передать данные от одного к другому, чтобы не дублировать.

  • 0
    Я собирался спросить примерно то же самое, мне потребовалось много времени, чтобы найти этот ответ. Вот мой вопрос Я добавлю его сюда по причинам SEO / находимости, надеюсь, все в порядке: Laravel 5.0 - загрузка модели в промежуточное ПО и контроллер. Как загрузить экземпляр модели Users, чтобы один и тот же экземпляр (только один запрос к базе данных) был доступен как в Middleware, так и в Controller? Потому что в промежуточном программном обеспечении я хочу проверить, авторизован ли пользователь, а в контроллере я могу представить информацию о пользователе или каким-либо образом манипулировать им.
Теги:
laravel-5
laravel-middleware

11 ответов

82
Лучший ответ

Я считаю, что правильный способ сделать это (в Laravel 5.x) состоит в том, чтобы добавить ваши настраиваемые поля к свойству атрибутов.

Из комментариев исходного кода мы можем видеть, что атрибуты используются для пользовательских параметров:

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

Итак, вы бы выполнили это следующим образом:

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

Затем вы можете получить атрибут, вызвав:

\Request::get('myAttribute');
  • 0
    Я изменил это на правильный ответ. Хотя Норман был прав, похоже, это соответствует лучшим практикам Ларавела. Спасибо
  • 0
    Как вы тогда получаете доступ к атрибутам внутри принимающего контроллера?
Показать ещё 11 комментариев
13

В 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');
    ...
}
  • 0
    Этот подход здравого смысла работает для меня.
  • 9
    Почему вы $request к Request::instance() статически, а не используете $request ?
11

Вместо настраиваемых параметров запроса вы можете следовать шаблону инверсии управления и использовать инъекцию зависимостей.

В вашем промежуточном программном средстве зарегистрируйте экземпляр Page:

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

Затем объявите, что вашему контроллеру нужен экземпляр Page:

class PagesController 
{
    protected $page;

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

Laravel автоматически разрешит зависимость и создаст экземпляр вашего контроллера с экземпляром Page, который вы связали в своем промежуточном программном обеспечении.

  • 1
    Это действительно хорошая идея, я пошел дальше и создал поставщика услуг, затем зарегистрировал контейнер услуг. Таким образом, когда нужны некоторые атрибуты, я просто вставляю зависимости. Гораздо чище и прозрачнее. Спасибо!
  • 1
    @ArianAcosta Пожалуйста, не могли бы вы придумать ответ своим путем? Я имею в виду, как использовать внедрение зависимостей и как оно связано с промежуточным программным обеспечением.
Показать ещё 3 комментария
6

Я уверен, что если бы можно было передавать данные из промежуточного программного обеспечения в контроллер, это было бы в документации Laravel.

Посмотрите этот и этот, это может помочь.

Короче говоря, вы можете копировать свои данные на объект запроса, который передается промежуточному программному обеспечению. Фасад аутентификации Laravel тоже делает это.

Итак, в вашем промежуточном программном обеспечении вы можете:

$request->myAttribute = "myValue";
  • 0
    Спасибо @norman - это хорошее решение, и я не знал, что ты мог бы сделать это ...! Я задавался вопросом, должен ли я использовать промежуточное программное обеспечение на этом этапе вообще, но, похоже, я должен. В документации не упоминается ничего подобного. еще раз спасибо
  • 1
    @ Алекс Да, я думаю, что если это обычный кусок кода, который выполняется в каждом действии контроллера, неплохо было бы реализовать его в качестве промежуточного программного обеспечения.
4

Как упоминалось в одном из комментариев выше для laravel 5.3.x

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

Не работает. Но установка такой переменной в промежуточном программном обеспечении

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

Я мог бы извлечь данные, используя это в моем контроллере

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

Ларавел 5.7

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

а также

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

Это очень просто:

Вот код промежуточного программного обеспечения:

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

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

    return $next($request);
}

и вот код контроллера:

$request->customVar;
  • 0
    В моем случае это прекрасно работало, только не забудьте добавить запрос $ Request к вашему методу в контроллере.
2

$ request - это массив, так что мы можем просто добавить значение и ключ в массив и получить $ request с этим ключом в контроллере.

$ request ['id'] = $ id;

1

Я был в состоянии добавить значения к объекту запроса с:

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

и вернуть их позже с помощью:

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

Это возможно, потому что laravels Request расширяет запрос symfonys, имеющий атрибут " $ attribute " типа ParameterBag, предназначенный для хранения пользовательских параметров.

Я думаю, что это должна быть лучшая практика для передачи данных в последующее промежуточное ПО, контроллеры или любое другое место, где есть возможность доступа к объекту запроса.

Протестировано с Laravel 5.6, но, вероятно, также работает с другими версиями.

1

Я не говорю по-английски, поэтому... извините за возможные ошибки.

Для этого вы можете использовать привязку IoC. В вашем промежуточном программном обеспечении вы можете сделать это для привязки экземпляра $page:

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

После этого в контроллере вы вызываете этот экземпляр:

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

App:: instance не повторяет экземпляр класса, вместо этого возвращает экземпляр, предшествующий привязке.

0

Если на вашем сайте есть страницы 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>

Большое спасибо всем и наслаждайтесь кодом :)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню