Ho due controller SubmitPerformanceController
e PrintReportController
.
In PrintReportController
ho un metodo chiamato getPrintReport
.
Come accedere a questo metodo in SubmitPerformanceController
?
Ho due controller SubmitPerformanceController
e PrintReportController
.
In PrintReportController
ho un metodo chiamato getPrintReport
.
Come accedere a questo metodo in SubmitPerformanceController
?
Risposte:
È possibile accedere al metodo del controller in questo modo:
app('App\Http\Controllers\PrintReportController')->getPrintReport();
Funzionerà, ma è male in termini di organizzazione del codice (ricordati di usare lo spazio dei nomi giusto per il tuo PrintReportController
)
È possibile estendere PrintReportController
così SubmitPerformanceController
erediterà quel metodo
class SubmitPerformanceController extends PrintReportController {
// ....
}
Ma questo erediterà anche tutti gli altri metodi PrintReportController
.
L'approccio migliore sarà quello di creare un trait
(es. In app/Traits
), implementare la logica lì e dire ai controller di usarlo:
trait PrintReport {
public function getPrintReport() {
// .....
}
}
Di 'ai tuoi controller di usare questo tratto:
class PrintReportController extends Controller {
use PrintReport;
}
class SubmitPerformanceController extends Controller {
use PrintReport;
}
Entrambe le soluzioni SubmitPerformanceController
hanno un getPrintReport
metodo in modo da poterlo chiamare $this->getPrintReport();
dall'interno del controller o direttamente come route (se lo hai mappato nel routes.php
)
Puoi leggere di più sui tratti qui .
app('App\Http\Controllers\PrintReportController')->getPrintReport();
può trasformarsi in app(PrintReportController::class')->getPrintReport()
. Soluzione pulita per me.
Se hai bisogno di quel metodo in un altro controller, significa che devi estrarlo e renderlo riutilizzabile. Spostare l'implementazione in una classe di servizio (ReportingService o qualcosa di simile) e iniettarla nei controller.
Esempio:
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
}
}
Fare lo stesso per gli altri controller in cui è necessaria l'implementazione. Raggiungere metodi di controller da altri controller è un odore di codice.
Services
cartella se il progetto non è grande o una cartella delle caratteristiche chiamata Reporting
se è un progetto più grande e utilizza la Folders By Feature
struttura.
Non è consigliabile chiamare un controller da un altro controller, tuttavia se per qualsiasi motivo è necessario farlo, è possibile farlo:
Metodo compatibile Laravel 5
return \App::call('bla\bla\ControllerName@functionName');
Nota: questo non aggiornerà l'URL della pagina.
È meglio chiamare invece il percorso e lasciarlo chiamare il controller.
return \Redirect::route('route-name-here');
Non dovresti. È un anti-schema. Se hai un metodo in un controller a cui devi accedere in un altro controller, allora è un segno che devi ripetere il fattore.
Prendi in considerazione la possibilità di ricodificare il metodo in una classe di servizio, che puoi creare un'istanza in più controller. Quindi, se devi offrire rapporti di stampa per più modelli, puoi fare qualcosa del genere:
class ExampleController extends Controller
{
public function printReport()
{
$report = new PrintReport($itemToReportOn);
return $report->render();
}
}
\App::call('App\Http\Controllers\MyController@getFoo')
Innanzitutto, richiedere un metodo di un controller a un altro controller è EVIL. Ciò causerà molti problemi nascosti nel ciclo di vita di Laravel.
Ad ogni modo, ci sono molte soluzioni per farlo. È possibile selezionare uno di questi vari modi.
Ma non puoi aggiungere alcun parametro o autenticazione in questo modo.
app(\App\Http\Controllers\PrintReportContoller::class)->getPrintReport();
È possibile aggiungere qualsiasi parametro e qualcosa con questo. La migliore soluzione per la tua vita di programmazione. Puoi fare Repository
invece 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
tratto utilizzato nel Test unità applicazione.Lo consiglio se hai un motivo speciale per creare questo proxy, puoi usare qualsiasi parametro e intestazione personalizzata . Anche questa sarà una richiesta interna in laravel. (Richiesta HTTP falsa) Puoi vedere maggiori dettagli per il call
metodo qui .
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 ...
}
}
Tuttavia, questa non è una soluzione "buona".
Questa è la soluzione più terribile che penso. Puoi utilizzare anche qualsiasi parametro e intestazione personalizzata . Ma ciò comporterebbe una richiesta http extra esterna. Quindi HTTP Webserver deve essere in esecuzione.
$client = new Client([
'base_uri' => request()->getSchemeAndhttpHost(),
'headers' => request()->header()
]);
$a = $client->get('/performance/submit')->getBody()->getContents()
Finalmente sto usando il modo 1 del caso 2. Ho bisogno di parametri e
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();
}
}
È possibile utilizzare un metodo statico in PrintReportController e quindi chiamarlo da SubmitPerformanceController in questo modo;
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();
}
}
Questo approccio funziona anche con la stessa gerarchia dei file del controller:
$printReport = new PrintReportController;
$prinReport->getPrintReport();
Qui il tratto emula completamente il controller in esecuzione dal router laravel (incluso il supporto di middleware e iniezione di dipendenza). Testato solo con la versione 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();
}
}
Quindi aggiungilo alla tua classe ed esegui il controller. Si noti che l'iniezione di dipendenza verrà assegnata con il percorso corrente.
class CustomController extends Controller {
use RunsAnotherController;
public function someAction()
{
$controller = app()->make('App\Http\Controllers\AnotherController');
return $this->runController($controller, 'doSomething');
}
}
app()->make(......)
è uguale a app(......)
quindi è più breve.
È possibile accedere al controller istanziandolo e chiamando doAction: (inserito use Illuminate\Support\Facades\App;
prima della dichiarazione della classe controller)
$controller = App::make('\App\Http\Controllers\YouControllerName');
$data = $controller->callAction('controller_method', $parameters);
Si noti inoltre che facendo ciò non si eseguirà nessuno dei middleware dichiarati su quel controller.
Risposta in ritardo, ma ho cercato questo per qualche tempo. Questo è ora possibile in un modo molto semplice.
Senza parametri
return redirect()->action('HomeController@index');
Con parametri
return redirect()->action('UserController@profile', ['id' => 1]);
Documenti: https://laravel.com/docs/5.6/responses#redirecting-controller-actions
Nel 5.0 richiedeva l'intero percorso, ora è molto più semplice.