У мене два контролери SubmitPerformanceController
і PrintReportController
.
У PrintReportController
мене є метод, який називається getPrintReport
.
Як отримати доступ до цього методу SubmitPerformanceController
?
У мене два контролери SubmitPerformanceController
і PrintReportController
.
У PrintReportController
мене є метод, який називається getPrintReport
.
Як отримати доступ до цього методу SubmitPerformanceController
?
Відповіді:
Ви можете отримати доступ до свого методу контролера так:
app('App\Http\Controllers\PrintReportController')->getPrintReport();
Це буде працювати, але це погано з точки зору організації коду (не забудьте використовувати правильний простір імен для свого PrintReportController
)
Ви можете продовжити, PrintReportController
так SubmitPerformanceController
це успадкує цей метод
class SubmitPerformanceController extends PrintReportController {
// ....
}
Але це також успадкує всі інші методи від PrintReportController
.
Найкращим підходом буде створити trait
(наприклад, в 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
)
Більше про ознаки ви можете прочитати тут .
app('App\Http\Controllers\PrintReportController')->getPrintReport();
може трансформуватися в app(PrintReportController::class')->getPrintReport()
. Чисте рішення для мене.
Якщо вам потрібен метод в іншому контролері, це означає, що вам потрібно його абстрагувати та зробити його багаторазовим. Перемістіть цю реалізацію в клас обслуговування (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
}
}
Зробіть те саме для інших контролерів, де вам потрібна ця реалізація. Досягнення методів контролера від інших контролерів - це кодовий запах.
Services
папка, якщо проект не великий, або папка функцій, яка називається, Reporting
якщо це більший проект і використовує Folders By Feature
структуру.
Викликати контролер з іншого контролера не рекомендується, однак якщо з будь-якої причини вам це потрібно зробити, ви можете зробити це:
Сумісний метод 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();
}
}
\App::call('App\Http\Controllers\MyController@getFoo')
Перш за все, запитувати метод контролера від іншого контролера - EVIL. Це спричинить багато прихованих проблем у життєвому циклі Ларавеля.
У будь-якому випадку для цього існує багато рішень. Ви можете вибрати один із цих різних способів.
Але ви не можете додати жодних параметрів або автентифікації таким чином.
app(\App\Http\Controllers\PrintReportContoller::class)->getPrintReport();
Ви можете додати будь-які параметри і щось із цим. Найкраще рішення для вашого життя програмування. Ви можете зробити 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 ...
}
}
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 ...
}
}
Однак це також не є «хорошим» рішенням.
Це найстрашніше рішення, на мою думку. Ви також можете використовувати будь-які параметри та власні заголовки . Але це буде створення зовнішнього додаткового http запиту. Отже, HTTP-веб-сервер повинен працювати.
$client = new Client([
'base_uri' => request()->getSchemeAndhttpHost(),
'headers' => request()->header()
]);
$a = $client->get('/performance/submit')->getBody()->getContents()
Нарешті я використовую шлях 1 випадку 2. Мені потрібні параметри та
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();
}
}
Ви можете використовувати статичний метод у 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();
}
}
Тут ця ознака повністю імітує працюючий контролер ларавел-маршрутизатором (включаючи підтримку середнього рівня та введення залежності). Тестується лише з версією 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');
}
}
app()->make(......)
дорівнює app(......)
тому, що коротше.
Ви можете отримати доступ до контролера, інстанціюючи його та викликаючи doAction: (поставити use Illuminate\Support\Facades\App;
перед декларацією класу контролера)
$controller = App::make('\App\Http\Controllers\YouControllerName');
$data = $controller->callAction('controller_method', $parameters);
Також зауважте, що виконуючи це, ви не будете виконувати жодну з середніх програм, заявлених на цьому контролері.
Пізня відповідь, але я це шукав вже десь. Це зараз можливо дуже простим способом.
Без параметрів
return redirect()->action('HomeController@index');
З параметрами
return redirect()->action('UserController@profile', ['id' => 1]);
Документи: https://laravel.com/docs/5.6/responses#redirecting-controller-action
Ще в 5.0 вона потребувала всього шляху, тепер це набагато простіше.