Ich habe zwei Controller SubmitPerformanceController
und PrintReportController
.
In habe PrintReportController
ich eine Methode aufgerufen getPrintReport
.
Wie kann ich in auf diese Methode zugreifen SubmitPerformanceController
?
Ich habe zwei Controller SubmitPerformanceController
und PrintReportController
.
In habe PrintReportController
ich eine Methode aufgerufen getPrintReport
.
Wie kann ich in auf diese Methode zugreifen SubmitPerformanceController
?
Antworten:
Sie können wie folgt auf Ihre Controller-Methode zugreifen:
app('App\Http\Controllers\PrintReportController')->getPrintReport();
Dies wird funktionieren, ist jedoch in Bezug auf die Code-Organisation schlecht (denken Sie daran, den richtigen Namespace für Ihre zu verwenden PrintReportController
).
Sie können das erweitern PrintReportController
, SubmitPerformanceController
um diese Methode zu erben
class SubmitPerformanceController extends PrintReportController {
// ....
}
Dies erbt aber auch alle anderen Methoden von PrintReportController
.
Der beste Ansatz besteht darin, ein trait
(z. B. in app/Traits
) zu erstellen , die Logik dort zu implementieren und Ihre Controller anzuweisen, sie zu verwenden:
trait PrintReport {
public function getPrintReport() {
// .....
}
}
Sagen Sie Ihren Controllern, dass sie dieses Merkmal verwenden sollen:
class PrintReportController extends Controller {
use PrintReport;
}
class SubmitPerformanceController extends Controller {
use PrintReport;
}
Beide Lösungen SubmitPerformanceController
verfügen über eine getPrintReport
Methode, mit der Sie sie $this->getPrintReport();
innerhalb des Controllers oder direkt als Route aufrufen können (wenn Sie sie in der routes.php
) zugeordnet haben.
Sie können mehr über Züge lesen hier .
app('App\Http\Controllers\PrintReportController')->getPrintReport();
kann umgewandelt werden app(PrintReportController::class')->getPrintReport()
. Saubere Lösung für mich.
Wenn Sie diese Methode in einem anderen Controller benötigen, müssen Sie sie abstrahieren und wiederverwendbar machen. Verschieben Sie diese Implementierung in eine Serviceklasse (ReportingService oder ähnliches) und fügen Sie sie in Ihre Controller ein.
Beispiel:
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
}
}
Machen Sie dasselbe für die anderen Controller, auf denen Sie diese Implementierung benötigen. Das Erreichen von Controller-Methoden von anderen Controllern ist ein Code-Geruch.
Services
Ordner, wenn das Projekt nicht groß ist, oder ein Feature-Ordner, der aufgerufen wird, Reporting
wenn es sich um ein größeres Projekt handelt und Folders By Feature
Struktur verwendet.
Das Aufrufen eines Controllers von einem anderen Controller aus wird nicht empfohlen. Wenn Sie dies jedoch aus irgendeinem Grund tun müssen, können Sie Folgendes tun:
Laravel 5 kompatible Methode
return \App::call('bla\bla\ControllerName@functionName');
Hinweis: Dadurch wird die URL der Seite nicht aktualisiert.
Es ist besser, stattdessen die Route aufzurufen und den Controller anrufen zu lassen.
return \Redirect::route('route-name-here');
Das solltest du nicht. Es ist ein Anti-Muster. Wenn Sie in einem Controller eine Methode haben, auf die Sie in einem anderen Controller zugreifen müssen, ist dies ein Zeichen, das Sie neu faktorisieren müssen.
Ziehen Sie in Betracht, die Methode in eine Serviceklasse umzuwandeln, die Sie dann in mehreren Controllern instanziieren können. Wenn Sie also Druckberichte für mehrere Modelle anbieten müssen, können Sie Folgendes tun:
class ExampleController extends Controller
{
public function printReport()
{
$report = new PrintReport($itemToReportOn);
return $report->render();
}
}
\App::call('App\Http\Controllers\MyController@getFoo')
Zuallererst ist es böse, eine Methode eines Controllers von einem anderen Controller anzufordern. Dies wird viele versteckte Probleme in Laravels Lebenszyklus verursachen.
Dafür gibt es viele Lösungen. Sie können eine dieser verschiedenen Möglichkeiten auswählen.
Auf diese Weise können Sie jedoch keine Parameter oder Authentifizierung hinzufügen .
app(\App\Http\Controllers\PrintReportContoller::class)->getPrintReport();
Sie können damit beliebige Parameter und etwas hinzufügen . Die beste Lösung für Ihr Programmierleben. Sie können Repository
stattdessen machen 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
Merkmal, das beim Testen von Anwendungseinheiten verwendet wurde.Ich empfehle dies, wenn Sie einen besonderen Grund für die Erstellung dieses Proxys haben. Sie können beliebige Parameter und benutzerdefinierte Header verwenden . Auch dies wird eine interne Anfrage in Laravel sein. (Gefälschte HTTP-Anfrage) Weitere Details zur call
Methode finden Sie hier .
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 ...
}
}
Dies ist jedoch auch keine „gute“ Lösung.
Dies ist die schrecklichste Lösung, die ich denke. Sie können auch beliebige Parameter und benutzerdefinierte Header verwenden . Dies würde jedoch eine externe zusätzliche http-Anfrage stellen. Der HTTP-Webserver muss also ausgeführt werden.
$client = new Client([
'base_uri' => request()->getSchemeAndhttpHost(),
'headers' => request()->header()
]);
$a = $client->get('/performance/submit')->getBody()->getContents()
Schließlich verwende ich Weg 1 von Fall 2. Ich benötige Parameter und
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();
}
}
Sie können eine statische Methode in PrintReportController verwenden und sie dann wie folgt vom SubmitPerformanceController aus aufrufen.
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();
}
}
Dieser Ansatz funktioniert auch mit derselben Hierarchie von Controller-Dateien:
$printReport = new PrintReportController;
$prinReport->getPrintReport();
Hier emuliert das Merkmal die laufende Steuerung durch den Laravel-Router vollständig (einschließlich der Unterstützung von Middleware und der Abhängigkeitsinjektion). Nur mit Version 5.4 getestet
<?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();
}
}
Fügen Sie es dann einfach Ihrer Klasse hinzu und führen Sie den Controller aus. Beachten Sie, dass die Abhängigkeitsinjektion Ihrer aktuellen Route zugewiesen wird.
class CustomController extends Controller {
use RunsAnotherController;
public function someAction()
{
$controller = app()->make('App\Http\Controllers\AnotherController');
return $this->runController($controller, 'doSomething');
}
}
app()->make(......)
gleich ist, app(......)
also kürzer.
Sie können auf den Controller zugreifen, indem Sie ihn instanziieren und doAction aufrufen: ( use Illuminate\Support\Facades\App;
vor die Controller-Klassendeklaration setzen)
$controller = App::make('\App\Http\Controllers\YouControllerName');
$data = $controller->callAction('controller_method', $parameters);
Beachten Sie auch, dass Sie auf diese Weise keine der auf diesem Controller deklarierten Middlewares ausführen.
Späte Antwort, aber ich habe seit einiger Zeit danach gesucht. Dies ist jetzt auf sehr einfache Weise möglich.
Ohne Parameter
return redirect()->action('HomeController@index');
Mit Parametern
return redirect()->action('UserController@profile', ['id' => 1]);
Dokumente: https://laravel.com/docs/5.6/responses#redirecting-controller-actions
In 5.0 war der gesamte Pfad erforderlich, jetzt ist es viel einfacher.