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

60

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

В PrintReportController у меня есть метод под названием getPrintReport.

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

Теги:
laravel-5

8 ответов

142
Лучший ответ

Вы можете получить доступ к вашему методу контроллера следующим образом:

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)

Подробнее о признаках здесь.

  • 3
    где должен быть сохранен файл с чертой?
  • 8
    app('App\Http\Controllers\PrintReportController')->getPrintReport(); может быть преобразовано в app(PrintReportController::class')->getPrintReport() . Чистое решение для меня.
21

Если вам нужен этот метод в другом контроллере, это означает, что вам нужно абстрагироваться от него и сделать его многоразовым. Переместите эту реализацию в класс службы (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
  }
}

Сделайте то же самое для других контроллеров, где вам нужна эта реализация. Приобретение методов контроллера из других контроллеров - это запах кода.

  • 0
    Где бы вы сохранили этот класс с точки зрения структуры проекта?
  • 0
    Либо папка « Services », если проект не большой, либо папка с функциями « Reporting если это крупный проект, в котором используется структура « Folders By Feature .
Показать ещё 2 комментария
8

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

совместимый с Laravel 5 метод

return \App::call('bla\bla\ControllerName@functionName');

Примечание. это не приведет к обновлению URL-адреса страницы.

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

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

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

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

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

Прежде всего, метод запроса контроллера с другого контроллера - это ЗЛО. Это вызовет много скрытых проблем жизненного цикла в Laravel.

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

Случай 1) Если вы хотите позвонить на основе классов

Способ 1) Простой способ

Но вы не можете использовать никакие параметры или аутентификацию.

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

Способ 2) Разделите службы логики в контроллерах.

Вы можете использовать любые параметры и что-то. Лучшее решение для вашей жизни программирования. Вместо Repository можно сделать Repository.

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. (Fake HTTP Request). Вы можете найти более подробные руководства для метода 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. Мне нужны параметры и

  • 0
    Способ 2 не должен быть записан там, вы никогда не захотите самостоятельно запрашивать http, даже в плохой структуре кода.
2
\App::call('App\Http\Controllers\MyController@getFoo')
  • 8
    Несмотря на то, что ваш ответ может быть правильным, было бы неплохо немного его расширить и дать некоторые дополнительные пояснения.
1
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();   
    }
   }
  • 5
    Пожалуйста, отредактируйте с дополнительной информацией. Ответы «только код» и «попробуй это» не приветствуются, поскольку они не содержат контента для поиска и не объясняют, почему кто-то должен «попробовать это».
0

Здесь эта черта полностью эмулирует управляемый контроллер маршрутизатором 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');
    }
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню