Mam dwa kontrolery SubmitPerformanceController
i PrintReportController
.
W PrintReportController
mam metodę o nazwie getPrintReport
.
Jak uzyskać dostęp do tej metody w SubmitPerformanceController
?
Mam dwa kontrolery SubmitPerformanceController
i PrintReportController
.
W PrintReportController
mam metodę o nazwie getPrintReport
.
Jak uzyskać dostęp do tej metody w SubmitPerformanceController
?
Odpowiedzi:
Możesz uzyskać dostęp do metody kontrolera w następujący sposób:
app('App\Http\Controllers\PrintReportController')->getPrintReport();
To zadziała, ale jest złe pod względem organizacji kodu (pamiętaj, aby użyć odpowiedniej przestrzeni nazw PrintReportController
)
Możesz rozszerzyć, PrintReportController
więc SubmitPerformanceController
będzie dziedziczyć tę metodę
class SubmitPerformanceController extends PrintReportController {
// ....
}
Ale to również odziedziczy wszystkie inne metody z PrintReportController
.
Najlepszym podejściem będzie utworzenie trait
(np. In app/Traits
), zaimplementowanie tam logiki i poinformowanie kontrolerów, aby z niej korzystali:
trait PrintReport {
public function getPrintReport() {
// .....
}
}
Powiedz swoim kontrolerom, aby użyli tej cechy:
class PrintReportController extends Controller {
use PrintReport;
}
class SubmitPerformanceController extends Controller {
use PrintReport;
}
Oba rozwiązania sprawiają, SubmitPerformanceController
że getPrintReport
metoda ma , więc możesz wywołać ją z $this->getPrintReport();
poziomu kontrolera lub bezpośrednio jako trasę (jeśli zmapowałeś ją w routes.php
)
Możesz przeczytać więcej o cechach tutaj .
app('App\Http\Controllers\PrintReportController')->getPrintReport();
można przekształcić w app(PrintReportController::class')->getPrintReport()
. Czyste rozwiązanie dla mnie.
Jeśli potrzebujesz tej metody w innym kontrolerze, oznacza to, że musisz ją wyodrębnić i umożliwić jej ponowne użycie. Przenieś tę implementację do klasy usług (ReportingService lub podobnej) i wstrzyknij ją do kontrolerów.
Przykład:
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
}
}
Zrób to samo dla innych kontrolerów, w których potrzebujesz tej implementacji. Sięganie po metody kontrolera z innych kontrolerów to zapach kodu.
Services
folder, jeśli projekt nie jest duży, albo folder funkcji, Reporting
jeśli jest to większy projekt i używa Folders By Feature
struktury.
Wywołanie Kontrolera z innego Kontrolera nie jest zalecane, jednak jeśli z jakiegoś powodu musisz to zrobić, możesz to zrobić:
Metoda zgodna z Laravel 5
return \App::call('bla\bla\ControllerName@functionName');
Uwaga: to nie zaktualizuje adresu URL strony.
Lepiej jest zamiast tego wywołać trasę i pozwolić jej wywołać kontroler.
return \Redirect::route('route-name-here');
Nie powinieneś. To anty-wzór. Jeśli masz metodę w jednym kontrolerze, do której chcesz uzyskać dostęp w innym kontrolerze, to jest to znak, który musisz ponownie uwzględnić.
Rozważ ponowne uwzględnienie metody w klasie usługi, którą można następnie utworzyć na wielu kontrolerach. Jeśli więc chcesz oferować raporty drukowania dla wielu modeli, możesz zrobić coś takiego:
class ExampleController extends Controller
{
public function printReport()
{
$report = new PrintReport($itemToReportOn);
return $report->render();
}
}
\App::call('App\Http\Controllers\MyController@getFoo')
Po pierwsze, żądanie metody kontrolera od innego kontrolera jest ZŁE. Spowoduje to wiele ukrytych problemów w cyklu życia Laravel.
Zresztą istnieje wiele rozwiązań, jak to zrobić. Możesz wybrać jeden z tych różnych sposobów.
Ale w ten sposób nie możesz dodać żadnych parametrów ani uwierzytelnienia .
app(\App\Http\Controllers\PrintReportContoller::class)->getPrintReport();
Możesz dodać dowolne parametry i coś z tym. Najlepsze rozwiązanie dla Twojego życia programistycznego. Możesz Repository
zamiast tego zrobić 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
cechy używanej w testowaniu jednostkowym aplikacji.Polecam to, jeśli masz szczególny powód do tworzenia tego serwera proxy, możesz użyć dowolnych parametrów i niestandardowych nagłówków . Także to będzie wewnętrzna prośba w laravel. (Fałszywe żądanie HTTP) Więcej informacji na temat call
metody można znaleźć tutaj .
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 ...
}
}
Jednak nie jest to również „dobre” rozwiązanie.
Myślę, że to najstraszniejsze rozwiązanie. Możesz także użyć dowolnych parametrów i niestandardowych nagłówków . Ale oznaczałoby to wykonanie dodatkowego zewnętrznego żądania http. Dlatego serwer WWW HTTP musi być uruchomiony.
$client = new Client([
'base_uri' => request()->getSchemeAndhttpHost(),
'headers' => request()->header()
]);
$a = $client->get('/performance/submit')->getBody()->getContents()
Wreszcie używam sposobu 1 przypadku 2. Potrzebuję parametrów i
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();
}
}
Możesz użyć metody statycznej w PrintReportController, a następnie wywołać ją z SubmitPerformanceController w ten sposób;
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();
}
}
To podejście działa również z tą samą hierarchią plików kontrolera:
$printReport = new PrintReportController;
$prinReport->getPrintReport();
Tutaj cecha w pełni emuluje działający kontroler przez router laravel (w tym wsparcie dla oprogramowania pośredniego i wstrzykiwania zależności). Testowany tylko z wersją 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();
}
}
Następnie po prostu dodaj go do swojej klasy i uruchom kontroler. Należy pamiętać, że iniekcja zależności zostanie przypisana do bieżącej trasy.
class CustomController extends Controller {
use RunsAnotherController;
public function someAction()
{
$controller = app()->make('App\Http\Controllers\AnotherController');
return $this->runController($controller, 'doSomething');
}
}
app()->make(......)
jest równe, app(......)
więc jest krótsze.
Możesz uzyskać dostęp do kontrolera, tworząc jego instancję i wywołując doAction: (wstaw use Illuminate\Support\Facades\App;
przed deklaracją klasy kontrolera)
$controller = App::make('\App\Http\Controllers\YouControllerName');
$data = $controller->callAction('controller_method', $parameters);
Zwróć również uwagę, że robiąc to, nie wykonasz żadnego oprogramowania pośredniego zadeklarowanego na tym kontrolerze.
Późna odpowiedź, ale szukałem tego od jakiegoś czasu. Jest to teraz możliwe w bardzo prosty sposób.
Bez parametrów
return redirect()->action('HomeController@index');
Z parametrami
return redirect()->action('UserController@profile', ['id' => 1]);
Dokumenty: https://laravel.com/docs/5.6/responses#redirecting-controller-actions
W wersji 5.0 wymagało to całej ścieżki, teraz jest znacznie prostsze.