У меня есть два контроллера SubmitPerformanceController
и PrintReportController
.
В PrintReportController
у меня есть метод под названием getPrintReport
.
Как получить доступ к этому методу в SubmitPerformanceController
?
У меня есть два контроллера SubmitPerformanceController
и PrintReportController
.
В PrintReportController
у меня есть метод под названием getPrintReport
.
Как получить доступ к этому методу в SubmitPerformanceController
?
Вы можете получить доступ к своему методу контроллера следующим образом:
app('App\Http\Controllers\PrintReportController')->getPrintReport();
Это будет работать, но плохо с точки зрения организации кода (не забывайте использовать правильное пространство имен для вашего PrintReportController
)
Вы можете расширить PrintReportController
, чтобы SubmitPerformanceController
унаследовал этот метод
class SubmitPerformanceController extends PrintReportController {
// ....
}
Но это также унаследует все другие методы от PrintReportController
.
Наилучшим подходом будет создание trait
(например, в app/Traits
), реализация логики и указание контроллерам использовать его:
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\[email protected]');
Примечание. это не приведет к обновлению 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
вместо 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 ...
}
}
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 ...
}
}
Однако это тоже не "хорошее" решение.
Это самое ужасное решение, я думаю. Вы также можете использовать любые параметры и пользовательские заголовки. Но это будет делать внешний дополнительный http-запрос. Таким образом, HTTP Webserver должен быть запущен.
$client = new Client([
'base_uri' => request()->getSchemeAndhttpHost(),
'headers' => request()->header()
]);
$a = $client->get('/performance/submit')->getBody()->getContents()
Наконец, я использую способ 1 из случая 2. Мне нужны параметры и
\App::call('App\Http\Controllers\[email protected]')
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');
}
}
Поздний ответ, но я долго искал это. Теперь это возможно очень простым способом.
Без параметров
return redirect()->action('[email protected]');
с параметрами
return redirect()->action('[email protected]', ['id' => 1]);
Документы: https://laravel.com/docs/5.6/responses#redirecting-controller-actions
Еще в 5.0 для этого требовался весь путь, теперь все намного проще.
Вы можете использовать статический метод в PrintReportController и затем вызывать его из SubmitPerformanceController следующим образом:
namespace App\Http\Controllers;
class PrintReportController extends Controller
{
public static function getPrintReport()
{
return "Printing report";
}
}
namespace App\Http\Controllers;
use App\Http\Controllers\PrintReportController;
class SubmitPerformanceController extends Controller
{
public function index()
{
echo PrintReportController::getPrintReport();
}
}
Вы можете получить доступ к контроллеру, создав его экземпляр и вызвав doAction: (поместите use Illuminate\Support\Facades\App;
перед объявлением класса контроллера)
$controller = App::make('\App\Http\Controllers\YouControllerName');
$data = $controller->callAction('controller_method', $parameters);
Также обратите внимание, что при этом вы не будете запускать какое-либо промежуточное программное обеспечение, объявленное на этом контроллере.