У меня есть два контроллера 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
)
Вы можете прочитать больше о чертах здесь .
app('App\Http\Controllers\PrintReportController')->getPrintReport();
может преобразоваться в app(PrintReportController::class')->getPrintReport()
. Чистое решение для меня.
Если вам нужен этот метод в другом контроллере, это означает, что вам нужно абстрагировать его и сделать его многоразовым. Переместите эту реализацию в класс обслуживания (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();
}
}
\App::call('App\Http\Controllers\MyController@getFoo')
Прежде всего, запрос метода контроллера от другого контроллера - ЗЛО. Это вызовет много скрытых проблем в жизненном цикле 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. Мне нужны параметры и
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();
}
}
Вы можете использовать статический метод в 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();
}
}
Здесь эта черта полностью эмулирует работу контроллера через маршрутизатор laravel (включая поддержку промежуточного программного обеспечения и внедрение зависимостей). Протестировано только с версией 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()->make(......)
равно, app(......)
поэтому оно короче.
Вы можете получить доступ к контроллеру, создав его экземпляр и вызвав doAction: (поместите use Illuminate\Support\Facades\App;
перед объявлением класса контроллера)
$controller = App::make('\App\Http\Controllers\YouControllerName');
$data = $controller->callAction('controller_method', $parameters);
Также обратите внимание, что, выполнив это, вы не будете выполнять какие-либо промежуточные программы, объявленные на этом контроллере.
Поздний ответ, но я долго искал это. Теперь это возможно очень простым способом.
Без параметров
return redirect()->action('HomeController@index');
С параметрами
return redirect()->action('UserController@profile', ['id' => 1]);
Документы: https://laravel.com/docs/5.6/responses#redirecting-controller-actions
Еще в 5.0 для этого требовался весь путь, теперь все намного проще.