2013-03-21 8 views
19

मैं वाईआई ढांचे का उपयोग कर एक PHP/MySQL ऐप पर काम कर रहा हूं।नियंत्रक खराब अभ्यास में लेनदेन प्रबंधन कर रहा है?

मैं निम्नलिखित स्थिति का सामना करना पड़ा:

मेरे VideoController, मैं एक actionCreate जो बनाता है एक नया वीडियो और actionPrivacy जो वीडियो पर गोपनीयता सेट है। समस्या यह है कि actionCreatesetPrivacyVideo मॉडल के तरीके के दौरान वर्तमान में एक लेनदेन है। मैं वीडियो के निर्माण को लेन-देन में भी बनाना चाहता हूं जिससे लेनदेन पहले ही सक्रिय हो गया है।

this answer पर टिप्पणी में, बिल Karwin

लिखते हैं तो वहाँ बनाने के लिए कोई जरूरत नहीं डोमेन मॉडल वर्ग या वर्गों डीएओ लेनदेन के प्रबंधन नहीं है - केवल नियंत्रक स्तर पर यह कर

और this answer:

चूंकि आप PHP का उपयोग कर रहे हैं, इसलिए आपके लेनदेन का दायरा सबसे अधिकहैएकल अनुरोध। तो आपको केवल कंटेनर-प्रबंधित लेन-देन, सेवा-परत ट्रांज़ का उपयोग नहीं करना चाहिए। यही है, अनुरोध को संभालने के पर लेनदेन शुरू करें, और अनुरोध को संभालने के समाप्त करने के बाद प्रतिबद्ध (या रोलबैक) करें।

अगर मैं नियंत्रक में लेनदेन के प्रबंधन, मैं कोड है कि लग रहा है का एक समूह होता है जैसे:

public function actionCreate() { 
    $trans = Yii::app()->getDb()->beginTransaction(); 
    ...action code... 
    $trans->commit(); 
} 

कि स्थानों पर जहां मैं कार्रवाई के लिए लेन-देन की जरूरत है की एक बहुत कुछ डुप्लीकेट कोड की ओर जाता है ।

या मैं beforeAction() और afterAction() माता-पिता Controller कक्षा के तरीकों को दोबारा कर सकता हूं जो स्वचालित रूप से प्रत्येक कार्यवाही के लिए लेनदेन बनाते हैं।

क्या इस विधि के साथ कोई समस्या होगी? एक PHP ऐप के लिए लेनदेन प्रबंधन के लिए एक अच्छा अभ्यास क्या है?

+0

शानदार सवाल। मैं केवल बंद करने के लिए मतदान कर रहा हूं, क्योंकि आम तौर पर इस प्रकार की चर्चा http://codereview.stackexchange.com/ पर बेहतर तरीके से संभाली जाती है, क्योंकि यह प्रदान करने के बजाए "सर्वश्रेष्ठ" के बारे में बहुत सारी खुली-अंत चर्चा को बढ़ावा देती है ठोस, उद्देश्य कोड-आधारित उत्तरों। –

+1

मुझे उस साइट से अवगत नहीं था। मुझे अगली बार इसका इस्तेमाल याद रखना होगा। –

उत्तर

17

कारण मैं कहता हूं कि लेनदेन मॉडल परत में संबंधित नहीं है मूल रूप से यह है:

मॉडल अन्य मॉडलों में तरीकों कॉल कर सकते हैं।

एक मॉडल एक सौदे शुरू करने के लिए कोशिश करता है, लेकिन इसके बारे में है कि क्या उसके फोन करने वाले पहले से ही एक लेन-देन शुरू कर दिया कोई ज्ञान नहीं है, तो मॉडल के लिए सशर्त एक सौदे, के रूप में @Bubba's answer में कोड उदाहरण में दिखाया गया शुरू किया है। मॉडल के तरीकों को ध्वज स्वीकार करना है ताकि कॉलर इसे बता सके कि उसे अपना लेनदेन शुरू करने की अनुमति है या नहीं। अन्यथा मॉडल में अपने कॉलर के "लेनदेन में" राज्य से पूछताछ करने की क्षमता होनी चाहिए।

public function setPrivacy($privacy, $caller){ 
    if (! $caller->isInTransaction()) $this->beginTransaction(); 

    $this->privacy = $privacy; 
    // ...action code.. 

    if (! $caller->isInTransaction()) $this->commit(); 
} 

क्या होगा यदि कॉलर कोई ऑब्जेक्ट नहीं है? PHP में, यह एक स्थिर विधि या बस गैर-ऑब्जेक्ट उन्मुख कोड हो सकता है। यह बहुत गन्दा हो जाता है, और मॉडल में बहुत बार दोहराए गए कोड की ओर जाता है।

यह Control Coupling का एक उदाहरण भी है, जिसे बुरा माना जाता है क्योंकि कॉलर को बुलाए गए ऑब्जेक्ट के आंतरिक कार्यों के बारे में कुछ पता होना चाहिए।उदाहरण के लिए, आपके मॉडल के तरीकों के कुछ में $ ट्रांजैक्शनल पैरामीटर हो सकता है, लेकिन अन्य विधियों में वह पैरामीटर नहीं हो सकता है। कॉलर को पता होना चाहिए कि पैरामीटर कब मायने रखता है?

// I need to override method's attempt to commit 
$video->setPrivacy($privacy, false); 

// But I have no idea if this method might attempt to commit 
$video->setFormat($format); 

अन्य समाधान मैं सुझाव दिया देखा है (या यहाँ तक प्रोपेल जैसे कुछ चौखटे में लागू) beginTransaction() और commit() कोई-ऑप्स बनाने के लिए जब DBAL जानता है कि यह पहले से ही एक लेनदेन में है। लेकिन अगर आपका मॉडल प्रतिबद्ध करने की कोशिश करता है और पाते हैं कि यह वास्तव में प्रतिबद्ध नहीं है तो यह विसंगतियों का कारण बन सकता है। या रोलबैक करने की कोशिश करता है और उस अनुरोध को अनदेखा कर दिया है। मैंने पहले इन विसंगतियों के बारे में लिखा है।

समझौता मैंने सुझाया है कि मॉडल लेनदेन के बारे में नहीं जानते। मॉडल को पता नहीं है कि setPrivacy() पर इसका अनुरोध कुछ ऐसा करना चाहिए या यह एक बड़ी तस्वीर का हिस्सा है, जो कई मॉडलों को शामिल करने वाली परिवर्तनों की एक और जटिल श्रृंखला है और केवल किया जाना चाहिए यदि ये सभी परिवर्तन सफल होते हैं। लेनदेन का मुद्दा है।

तो अगर मॉडल नहीं जानते कि वे क्या कर सकते हैं या शुरू कर सकते हैं और अपना लेनदेन कर सकते हैं, तो कौन करता है? GRASP में Controller pattern शामिल है जो उपयोग के मामले के लिए एक गैर-UI श्रेणी है, और इसे उस केस केस को पूरा करने के लिए सभी टुकड़ों को बनाने और नियंत्रित करने की ज़िम्मेदारी सौंपी जाती है। नियंत्रकों को लेनदेन के बारे में पता है क्योंकि यह जगह है कि सभी जानकारी इस बात के बारे में सुलभ है कि पूर्ण उपयोग केस जटिल है या नहीं, और एक लेनदेन (या शायद कई लेनदेन के भीतर) में मॉडल में कई बदलाव किए जाने की आवश्यकता है।

उदाहरण मैं के बारे में पहले लिखा है, कि एक MVC नियंत्रक के beforeAction() विधि में एक सौदे शुरू करने और afterAction() विधि में यह प्रतिबद्ध करने के लिए, एक सरलीकरण है। नियंत्रक को कई लेनदेन शुरू करने और प्रतिबद्ध करने के लिए स्वतंत्र होना चाहिए क्योंकि इसे वर्तमान कार्रवाई को पूरा करने के लिए तर्कसंगत रूप से आवश्यक है। या कभी-कभी नियंत्रक स्पष्ट लेनदेन नियंत्रण से बचना कर सकता है, और मॉडल को प्रत्येक परिवर्तन को स्वत: सूचित करने की अनुमति देता है।

लेकिन मुद्दा यह है कि क्या ट्रांज़ेक्शन आवश्यक है, इस बारे में जानकारी कुछ है जो मॉडल को नहीं पता - उन्हें बताया जाना चाहिए (एक $ लेनदेन पैरामीटर के रूप में) या फिर इसे से पूछें उनके कॉलर, जिसे कंट्रोलर की कार्रवाई तक वैसे भी सवाल उठाना होगा।

आप कक्षाओं के Service Layer भी बना सकते हैं जो प्रत्येक जानते हैं कि इस तरह के जटिल उपयोग मामलों को कैसे कार्यान्वित किया जाए, और एक ही लेनदेन में सभी परिवर्तनों को संलग्न करना है या नहीं। इस तरह आप बहुत बार दोहराए गए कोड से बचते हैं। लेकिन PHP ऐप्स के लिए एक अलग सेवा परत शामिल करना आम बात नहीं है; नियंत्रक की कार्रवाई आमतौर पर एक सेवा परत के साथ संयोग होता है।

+1

ठीक है तो अगर नियंत्रक वह होता है जो लेन-देन शुरू करता है और करता है, तो इसका मतलब यह है कि नियंत्रक भंडारण/कनेक्शन एडाप्टर पर निर्भर है? – CMCDragonkai

+1

@CMCDragonkai, नियंत्रक कम से कम एक स्टोरेज * इंटरफेस * पर निर्भर है। कार्यान्वयन भिन्न हो सकता है, लेकिन हां, नियंत्रक (या सेवा परत) उस इंटरफ़ेस को लॉजिकल लेनदेन शुरू करने और प्रतिबद्ध करने के लिए कॉल करता है। ओओ decoupling की मात्रा के लिए एक व्यावहारिक सीमा है जो आप कर सकते हैं। आखिरकार आपको व्यवसाय करना होगा। :-) –

3

नहीं आप सही हैं। लेनदेन को "निर्माण" विधि द्वारा प्रस्तुत किया जाता है जो नियंत्रक को करना होता है। पहले 'एक्शन() जैसे' रैपर 'का उपयोग करने का आपका सुझाव है। बस नियंत्रक को इस वर्ग का विस्तार या कार्यान्वित करें। ऐसा लगता है कि आप एक पर्यवेक्षक प्रकार पैटर्न या कारखाने की तरह कार्यान्वयन की तलाश में हैं।

0

अच्छा, इन व्यापक लेनदेन (पूरे अनुरोध पर) का एक नुकसान यह है कि आप अपने डेटाबेस इंजन की समवर्ती क्षमताओं को सीमित करते हैं और आप डेडलॉक्स संभावना भी बढ़ाते हैं। इस दृष्टिकोण से, यह केवल लेनदेन लगाने के लिए भुगतान कर सकता है जहां आपको उनकी आवश्यकता है और उन्हें केवल उस कोड को कवर करने दें जो कवर करने की आवश्यकता है।

यदि संभव हो, तो मैं निश्चित रूप से मॉडल में लेनदेन रखने के लिए जाऊंगा। ओवरलैपिंग लेनदेन के साथ समस्या को बेसमोडेल (सभी मॉडलों के पूर्वजों) और परिवर्तनीय लेनदेन को उस मॉडल में लॉक करके हल किया जा सकता है। फिर आप अपने प्रारंभ/प्रतिबद्ध लेनदेन निर्देशों को बेसमॉडल विधियों में लपेटें जो इस चर का सम्मान करते हैं।

7

सर्वश्रेष्ठ अभ्यास:मॉडल में लेनदेन रखो, लेनदेन को नियंत्रक में न रखें।

एमवीसी डिजाइन पैटर्न का प्राथमिक लाभ यह है: एमवीसी मॉडल कक्षाओं को संशोधन के बिना पुन: प्रयोज्य बनाता है। नई सुविधाओं को रखरखाव और कार्यान्वित करना आसान बनाएं।

उदाहरण के लिए, संभवतः आप मुख्य रूप से ऐसे ब्राउज़र के लिए विकास कर रहे हैं जहां उपयोगकर्ता एक समय में डेटा संग्रह का प्रवेश करता है, और आप डेटा मैनिपुलेशन को नियंत्रक में ले जाते हैं। बाद में आपको एहसास हुआ कि आपको कमांड लाइन से सर्वर पर आयात किए जाने वाले डेटा की बड़ी संख्या में संग्रह अपलोड करने की अनुमति देने का समर्थन करने की आवश्यकता है।

यदि सभी डेटा मैनिपुलेशन मॉडल में था, तो आप आसानी से डेटा में फिसल सकते हैं और इसे संभालने के लिए मॉडल को पास कर सकते हैं। यदि नियंत्रक में आवश्यक (लेनदेन) कार्यक्षमता है, तो आपको इसे अपनी सीएलआई लिपि में दोहराना होगा।

दूसरी ओर, शायद आप एक और नियंत्रक के साथ समाप्त हो जाते हैं जिसे एक अलग बिंदु से समान कार्यक्षमता करने की आवश्यकता होती है। आपको उस अन्य नियंत्रक में कोड को दोहराने की आवश्यकता होगी।

इसके अंत में, आपको मॉडल में लेनदेन चुनौतियों को हल करने की आवश्यकता है।

मान लीजिए कि आपके पास सेटप्राइसी() विधि के साथ एक वीडियो क्लास (मॉडल) है जिसमें पहले से ही लेनदेन का निर्माण होता है; और आप इसे किसी अन्य विधि से कॉल करना चाहते हैं() जिसे एक बड़ी लेनदेन में अपनी कार्यक्षमता को भी लपेटने की आवश्यकता है, आप सशर्त लेनदेन करने के लिए केवल सेट प्राइवेटसी() को संशोधित कर सकते हैं।

शायद ऐसा कुछ।

class Video{ 
    private $privacy; 
    private $transaction; 

    public function __construct($privacy){ 

     $this->privacy = $privacy; 
    } 

    public function persist(){ 
     $this->beginTransaction(); 
     // ...action code... 
     $this->setPrivacy($this->privacy, false); 
     // ...action code... 
     $this->commit(); 
    } 

    public function setPrivacy($privacy, $transactional = true){ 
     if ($transactional) $this->beginTransaction(); 

     $this->privacy = $privacy; 
     // ...action code.. 

     if ($transactional) $this->commit(); 
    } 


    private function beginTransaction(){ 
     $this->transaction = Yii::app()->getDb()->beginTransaction(); 
    } 

    private function commit(){ 
     $this->transaction->commit(); 
    } 
} 

अंत में, अपने सहज ज्ञान सही (: कि स्थानों पर जहां मैं कार्रवाई के लिए लेन-देन की जरूरत है की एक बहुत कुछ डुप्लीकेट कोड होता है। फिर से) कर रहे हैं। आपके मॉडल को आपके पास लेनदेन संबंधी ज़रूरतों के असंख्य समर्थन के लिए आर्किटेक्ट करें, और नियंत्रक को यह निर्धारित करने दें कि यह किस प्रविष्टि बिंदु (विधि) का उपयोग अपने संदर्भ में करेगा।

संबंधित मुद्दे