2012-12-24 20 views
5

ज़ेन फ्रेमवर्क 1 में मेरे पास कई मैपर थे जो एक सेटडबटेबल को विरासत में मिला और माता-पिता मैपर वर्ग से getDbTable प्राप्त किया।zf2: मैपर में सेवा प्रबंधक कैसे प्राप्त करें

अब ZF2 एक चेहरा समस्या यह है कि मैं एक मॉडल में सेवा प्रबंधक की जरूरत है और मैं इसे कैसे प्राप्त करने के लिए के रूप में एक सुराग नहीं है में:

class Mapper 
    { 
     protected $tableGateway; 
     protected $module = 'application'; 

     public function setTableGateway($table) 
      { 
       if (is_string($table)) { 
        $class = $this->module . '\Model\DbTable\\' . ucfirst($table); 
        $sm = $this->getServiceLocator(); <= Fatal error: Call to undefined method Mapper::getServiceLocator() 
        $tableGateway = (class_exists($class)) ? $sm->get($class) : $sm->get(new TableGateway($table)); 
       } else { 
        $tableGateway = $table; 
       } 

       if (!$tableGateway instanceof Zend\Db\TableGateway\AbstractTableGateway) { 
        throw new \Exception('Invalid table data gateway provided'); 
       } 
       $this->tableGateway = $tableGateway; 
       return $this; 
      } 

     // more code 

लाइन:

$sm = $this->getServiceLocator(); 

एक घातक त्रुटि देता है:

Call to undefined method Application\Model\Mapper\Doc::getServiceLocator() 

मैं अपने मॉडल में सेवा प्रबंधक कैसे प्राप्त करूं? या मैं चीजों को ZF2 तरीके से नहीं कर रहा हूं? मुझे पता है कि मेरे नियंत्रक में सेवा प्रबंधक कैसे प्राप्त करें और टेबल गेटवे को मैपर पर पास करें, लेकिन ऐसा लगता है कि मुझे कोड के बहुत सारे नकल की तरह लगता है।

+1

आम तौर पर आपके मॉडल में सेवा प्रबंधकों को इंजेक्ट करना बहुत बुरा विचार है। इंजेक्शन के लिए सेवा कंटेनर पर भरोसा करने के बजाय अपनी कक्षा में निर्भरता को इंजेक्ट करने का प्रयास करें। यह "निर्भरता इंजेक्शन" बनाम "सेवा कंटेनर" चर्चा है और इस मामले में से कुछ को पढ़ना और समझना अच्छा होगा कि वे इस प्रकार के इंजेक्शन को अक्सर एंटी-पैटर्न क्यों कहते हैं। –

+0

@ जूरियन स्लूइमन: मेरे लिए मुश्किल चर्चा क्योंकि मैंने हाल ही में निर्भरता इंजेक्शन के बारे में सीखा, लेकिन मुझे लगता है कि मुझे मूल विचार मिलता है। एंडी के उत्तर के बारे में क्या जवाब है (जिसे मैंने स्वीकार किया क्योंकि यह काम करता है)? क्या यह आपकी राय में एक विरोधी पैटर्न भी होगा? – tihe

+0

आप इस आलेख के साथ एक अच्छा पढ़ सकते हैं: http://blog.ircmaxell.com/2012/08/object-scoping-triste-against-service.html (मेरे लिए, एंथनी फेरारा एक बहुत ही सम्मानित डेवलपर है)। यह वास्तव में काला/सफ़ेद नहीं है, लेकिन इसी मामले के बारे में SO पर एक समान प्रश्न पूछा गया है: http://stackoverflow.com/questions/9011787/why-the-service-locator-is-a-anti-pattern -इन-द-अंडर-उदाहरण –

उत्तर

8

सबसे पहले, मुझे लगता है कि आप का मतलब है कि आप एक मैपर वर्ग से सेवा प्रबंधक तक पहुंचना चाहते हैं, न कि मॉडल। मैं बाद वाले करने से बचना होगा। अधिक जानकारी के लिए कृपया राज के जवाब पर मेरी टिप्पणी देखें।

दूसरा, इसके बारे में जाने के कई तरीके हैं। इस जवाब में, मैं आपको एक दृष्टिकोण का उदाहरण दूंगा और केवल एक और उल्लेख करूंगा।

service manager's documentation (थोड़ा नीचे स्क्रॉल करें) को देखते हुए, यह बताता है कि एक डिफ़ॉल्ट प्रारंभकर्ता डिफ़ॉल्ट रूप से जोड़ा जाता है। यह प्रारंभकर्ता यह देखने के लिए जांच करता है कि सेवा प्रबंधक से पुनर्प्राप्त किया जा रहा कोई ऑब्जेक्ट Zend\ServiceManager\ServiceLocatorAwareInterface लागू करता है या नहीं। यदि ऐसा होता है, तो सेवा प्रबंधक को वस्तु में इंजेक्शन दिया जाता है। इस प्रकार, यह स्वचालित रूप से हो सकता है यदि आप बस अपने मैपर वर्गों में इंटरफेस को लागू करते हैं। आप प्रत्येक मैपर वर्ग के लिए इसे फिर से लिखने से बचने के लिए एक सार आधार वर्ग का उपयोग कर सकते हैं। शायद नीचे की तरह कुछ।

बेस नक्शाकार वर्ग:

namespace User\Mapper; 

use Zend\ServiceManager\ServiceLocatorAwareInterface; 
use Zend\ServiceManager\ServiceLocatorInterface; 

class AbstractMapper implements ServiceLocatorAwareInterface { 
    protected $service_manager; 

    public function setServiceLocator(ServiceLocatorInterface $serviceLocator) 
    { 
     $this->service_manager = $serviceLocator; 
    } 

    public function getServiceLocator() 
    { 
     return $this->service_manager; 
    } 
} 

मैपर वर्ग:

namespace User\Mapper; 

use User\Mapper\AbstractMapper; 

class UserMapper extends AbstractMapper { 
    public function doSomething() { 
     $sm = $this->getServiceLocator(); 
     $sm->get('something'); 
    } 
} 

के बाद से सेवा प्रबंधक जब प्रारंभकर्ता चलाया जाता है इंजेक्ट किया जाता है, नक्शाकार सेवा प्रबंधक से प्राप्त किया जाना चाहिए। यदि आप अपने मैपर वर्ग में कुछ भी इंजेक्ट नहीं करना चाहते हैं, तो एक अनावश्यक पर्याप्त हो सकता है। उन्हें invokables कुंजी के तहत जोड़ा जा सकता है, जो कुंजी module_name/config/module.config.php में निहित है। या, इसे मॉड्यूल क्लास 'getServiceConfig विधि में कॉन्फ़िगर किया जा सकता है। हालांकि, आपके मैपर कक्षाओं में अब या भविष्य में कुछ निर्भरताएं होंगी, इसलिए आप शायद इसके बजाय एक कारखाना का उपयोग करना चाहेंगे। इस तरह, उदाहरण के लिए आप सेवा प्रबंधक मैपर कक्षाओं में एक टेबल गेटवे इंजेक्ट कर सकते हैं।

// Remember to include the appropriate namespaces 
return array(
    'factories' => array(
     'User\Mapper\UserMapper' => function($service_manager) { 
      $table_gateway = $service_manager->get('User\Model\DbTable\UserGateway'); 
      return new UserMapper($table_gateway); 
     }, 
    ), 
); 

ऊपर मॉड्यूल के Module.php फ़ाइल के भीतर एक getServiceConfig विधि में जोड़ा जा सकता है - या module_name/config/module.config.php में service_manager कुंजी भीतर factories कुंजी जोड़ें। आपको अभी भी एक कारखाना जोड़ना होगा जो डेटाबेस गेटवे बनाता है; उपरोक्त सिर्फ एक उदाहरण है।

इस प्रकार मैं इसके बारे में जाऊंगा। बेशक कोई भी मैपर वर्ग में सेवा प्रबंधक के लिए गेटटर और सेटर विधि प्राप्त कर सकता है और इन्हें नियंत्रक से एक्सेस कर सकता है (नियंत्रक के पास getServiceLocator विधि है) और इसे इस तरह इंजेक्ट करें। हालांकि, मैं उस दृष्टिकोण से खुद नहीं जाऊंगा।

2

नोट: के रूप में Jurian Sluiman और andy124 उनकी टिप्पणी में बताया, कभी नहीं सेवा चरनी इंजेक्षन और अपने डोमेन विशिष्ट मॉडल/वस्तु है, जो एक अच्छा अभ्यास के रूप में अपने डोमेन का विशिष्ट वस्तु कठोर कर देगा नहीं है अंदर सेवा प्रबंधक पर निर्भर और पोर्टेबिलिटी पर प्रभाव। समाधान नीचे, अधिक विशिष्ट करने के लिए प्रश्न पूछा

मैं नीचे दिए गए चरणों मेरी कक्षा, मॉडल में sevicelocator (सेवा प्रबंधक) प्राप्त करने के लिए का पालन करें आदि
1. वर्ग जो ServiceMangerAwareInterface
2 को लागू बनाने । परिभाषित करें इस

 
    public function getServiceConfig(){ 
    return array(
     'factories' => array(
        /* Models */ 
      'MyModule\MyModel' => function($sm) { 
       return new Models\MyModel($sm); 
      }, 
        /* Entities */ 
      'MyModule\MyEntity1' => function($sm) { 
       return new Entity\MyEntity1($sm); 
      }, 
      'MyModule\MyEntity2' => function($sm) { 
       return new Entity\MyEntity2($sm); 
      }, 
     . 
     . 
     . 
     ), 
    ); 
`
  1. पहुँच अपने मॉडल या सेवा मा के साथ वर्ग की तरह अपने Module.php में serviceconfig में प्रवेश नीचे की तरह नाराज (उदा। नियंत्रक के तहत)
     
    $model = $this->getServiceLocator()->get('MyModule\MyModel'); 
    
तुम भी सेवा प्रबंधक विन्यास module.config.php में
 
    'service_manager' => array(
     'factories' => array(
      'MyModel' => 'MyModule\Models\MyModel', 
      'MyEntity' => 'MyModule\Entity\MyEntity', 
     ), 
    ), 
4. पहुँच अपने मॉडल या सेवा प्रबंधक के साथ वर्ग नीचे (जैसे नियंत्रक के तहत कर सकते हैं उदा।)
 
    $model = $this->getServiceLocator()->get('MyModel'); 
+0

आपके उत्तर में कुछ त्रुटियां हैं: 1. यदि आपके पास अपना कारखाना है जहां आप पहले ही एसएम इंजेक्ट करते हैं तो आपको 'ServiceManagerAwareInterface' को लागू करने की आवश्यकता नहीं है। 2. एन सामान्य डोमेन में आपके एसएम इंजेक्ट करने का विचार एक बहुत ही बुरा विचार है और 3. आपके 'config.php' में (जहां आप शायद' module.config.php' 'का मतलब रखते हैं) आप मॉडल का उपयोग करते हैं एक अचूक सेवा लेकिन आप फैक्ट्री सेवा का उपयोग करते हैं। इन चीजों के कारण मैं आपको वोट देता हूं, लेकिन आप इसे अपने उत्तर में आसानी से समायोजित कर सकते हैं ताकि मैं इसे दोबारा हटा दूं। –

+0

@ जूरियन स्लूइमन त्रुटियों को इंगित करने के लिए धन्यवाद, मैंने अपना जवाब अपडेट किया था, दूसरा आपने कहा था ** आम तौर पर आपके डोमेन मॉडल में एसएम इंजेक्ट करने का विचार एक बहुत ही बुरा विचार है ** क्या आप इसे खराब कर सकते हैं कि यह बुरा क्यों है विचार, क्या आप इससे संबंधित किसी भी लेख को इंगित कर सकते हैं, मुझे इसके बारे में और जानना है, धन्यवाद – Raj

+1

@राज व्यक्तिगत रूप से, मैं अपने मॉडलों को किसी भी ढांचे के विशिष्ट व्यवहार से साफ रखने की कोशिश करता हूं जैसे कि यह व्यवसाय तर्क के साथ संयुक्त नहीं है। इस तरह, व्यापार तर्क की पोर्टेबिलिटी संरक्षित है और तर्क अलग है। मेरे पास अभी तक ZF2 के साथ इतना व्यावहारिक अनुभव नहीं है, लेकिन मेरे सिर के ऊपर से, मैं ऐसे परिदृश्य के बारे में नहीं सोच सकता जहां मुझे अपने मॉडल में सेवा प्रबंधक की आवश्यकता होगी। निर्भरता इंजेक्शन का उपयोग करके, मॉडलों को _how_ से संबंधित नहीं होना चाहिए निर्भरताओं को हल किया गया है और उन्हें हल करने की आवश्यकता नहीं है। यह शायद एक सेवा परत के भीतर से किया जाना चाहिए। – Andy0708