Eu tenho dois controladores SubmitPerformanceController
e PrintReportController
.
No PrintReportController
eu tenho um método chamado getPrintReport
.
Como acessar esse método no SubmitPerformanceController
?
Eu tenho dois controladores SubmitPerformanceController
e PrintReportController
.
No PrintReportController
eu tenho um método chamado getPrintReport
.
Como acessar esse método no SubmitPerformanceController
?
Respostas:
Você pode acessar seu método de controle como este:
app('App\Http\Controllers\PrintReportController')->getPrintReport();
Isso funcionará, mas é ruim em termos de organização do código (lembre-se de usar o espaço para nome certo para o seu PrintReportController
)
Você pode estender o PrintReportController
modo SubmitPerformanceController
herdará esse método
class SubmitPerformanceController extends PrintReportController {
// ....
}
Mas isso também herdará todos os outros métodos de PrintReportController
.
A melhor abordagem será criar trait
(por exemplo, in app/Traits
), implementar a lógica e dizer aos seus controladores para usá-la:
trait PrintReport {
public function getPrintReport() {
// .....
}
}
Diga a seus controladores para usar esta característica:
class PrintReportController extends Controller {
use PrintReport;
}
class SubmitPerformanceController extends Controller {
use PrintReport;
}
Ambas as soluções criam SubmitPerformanceController
um getPrintReport
método para que você possa chamá-lo $this->getPrintReport();
de dentro do controlador ou diretamente como uma rota (se você o mapeou no routes.php
)
Você pode ler mais sobre características aqui .
app('App\Http\Controllers\PrintReportController')->getPrintReport();
pode transformado para app(PrintReportController::class')->getPrintReport()
. Solução limpa para mim.
Se você precisar desse método em outro controlador, isso significa que você deve abstraí-lo e torná-lo reutilizável. Mova essa implementação para uma classe de serviço (ReportingService ou algo semelhante) e injete-a em seus controladores.
Exemplo:
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
}
}
Faça o mesmo para os outros controladores em que você precisa dessa implementação. Chegar a métodos de controle de outros controladores é um cheiro de código.
Services
pasta se o projeto não for grande ou uma pasta de recurso chamada Reporting
se for um projeto maior e usar Folders By Feature
estrutura.
Não é recomendável chamar um controlador de outro controlador; no entanto, se por algum motivo você precisar fazer isso, poderá fazer o seguinte:
Método compatível com Laravel 5
return \App::call('bla\bla\ControllerName@functionName');
Nota: isso não atualizará o URL da página.
É melhor chamar a rota e deixá-la chamar o controlador.
return \Redirect::route('route-name-here');
Você não deveria. É um anti-padrão. Se você possui um método em um controlador que precisa acessar em outro controlador, isso é um sinal de que você precisa refatorar.
Considere re-fatorar o método em uma classe de serviço, que você pode instanciar em vários controladores. Portanto, se você precisar oferecer relatórios de impressão para vários modelos, faça algo assim:
class ExampleController extends Controller
{
public function printReport()
{
$report = new PrintReport($itemToReportOn);
return $report->render();
}
}
\App::call('App\Http\Controllers\MyController@getFoo')
Primeiro de tudo, solicitar um método de um controlador de outro controlador é MAU. Isso causará muitos problemas ocultos no ciclo de vida do Laravel.
De qualquer forma, existem muitas soluções para isso. Você pode selecionar uma dessas várias maneiras.
Mas você não pode adicionar nenhum parâmetro ou autenticação dessa maneira.
app(\App\Http\Controllers\PrintReportContoller::class)->getPrintReport();
Você pode adicionar quaisquer parâmetros e algo com isso. A melhor solução para sua vida de programação. Você pode fazer em seu 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
característica usada no Teste de Unidade de Aplicativo.Eu recomendo isso se você tiver um motivo especial para criar esse proxy, poderá usar quaisquer parâmetros e cabeçalhos personalizados . Além disso, este será um pedido interno no laravel. (Solicitação HTTP falsa) Você pode ver mais detalhes sobre o call
método aqui .
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 ...
}
}
No entanto, essa também não é uma solução 'boa'.
Esta é a solução mais terrível que eu acho. Você também pode usar parâmetros e cabeçalhos personalizados . Mas isso faria uma solicitação http extra externa. Portanto, o servidor Web HTTP deve estar em execução.
$client = new Client([
'base_uri' => request()->getSchemeAndhttpHost(),
'headers' => request()->header()
]);
$a = $client->get('/performance/submit')->getBody()->getContents()
Finalmente, estou usando o Caminho 1 do Caso 2. Preciso de parâmetros 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();
}
}
Você pode usar um método estático no PrintReportController e chamá-lo no SubmitPerformanceController como este;
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();
}
}
Essa abordagem também funciona com a mesma hierarquia de arquivos do Controller:
$printReport = new PrintReportController;
$prinReport->getPrintReport();
Aqui, a característica emula totalmente o controlador em execução pelo roteador laravel (incluindo suporte de middlewares e injeção de dependência). Testado apenas com a versão 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();
}
}
Em seguida, basta adicioná-lo à sua classe e executar o controlador. Observe que a injeção de dependência será atribuída à sua rota atual.
class CustomController extends Controller {
use RunsAnotherController;
public function someAction()
{
$controller = app()->make('App\Http\Controllers\AnotherController');
return $this->runController($controller, 'doSomething');
}
}
app()->make(......)
é igual a, app(......)
portanto é mais curto.
Você pode acessar o controlador instanciando-o e chamando doAction: (colocado use Illuminate\Support\Facades\App;
antes da declaração da classe do controlador)
$controller = App::make('\App\Http\Controllers\YouControllerName');
$data = $controller->callAction('controller_method', $parameters);
Observe também que, ao fazer isso, você não executará nenhum dos middlewares declarados nesse controlador.
Resposta tardia, mas estou procurando isso há algum tempo. Agora isso é possível de uma maneira muito simples.
Sem parâmetros
return redirect()->action('HomeController@index');
Com parâmetros
return redirect()->action('UserController@profile', ['id' => 1]);
Documentos: https://laravel.com/docs/5.6/responses#redirecting-controller-actions
De volta à versão 5.0, era necessário todo o caminho, agora é muito mais simples.