来自Laravel 5中另一个控制器的访问控制器方法

我有两个控制器SubmitPerformanceControllerPrintReportController

PrintReportController我有一个名为getPrintReport的方法。

如何在SubmitPerformanceController访问此方法?

你可以像这样访问你的控制器方法:

 app('App\Http\Controllers\PrintReportController')->getPrintReport(); 

这将起作用,但在代码组织方面却不好(请记住为您的PrintReportController使用正确的名称空间)

您可以扩展PrintReportController以便SubmitPerformanceController将inheritance该方法

 class SubmitPerformanceController extends PrintReportController { // .... } 

但是这也会inheritancePrintReportController所有其他方法。

最好的方法是创build一个trait ,实现那里的逻辑并告诉你的控制器使用它:

 trait PrintReport { public function getPrintReport() { // ..... } } 

告诉你的控制器使用这个特性:

 class PrintReportController extends Controller { use PrintReport; } class SubmitPerformanceController extends Controller { use PrintReport; } 

两种解决scheme都使SubmitPerformanceController具有getPrintReport方法,因此您可以使用$this->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 } } 

对于其他需要执行的控制器,请执行相同的操作。 从其他控制器到达控制器方法是一种代码味道。

不build议从另一个控制器调用控制器,但是如果出于任何原因必须这样做,可以这样做:

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(); } } 
 \App::call('App\Http\Controllers\MyController@getFoo') 

首先,从另一个控制器请求控制器的方法是EVIL。 这将导致许多Laravel生命周期的隐藏问题。

无论如何,有很多解决scheme来做到这一点。 您可以select其中一种方法。

情况1)如果你想要基于类的调用

方法1)简单的方法

但是你不能以这种方式进行任何参数或authentication

 app(\App\Http\Controllers\PrintReportContoller::class)->getPrintReport(); 

方式2)制定控制器中的服务逻辑。

可以用任何参数和东西 。 为您的编程生活提供最佳解决scheme。 您可以将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特征,用于应用程序unit testing。

我build议如果你有这个代理的特殊原因。 您可以使用任何参数和自定义标题 。 这也将是 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 ... } } 

然而,这也不是“好”的解决scheme。

方法2)使用guzzlehttp客户端

我想最可怕的解决scheme。 您也可以使用任何参数和自定义标题 。 但是这使得外部额外的http请求。 所以HTTP Webserver必须运行。

 $client = new Client([ 'base_uri' => request()->getSchemeAndhttpHost(), 'headers' => request()->header() ]); $a = $client->get('/performance/submit')->getBody()->getContents() 

最后,我正在使用案例2的方法1.我需要参数和

这里trait完全模拟laravel路由器的运行控制器(包括中间件和dependency injection的支持)。 仅testing5.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级并运行控制器。 请注意,dependency injection将被分配您的当前路线。

 class CustomController extends Controller { use RunsAnotherController; public function someAction() { $controller = app()->make('App\Http\Controllers\AnotherController'); return $this->runController($controller, 'doSomething'); } } 
 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(); } }