Laravel 5'te başka bir denetleyiciden Erişim Denetleyicisi yöntemi


162

İki denetleyicim var SubmitPerformanceControllerve PrintReportController.

İçinde PrintReportControllerbir yöntem var getPrintReport.

Bu yönteme nasıl erişilir SubmitPerformanceController?

Yanıtlar:


366

Denetleyici yönteminize şu şekilde erişebilirsiniz:

app('App\Http\Controllers\PrintReportController')->getPrintReport();

Bu işe yarayacak, ancak kod organizasyonu açısından kötü (sizin için doğru ad alanını kullanmayı unutmayın PrintReportController)

Sen uzatabilirsiniz PrintReportControllerböylece SubmitPerformanceControllerbu yöntemi devralır

class SubmitPerformanceController extends PrintReportController {
     // ....
}

Ancak bu, diğer tüm yöntemleri de miras alacaktır PrintReportController.

En iyi yaklaşım bir trait(ör. app/Traitsİçinde) oluşturmak , mantığı oraya uygulamak ve denetleyicilerinize bunu kullanmasını söylemek olacaktır:

trait PrintReport {

    public function getPrintReport() {
        // .....
    }
}

Denetleyicilerinize bu özelliği kullanmasını söyleyin:

class PrintReportController extends Controller {
     use PrintReport;
}

class SubmitPerformanceController extends Controller {
     use PrintReport;
}

Her iki çözüm de yapmak SubmitPerformanceControllerzorunda getPrintReportolan arayabilirsin böylece yöntemi $this->getPrintReport();kontrolörü içinde veya doğrudan bir yol olarak gelen (sen eşledikten eğer routes.php)

Özellikler hakkında daha fazla bilgiyi buradan edinebilirsiniz .


10
Özelliği içeren dosya nereye kaydedilmelidir?
Brainmaniac

24
app('App\Http\Controllers\PrintReportController')->getPrintReport();dönüşebilir app(PrintReportController::class')->getPrintReport(). Benim için temiz çözüm.
Vincent Decaux

Özellik dosya nerede depolanır?
Eric McWinNEr

@EricMcWinNEr App \ Traits varsayalım, istediğiniz herhangi bir yerde saklanabilir. Ancak bu özellikte uygun ad alanını kullandığınızdan emin olun.
Mahkeme

1
Laravel'deki özellikleri kullanmak için sadece küçük bir örnek: developdesign.co.uk/news/…
Erenor Paz

48

Bu yönteme başka bir denetleyicide ihtiyacınız varsa, bunu soyutlamanız ve yeniden kullanılabilir hale getirmeniz gerekir. Bu uygulamayı bir hizmet sınıfına (ReportingService veya benzeri bir şey) taşıyın ve denetleyicilerinize enjekte edin.

Misal:

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
  }
}

Bu uygulamaya ihtiyaç duyduğunuz diğer denetleyiciler için de aynısını yapın. Diğer denetleyicilerden denetleyici yöntemlerine ulaşmak bir kod kokusudur.


Bu sınıfı proje yapısı açısından nereye kaydedersiniz?
Amitay

1
ServicesProje büyük değilse bir klasör ya da Reportingdaha büyük bir proje ve Folders By Featureyapı kullanıyorsa çağrılan bir özellik klasörü .
Ruffles

Laravel.com/docs/5.7/providers veya laravel.com/docs/5.7/container gibi bir Servis Sağlayıcıya (servis sınıfı) mı başvuruyorsunuz ?
Baspa

1
@Baspa Hayır, normal bir PHP sınıfı.
Ruffles

28

Bir Denetleyiciyi başka bir Denetleyiciden çağırmanız önerilmez, ancak herhangi bir nedenle yapmanız gerekirse, bunu yapabilirsiniz:

Laravel 5 uyumlu yöntem

return \App::call('bla\bla\ControllerName@functionName');

Not: bu sayfanın URL'sini güncellemez.

Bunun yerine Rotayı aramak ve denetleyiciyi aramasına izin vermek daha iyidir.

return \Redirect::route('route-name-here');

2
Neden önerilmez?
brunouno

Bu en iyi cevap olmalı.
Justin Vincent

13

Yapmamalısın. Bu bir anti-desen. Bir denetleyicide, başka bir denetleyicide erişmeniz gereken bir yönteminiz varsa, bu, yeniden faktörleştirmeniz gereken bir işarettir.

Yöntemi, birden çok denetleyicide başlatabileceğiniz bir hizmet sınıfına yeniden çarpanlara ayırmayı düşünün. Dolayısıyla, birden fazla model için baskı raporları sunmanız gerekiyorsa, bunun gibi bir şey yapabilirsiniz:

class ExampleController extends Controller
{
    public function printReport()
    {
        $report = new PrintReport($itemToReportOn);
        return $report->render();
    }
}

10
\App::call('App\Http\Controllers\MyController@getFoo')

11
Cevabınızın doğru olmasına rağmen, biraz uzatmak ve daha fazla açıklama yapmak güzel olurdu.
scana

9

Her şeyden önce, başka bir denetleyiciden bir denetleyici yöntemi istemek EVIL'dir. Bu Laravel'in yaşam döngüsünde birçok gizli soruna neden olacaktır.

Her neyse, bunu yapmak için birçok çözüm var. Bu çeşitli yollardan birini seçebilirsiniz.

Durum 1) Sınıflara göre aramak istiyorsanız

Yol 1) Basit yol

Ancak bu şekilde herhangi bir parametre veya kimlik doğrulama ekleyemezsiniz .

app(\App\Http\Controllers\PrintReportContoller::class)->getPrintReport();

Yol 2) Kontrolör mantığını servislere ayırın.

Sen herhangi bir parametre ve bir şeyler ekleyebilir bununla. Programlama hayatınız için en iyi çözüm. Bunun Repositoryyerine yapabilirsiniz 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 ...
    }
}

Durum 2) Güzergahlara göre aramak istiyorsanız

Yol 1) MakesHttpRequestsUygulama Birimi Testinde kullanılan özelliği kullanın .

Bu proxy'yi oluşturmak için özel bir nedeniniz varsa , herhangi bir parametre ve özel üstbilgi kullanabilirsiniz . Ayrıca bu laravel'de dahili bir istek olacaktır. (Sahte HTTP İsteği) Buradacall yöntem için daha fazla ayrıntı görebilirsiniz .

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 ...
    }
}

Ancak bu da 'iyi' bir çözüm değildir.

Yol 2) guzzlehttp istemcisini kullanın

Bu bence en korkunç çözüm. Sen herhangi bir parametre ve özel başlıklarını kullanabilirsiniz da. Ancak bu harici bir ek http isteği yapar. Bu nedenle HTTP Web sunucusu çalışıyor olmalıdır.

$client = new Client([
    'base_uri' => request()->getSchemeAndhttpHost(),
    'headers' => request()->header()
]);
$a = $client->get('/performance/submit')->getBody()->getContents()

Son olarak Vaka 2'nin 1. Yolu'nu kullanıyorum. Parametrelere ve


1
Yol 2 orada yazılmamalıdır, kötü bir kod yapısında bile asla kendiniz http-istemek istemezsiniz.
Sw0ut

5
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();   
    }
   }

7
Lütfen daha fazla bilgi ile düzenleyin. Yalnızca kod ve "bunu dene" yanıtları önerilmez çünkü bunlar aranabilir içerik içermez ve birisinin neden "bunu denemesi" gerektiğini açıklamaz.
abarisone

2

PrintReportController içinde statik bir yöntem kullanabilir ve SubmitPerformanceController'dan bu şekilde çağırabilirsiniz;

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();

    }

}

2

Bu yaklaşım aynı zamanda Denetleyici dosyaları hiyerarşisiyle de çalışır:

$printReport = new PrintReportController;

$prinReport->getPrintReport();

Ben bu blokları App :: ile karşılaştırıldığında gibi yapmak çünkü doc blokları tip ipucu hala phpStorm bu şekilde çalışır.
Floris

1

Burada özellik, laravel yönlendirici tarafından çalışan denetleyiciyi tamamen öykünür (orta ağ desteği ve bağımlılık enjeksiyonu dahil). Yalnızca 5.4 sürümü ile test edilmiştir

<?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();
    }
}

Daha sonra sınıfınıza ekleyin ve denetleyiciyi çalıştırın. Bağımlılık enjeksiyonunun geçerli rotanıza atanacağını unutmayın.

class CustomController extends Controller {
    use RunsAnotherController;

    public function someAction() 
    {
        $controller = app()->make('App\Http\Controllers\AnotherController');

        return $this->runController($controller, 'doSomething');
    }
}

Yapmanın app()->make(......)eşit app(......)olduğu ve daha kısa olduğu göz önünde bulundurun .
matiaslauriti

1

Denetleyiciyi başlatarak ve doAction'ı çağırarak erişebilirsiniz: ( use Illuminate\Support\Facades\App;denetleyici sınıfı bildiriminden önce koyun )

$controller = App::make('\App\Http\Controllers\YouControllerName');
$data = $controller->callAction('controller_method', $parameters);

Bunu yaparak, o denetleyicide bildirilen herhangi bir ara yazılımı yürütmeyeceğinizi de unutmayın.


-2

Geç cevap, ama bir süredir bunu arıyorum. Bu artık çok basit bir şekilde mümkün.

Parametresiz

return redirect()->action('HomeController@index');

Parametrelerle

return redirect()->action('UserController@profile', ['id' => 1]);

Dokümanlar: https://laravel.com/docs/5.6/responses#redirecting-controller-actions

5.0'a dönünce tüm yolu gerektiriyordu, şimdi çok daha basit.


3
Orijinal soru, bir denetleyicinin yöntemine, diğer belirli yöntemin eylemine nasıl yönlendirileceği değil, diğer denetleyiciden nasıl erişileceği idi, bu nedenle çözümünüz soruyla ilgili değildir.
matiaslauriti
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.