J'ai deux contrôleurs SubmitPerformanceController
et PrintReportController
.
Dans PrintReportController
j'ai une méthode appelée getPrintReport
.
Comment accéder à cette méthode dans SubmitPerformanceController
?
Vous pouvez accéder à votre méthode de contrôleur comme ceci:
app('App\Http\Controllers\PrintReportController')->getPrintReport();
Cela fonctionnera, mais c'est mauvais en termes d'organisation du code (n'oubliez pas d'utiliser le bon espace de noms pour votre PrintReportController
)
Vous pouvez étendre la PrintReportController
pour que SubmitPerformanceController
hérite de cette méthode
class SubmitPerformanceController extends PrintReportController {
// ....
}
Mais cela héritera également de toutes les autres méthodes de PrintReportController
.
La meilleure approche consiste à créer une trait
, à y implémenter la logique et à dire à vos contrôleurs de l’utiliser:
trait PrintReport {
public function getPrintReport() {
// .....
}
}
Dites à vos contrôleurs d'utiliser ce trait:
class PrintReportController extends Controller {
use PrintReport;
}
class SubmitPerformanceController extends Controller {
use PrintReport;
}
Les deux solutions permettent à SubmitPerformanceController
d’avoir la méthode getPrintReport
afin que vous puissiez l’appeler avec $this->getPrintReport();
à partir du contrôleur ou directement sous forme de route (si vous l’avez mappée dans le routes.php
)
Vous pouvez en savoir plus sur les traits ici .
Si vous avez besoin de cette méthode dans un autre contrôleur, cela signifie que vous devez la résumer et la rendre réutilisable. Déplacez cette implémentation dans une classe de service (ReportingService ou similaire) et injectez-la dans vos contrôleurs.
Exemple:
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
}
}
Faites de même pour les autres contrôleurs pour lesquels vous avez besoin de cette implémentation. Atteindre des méthodes de contrôleur à partir d'autres contrôleurs est une odeur de code.
Il n'est pas recommandé d'appeler un contrôleur à partir d'un autre contrôleur. Toutefois, si, pour une raison quelconque, vous devez le faire, vous pouvez le faire:
méthode compatible Laravel 5
return \App::call('bla\bla\ControllerName@functionName');
Note: cela ne mettra pas à jour l'URL de la page.
Il est préférable d'appeler la Route à la place et de la laisser appeler le contrôleur.
return \Redirect::route('route-name-here');
Tu ne devrais pas. C’est un anti-modèle. Si vous avez besoin d’une méthode dans un contrôleur auquel vous devez accéder dans un autre contrôleur, c’est un signe que vous devez reformater.
Envisagez de re-factoriser la méthode dans une classe de service, que vous pouvez ensuite instancier dans plusieurs contrôleurs. Ainsi, si vous devez proposer des rapports d'impression pour plusieurs modèles, vous pouvez procéder comme suit:
class ExampleController extends Controller
{
public function printReport()
{
$report = new PrintReport($itemToReportOn);
return $report->render();
}
}
Tout d'abord, demander une méthode d'un contrôleur à un autre contrôleur est EVIL. Cela causera de nombreux problèmes cachés dans le cycle de vie de Laravel.
Quoi qu’il en soit, il existe de nombreuses solutions pour le faire. Vous pouvez sélectionner l'une de ces différentes manières.
Mais vous ne pouvez ajouter aucun paramètre ni aucune authentification avec cette méthode.
app(\App\Http\Controllers\PrintReportContoller::class)->getPrintReport();
Vous pouvez ajouter tous les paramètres et quelque chose avec cela. La meilleure solution pour votre vie de programmation. Vous pouvez créer Repository
à la place de 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
le trait utilisé dans les tests d’unités d’application.Je le recommande si vous avez une raison particulière de créer ce proxy, vous pouvez utiliser tous les paramètres et en-têtes personnalisés . De plus, ceci sera une requête interne en laravel. (Demande HTTP fictive) Vous pouvez voir plus de détails pour la méthode call
dans ici .
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 ...
}
}
Cependant, ce n’est pas non plus une "bonne" solution.
C’est la solution la plus terrible à mon avis. Vous pouvez également utiliser tous les paramètres et en-têtes personnalisés . Mais ce serait faire une requête http externe supplémentaire. Donc, HTTP Webserver doit être en cours d'exécution.
$client = new Client([
'base_uri' => request()->getSchemeAndhttpHost(),
'headers' => request()->header()
]);
$a = $client->get('/performance/submit')->getBody()->getContents()
Enfin, j'utilise la voie 1 du cas 2. J'ai besoin de paramètres et
\App::call('App\Http\Controllers\MyController@getFoo')
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();
}
}
Ici, le trait émule complètement le contrôleur en cours d’exécution par le routeur laravel (y compris la prise en charge des middlewares et l’injection de dépendances). Testé uniquement avec la version 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();
}
}
Ensuite, ajoutez-le simplement à votre classe et exécutez le contrôleur. Notez que cette injection de dépendance sera affectée à votre itinéraire actuel.
class CustomController extends Controller {
use RunsAnotherController;
public function someAction()
{
$controller = app()->make('App\Http\Controllers\AnotherController');
return $this->runController($controller, 'doSomething');
}
}
Réponse tardive, mais je le cherche depuis un moment. Ceci est maintenant possible d'une manière très simple.
Sans paramètres
return redirect()->action('HomeController@index');
Avec paramètres
return redirect()->action('UserController@profile', ['id' => 1]);
Docs: https://laravel.com/docs/5.6/responses#redirecting-controller-actions
De retour dans la version 5.0, il fallait tout le chemin, maintenant c'est beaucoup plus simple.