来自Laravel 5中另一个控制器的访问控制器方法
我有两个控制器SubmitPerformanceController
和PrintReportController
。
在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(); } }