IT story

Laravel 5의 다른 컨트롤러에서 액세스 컨트롤러 방법

hot-time 2020. 7. 12. 09:31
반응형

Laravel 5의 다른 컨트롤러에서 액세스 컨트롤러 방법


두 개의 컨트롤러 SubmitPerformanceControllerPrintReportController있습니다.

에라 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)

특성에 대한 자세한 내용은 여기를 참조 하십시오 .


다른 컨트롤러에서 해당 방법이 필요한 경우이를 추상화하여 재사용 할 수 있어야합니다. 해당 구현을 서비스 클래스 (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
  }
}

해당 구현이 필요한 다른 컨트롤러에 대해서도 동일하게 수행하십시오. 다른 컨트롤러에서 컨트롤러 방법에 도달하면 코드 냄새가납니다.


다른 컨트롤러에서 컨트롤러를 호출하는 것은 권장되지 않지만 어떤 이유로 든해야 할 경우 다음을 수행 할 수 있습니다.

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

우선, 다른 컨트롤러에서 컨트롤러의 메소드를 요청하는 것은 EVIL입니다. 이것은 라 라벨의 라이프 사이클에서 많은 숨겨진 문제를 일으킬 것입니다.

어쨌든, 그렇게하는 많은 솔루션이 있습니다. 이러한 다양한 방법 중 하나를 선택할 수 있습니다.

사례 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) 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 ...
    }
}

그러나 이것은 또한 '좋은'해결책이 아닙니다.

방법 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.

$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


\App::call('App\Http\Controllers\MyController@getFoo')

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

Here the trait fully emulates running controller by laravel router (including support of middlewares and dependency injection). Tested only with 5.4 version

<?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');
    }
}

Late reply, but I have been looking for this for sometime. This is now possible in a very simple way.

Without parameters

return redirect()->action('HomeController@index');

With Parameters

return redirect()->action('UserController@profile', ['id' => 1]);

Docs: https://laravel.com/docs/5.6/responses#redirecting-controller-actions

Back in 5.0 it required the entire path, now it's much simpler.


You can use a static method in PrintReportController and then call it from the SubmitPerformanceController like this;

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();

    }

}

참고URL : https://stackoverflow.com/questions/30365169/access-controller-method-from-another-controller-in-laravel-5

반응형