from - laravel route parameter to controller




Méthode du contrôleur d'accès à partir d'un autre contrôleur dans Laravel 5 (8)

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 ?


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\[email protected]');

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');

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épendance). 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');
    }
}

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.


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.

Cas 1) Si vous souhaitez appeler en fonction des classes

Voie 1) La manière simple

Mais vous ne pouvez pas ajouter de paramètres ou d’authentification de cette façon.

app(\App\Http\Controllers\PrintReportContoller::class)->getPrintReport();

Voie 2) Divisez la logique du contrôleur en services.

Vous pouvez ajouter n'importe quels paramètres et quelque chose avec cela. La meilleure solution pour votre vie de programmation. Vous pouvez rendre le Repository place du 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 ...
    }
}

Cas 2) Si vous souhaitez appeler en fonction des itinéraires

MakesHttpRequests 1) Utilisez le trait MakesHttpRequests 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 . Ce sera aussi une demande interne à Laravel. (Demande HTTP fictive) Vous pouvez voir plus de détails pour la méthode d' call here .

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.

Way 2) Utiliser le client guzzlehttp

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


Vous pouvez accéder à votre méthode de contrôleur comme ceci:

app('App\Http\Controllers\PrintReportController')->getPrintReport();

Cela fonctionnera, mais c'est mauvais pour l'organisation du code (n'oubliez pas d'utiliser le bon espace de noms pour votre PrintReportController )

Vous pouvez étendre 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 un trait (par exemple, dans app/Traits ), à 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(); depuis le contrôleur ou directement en tant routes.php (si vous l'avez mappé dans le routes.php )

Vous pouvez en savoir plus sur les traits here .


Vous pouvez accéder au contrôleur en l'instanciant et en appelant doAction: (mettez use Illuminate\Support\Facades\App; avant la déclaration de classe du contrôleur)

return redirect()->action('[email protected]', ['id' => 1]);

Notez également qu'en faisant cela, vous n'exécuterez aucun des middlewares déclarés sur ce contrôleur.


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();   
    }
   }





laravel-5