Способ контроллера доступа от другого контроллера в Laravel 5


у меня есть два контроллера SubmitPerformanceController и PrintReportController.

на PrintReportController У меня есть метод, называемый getPrintReport.

как получить доступ к этому методу в SubmitPerformanceController?

8 87

8 ответов:

вы можете получить доступ к методу контроллера, как это:

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

это будет работать, но это плохо с точки зрения организации кода (не забудьте использовать правильные пространства имен PrintReportController)

вы можете продлить PrintReportController так SubmitPerformanceController унаследует этот метод

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

но это также наследует все другие методы от PrintReportController.

лучшим подходом будет создание trait, реализуйте логику там и скажите своим контроллерам чтобы использовать его:

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-адрес страницы.

вместо этого лучше вызвать маршрут и позволить ему вызвать контроллер.

return \Redirect::route('route-name-here');

вы не должны. Это анти-паттерн. Если у вас есть метод в одном контроллере, к которому вам нужно получить доступ в другом контроллере, то это знак, который вам нужно изменить.

рассмотрите возможность повторного факторинга метода в класс обслуживания, который затем можно создать в нескольких контроллерах. Так что если вам нужно предложить печать отчетов для нескольких моделей, вы можете сделать что-то вроде этого:

class ExampleController extends Controller
{
    public function printReport()
    {
        $report = new PrintReport($itemToReportOn);
        return $report->render();
    }
}

прежде всего, метод запроса контроллера от другого контроллера-это зло. Это вызовет много скрытых проблем жизненного цикла в 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) Использовать 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

самое страшное решение, я думаю. Ты можно использовать любые параметры и пользовательские заголовки тоже. Но это делает внешний дополнительный HTTP-запрос. Так что HTTP веб-сервер должен быть бегущий.

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

наконец, я использую Способ 1 случая 2. Мне нужны параметры и

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

здесь признак полностью эмулирует запущенный контроллер маршрутизатором laravel (включая поддержку middlewares и инъекцию зависимостей). Протестировано только с версией 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');
    }
}