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
?
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
?
Réponses:
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 le PrintReportController
donc SubmitPerformanceController
héritera de cette méthode
class SubmitPerformanceController extends PrintReportController {
// ....
}
Mais cela héritera également de toutes les autres méthodes de PrintReportController
.
La meilleure approche sera de créer un trait
(par exemple dans app/Traits
), d'y implémenter la logique et de dire à vos contrôleurs de l'utiliser:
trait PrintReport {
public function getPrintReport() {
// .....
}
}
Dites à vos contrôleurs d'utiliser cette caractéristique:
class PrintReportController extends Controller {
use PrintReport;
}
class SubmitPerformanceController extends Controller {
use PrintReport;
}
Les deux solutions font SubmitPerformanceController
pour avoir une getPrintReport
méthode afin que vous puissiez l'appeler $this->getPrintReport();
depuis le contrôleur ou directement comme route (si vous l'avez mappée dans le routes.php
)
Vous pouvez en savoir plus sur les traits ici .
app('App\Http\Controllers\PrintReportController')->getPrintReport();
peut être transformé en app(PrintReportController::class')->getPrintReport()
. Solution propre pour moi.
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 quelque chose de 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 les méthodes de contrôleur d'autres contrôleurs est une odeur de code.
Services
dossier si le projet n'est pas volumineux, soit un dossier de fonctionnalités appelé Reporting
s'il s'agit d'un projet plus grand et utilise une Folders By Feature
structure.
L'appel d'un contrôleur depuis un autre contrôleur n'est pas recommandé, mais 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');
Remarque: 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-pattern. Si vous avez une méthode dans un contrôleur à laquelle vous devez accéder dans un autre contrôleur, c'est un signe que vous devez re-factoriser.
Envisagez de refactoriser la méthode dans une classe de service, que vous pouvez ensuite instancier dans plusieurs contrôleurs. Donc, si vous devez proposer des rapports d'impression pour plusieurs modèles, vous pouvez faire quelque chose comme ceci:
class ExampleController extends Controller
{
public function printReport()
{
$report = new PrintReport($itemToReportOn);
return $report->render();
}
}
\App::call('App\Http\Controllers\MyController@getFoo')
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 y parvenir. Vous pouvez sélectionner l'une de ces différentes manières.
Mais vous ne pouvez pas ajouter de paramètres ou d'authentification de cette manière.
app(\App\Http\Controllers\PrintReportContoller::class)->getPrintReport();
Vous pouvez ajouter des paramètres et quelque chose avec ça. La meilleure solution pour votre vie de programmation. Vous pouvez faire à la Repository
place 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
trait utilisé dans les tests unitaires d'application.Je recommande cela 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 . Ce sera également une demande interne dans laravel. (Fake HTTP Request) Vous pouvez voir plus de détails sur la call
méthode 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 que je pense. Vous pouvez également utiliser tous les paramètres et en-têtes personnalisés . Mais ce serait faire une demande externe http supplémentaire. Le serveur Web HTTP doit donc ê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
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();
}
}
Vous pouvez utiliser une méthode statique dans PrintReportController, puis l'appeler à partir de SubmitPerformanceController comme ceci;
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();
}
}
Cette approche fonctionne également avec la même hiérarchie de fichiers Controller:
$printReport = new PrintReportController;
$prinReport->getPrintReport();
Ici, le trait émule entièrement le contrôleur en cours d'exécution par le routeur laravel (y compris le support 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 l'injection de dépendances sera affectée à votre route actuelle.
class CustomController extends Controller {
use RunsAnotherController;
public function someAction()
{
$controller = app()->make('App\Http\Controllers\AnotherController');
return $this->runController($controller, 'doSomething');
}
}
app()->make(......)
est égal à app(......)
donc c'est plus court.
Vous pouvez accéder au contrôleur en l'instanciant et en appelant doAction: (mis use Illuminate\Support\Facades\App;
avant la déclaration de classe du contrôleur)
$controller = App::make('\App\Http\Controllers\YouControllerName');
$data = $controller->callAction('controller_method', $parameters);
Notez également qu'en faisant cela, vous n'exécuterez aucun des middlewares déclarés sur ce contrôleur.
Réponse tardive, mais je le cherche depuis un certain temps. C'est désormais possible de manière très simple.
Sans paramètres
return redirect()->action('HomeController@index');
Avec des paramètres
return redirect()->action('UserController@profile', ['id' => 1]);
Docs: https://laravel.com/docs/5.6/responses#redirecting-controller-actions
Dans la version 5.0, il fallait tout le chemin, maintenant c'est beaucoup plus simple.