我有两个控制器SubmitPerformanceController和PrintReportController。

在PrintReportController中,我有一个叫做getPrintReport的方法。

如何在submitperformanceccontroller中访问此方法?


当前回答

如果您在另一个控制器中需要该方法,这意味着您需要抽象它并使其可重用。将该实现移动到服务类(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
  }
}

对需要该实现的其他控制器执行相同的操作。从其他控制器中获取控制器方法是一种代码气味。

其他回答

当然,你可以实例化另一个控制器并调用你想要的方法。也许这不是一个好的做法,但我不知道为什么:

$otherController = new OtherController();
$otherController->methodFromOtherController($param1, $param2 ...);

但是,这样做,你会有一个问题:另一个方法返回类似response()->json($result)的东西,这不是你想要的。 为了解决这个问题,定义另一个控制器的方法的第一个参数为:

public function methodFromOtherController(Request $request = null, ...

当你从主控制器调用methodFromOtherController时,你将把null作为第一个参数值:

$otherController = new OtherController();
$otherController->methodFromOtherController(null, $param1, $param2 ...);

最后,在methodFromOtherController方法的末尾创建一个条件:

public function methodFromOtherController(Request $request = null, ...) 
{
  ...
  if (is_null($request)) {
    return $result;
  } else {
    return response()->json($result);
  }
}

一旦Laravel在通过直接路由调用时设置$request,您就可以区分每种情况并返回相应的值。

这里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();
    }
}

然后将它添加到类中并运行控制器。注意,依赖注入将与当前路由一起分配。

class CustomController extends Controller {
    use RunsAnotherController;

    public function someAction() 
    {
        $controller = app()->make('App\Http\Controllers\AnotherController');

        return $this->runController($controller, 'doSomething');
    }
}
//In Controller A <br >
public static function function1(){

}


//In Controller B, View or anywhere <br>
A::function1();

首先,从另一个控制器请求一个控制器的方法是邪恶的。这将在Laravel的生命周期中造成许多隐藏的问题。

不管怎样,有很多解决方法。你可以从这些不同的方法中选择一种。

案例1)如果你想基于类调用

方法1)简单的方法

但是您不能用这种方式添加任何参数或身份验证。

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

方法2)将控制器逻辑划分为服务。

你可以添加任何参数。这是您编程生涯的最佳解决方案。您可以使用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)使用应用单元测试中使用的makeshttprequest特性。

我建议,如果你有特殊的原因做这个代理,你可以使用任何参数和自定义头。这也将是laravel的内部要求。(假HTTP请求)你可以在这里看到调用方法的更多细节。

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 ...
    }
}

然而,这也不是一个“好的”解决方案。

方法2)使用guzzlehttp客户端

我认为这是最糟糕的解决方案。您还可以使用任何参数和自定义标头。但是这会产生一个外部额外的http请求。所以HTTP web服务器必须在运行。

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

你可以在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();

    }

}