2012-02-15 12 views
25

मैं सेवा में सभी पैरामीटर कैसे इंजेक्ट कर सकता हूं?Symfony2: सेवा में सभी पैरामीटर कैसे इंजेक्ट करें?

मुझे पता है कि मैं कर सकता हूं: arguments: [%some.key%] जो सेवा __construct सेवा के लिए parameters: some.key: "value" पास करेगा।

मेरा प्रश्न है, सेवा में parameters के तहत जो कुछ भी है, उसे इंजेक्ट कैसे करें?

मुझे नेविगेशन प्रबंधक सेवा बनाने के लिए इसकी आवश्यकता है, जहां विभिन्न विन्यास प्रविष्टियों के माध्यम से विभिन्न सेटिंग्स के अनुसार विभिन्न मेनू/नेविगेशन/ब्रेडक्रंब उत्पन्न किए जाने हैं।

मुझे पता है कि मैं जितना चाहूं उतने पैरामीटर इंजेक्ट कर सकता हूं, लेकिन चूंकि यह उनमें से कई का उपयोग करने जा रहा है और समय के साथ विस्तार करने जा रहा है, मुझे लगता है कि शुरुआत में पूरी चीज को सही तरीके से पार करना बेहतर होगा।

अन्य दृष्टिकोण हो सकता है अगर मैं नियंत्रक $this -> container -> getParameter('some.key'); में सेवा के अंदर पैरामीटर प्राप्त कर सकता हूं, लेकिन मुझे लगता है कि यह निर्भरता इंजेक्शन के विचार के खिलाफ होगा?

अग्रिम धन्यवाद!

उत्तर

7

नोट: मुझे पता है कि यह समाधान डिजाइन बिंदु से सबसे अच्छा नहीं है, लेकिन यह काम करता है, इसलिए कृपया नीचे मतदान से बचें।

आप \ AppKernel वस्तु इंजेक्षन कर सकते हैं और फिर इस तरह सभी मापदंडों का उपयोग:

config.yml:

my_service: 
    class: MyService\Class 
    arguments: [@kernel] 

और MyService\Class अंदर:

public function __construct($kernel) 
{ 
    $this->parameter = $kernel->getContainer()->getParameter('some.key'); 
    // or to get all: 
    $this->parameters = $kernel->getContainer()->getParameterBag()->all(); 
} 
+0

बिल्कुल मुझे जो चाहिए, मैं कर्नेल के बारे में भूल गया। धन्यवाद! –

+0

वाह! मेरे पास एक पूरी तरह से अलग सवाल था, आपके जवाब ने मेरी समस्या हल की! – Arsham

+33

कर्नेल – kratos

7

AppKernel काम करेगा, लेकिन यह है कंटेनर इंजेक्शन करने से भी बदतर (एक दायरे परिप्रेक्ष्य से) भी कर्नेल में इसमें और भी सामान है।

आप अपनी कैश निर्देशिका में xxxProjectContainer देख सकते हैं। यह पता चला है कि मिश्रित पैरामीटर को सीधे एक बड़ी सरणी के रूप में संकलित किया जाता है। तो आप कंटेनर इंजेक्ट कर सकते हैं और फिर पैरामीटर खींच सकते हैं। कानून के पत्र का उल्लंघन करता है लेकिन कानून की भावना नहीं।

class MyService { 
    public function __construct($container) { 
     $this->parameters = $container->parameters; // Then discard container to preclude temptation 

और बस एक तरह से चारों ओर खिलवाड़ मुझे लगता है मैं ऐसा कर सकता है पाया:

$container = new \arbiterDevDebugProjectContainer(); 
    echo 'Parameter Count ' . count($container->parameters) . "\n"; 

तो आप वास्तव में एक सेवा है जो मूल रूप से मास्टर कंटेनर का एक खाली प्रतिलिपि था बना सकते हैं और इसकी सुई सिर्फ पाने के लिए पैरामीटर देव/डीबग झंडे को ध्यान में रखना है जो दर्द हो सकता है।

मुझे संदेह है कि आप इसे एक कंपाइलर पास के साथ भी कर सकते हैं लेकिन कभी कोशिश नहीं की है।

+3

है, मैं सीधे कंटेनर सेवा इंजेक्ट करने की अनुशंसा नहीं करता क्योंकि यह निर्भरता इंजेक्शन की अवधारणा को तोड़ देगा। – GusDeCooL

8

मुझे विश्वास है कि आपको अलग-अलग पैरामीटर पारित करना होगा। मुझे लगता है कि यह डिजाइन द्वारा इस तरह से बनाया गया है ताकि आपकी सेवा कक्षा AppKernel पर निर्भर न हो। इस तरह आप अपने सिम्फनी प्रोजेक्ट के बाहर अपनी सर्विस क्लास का पुन: उपयोग कर सकते हैं। आपकी सेवा कक्षा का परीक्षण करते समय कुछ उपयोगी होता है।

+1

+1 अलग-अलग पैरामीटर के लिए +1 – kratos

3

वैकल्पिक दृष्टिकोण के रूप में हो सकता है कि आप वास्तव में आप में के माध्यम से Container-> getParameterBag आपकी सेवा में आवेदन मानकों इंजेक्षन कर सकते हैं बंडल डि एक्सटेंशन

<?php 

    namespace Vendor\ProjectBundle\DependencyInjection; 

    use Symfony\Component\DependencyInjection\ContainerBuilder; 
    use Symfony\Component\Config\FileLocator; 
    use Symfony\Component\HttpKernel\DependencyInjection\Extension; 
    use Symfony\Component\DependencyInjection\Loader; 

    /** 
    * This is the class that loads and manages your bundle configuration 
    * 
    * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html} 
    */ 
    class VendorProjectExtension extends Extension { 

     /** 
     * {@inheritDoc} 
     */ 
     public function load(array $configs, ContainerBuilder $container) { 
      $configuration = new Configuration(); 
      $config = $this->processConfiguration($configuration, $configs); 
      $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); 
      $loader->load('services.yml'); 
      /** set params for services */ 
      $container->getDefinition('my.managed.service.one') 
        ->addMethodCall('setContainerParams', array($container->getParameterBag()->all())); 
      $container->getDefinition('my.managed.service.etc') 
        ->addMethodCall('setContainerParams', array($container->getParameterBag()->all())); 

     } 
} 

कृपया ध्यान दें कि हम ParameterBag वस्तु सीधे इंजेक्षन नहीं कर सकते, कारण फेंक देता है :

[Symfony \ घटक \ DependencyInjection \ अपवाद \ RuntimeException]
एक सेवा कंटेनर डंप करने के लिए अगर एक पैरामीटर एक वस्तु या एक संसाधन है असमर्थ।

Symfony संस्करण 2.3.4

+0

डी – kratos

+0

$ कंटेनर इंजेक्ट करने के लिए बुरा विचार-> getParameterBag() -> सभी() वास्तव में वापस [सरणी] (https://github.com/symfony/symfony/blob/master/src/ सिम्फनी/घटक/निर्भरता इंजेक्शन/पैरामीटरबैग/पैरामीटर Bag.php # L75) – andrew

42

यह एक सेवा में पूरे कंटेनर इंजेक्षन एक अच्छा अभ्यास नहीं है के तहत परीक्षण किया गया। इसके अलावा यदि आपके पास अपनी सेवा के लिए आवश्यक कई पैरामीटर हैं, तो उन सभी को एक-एक करके अपनी सेवा में इंजेक्ट करना अच्छा नहीं है। इसके बजाय मैं इस विधि का उपयोग:

parameters: 
    product.shoppingServiceParams: 
     parameter1: 'Some data' 
     parameter2: 'some data' 
     parameter3: 'some data' 
     parameter4: 'some data' 
     parameter5: 'some data' 
     parameter6: 'some data' 

2) तो फिर मैं की तरह मेरी सेवा करने के लिए इस रूट पैरामीटर इंजेक्षन:

1) config.yml में मैं पैरामीटर है कि मैं इस तरह मेरी सेवा के लिए की जरूरत को परिभाषित

services: 
    product.shoppingService: 
    class: Saman\ProductBundle\Service\Shopping 
    arguments: [@translator.default, %product.shoppingServiceParams%] 

3) मई सेवा में मैं की तरह इस पैरामीटर के लिए उपयोग कर सकते हैं:

namespace Saman\ProductBundle\Service; 

use Symfony\Bundle\FrameworkBundle\Translation\Translator; 

class Shopping 
{ 
    protected $translator; 
    protected $paramaters; 

    public function __construct(
     Translator $translator, 
     $parameters 
     ) 
    { 
     $this->translator = $translator; 
     $this->parameters = $parameters; 
    } 

    public function dummyFunction() 
    { 
     var_dump($this->getParameter('parameter2')); 
    } 

    private function getParameter($key, $default = null) 
    { 
     if (isset($this->parameters[$key])) { 
      return $this->parameters[$key]; 
     } 

     return $default; 
    } 
} 

4) मैं भी एस कर सकते हैं और विभिन्न वातावरण के लिए अलग-अलग मूल्य। config_dev.yml में उदाहरण के लिए

parameters: 
    product.shoppingServiceParams: 
     parameter1: 'Some data for dev' 
     parameter2: 'some data for dev' 
     parameter3: 'some data for dev' 
     parameter4: 'some data for dev' 
     parameter5: 'some data for dev' 
     parameter6: 'some data' 
+3

निश्चित रूप से सबसे अच्छा दृष्टिकोण imho! – MediaVince

+0

@Saman अगर आप पैरामीटर के लिए शून्य वापस नहीं करते हैं तो array_key_exists का उपयोग क्यों करें? isset() एक ही परिणाम उत्पन्न करेगा, केवल तेज़। - अन्यथा अच्छा जवाब। – OIS

+0

धन्यवाद, हाँ आप पूरी तरह से –

4

सुझाव services.yml पर एक सेवा है, जो आपके पैरामीटर

service.container_parameters: 
    public: false 
    class: stdClass 
    factory_service: service_container 
    factory_method: getParameterBag 

में से किसी को parameterBag इंजेक्षन और उपयोग की अनुमति देगा परिभाषित करने के लिए आपकी सेवा सम्मिलित करें, और कर सकते हो

$parameterService->get('some.key'); 
7

पैरामीटर को आसान तरीके से प्राप्त करने का एक और संस्करण - आप बस पैरामीटरबैग को अपनी सेवा में सेट कर सकते हैं। आप तर्कों के माध्यम से या सेट विधियों के माध्यम से इसे विभिन्न तरीकों से कर सकते हैं। मुझे सेट विधि के साथ अपना उदाहरण दिखाएं।

my_service: 
    class: MyService\Class 
    calls: 
     - [setParameterBag, ["@=service('kernel').getContainer().getParameterBag()"]] 

और वर्ग MyService \ कक्षा में सिर्फ उपयोग जोड़ें::

तो services.yml में आप की तरह कुछ जोड़ना चाहिए

use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; 

और 2 तरीकों बनाएँ:

/**                                          
* Set ParameterBag for repository                                  
*                                          
* @param ParameterBagInterface $params                                 
*/ 
public function setParameterBag(ParameterBagInterface $params) 
{ 
    $this->parameterBag = $params; 
} 

/**                                          
* Get parameter from ParameterBag                                  
*                                          
* @param string $name                                     
* @return mixed                                       
*/ 
public function getParameter($name) 
{ 
    return $this->parameterBag->get($name); 
} 

और अब आप कक्षा में उपयोग कर सकते हैं:

$this->getParameter('your_parameter_name'); 
संबंधित मुद्दे