来自 Laravel 5 中另一个控制器的访问控制器方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30365169/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Access Controller method from another controller in Laravel 5
提问by Iftakharul Alam
I have two controllers SubmitPerformanceController
and PrintReportController
.
我有两个控制器SubmitPerformanceController
和PrintReportController
.
In PrintReportController
I have a method called getPrintReport
.
在PrintReportController
我有一个名为getPrintReport
.
How to access this method in SubmitPerformanceController
?
如何访问此方法SubmitPerformanceController
?
回答by Sh1d0w
You can access your controller method like this:
您可以像这样访问控制器方法:
app('App\Http\Controllers\PrintReportController')->getPrintReport();
This will work, but it's bad in terms of code organisation (remember to use the right namespace for your PrintReportController
)
这会起作用,但在代码组织方面很糟糕(记住为您的 使用正确的命名空间PrintReportController
)
You can extend the PrintReportController
so SubmitPerformanceController
will inherit that method
您可以扩展PrintReportController
所以SubmitPerformanceController
将继承该方法
class SubmitPerformanceController extends PrintReportController {
// ....
}
But this will also inherit all other methods from PrintReportController
.
但这也将从PrintReportController
.
The best approach will be to create a trait
(e.g. in app/Traits
), implement the logic there and tell your controllers to use it:
最好的方法是创建一个trait
(例如 in app/Traits
),在那里实现逻辑并告诉您的控制器使用它:
trait PrintReport {
public function getPrintReport() {
// .....
}
}
Tell your controllers to use this trait:
告诉你的控制器使用这个特性:
class PrintReportController extends Controller {
use PrintReport;
}
class SubmitPerformanceController extends Controller {
use PrintReport;
}
Both solutions make SubmitPerformanceController
to have getPrintReport
method so you can call it with $this->getPrintReport();
from within the controller or directly as a route (if you mapped it in the routes.php
)
两种解决方案都SubmitPerformanceController
具有getPrintReport
方法,因此您可以$this->getPrintReport();
从控制器内部或直接作为路由调用它(如果您将其映射到routes.php
)
You can read more about traits here.
您可以在此处阅读有关特征的更多信息。
回答by Ruffles
If you need that method in another controller, that means you need to abstract it and make it reusable. Move that implementation into a service class (ReportingService or something similar) and inject it into your controllers.
如果您需要在另一个控制器中使用该方法,则意味着您需要对其进行抽象并使其可重用。将该实现移动到一个服务类(ReportingService 或类似的东西)中并将其注入到您的控制器中。
Example:
例子:
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
}
}
Do the same for the other controllers where you need that implementation. Reaching for controller methods from other controllers is a code smell.
对需要该实现的其他控制器执行相同操作。从其他控制器获取控制器方法是一种代码味道。
回答by Mahmoud Zalt
Calling a Controller from another Controller is not recommended, however if for any reason you have to do it, you can do this:
不建议从另一个控制器调用控制器,但是如果出于任何原因必须这样做,您可以这样做:
Laravel 5 compatible method
Laravel 5 兼容方法
return \App::call('bla\bla\ControllerName@functionName');
Note:this will not update the URL of the page.
注意:这不会更新页面的 URL。
It's better to call the Route instead and let it call the controller.
最好改为调用 Route 并让它调用控制器。
return \Redirect::route('route-name-here');
回答by Martin Bean
You shouldn't. It's an anti-pattern. If you have a method in one controller that you need to access in another controller, then that's a sign you need to re-factor.
你不应该。这是一种反模式。如果您需要在另一个控制器中访问一个控制器中的方法,那么这是您需要重构的标志。
Consider re-factoring the method out in to a service class, that you can then instantiate in multiple controllers. So if you need to offer print reports for multiple models, you could do something like this:
考虑将方法重构为一个服务类,然后您可以在多个控制器中实例化。因此,如果您需要为多个模型提供打印报告,您可以执行以下操作:
class ExampleController extends Controller
{
public function printReport()
{
$report = new PrintReport($itemToReportOn);
return $report->render();
}
}
回答by the_hasanov
\App::call('App\Http\Controllers\MyController@getFoo')
回答by kargnas
First of all, requesting a method of a controller from another controller is EVIL. This will cause many hidden problems in Laravel's life-cycle.
首先,从另一个控制器请求一个控制器的方法是邪恶的。这会在 Laravel 的生命周期中造成很多隐藏的问题。
Anyway, there are many solutions for doing that. You can select one of these various ways.
无论如何,有很多解决方案可以做到这一点。您可以选择这些不同的方式之一。
Case 1) If you want to call based on Classes
案例 1) 如果您想基于 Classes 调用
Way 1) The simple way
方式1)简单的方式
But you can't add any parameters or authenticationwith this way.
但是您不能通过这种方式添加任何参数或身份验证。
app(\App\Http\Controllers\PrintReportContoller::class)->getPrintReport();
Way 2) Divide the controller logic into services.
方式2)将控制器逻辑划分为服务。
You can add any parameters and somethingwith this. The best solution for your programming life. You can make Repository
instead Service
.
你可以添加任何参数和一些东西。编程生活的最佳解决方案。你可以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 ...
}
}
Case 2) If you want to call based on Routes
案例 2) 如果您想根据 Routes 进行呼叫
Way 1) Use MakesHttpRequests
trait that used in Application Unit Testing.
方式1)使用MakesHttpRequests
应用程序单元测试中使用的特征。
I recommend this if you have special reason for making this proxy, you can use any parameters and custom headers. Also this will be an internal requestin laravel. (Fake HTTP Request) You can see more details for the call
method in here.
如果您有特殊原因制作此代理,我建议您这样做,您可以使用任何参数和自定义标头。这也将是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 ...
}
}
However this is not a 'good' solution, too.
然而,这也不是一个“好”的解决方案。
Way 2) Use guzzlehttp client
方式2)使用guzzlehttp客户端
This is the most terrible solution I think. You can use any parameters and custom headers, too. But this would be making an external extra http request. So HTTP Webserver must be running.
这是我认为最糟糕的解决方案。您也可以使用任何参数和自定义标头。但这将是一个外部额外的 http 请求。所以HTTP Webserver 必须正在运行。
$client = new Client([
'base_uri' => request()->getSchemeAndhttpHost(),
'headers' => request()->header()
]);
$a = $client->get('/performance/submit')->getBody()->getContents()
Finally I am using Way 1 of Case 2. I need parameters and
最后我使用案例 2 的方式 1。我需要参数和
回答by Ahmed Mahmoud
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();
}
}
回答by Anton
Here the trait fully emulates running controller by laravel router (including support of middlewares and dependency injection). Tested only with 5.4 version
这里 trait 完全模拟了 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();
}
}
Then just add it to your class and run the controller. Note, that dependency injection will be assigned with your current route.
然后只需将它添加到您的类并运行控制器。请注意,依赖注入将分配给您当前的路由。
class CustomController extends Controller {
use RunsAnotherController;
public function someAction()
{
$controller = app()->make('App\Http\Controllers\AnotherController');
return $this->runController($controller, 'doSomething');
}
}
回答by TheLastCodeBender
You can use a static method in PrintReportController and then call it from the SubmitPerformanceController like this;
您可以在 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();
}
}
回答by Abhijeet Navgire
You can access the controller by instantiating it and calling doAction: (put use Illuminate\Support\Facades\App;
before the controller class declaration)
您可以通过实例化它并调用 doAction 来访问控制器:(放在use Illuminate\Support\Facades\App;
控制器类声明之前)
$controller = App::make('\App\Http\Controllers\YouControllerName');
$data = $controller->callAction('controller_method', $parameters);
Also note that by doing this you will not execute any of the middlewares declared on that controller.
另请注意,通过这样做,您将不会执行在该控制器上声明的任何中间件。