Saya memiliki dua pengendali SubmitPerformanceController
dan PrintReportController
.
Dalam PrintReportController
saya punya metode yang disebut getPrintReport
.
Bagaimana cara mengakses metode ini SubmitPerformanceController
?
Saya memiliki dua pengendali SubmitPerformanceController
dan PrintReportController
.
Dalam PrintReportController
saya punya metode yang disebut getPrintReport
.
Bagaimana cara mengakses metode ini SubmitPerformanceController
?
Jawaban:
Anda dapat mengakses metode pengontrol Anda seperti ini:
app('App\Http\Controllers\PrintReportController')->getPrintReport();
Ini akan berhasil, tetapi buruk dalam hal pengaturan kode (ingat untuk menggunakan namespace yang tepat untuk Anda PrintReportController
)
Anda dapat memperpanjang PrintReportController
sehingga SubmitPerformanceController
akan mewarisi metode itu
class SubmitPerformanceController extends PrintReportController {
// ....
}
Tetapi ini juga akan mewarisi semua metode lain dari PrintReportController
.
Pendekatan terbaik adalah dengan membuat trait
(misalnya dalam app/Traits
), mengimplementasikan logika di sana dan memberi tahu pengendali Anda untuk menggunakannya:
trait PrintReport {
public function getPrintReport() {
// .....
}
}
Beri tahu pengontrol Anda untuk menggunakan sifat ini:
class PrintReportController extends Controller {
use PrintReport;
}
class SubmitPerformanceController extends Controller {
use PrintReport;
}
Kedua solusi membuat SubmitPerformanceController
memiliki getPrintReport
metode sehingga Anda dapat memanggilnya $this->getPrintReport();
dari dalam controller atau langsung sebagai rute (jika Anda memetakannya dalam routes.php
)
Anda dapat membaca lebih lanjut tentang ciri-ciri di sini .
app('App\Http\Controllers\PrintReportController')->getPrintReport();
dapat ditransformasikan menjadi app(PrintReportController::class')->getPrintReport()
. Solusi bersih untuk saya.
Jika Anda memerlukan metode itu di pengontrol lain, itu artinya Anda perlu mengabstraksikannya dan membuatnya bisa digunakan kembali. Pindahkan implementasi itu ke kelas layanan (ReportingService atau yang serupa) dan suntikkan ke controller Anda.
Contoh:
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
}
}
Lakukan hal yang sama untuk pengontrol lain di mana Anda memerlukan implementasi itu. Mencapai metode pengontrol dari pengontrol lain adalah bau kode.
Services
folder jika proyek tidak besar atau folder fitur disebut Reporting
apakah itu proyek yang lebih besar dan menggunakan Folders By Feature
struktur.
Memanggil Pengendali dari Pengontrol lain tidak disarankan, namun jika karena alasan apa pun Anda harus melakukannya, Anda dapat melakukan ini:
Metode kompatibel Laravel 5
return \App::call('bla\bla\ControllerName@functionName');
Catatan: ini tidak akan memperbarui URL halaman.
Lebih baik untuk memanggil Rute dan membiarkannya memanggil controller.
return \Redirect::route('route-name-here');
Anda seharusnya tidak. Ini anti-pola. Jika Anda memiliki metode dalam satu pengontrol yang perlu Anda akses di pengontrol lain, maka itu pertanda Anda perlu faktor ulang.
Pertimbangkan untuk memfaktorkan ulang metode keluar ke kelas layanan, yang kemudian dapat Anda instantiate di beberapa pengontrol. Jadi, jika Anda perlu menawarkan laporan cetak untuk banyak model, Anda dapat melakukan sesuatu seperti ini:
class ExampleController extends Controller
{
public function printReport()
{
$report = new PrintReport($itemToReportOn);
return $report->render();
}
}
\App::call('App\Http\Controllers\MyController@getFoo')
Pertama-tama, meminta metode pengontrol dari pengontrol lain adalah JAHAT. Ini akan menyebabkan banyak masalah tersembunyi dalam siklus hidup Laravel.
Bagaimanapun, ada banyak solusi untuk melakukan itu. Anda dapat memilih salah satu dari berbagai cara ini.
Tetapi Anda tidak dapat menambahkan parameter atau autentikasi dengan cara ini.
app(\App\Http\Controllers\PrintReportContoller::class)->getPrintReport();
Anda dapat menambahkan parameter dan sesuatu dengan ini. Solusi terbaik untuk kehidupan pemrograman Anda. Anda dapat membuat Repository
sebagai gantinya 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
sifat yang digunakan dalam Pengujian Unit Aplikasi.Saya merekomendasikan ini jika Anda memiliki alasan khusus untuk membuat proksi ini, Anda dapat menggunakan parameter dan header khusus apa pun . Juga ini akan menjadi permintaan internal di laravel. (Permintaan HTTP Palsu) Anda dapat melihat detail lebih lanjut untuk call
metode ini di sini .
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 ...
}
}
Namun ini bukan solusi yang 'baik' juga.
Ini adalah solusi paling mengerikan yang saya pikir. Anda dapat menggunakan parameter dan tajuk khusus apa pun. Tapi ini akan membuat permintaan http eksternal tambahan. Jadi HTTP Webserver harus dijalankan.
$client = new Client([
'base_uri' => request()->getSchemeAndhttpHost(),
'headers' => request()->header()
]);
$a = $client->get('/performance/submit')->getBody()->getContents()
Akhirnya saya menggunakan Way 1 dari Kasus 2. Saya perlu parameter dan
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();
}
}
Anda dapat menggunakan metode statis di PrintReportController dan kemudian memanggilnya dari SubmitPerformanceController seperti ini;
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();
}
}
Pendekatan ini juga berfungsi dengan hierarki file Controller yang sama:
$printReport = new PrintReportController;
$prinReport->getPrintReport();
Di sini sifat sepenuhnya mengemulasi menjalankan controller oleh router laravel (termasuk dukungan middlewares dan injeksi ketergantungan). Diuji hanya dengan versi 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();
}
}
Kemudian tambahkan saja ke kelas Anda dan jalankan controller. Perhatikan, injeksi ketergantungan akan diberikan dengan rute Anda saat ini.
class CustomController extends Controller {
use RunsAnotherController;
public function someAction()
{
$controller = app()->make('App\Http\Controllers\AnotherController');
return $this->runController($controller, 'doSomething');
}
}
app()->make(......)
sama dengan app(......)
sehingga lebih pendek.
Anda dapat mengakses controller dengan membuat instance dan memanggil doAction: (diletakkan use Illuminate\Support\Facades\App;
sebelum deklarasi kelas controller)
$controller = App::make('\App\Http\Controllers\YouControllerName');
$data = $controller->callAction('controller_method', $parameters);
Perhatikan juga bahwa dengan melakukan ini, Anda tidak akan menjalankan middlewares yang dideklarasikan pada pengontrol itu.
Terlambat membalas, tetapi saya telah mencari ini untuk beberapa waktu. Ini sekarang mungkin dengan cara yang sangat sederhana.
Tanpa parameter
return redirect()->action('HomeController@index');
Dengan Parameter
return redirect()->action('UserController@profile', ['id' => 1]);
Documents: https://laravel.com/docs/5.6/responses#redirecting-controller-actions
Kembali di 5.0 diperlukan seluruh path, sekarang jauh lebih sederhana.