एक सेवा से एक आवेदन मापदंडों का उपयोग कैसे करें?


81

अपने नियंत्रकों से, मैं एप्लिकेशन पैरामीटर (उन में /app/config) का उपयोग करता हूं

$this->container->getParameter('my_param')

लेकिन मुझे नहीं पता कि इसे एक सेवा से कैसे एक्सेस किया जाए (मुझे लगता है कि मेरी सेवा वर्ग का विस्तार नहीं होना चाहिए Symfony\Bundle\FrameworkBundle\Controller\Controller)।

क्या मुझे इस तरह अपने सेवा पंजीकरण में आवश्यक मापदंडों को मैप करना चाहिए:

#src/Me/MyBundle/Service/my_service/service.yml
parameters:
    my_param1: %my_param1%
    my_param2: %my_param2%
    my_param3: %my_param3%

या ऐसा ही कुछ? मुझे किसी सेवा से अपने आवेदन मापदंडों तक कैसे पहुंचना चाहिए?


यह प्रश्न समान लगता है, लेकिन मेरा वास्तव में इसका उत्तर देता है (एक नियंत्रक से पैरामीटर), मैं एक सेवा से पहुंचने के बारे में बात कर रहा हूं।



मेरा सवाल वास्तव में इस एक (एक नियंत्रक से मापदंडों) का जवाब देता है, मैं यहां एक सेवा से पहुंचने के बारे में बात कर रहा हूं
पियरे डे लेसपिन

मुझे यकीन नहीं है कि मैं आपको समझता हूं। क्या आप डुप्लिकेट से सहमत हैं? कंट्रोलर आजकल सिम्फनी में सेवाएं दे रहे हैं।
टोमैटो वोटरुबा

मैं डुप्लिकेट से सहमत नहीं हूं। दूसरा प्रश्न विशेष रूप से नियंत्रकों के लिए पूछ रहा है जो आसानी से मापदंडों के साथ मिल रहा है $this->getParameter()
पियरे डे लेसपिन

यह सच है, मैं सहमत हूं। और यह अभी भी संभव है। कंटेनर को कहीं भी इंजेक्ट करने और कंस्ट्रक्टर इंजेक्शन में स्थानांतरित करने की प्रवृत्ति भी है। PSR-4 सेवा ऑटोडिस्कवरी और मापदंडों बाइंडिंग के लिए धन्यवाद: symfony.com/blog/new-in-symfony-3-4-local-service-binding , यह साफ और बहुत कम के साथ काम करने के लिए है।
टॉमॉ वोटरूबा

जवाबों:


123

आप अपनी सेवा में उसी तरह से पैरामीटर पारित कर सकते हैं जैसे आप अन्य सेवाओं को इंजेक्ट करते हैं, उन्हें अपनी सेवा परिभाषा में निर्दिष्ट करके। उदाहरण के लिए, YAML में:

services:
    my_service:
        class:  My\Bundle\Service\MyService
        arguments: [%my_param1%, %my_param2%]

जहां %my_param1%आदि नाम के पैरामीटर से मेल खाती है my_param1। तब आपका सर्विस क्लास कंस्ट्रक्टर तब हो सकता है:

public function __construct($myParam1, $myParam2)
{
    // ...
}

क्या पैरामीटर के मामले में संभालने का कोई तरीका मौजूद नहीं है? सिम्फनी अपवाद IOC से परे है।
मोहम्मद यासीन CHABLI

और मूल्य कहां से my_param1आता है?
सिल्ली

@ स्लीक, आप इसे मापदंडों में परिभाषित करते हैं ।yml
ग्राफ़

35

द क्लीन वे 2018

2018 और सिम्फनी 3.4 के बाद से बहुत क्लीनर तरीका है - सेटअप और उपयोग में आसान।

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

इसे 2 चरणों में कैसे सेट करें?

1 है। config.yml

# config.yml
parameters:
    api_pass: 'secret_password'
    api_user: 'my_name'

services:
    _defaults:
        autowire: true
        bind:
            $apiPass: '%api_pass%'
            $apiUser: '%api_user%'

    App\:
        resource: ..

2. कोई भी Controller

<?php declare(strict_types=1);

final class ApiController extends SymfonyController
{
    /**
     * @var string 
     */
    private $apiPass;

    /**
     * @var string
     */
    private $apiUser;

    public function __construct(string $apiPass, string $apiUser)
    {
        $this->apiPass = $apiPass;
        $this->apiUser = $apiUser;
    }

    public function registerAction(): void
    {
        var_dump($this->apiPass); // "secret_password"
        var_dump($this->apiUser); // "my_name"
    }
}

झटपट अपग्रेड तैयार!

यदि आप पुराने दृष्टिकोण का उपयोग करते हैं, तो आप इसे रेक्टर के साथ स्वचालित कर सकते हैं ।

अधिक पढ़ें

इसे लोकेटर अप्रोच पर सेवाओं का निर्माणकर्ता कहा जाता है ।

इसके बारे में अधिक पढ़ने के लिए, मेरी पोस्ट की जाँच करें कि सिम्फनी कंट्रोलर द क्लीन वे में पैरामीटर कैसे प्राप्त करें

(यह परीक्षण किया गया है और मैं इसे नए सिम्फनी प्रमुख संस्करण (5, 6 ...) के लिए अद्यतन रखता हूं)।


1
मैं एक कंट्रोलर क्लास की तुलना में कोड उदाहरण के रूप में कुछ और ले सकता हूं क्योंकि ओपी किसी भी सेवा में मापदंडों को इंजेक्ट करना चाहता है और एसएफ 3 नियंत्रकों में डिफ़ॉल्ट रूप से
ऑटोवायरिंग

आपके कमेंट के लिए धन्यवाद। ऊपर दिया गया कॉन्फ़िगरेशन किसी भी सेवा, नियंत्रक, रिपॉजिटरी या स्वयं की सेवा के लिए काम करता है। इसमें कोई फर्क नही है।
टॉमस वोटरुबा

18

एक-एक करके अपने आवश्यक मापदंडों की मैपिंग करने के बजाय, अपनी सेवा को सीधे कंटेनर तक पहुंचने की अनुमति क्यों न दें? ऐसा करने पर, यदि नए पैरामीटर जोड़े गए हैं (जो आपकी सेवा से संबंधित हैं) तो आपको अपनी मैपिंग को अपडेट करने की आवश्यकता नहीं है।

ऐसा करने के लिए:

अपनी सेवा श्रेणी में निम्नलिखित परिवर्तन करें

use Symfony\Component\DependencyInjection\ContainerInterface; // <- Add this

class MyServiceClass
{
    private $container; // <- Add this
    public function __construct(ContainerInterface $container) // <- Add this
    {
        $this->container = $container;
    }
    public function doSomething()
    {
        $this->container->getParameter('param_name_1'); // <- Access your param
    }
}

@Service_container को अपनी सेवाओं में "तर्क" के रूप में जोड़ें

services:
  my_service_id:
    class: ...\MyServiceClass
    arguments: ["@service_container"]  // <- Add this

1
वास्तव में मैं क्या देख रहा था, इसीलिए मुझे निर्भरता इंजेक्शन पसंद है :)
klimpond

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

@ समृद्ध, क्या समान परिणाम प्राप्त करने का विकल्प है - इसलिए प्रत्येक पैरामीटर के लिए सेवा घोषणा अपडेट नहीं की गई है? यह भी एक-एक करके मापदंडों को इंजेक्ट करने की तुलना में थोड़ा नीच दिखता है।
बटांडवा

1
एक सेवा के लिए पूरे कंटेनर को पास करना वास्तव में एक बुरा विचार है। जैसा कि @richsage कहता है, यह निर्भरता इंजेक्शन के उद्देश्य के अनुरूप नहीं है। यदि आप निर्भरता इंजेक्शन का उपयोग नहीं करना चाहते हैं, तो Symfony2 का उपयोग न करें :)
tersakyan

2
@ बेटकन्या, लेकिन नियंत्रकों के बारे में क्या? डिफ़ॉल्ट रूप से सभी नियंत्रकों की पहुंच नियंत्रक तक होती है। फिर क्या हमें कंट्रोलर्स का भी इस्तेमाल नहीं करना चाहिए? :)
एलेक्स

9

सिम्फनी 4.1 के बाद से इसे प्राप्त करने का एक बहुत ही नया तरीका है

<?php
// src/Service/MessageGeneratorService.php

use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;

class MessageGeneratorService
{
 private $params;
 public function __construct(ParameterBagInterface $params)
 {
      $this->params = $params;
 }
 public function someMethod()
 {
     $parameterValue = $this->params->get('parameter_name');
...
 }
}

स्रोत: https://symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service


6

उल्लिखित कुछ मुद्दों के समाधान के रूप में, मैं एक सरणी पैरामीटर को परिभाषित करता हूं फिर इसे इंजेक्ट करता हूं। एक नया पैरामीटर जोड़ना बाद में पैरामीटर सरणी के अलावा service_container तर्कों या निर्माण में कोई बदलाव किए बिना आवश्यक है।

इसलिए @ उत्तर पर विस्तार:

पैरामीटर

parameters:
    array_param_name:
        param_name_1:   "value"
        param_name_2:   "value"

सेवाओं

services:
    my_service:
        class:  My\Bundle\Service\MyService
        arguments: [%array_param_name%]

फिर कक्षा के अंदर पहुंचें

public function __construct($params)
{
    $this->param1 = array_key_exists('param_name_1',$params)
        ? $params['param_name_1'] : null;
    // ...
}

इस टिप्पणी को लिखने के समय, दुर्भाग्य से, सिम्फनी में परमों का घोंसला बनाना
Tomáš Votruba

5

साथ Symfony 4.1 समाधान काफी सरल है।

यहाँ मूल पोस्ट से एक स्निपेट दिया गया है:

// src/Service/MessageGenerator.php
// ...

use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;

class MessageGenerator
{
    private $params;

    public function __construct(ParameterBagInterface $params)
    {
        $this->params = $params;
    }

    public function someMethod()
    {
        $parameterValue = $this->params->get('parameter_name');
        // ...
    }
}

मूल पोस्ट का लिंक: https://symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service


0

@richsage सही है (सिम्फनी 3. के लिए?) लेकिन यह मेरे सिम्फनी 4.x के लिए काम नहीं आया। तो यहाँ सिम्फनी 4 के लिए है।

in.aml फ़ाइल

parameters:
    param1: 'hello'

Services:
    App\Service\routineCheck:
            arguments:
                $toBechecked: '%param1%'  # argument must match in class constructor

अपने सर्विस क्लास के रूटीन चेक.फैप फाइल में कंस्ट्रक्टर को पसंद करें

private $toBechecked;

public function __construct($toBechecked)
{
    $this->toBechecked = $toBechecked;
}

public function echoSomething()
{
    echo $this->toBechecked;
}

किया हुआ।


क्या आप आगे बता सकते हैं? क्या वास्तव में दूसरे समाधान के साथ काम नहीं किया गया - क्या कोई त्रुटि संदेश दिया गया है?
निको हसे

उन्होंने अपने कंस्ट्रक्टर में ParameterBagInterface $ params का उपयोग किया, लेकिन पूरी तरह से services.yaml में पैरामीटर कॉन्फ़िगरेशन का उपयोग करने के लिए मैंने भरोसेमंद इंजेक्शन का उपयोग किया।
गोबर

क्या आप आगे बता सकते हैं? रिचेज द्वारा दिए गए उत्तर में वह पैरामीटर पैरामीटर शामिल नहीं है, लेकिन आपके कोड की तरह ही इंजेक्ट किए जाने वाले मापदंडों की एक सूची
निको हसे

मेरा जवाब 2012 में पोस्ट किया गया था, जब पारिस्थितिकी तंत्र केवल सिम्फनी 2 था। मैं अब सिम्फनी का उपयोग नहीं करता हूं इसलिए बाद के संस्करणों के लिए अपडेट नहीं किया गया है।
richsage

-1

यहाँ सिम्फनी 3.4।

कुछ शोधों के बाद, मुझे नहीं लगता कि यह एक रचनाकार के माध्यम से एक वर्ग / सेवा के लिए पैरामीटर पारित करना है, हमेशा एक अच्छा विचार है। सोचिए अगर आपको किसी कंट्रोलर / सर्विस को 2 या 3 से कुछ अधिक पैरामीटर पास करने हों, तो क्या होगा? पास करने के लिए हास्यास्पद होगा, मान लीजिए कि 10 पैरामीटर तक हैं।

इसके बजाय, ParameterBagवर्ग का उपयोग निर्भरता के रूप में करें, जब yml में सेवा की घोषणा करें, और फिर अपनी इच्छानुसार कई मापदंडों का उपयोग करें।

एक ठोस उदाहरण, मान लें कि आपके पास PHPMailer जैसी मेलर सेवा है, और आप paramters.ymlफ़ाइल में PHPMailer कनेक्शन पैरामीटर रखना चाहते हैं :

#parameters.yml
parameters:
    mail_admin: abc@abc.abc
    mail_host: mail.abc.com
    mail_username: noreply@abc.com
    mail_password: pass
    mail_from: contact@abc.com
    mail_from_name: contact@abc.com
    mail_smtp_secure: 'ssl'
    mail_port: 465

#services.yml
services:
    app.php_mailer:
        class: AppBundle\Services\PHPMailerService
        arguments: ['@assetic.parameter_bag'] #here one could have other services to be injected
        public: true

# AppBundle\Services\PHPMailerService.php
...
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
...
class PHPMailerService
{
    private $parameterBag;
    private $mailAdmin;
    private $mailHost;
    private $mailUsername;
    private $mailPassword;
    private $mailFrom;
    private $mailFromName;
    private $mailSMTPSecure;
    private $mailPort;
}
public function __construct(ParameterBag $parameterBag)
{
    $this->parameterBag = $parameterBag;

    $this->mailAdmin      = $this->parameterBag->get('mail_admin');
    $this->mailHost       = $this->parameterBag->get('mail_host');
    $this->mailUsername   = $this->parameterBag->get('mail_username');
    $this->mailPassword   = $this->parameterBag->get('mail_password');
    $this->mailFrom       = $this->parameterBag->get('mail_from');
    $this->mailFromName   = $this->parameterBag->get('mail_from_name');
    $this->mailSMTPSecure = $this->parameterBag->get('mail_smtp_secure');
    $this->mailPort       = $this->parameterBag->get('mail_port');
}
public function sendEmail()
{
    //...
}

मुझे लगता है कि यह एक बेहतर तरीका है।


-1

सिम्फनी 4 में, हम निर्भरता इंजेक्शन के माध्यम से मापदंडों का उपयोग कर सकते हैं:

सेवाएं:

   use Symfony\Component\DependencyInjection\ContainerInterface as Container;

   MyServices {

         protected $container;
         protected $path;

         public function __construct(Container $container)
         {
             $this->container = $container;
             $this->path = $this->container->getParameter('upload_directory');
         }
    }

पैरामीटर।

parameters:
     upload_directory: '%kernel.project_dir%/public/uploads'

प्रदान किया गया कोड DI का ठीक से उपयोग नहीं करता है - पूरे कंटेनर को इंजेक्ट करना खराब शैली माना जाता है, क्योंकि आप असली निर्भरता को छिपाते हैं
निको हसे

मुझे लगता है कि आप अवधारणाओं को गलत कर रहे हैं, उदाहरण में मैं केवल एक सामान्य मामला दिखाता हूं। यदि संदेह है, तो वोट डालने से पहले आधिकारिक सिम्फनी प्रलेखन से परामर्श करें। symfony.com/doc/current/compenders/dependency_injection.html
shades3002

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