Tôi có hai bộ điều khiển SubmitPerformanceController
và PrintReportController
.
Trong PrintReportController
tôi có một phương pháp gọi là getPrintReport
.
Làm thế nào để truy cập phương pháp này trong SubmitPerformanceController
?
Tôi có hai bộ điều khiển SubmitPerformanceController
và PrintReportController
.
Trong PrintReportController
tôi có một phương pháp gọi là getPrintReport
.
Làm thế nào để truy cập phương pháp này trong SubmitPerformanceController
?
Câu trả lời:
Bạn có thể truy cập phương thức điều khiển của bạn như thế này:
app('App\Http\Controllers\PrintReportController')->getPrintReport();
Điều này sẽ hoạt động, nhưng nó không tốt về mặt tổ chức mã (hãy nhớ sử dụng không gian tên phù hợp cho bạn PrintReportController
)
Bạn có thể mở rộng PrintReportController
vì vậy SubmitPerformanceController
sẽ kế thừa phương thức đó
class SubmitPerformanceController extends PrintReportController {
// ....
}
Nhưng điều này cũng sẽ kế thừa tất cả các phương pháp khác từ PrintReportController
.
Cách tiếp cận tốt nhất sẽ là tạo một trait
(ví dụ trong app/Traits
), triển khai logic ở đó và báo cho bộ điều khiển của bạn sử dụng nó:
trait PrintReport {
public function getPrintReport() {
// .....
}
}
Nói với bộ điều khiển của bạn để sử dụng đặc điểm này:
class PrintReportController extends Controller {
use PrintReport;
}
class SubmitPerformanceController extends Controller {
use PrintReport;
}
Cả hai giải pháp SubmitPerformanceController
đều có getPrintReport
phương thức để bạn có thể gọi nó bằng $this->getPrintReport();
từ bên trong bộ điều khiển hoặc trực tiếp dưới dạng tuyến đường (nếu bạn ánh xạ nó trongroutes.php
)
Bạn có thể đọc thêm về đặc điểm ở đây .
app('App\Http\Controllers\PrintReportController')->getPrintReport();
có thể biến thành app(PrintReportController::class')->getPrintReport()
. Giải pháp sạch cho tôi.
Nếu bạn cần phương thức đó trong một bộ điều khiển khác, điều đó có nghĩa là bạn cần trừu tượng hóa nó và làm cho nó có thể sử dụng lại. Chuyển việc triển khai đó vào một lớp dịch vụ (ReportingService hoặc một cái gì đó tương tự) và đưa nó vào bộ điều khiển của bạn.
Thí dụ:
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
}
}
Làm tương tự cho các bộ điều khiển khác mà bạn cần thực hiện. Tiếp cận các phương thức điều khiển từ các bộ điều khiển khác là mùi mã.
Services
thư mục nếu dự án không lớn hoặc thư mục tính năng được gọi Reporting
nếu đó là một dự án lớn hơn và sử dụng Folders By Feature
cấu trúc.
Không nên gọi Bộ điều khiển từ Bộ điều khiển khác, tuy nhiên nếu vì bất kỳ lý do gì bạn phải thực hiện, bạn có thể thực hiện việc này:
Phương pháp tương thích với Laravel 5
return \App::call('bla\bla\ControllerName@functionName');
Lưu ý: điều này sẽ không cập nhật URL của trang.
Thay vào đó, tốt hơn là gọi Tuyến và để nó gọi bộ điều khiển.
return \Redirect::route('route-name-here');
Bạn không nên. Đó là một mô hình chống. Nếu bạn có một phương thức trong một bộ điều khiển mà bạn cần truy cập trong một bộ điều khiển khác, thì đó là một dấu hiệu bạn cần phải xác định lại.
Xem xét việc bao thanh toán lại phương thức trong một lớp dịch vụ, sau đó bạn có thể khởi tạo trong nhiều bộ điều khiển. Vì vậy, nếu bạn cần cung cấp báo cáo in cho nhiều mô hình, bạn có thể làm một cái gì đó như thế này:
class ExampleController extends Controller
{
public function printReport()
{
$report = new PrintReport($itemToReportOn);
return $report->render();
}
}
\App::call('App\Http\Controllers\MyController@getFoo')
Trước hết, yêu cầu một phương thức của bộ điều khiển từ bộ điều khiển khác là EVIL. Điều này sẽ gây ra nhiều vấn đề tiềm ẩn trong vòng đời của Laravel.
Dù sao, có nhiều giải pháp để làm điều đó. Bạn có thể chọn một trong những cách khác nhau.
Nhưng bạn không thể thêm bất kỳ tham số hoặc xác thực theo cách này.
app(\App\Http\Controllers\PrintReportContoller::class)->getPrintReport();
Bạn có thể thêm bất kỳ tham số và một cái gì đó với điều này. Giải pháp tốt nhất cho cuộc sống lập trình của bạn. Bạn có thể thực hiện Repository
thay thế 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
đặc điểm được sử dụng trong Kiểm tra đơn vị ứng dụng.Tôi khuyên bạn nên điều này nếu bạn có lý do đặc biệt để tạo proxy này, bạn có thể sử dụng bất kỳ tham số và tiêu đề tùy chỉnh nào . Ngoài ra đây sẽ là một yêu cầu nội bộ trong laravel. (Yêu cầu HTTP giả) Bạn có thể xem thêm chi tiết cho call
phương thức tại đây .
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 ...
}
}
Tuy nhiên, đây cũng không phải là một giải pháp 'tốt'.
Đây là giải pháp khủng khiếp nhất tôi nghĩ. Bạn cũng có thể sử dụng bất kỳ tham số và tiêu đề tùy chỉnh nào . Nhưng điều này sẽ làm cho một yêu cầu http thêm bên ngoài. Vì vậy, HTTP Webserver phải được chạy.
$client = new Client([
'base_uri' => request()->getSchemeAndhttpHost(),
'headers' => request()->header()
]);
$a = $client->get('/performance/submit')->getBody()->getContents()
Cuối cùng tôi đang sử dụng Cách 1 của Trường hợp 2. Tôi cần các tham số và
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();
}
}
Bạn có thể sử dụng một phương thức tĩnh trong PrintReportControll và sau đó gọi nó từ SendPerformanceControll như thế này;
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();
}
}
Cách tiếp cận này cũng hoạt động với cùng phân cấp các tệp Trình điều khiển:
$printReport = new PrintReportController;
$prinReport->getPrintReport();
Ở đây, đặc điểm mô phỏng hoàn toàn bộ điều khiển đang chạy bằng bộ định tuyến laravel (bao gồm hỗ trợ phần mềm trung gian và tiêm phụ thuộc). Chỉ được thử nghiệm với phiên bả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();
}
}
Sau đó, chỉ cần thêm nó vào lớp của bạn và chạy bộ điều khiển. Lưu ý, tiêm phụ thuộc sẽ được chỉ định với tuyến đường hiện tại của bạn.
class CustomController extends Controller {
use RunsAnotherController;
public function someAction()
{
$controller = app()->make('App\Http\Controllers\AnotherController');
return $this->runController($controller, 'doSomething');
}
}
app()->make(......)
là bằng để app(......)
nó ngắn hơn.
Bạn có thể truy cập bộ điều khiển bằng cách khởi tạo nó và gọi doAction: (đặt use Illuminate\Support\Facades\App;
trước khai báo lớp của bộ điều khiển)
$controller = App::make('\App\Http\Controllers\YouControllerName');
$data = $controller->callAction('controller_method', $parameters);
Cũng lưu ý rằng bằng cách này, bạn sẽ không thực thi bất kỳ phần mềm trung gian nào được khai báo trên bộ điều khiển đó.
Trả lời muộn, nhưng đôi khi tôi đã tìm kiếm điều này. Điều này bây giờ có thể theo một cách rất đơn giản.
Không có tham số
return redirect()->action('HomeController@index');
Với thông số
return redirect()->action('UserController@profile', ['id' => 1]);
Tài liệu: https://laravel.com/docs/5.6/responses#redirecting-controll-ilities
Trở lại 5.0, nó yêu cầu toàn bộ đường dẫn, bây giờ nó đơn giản hơn nhiều.