Способ контроллера доступа от другого контроллера в Laravel 5
у меня есть два контроллера SubmitPerformanceController
и PrintReportController
.
на PrintReportController
У меня есть метод, называемый getPrintReport
.
как получить доступ к этому методу в SubmitPerformanceController
?
8 ответов:
вы можете получить доступ к методу контроллера, как это:
app('App\Http\Controllers\PrintReportController')->getPrintReport();
это будет работать, но это плохо с точки зрения организации кода (не забудьте использовать правильные пространства имен
PrintReportController
)вы можете продлить
PrintReportController
такSubmitPerformanceController
унаследует этот методclass SubmitPerformanceController extends PrintReportController { // .... }
но это также наследует все другие методы от
PrintReportController
.лучшим подходом будет создание
trait
, реализуйте логику там и скажите своим контроллерам чтобы использовать его:trait PrintReport { public function getPrintReport() { // ..... } }
скажите вашим контроллерам использовать эту особенность:
class PrintReportController extends Controller { use PrintReport; } class SubmitPerformanceController extends Controller { use PrintReport; }
как сделать
SubmitPerformanceController
иметьgetPrintReport
метод, так что вы можете вызвать его с$this->getPrintReport();
внутри контроллера или непосредственно в качестве маршрута (если вы нанесли его вroutes.php
)вы можете прочитать больше о чертах здесь.
Если вам нужен этот метод в другом контроллере, это означает, что вам нужно абстрагировать его и сделать его многоразовым. Переместите эту реализацию в класс обслуживания (ReportingService или что-то подобное) и вставьте ее в свои контроллеры.
пример:
class ReportingService { public function getPrintReport() { // your implementation here. } } // don't forget to import ReportingService at the top (use Path\To\Class) class SubmitPerformanceController extends Controller { protected $reportingService; public function __construct(ReportingService $reportingService) { $this->reportingService = $reportingService; } public function reports() { // call the method $this->reportingService->getPrintReport(); // rest of the code here } }
сделайте то же самое для других контроллеров, где вам нужна эта реализация. Достижение методов контроллера от других контроллеров-это запах кода.
вызов контроллера с другого контроллера не рекомендуется, однако если по какой-либо причине вы должны это сделать, вы можете сделать это:
фреймворк Laravel 5 совместимый метод
return \App::call('bla\bla\ControllerName@functionName');
Примечание: это не будет обновлять URL-адрес страницы.
вместо этого лучше вызвать маршрут и позволить ему вызвать контроллер.
return \Redirect::route('route-name-here');
вы не должны. Это анти-паттерн. Если у вас есть метод в одном контроллере, к которому вам нужно получить доступ в другом контроллере, то это знак, который вам нужно изменить.
рассмотрите возможность повторного факторинга метода в класс обслуживания, который затем можно создать в нескольких контроллерах. Так что если вам нужно предложить печать отчетов для нескольких моделей, вы можете сделать что-то вроде этого:
class ExampleController extends Controller { public function printReport() { $report = new PrintReport($itemToReportOn); return $report->render(); } }
прежде всего, метод запроса контроллера от другого контроллера-это зло. Это вызовет много скрытых проблем жизненного цикла в Laravel.
в любом случае, есть много решений для этого. Вы можете выбрать один из этих различных способов.
Случай 1) Если вы хотите позвонить на основе классов
Способ 1) простой способ
а вы не может никаких параметров или аутентификации таким образом.
app(\App\Http\Controllers\PrintReportContoller::class)->getPrintReport();
Способ 2) Сделать разделите логику службы в контроллерах.
вы может какие-то параметры и что-то С этим. Лучшее решение для вашего программирования жизни. Вы можете сделать
Repository
вместоService
.class PrintReportService { ... public function getPrintReport() { return ... } } class PrintReportController extends Controller { ... public function getPrintReport() { return (new PrintReportService)->getPrintReport(); } } class SubmitPerformanceController { ... public function getSomethingProxy() { ... $a = (new PrintReportService)->getPrintReport(); ... return ... } }
случай 2) Если вы хотите позвонить на основе маршрута
Способ 1) Использовать
MakesHttpRequests
признак, который используется в модульном тестировании приложений.я рекомендую, если у вас есть особые причины для этого прокси. Ты смогите использовать все параметры и таможню заголовки. И это будет внутренний запрос в фреймворк Laravel. (Поддельный HTTP-запрос) вы можете увидеть более подробные инструкции для
call
метод здесь.class SubmitPerformanceController extends \App\Http\Controllers\Controller { use \Illuminate\Foundation\Testing\Concerns\MakesHttpRequests; protected $baseUrl = null; protected $app = null; function __construct() { // Require if you want to use MakesHttpRequests $this->baseUrl = request()->getSchemeAndHttpHost(); $this->app = app(); } public function getSomethingProxy() { ... $a = $this->call('GET', '/printer/report')->getContent(); ... return ... } }
однако это тоже не "хорошее" решение.
Способ 2) Используйте клиент guzzlehttp
самое страшное решение, я думаю. Ты можно использовать любые параметры и пользовательские заголовки тоже. Но это делает внешний дополнительный HTTP-запрос. Так что HTTP веб-сервер должен быть бегущий.
$client = new Client([ 'base_uri' => request()->getSchemeAndhttpHost(), 'headers' => request()->header() ]); $a = $client->get('/performance/submit')->getBody()->getContents()
наконец, я использую Способ 1 случая 2. Мне нужны параметры и
namespace App\Http\Controllers; //call the controller you want to use its methods use App\Http\Controllers\AdminController; use Illuminate\Http\Request; use App\Http\Requests; class MealController extends Controller { public function try_call( AdminController $admin){ return $admin->index(); } }
здесь признак полностью эмулирует запущенный контроллер маршрутизатором laravel (включая поддержку middlewares и инъекцию зависимостей). Протестировано только с версией 5.4
<?php namespace App\Traits; use Illuminate\Pipeline\Pipeline; use Illuminate\Routing\ControllerDispatcher; use Illuminate\Routing\MiddlewareNameResolver; use Illuminate\Routing\SortedMiddleware; trait RunsAnotherController { public function runController($controller, $method = 'index') { $middleware = $this->gatherControllerMiddleware($controller, $method); $middleware = $this->sortMiddleware($middleware); return $response = (new Pipeline(app())) ->send(request()) ->through($middleware) ->then(function ($request) use ($controller, $method) { return app('router')->prepareResponse( $request, (new ControllerDispatcher(app()))->dispatch( app('router')->current(), $controller, $method ) ); }); } protected function gatherControllerMiddleware($controller, $method) { return collect($this->controllerMidlleware($controller, $method))->map(function ($name) { return (array)MiddlewareNameResolver::resolve($name, app('router')->getMiddleware(), app('router')->getMiddlewareGroups()); })->flatten(); } protected function controllerMidlleware($controller, $method) { return ControllerDispatcher::getMiddleware( $controller, $method ); } protected function sortMiddleware($middleware) { return (new SortedMiddleware(app('router')->middlewarePriority, $middleware))->all(); } }
затем просто добавьте его в свой класс и запустить контроллер. Обратите внимание, что инъекция зависимостей будет назначена с вашим текущим маршрутом.
class CustomController extends Controller { use RunsAnotherController; public function someAction() { $controller = app()->make('App\Http\Controllers\AnotherController'); return $this->runController($controller, 'doSomething'); } }