두 개의 컨트롤러 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
(예 : in 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')
우선, 다른 컨트롤러에서 컨트롤러의 메소드를 요청하는 것은 EVIL입니다. 이것은 라 라벨의 라이프 사이클에서 많은 숨겨진 문제를 일으킬 것입니다.
어쨌든, 그렇게하는 많은 솔루션이 있습니다. 이러한 다양한 방법 중 하나를 선택할 수 있습니다.
그러나이 방법으로는 매개 변수 나 인증 을 추가 할 수 없습니다 .
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 웹 서버가 실행 중이어야합니다.
$client = new Client([
'base_uri' => request()->getSchemeAndhttpHost(),
'headers' => request()->header()
]);
$a = $client->get('/performance/submit')->getBody()->getContents()
마지막으로 Case 2의 Way 1을 사용하고 있습니다.
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();
}
}
여기서 특성은 라 라벨 라우터 (미들웨어 및 종속성 주입 지원 포함)에 의해 실행중인 컨트롤러를 완전히 에뮬레이트합니다. 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으로 돌아 가면 전체 경로가 필요했지만 훨씬 간단 해졌습니다.