У меня есть два контроллера SubmitPerformanceController
и PrintReportController
.
В PrintReportController
у меня есть метод под названием getPrintReport
.
Как получить доступ к этому методу в SubmitPerformanceController
?
Вы можете получить доступ к вашему методу контроллера следующим образом:
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
}
}
Сделайте то же самое для других контроллеров, где вам нужна эта реализация. Приобретение методов контроллера из других контроллеров - это запах кода.
Services
», если проект не большой, либо папка с функциями « Reporting
если это крупный проект, в котором используется структура « Folders By Feature
.
Вызов контроллера из другого контроллера не рекомендуется, однако если по какой-либо причине вы должны это сделать, вы можете сделать это:
совместимый с Laravel 5 метод
return \App::call('bla\bla\ControllerName@functionName');
Примечание. это не приведет к обновлению URL-адреса страницы.
Лучше называть Route вместо этого и позволить ему вызвать контроллер.
return \Redirect::route('route-name-here');
Вы не должны. Его анти-шаблон. Если у вас есть метод в одном контроллере, который вам нужен для доступа к другому контроллеру, то это знак, который вам нужно изменить.
Рассмотрим перефакторинг метода в классе обслуживания, который затем можно создать в нескольких контроллерах. Поэтому, если вам нужно предлагать отчеты о печати для нескольких моделей, вы можете сделать что-то вроде этого:
class ExampleController extends Controller
{
public function printReport()
{
$report = new PrintReport($itemToReportOn);
return $report->render();
}
}
Прежде всего, метод запроса контроллера с другого контроллера - это ЗЛО. Это вызовет много скрытых проблем жизненного цикла в Laravel.
Во всяком случае, для этого есть много решений. Вы можете выбрать один из этих способов.
Но вы не можете использовать никакие параметры или аутентификацию.
app(\App\Http\Controllers\PrintReportContoller::class)->getPrintReport();
Вы можете использовать любые параметры и что-то. Лучшее решение для вашей жизни программирования. Вместо Repository
можно сделать Repository
.
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 ...
}
}
MakesHttpRequests
, используемый при тестировании блока приложений.Я рекомендую, если у вас есть особые причины для создания этого прокси. Вы можете использовать любые параметры и пользовательские заголовки. Также этот будет внутренним запросом в laravel. (Fake HTTP Request). Вы можете найти более подробные руководства для метода 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 ...
}
}
Однако это тоже не "хорошее" решение.
Самое страшное решение, которое я думаю. Вы можете использовать любые параметры и настраиваемые заголовки. Но это делает внешний дополнительный HTTP-запрос. Таким образом, должен работать HTTP-сервер.
$client = new Client([
'base_uri' => request()->getSchemeAndhttpHost(),
'headers' => request()->header()
]);
$a = $client->get('/performance/submit')->getBody()->getContents()
Наконец, я использую способ 1 случая 2. Мне нужны параметры и
\App::call('App\Http\Controllers\MyController@getFoo')
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');
}
}
app('App\Http\Controllers\PrintReportController')->getPrintReport();
может быть преобразовано вapp(PrintReportController::class')->getPrintReport()
. Чистое решение для меня.