Tengo dos controladores SubmitPerformanceController
y PrintReportController
.
En PrintReportController
tengo un método llamado getPrintReport
.
¿Cómo acceder a este método en SubmitPerformanceController
?
Tengo dos controladores SubmitPerformanceController
y PrintReportController
.
En PrintReportController
tengo un método llamado getPrintReport
.
¿Cómo acceder a este método en SubmitPerformanceController
?
Respuestas:
Puede acceder a su método de controlador de esta manera:
app('App\Http\Controllers\PrintReportController')->getPrintReport();
Esto funcionará, pero es malo en términos de organización del código (recuerde usar el espacio de nombres correcto para su PrintReportController
)
Puede extender el PrintReportController
modo SubmitPerformanceController
heredará ese método
class SubmitPerformanceController extends PrintReportController {
// ....
}
Pero esto también heredará todos los demás métodos de PrintReportController
.
El mejor enfoque será crear un trait
(por ejemplo, en app/Traits
), implementar la lógica allí y decirles a sus controladores que lo usen:
trait PrintReport {
public function getPrintReport() {
// .....
}
}
Dígale a sus controladores que usen este rasgo:
class PrintReportController extends Controller {
use PrintReport;
}
class SubmitPerformanceController extends Controller {
use PrintReport;
}
Ambas soluciones SubmitPerformanceController
tienen un getPrintReport
método para que pueda llamarlo $this->getPrintReport();
desde dentro del controlador o directamente como una ruta (si lo asignó en elroutes.php
)
Puedes leer más sobre los rasgos aquí .
app('App\Http\Controllers\PrintReportController')->getPrintReport();
puede transformarse a app(PrintReportController::class')->getPrintReport()
. Solución limpia para mi.
Si necesita ese método en otro controlador, eso significa que debe abstraerlo y hacerlo reutilizable. Mueva esa implementación a una clase de servicio (ReportingService o algo similar) e inyéctela en sus controladores.
Ejemplo:
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
}
}
Haga lo mismo para los otros controladores donde necesita esa implementación. Alcanzar métodos de controlador desde otros controladores es un olor a código.
Services
carpeta si el proyecto no es grande o una carpeta de características llamada Reporting
si es un proyecto más grande y usa Folders By Feature
estructura.
No se recomienda llamar a un controlador desde otro controlador, sin embargo, si por alguna razón tiene que hacerlo, puede hacerlo:
Método compatible con Laravel 5
return \App::call('bla\bla\ControllerName@functionName');
Nota: esto no actualizará la URL de la página.
Es mejor llamar a la ruta y dejar que llame al controlador.
return \Redirect::route('route-name-here');
No deberías Es un antipatrón. Si tiene un método en un controlador al que necesita acceder en otro controlador, entonces esa es una señal que necesita re-factorizar.
Considere volver a factorizar el método en una clase de servicio, que luego puede instanciar en múltiples controladores. Entonces, si necesita ofrecer informes impresos para varios modelos, podría hacer algo como esto:
class ExampleController extends Controller
{
public function printReport()
{
$report = new PrintReport($itemToReportOn);
return $report->render();
}
}
\App::call('App\Http\Controllers\MyController@getFoo')
En primer lugar, solicitar un método de un controlador de otro controlador es MAL. Esto causará muchos problemas ocultos en el ciclo de vida de Laravel.
De todos modos, hay muchas soluciones para hacerlo. Puede seleccionar una de estas diversas formas.
Pero no puede agregar ningún parámetro o autenticación de esta manera.
app(\App\Http\Controllers\PrintReportContoller::class)->getPrintReport();
Puede agregar cualquier parámetro y algo con esto. La mejor solución para tu vida de programación. Puedes hacer en su Repository
lugar 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
rasgo que utilizó en la Prueba de la Unidad de Aplicación.Recomiendo esto si tiene una razón especial para hacer este proxy, puede usar cualquier parámetro y encabezado personalizado . También será una solicitud interna en laravel. (Solicitud HTTP falsa) Puede ver más detalles para el call
método aquí .
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 ...
}
}
Sin embargo, esta tampoco es una "buena" solución.
Esta es la solución más terrible, creo. También puede usar cualquier parámetro y encabezados personalizados . Pero esto sería hacer una solicitud http externa adicional. Por lo tanto, el servidor web HTTP debe estar ejecutándose.
$client = new Client([
'base_uri' => request()->getSchemeAndhttpHost(),
'headers' => request()->header()
]);
$a = $client->get('/performance/submit')->getBody()->getContents()
Finalmente estoy usando el camino 1 del caso 2. Necesito parámetros y
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();
}
}
Puede usar un método estático en PrintReportController y luego llamarlo desde SubmitPerformanceController de esta manera;
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();
}
}
Este enfoque también funciona con la misma jerarquía de archivos del controlador:
$printReport = new PrintReportController;
$prinReport->getPrintReport();
Aquí el rasgo emula completamente el controlador en ejecución mediante un enrutador laravel (incluido el soporte de middlewares y la inyección de dependencia). Probado solo con la versión 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();
}
}
Luego solo agrégalo a tu clase y ejecuta el controlador. Tenga en cuenta que esa inyección de dependencia se asignará con su ruta actual.
class CustomController extends Controller {
use RunsAnotherController;
public function someAction()
{
$controller = app()->make('App\Http\Controllers\AnotherController');
return $this->runController($controller, 'doSomething');
}
}
app()->make(......)
es igual a app(......)
lo que es más corto.
Puede acceder al controlador instanciando y llamando a doAction: (poner use Illuminate\Support\Facades\App;
antes de la declaración de clase del controlador)
$controller = App::make('\App\Http\Controllers\YouControllerName');
$data = $controller->callAction('controller_method', $parameters);
También tenga en cuenta que al hacer esto no ejecutará ninguno de los middlewares declarados en ese controlador.
Respuesta tardía, pero he estado buscando esto por algún tiempo. Esto ahora es posible de una manera muy simple.
Sin parámetros
return redirect()->action('HomeController@index');
Con parámetros
return redirect()->action('UserController@profile', ['id' => 1]);
Documentos: https://laravel.com/docs/5.6/responses#redirecting-controller-actions
En 5.0, requería todo el camino, ahora es mucho más simple.