लारवेल 5 में एक अन्य नियंत्रक से एक्सेस कंट्रोलर विधि


162

मेरे पास दो नियंत्रक SubmitPerformanceControllerऔर हैं PrintReportController

में PrintReportControllerमुझे एक विधि कहा जाता है getPrintReport

इस पद्धति का उपयोग कैसे करें SubmitPerformanceController?

जवाबों:


364

आप इस तरह से अपनी कंट्रोलर विधि का उपयोग कर सकते हैं:

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) में कॉल कर सकते हैं

आप लक्षणों के बारे में अधिक यहाँ पढ़ सकते हैं ।


10
विशेषता सहित फ़ाइल को कहाँ सहेजा जाना चाहिए?
8

24
app('App\Http\Controllers\PrintReportController')->getPrintReport();में तब्दील हो सकता है app(PrintReportController::class')->getPrintReport()। मेरे लिए स्वच्छ समाधान।
विंसेंट डेकाक्स

विशेषता फ़ाइल कहाँ संग्रहीत होती है?
बजे एरिक मैकविनेर

@EricMcWinNEr यह आपकी पसंद के अनुसार कहीं भी संग्रहीत किया जा सकता है, जैसे मान लें कि App \ Traits। लेकिन उस विशेषता में उपयुक्त नाम स्थान का उपयोग करना सुनिश्चित करें।
ट्रिब्यूनल


48

यदि आपको किसी अन्य नियंत्रक में उस विधि की आवश्यकता है, तो इसका मतलब है कि आपको इसे सार करने और इसे पुन: उपयोग करने की आवश्यकता है। उस कार्यान्वयन को एक सेवा वर्ग (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
  }
}

अन्य नियंत्रकों के लिए भी वही करें जहाँ आपको उस कार्यान्वयन की आवश्यकता है। अन्य नियंत्रकों से नियंत्रक विधियों के लिए पहुंचना एक कोड गंध है।


प्रोजेक्ट संरचना के संदर्भ में आप इस वर्ग को कहाँ बचा पाएंगे?
अमिताभ जूल

1
या तो एक Servicesफ़ोल्डर अगर प्रोजेक्ट बड़ा नहीं है या एक फीचर फ़ोल्डर है जिसे कॉल किया जाता है Reportingअगर यह एक बड़ा प्रोजेक्ट है और Folders By Featureसंरचना का उपयोग करता है।
रफल्स

आप की तरह यहाँ एक सेवा प्रदाता (सेवा वर्ग) की बात कर रहे laravel.com/docs/5.7/providers या एक सेवा कंटेनर यहाँ की तरह laravel.com/docs/5.7/container ?
बसपा

1
@Baspa नहीं, एक सामान्य PHP वर्ग।
रफल्स

27

किसी अन्य नियंत्रक से नियंत्रक को बुलाने की अनुशंसा नहीं की जाती है, हालाँकि यदि किसी भी कारण से आपको यह करना है, तो आप यह कर सकते हैं:

लारवेल 5 संगत विधि

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

नोट: यह पृष्ठ के URL को अपडेट नहीं करेगा।

इसके बजाय रूट को कॉल करना बेहतर है और इसे नियंत्रक को कॉल करने दें।

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

2
क्यों अनुशंसित नहीं है?
ब्रुनेउ

यह शीर्ष उत्तर होना चाहिए।
जस्टिन विंसेंट

13

आपको नहीं करना चाहिए यह एक विरोधी पैटर्न है। यदि आपके पास एक नियंत्रक में एक विधि है जिसे आपको दूसरे नियंत्रक में एक्सेस करने की आवश्यकता है, तो यह एक संकेत है जिसे आपको फिर से कारक करने की आवश्यकता है।

सेवा वर्ग में विधि को फिर से फैक्टर करने पर विचार करें, ताकि आप बाद में कई नियंत्रकों में त्वरित कर सकें। इसलिए यदि आपको कई मॉडलों के लिए प्रिंट रिपोर्ट देने की आवश्यकता है, तो आप कुछ ऐसा कर सकते हैं:

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

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

11
इस तथ्य के बावजूद कि आपका उत्तर सही हो सकता है, यह अच्छा होगा कि इसे थोड़ा बढ़ाया जाए और कुछ और स्पष्टीकरण दिया जाए।
स्कैना

9

सबसे पहले, किसी अन्य नियंत्रक से नियंत्रक की एक विधि का अनुरोध ईवीआईएल है। यह लारवेल के जीवन-चक्र में कई छिपी हुई समस्याओं का कारण बनेगा।

वैसे भी, ऐसा करने के लिए कई समाधान हैं। आप इन विभिन्न तरीकों में से एक का चयन कर सकते हैं।

केस 1) यदि आप कक्षाओं के आधार पर कॉल करना चाहते हैं

रास्ता 1) सरल तरीका

लेकिन आप इस तरह से कोई पैरामीटर या प्रमाणीकरण नहीं जोड़ सकते

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

मार्ग 2) नियंत्रक तर्क को सेवाओं में विभाजित करें।

आप इसके साथ कोई भी पैरामीटर और कुछ जोड़ सकते हैं । आपके प्रोग्रामिंग जीवन के लिए सबसे अच्छा समाधान। आप 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 ...
    }
}

केस 2) यदि आप रूट्स के आधार पर कॉल करना चाहते हैं

तरीका 1) MakesHttpRequestsएप्लिकेशन यूनिट टेस्टिंग में उपयोग होने वाले विशेषता का उपयोग करें ।

मैं इसे सुझाता हूं यदि आपके पास इस प्रॉक्सी को बनाने का विशेष कारण है, तो आप किसी भी पैरामीटर और कस्टम हेडर का उपयोग कर सकते हैं । इसके अलावा यह लार्वा में एक आंतरिक अनुरोध होगा । (फेक एचटीटीपी रिक्वेस्ट) आप यहां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 ...
    }
}

हालाँकि यह 'अच्छा' समाधान नहीं है।

तरीका 2) guzzlehttp क्लाइंट का उपयोग करें

मुझे लगता है कि यह सबसे भयानक समाधान है। आप किसी भी पैरामीटर और कस्टम हेडर का भी उपयोग कर सकते हैं । लेकिन यह एक बाहरी अतिरिक्त http अनुरोध कर रहा होगा। तो HTTP वेबसर्वर चलना चाहिए।

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

अंत में मैं केस 2 के मार्ग 1 का उपयोग कर रहा हूं। मुझे मापदंडों और की आवश्यकता है


1
रास्ते 2 को नीचे नहीं लिखा जाना चाहिए, आप कभी भी खराब कोड संरचना में स्वयं को स्वयं अनुरोध करने की इच्छा नहीं रखते हैं।
स्वॉट

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
कृपया अधिक जानकारी के साथ संपादित करें। कोड-ओनली एंड "ट्राय दिस" जवाबों को हतोत्साहित किया जाता है, क्योंकि उनमें कोई खोज योग्य सामग्री नहीं होती है, और यह नहीं समझाते कि किसी को "कोशिश" क्यों करनी चाहिए।
अबरिसोन

2

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

    }

}

2

यह दृष्टिकोण नियंत्रक फ़ाइलों के समान पदानुक्रम के साथ भी काम करता है:

$printReport = new PrintReportController;

$prinReport->getPrintReport();

मैं इस दृष्टिकोण को ऐप की तुलना में पसंद करता हूं :: एक बना देता हूं क्योंकि डॉक्टर ब्लॉक के प्रकार का संकेत अभी भी phpStorm में इस तरह से काम करता है।
फ्लोरिस

1

यहाँ विशेषता पूरी तरह से लार्वा राउटर (बिचौलियों और निर्भरता इंजेक्शन के समर्थन सहित) द्वारा चलने वाले नियंत्रक का अनुकरण करती है। केवल 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(......)इसलिए यह छोटा है।
मतिलसौरिटी

1

आप इसे इंस्टेंट करके कंट्रोलर को कॉल कर सकते हैं और doAction: ( use Illuminate\Support\Facades\App;कंट्रोलर क्लास डिक्लेरेशन से पहले डाल सकते हैं )

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

यह भी ध्यान दें कि ऐसा करने से आप उस नियंत्रक पर घोषित किसी भी बिचौलिये को निष्पादित नहीं करेंगे।


-2

देर से जवाब, लेकिन मैं कुछ समय के लिए इस के लिए देख रहा हूँ। यह अब बहुत सरल तरीके से संभव है।

मापदंडों के बिना

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

पैरामीटर्स के साथ

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

डॉक्स: https://laravel.com/docs/5.6/responses#redirecting-controller-actions

5.0 में वापस पूरे रास्ते की आवश्यकता थी, अब यह बहुत सरल है।


3
मूल प्रश्न यह था कि किसी नियंत्रक की विधि को अन्य नियंत्रक से कैसे प्राप्त किया जाए, न कि अन्य विशिष्ट विधि की कार्रवाई के लिए कैसे पुनर्निर्देशित किया जाए, इसलिए आपका समाधान प्रश्न से संबंधित नहीं है।
मतिलसौरिटी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.