ฉันมีสองตัวควบคุมและSubmitPerformanceController
PrintReportController
ในฉันมีวิธีที่เรียกว่าPrintReportController
getPrintReport
จะเข้าถึงวิธีนี้ได้SubmitPerformanceController
อย่างไร
ฉันมีสองตัวควบคุมและSubmitPerformanceController
PrintReportController
ในฉันมีวิธีที่เรียกว่าPrintReportController
getPrintReport
จะเข้าถึงวิธีนี้ได้SubmitPerformanceController
อย่างไร
คำตอบ:
คุณสามารถเข้าถึงวิธีการควบคุมของคุณเช่นนี้:
app('App\Http\Controllers\PrintReportController')->getPrintReport();
สิ่งนี้จะใช้งานได้ แต่ไม่ดีในแง่ของการจัดระเบียบโค้ด (อย่าลืมใช้เนมสเปซที่เหมาะสมสำหรับคุณPrintReportController
)
คุณสามารถขยายPrintReportController
ดังนั้นSubmitPerformanceController
จะสืบทอดวิธีนั้น
class SubmitPerformanceController extends PrintReportController {
// ....
}
แต่นี้ยังจะได้รับมรดกวิธีการอื่น ๆ PrintReportController
ทั้งหมดจาก
วิธีที่ดีที่สุดคือการสร้างtrait
(เช่นในapp/Traits
) ใช้ตรรกะที่นั่นและบอกให้ผู้ควบคุมของคุณใช้:
trait PrintReport {
public function getPrintReport() {
// .....
}
}
บอกผู้ควบคุมของคุณให้ใช้คุณลักษณะนี้:
class PrintReportController extends Controller {
use PrintReport;
}
class SubmitPerformanceController extends Controller {
use PrintReport;
}
ทั้งสองวิธีSubmitPerformanceController
มีgetPrintReport
วิธีการเพื่อให้คุณสามารถเรียกใช้$this->getPrintReport();
จากภายในตัวควบคุมหรือโดยตรงเป็นเส้นทาง (ถ้าคุณแมปในroutes.php
)
app('App\Http\Controllers\PrintReportController')->getPrintReport();
app(PrintReportController::class')->getPrintReport()
สามารถเปลี่ยนเป็น น้ำยาทำความสะอาดสำหรับฉัน
หากคุณต้องการวิธีการนั้นในตัวควบคุมอื่นนั่นหมายความว่าคุณจำเป็นต้องทำให้เป็นนามธรรมและทำให้มันสามารถใช้ซ้ำได้ ย้ายการนำไปใช้นั้นลงในคลาสบริการ (ReportingService หรือสิ่งที่คล้ายกัน) แล้วแทรกลงในคอนโทรลเลอร์ของคุณ
ตัวอย่าง:
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
}
}
ทำเช่นเดียวกันสำหรับคอนโทรลเลอร์อื่นที่คุณต้องการใช้งาน การเข้าถึงวิธีการควบคุมจากคอนโทรลเลอร์อื่นเป็นกลิ่นรหัส
Services
โฟลเดอร์หากโปรเจ็กต์ไม่ใหญ่หรือมีฟีเจอร์ที่เรียกว่าReporting
เป็นโปรเจ็กต์ที่ใหญ่กว่าและใช้Folders By Feature
โครงสร้าง
ไม่แนะนำให้เรียกตัวควบคุมจากตัวควบคุมอื่นอย่างไรก็ตามถ้าด้วยเหตุผลใดก็ตามที่คุณต้องทำคุณสามารถทำสิ่งนี้ได้:
วิธีที่เข้ากันได้ของ Laravel 5
return \App::call('bla\bla\ControllerName@functionName');
หมายเหตุ:สิ่งนี้จะไม่อัปเดต URL ของหน้า
มันจะดีกว่าที่จะเรียกเส้นทางแทนและปล่อยให้มันเรียกตัวควบคุม
return \Redirect::route('route-name-here');
คุณไม่ควร มันเป็นรูปแบบการต่อต้าน หากคุณมีวิธีในตัวควบคุมหนึ่งที่คุณต้องการเข้าถึงในตัวควบคุมอื่นนั่นเป็นสัญญาณที่คุณต้องพิจารณาปัจจัยอีกครั้ง
พิจารณาการคำนวณหาวิธีอื่นในคลาสบริการซึ่งคุณสามารถสร้างอินสแตนซ์ในคอนโทรลเลอร์หลายตัวได้ ดังนั้นหากคุณต้องการเสนอรายงานการพิมพ์สำหรับหลายรุ่นคุณสามารถทำสิ่งนี้:
class ExampleController extends Controller
{
public function printReport()
{
$report = new PrintReport($itemToReportOn);
return $report->render();
}
}
\App::call('App\Http\Controllers\MyController@getFoo')
ก่อนอื่นการร้องขอวิธีการควบคุมจากคอนโทรลเลอร์อื่นคือ EVIL สิ่งนี้จะทำให้เกิดปัญหาที่ซ่อนอยู่มากมายในวงจรชีวิตของ Laravel
อย่างไรก็ตามมีวิธีแก้ไขมากมายสำหรับการทำเช่นนั้น คุณสามารถเลือกได้หลายวิธี
แต่คุณไม่สามารถเพิ่มพารามิเตอร์หรือการรับรองความถูกต้องด้วยวิธีนี้
app(\App\Http\Controllers\PrintReportContoller::class)->getPrintReport();
คุณสามารถเพิ่มพารามิเตอร์และอะไรก็ได้ด้วยสิ่งนี้ ทางออกที่ดีที่สุดสำหรับชีวิตการเขียนโปรแกรมของคุณ คุณสามารถทำแทนRepository
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
คุณลักษณะที่ใช้ในการทดสอบหน่วยแอปพลิเคชันฉันแนะนำสิ่งนี้หากคุณมีเหตุผลพิเศษในการสร้างพร็อกซีนี้คุณสามารถใช้พารามิเตอร์และส่วนหัวที่กำหนดเองได้ นอกจากนี้จะเป็นการร้องขอภายในเป็น laravel (ขอ HTTP ปลอม) ท่านสามารถดูรายละเอียดเพิ่มเติมสำหรับcall
วิธีการในที่นี่
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 ...
}
}
อย่างไรก็ตามนี่ไม่ใช่วิธีที่ 'ดี' เช่นกัน
นี่เป็นทางออกที่น่ากลัวที่สุดที่ฉันคิด คุณสามารถใช้พารามิเตอร์และส่วนหัวที่กำหนดเองได้เช่นกัน แต่นี่จะเป็นการร้องขอ http พิเศษภายนอก ดังนั้น HTTP Webserver จึงต้องทำงาน
$client = new Client([
'base_uri' => request()->getSchemeAndhttpHost(),
'headers' => request()->header()
]);
$a = $client->get('/performance/submit')->getBody()->getContents()
ในที่สุดฉันก็ใช้วิธีที่ 1 ของกรณีที่ 2 ฉันต้องการพารามิเตอร์และ
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();
}
}
คุณสามารถใช้วิธีการคงที่ใน PrintReportController แล้วเรียกมันจาก SubmitPerformanceController ดังนี้
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();
}
}
วิธีการนี้ยังใช้งานได้กับลำดับชั้นของไฟล์คอนโทรลเลอร์:
$printReport = new PrintReportController;
$prinReport->getPrintReport();
นี่คือลักษณะที่จำลองการทำงานของคอนโทรลเลอร์อย่างสมบูรณ์โดยเราเตอร์ laravel (รวมถึงการสนับสนุนของมิดเดิลแวร์และการฉีดพึ่งพา) ทดสอบกับรุ่น 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();
}
}
จากนั้นเพิ่มไปยังคลาสของคุณและเรียกใช้คอนโทรลเลอร์ โปรดทราบว่าการฉีดพึ่งพาจะถูกกำหนดให้กับเส้นทางปัจจุบันของคุณ
class CustomController extends Controller {
use RunsAnotherController;
public function someAction()
{
$controller = app()->make('App\Http\Controllers\AnotherController');
return $this->runController($controller, 'doSomething');
}
}
app()->make(......)
นั้นมีค่าเท่ากับapp(......)
ดังนั้นจึงสั้นกว่า
คุณสามารถเข้าถึงคอนโทรลเลอร์ได้โดยการสร้างอินสแตนซ์และเรียกใช้ doAction: (ใส่use Illuminate\Support\Facades\App;
ก่อนการประกาศคลาสคอนโทรลเลอร์)
$controller = App::make('\App\Http\Controllers\YouControllerName');
$data = $controller->callAction('controller_method', $parameters);
โปรดทราบด้วยการทำเช่นนี้คุณจะไม่ใช้งานมิดเดิลแวร์ใด ๆ ที่ประกาศในตัวควบคุมนั้น
ตอบกลับช้า แต่ฉันได้ค้นหาสิ่งนี้มาระยะหนึ่งแล้ว ตอนนี้เป็นไปได้ในวิธีที่ง่ายมาก
ไม่มีพารามิเตอร์
return redirect()->action('HomeController@index');
ด้วยพารามิเตอร์
return redirect()->action('UserController@profile', ['id' => 1]);
เอกสาร: https://laravel.com/docs/5.6/responses#redirecting-controller- ปฏิกิริยา
ย้อนกลับไปใน 5.0 มันต้องการเส้นทางทั้งหมดตอนนี้มันง่ายกว่ามาก