MVC (Laravel) जहां तर्क जोड़ना है


137

मान लीजिए कि जब भी मैं CRUD ऑपरेशन करता हूं या किसी विशिष्ट तरीके से किसी रिश्ते को संशोधित करता हूं तो मैं भी कुछ और करना चाहता हूं। उदाहरण के लिए, जब भी कोई पोस्ट प्रकाशित करता है, मैं भी एनालिटिक्स के लिए एक टेबल पर कुछ सहेजना चाहता हूं। शायद सबसे अच्छा उदाहरण नहीं है, लेकिन सामान्य रूप से इस "समूहीकृत" कार्यक्षमता का एक बहुत कुछ है।

आम तौर पर मैं इस प्रकार के तर्क को नियंत्रकों में देखता हूं। यह सब ठीक है जब तक आप बहुत सारी जगहों पर इस कार्यक्षमता को पुन: उत्पन्न नहीं करना चाहते। जब आप पार्टिकल्स में आने लगते हैं, तो एपीआई बनाते हैं और डमी कंटेंट जेनरेट करते हैं।

इस तरीके को प्रबंधित करने के लिए मैंने जो तरीके देखे हैं, वे हैं, रिपॉजिटरी, लाइब्रेरी और मॉडल को जोड़ना। यहाँ प्रत्येक की मेरी समझ है:

सेवाएँ: यह वह जगह है जहाँ ज्यादातर लोग इस कोड को डालते हैं। सेवाओं के साथ मेरा मुख्य मुद्दा यह है कि कभी-कभी उनमें विशिष्ट कार्यक्षमता ढूंढना कठिन होता है और मुझे लगता है कि वे उस समय भूल जाते हैं जब लोग एलोक्वेंट का उपयोग करने पर ध्यान केंद्रित करते हैं। मुझे कैसे पता चलेगा कि मुझे publishPost()लाइब्रेरी में एक विधि को कॉल करने की आवश्यकता है जब मैं बस कर सकता हूं $post->is_published = 1?

एकमात्र शर्त यह है कि मैं इसे अच्छी तरह से काम करता देख रहा हूं, यदि आप केवल सेवाओं का उपयोग करते हैं (और आदर्श रूप से किसी भी तरह नियंत्रकों से किसी भी तरह से अप्राप्य बना सकते हैं)।

अंततः ऐसा लगता है कि यह सिर्फ अतिरिक्त अनावश्यक फ़ाइलों का एक गुच्छा बना देगा यदि आपके अनुरोध आमतौर पर आपके मॉडल संरचना का पालन करते हैं।

रिपोजिटरी: जो मैं समझता हूं कि यह मूल रूप से एक सेवा की तरह है, लेकिन एक इंटरफ़ेस है ताकि आप ORMs के बीच स्विच कर सकें, जिसकी मुझे आवश्यकता नहीं है।

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

मॉडल: परंपरागत रूप से मेरे पास ऐसी कक्षाएं होंगी जिन्होंने CRUD का प्रदर्शन किया और महत्वपूर्ण युग्मन भी संभाला। यह वास्तव में चीजों को आसान बनाता है क्योंकि आप CRUD + के आसपास सभी कार्यक्षमता जानते थे जो भी इसके साथ किया जाना था।

सरल, लेकिन MVC आर्किटेक्चर में यह सामान्य रूप से वह नहीं है जो मैंने किया है। एक अर्थ में, हालांकि मैं इस सेवा को पसंद करता हूं क्योंकि इसे ढूंढना थोड़ा आसान है, और इस पर नज़र रखने के लिए कम फाइलें हैं। हालांकि यह थोड़ा अव्यवस्थित हो सकता है। मैं इस विधि के बारे में सुनना चाहता हूँ और अधिकांश लोग ऐसा क्यों नहीं करते हैं।

प्रत्येक विधि के फायदे / नुकसान क्या हैं? क्या मैं कुछ भूल रहा हूँ?


3
क्या आप अपना प्रश्न कम कर सकते हैं?
अल्फा

3
इसके अलावा आप इसकी जांच कर सकते हैं ।
अल्फा

1
"मुझे कैसे पता चलेगा कि मुझे लाइब्रेरी में एक पब्लिशपोस्ट () कॉल करने की आवश्यकता है, जब मैं सिर्फ $ पोस्ट कर सकता हूं-> is_published = 1?" प्रलेखन?
सियजयोज़

सुंदर और ओआरएमएस के बारे में सुंदरियों में से एक यह बहुत सारे डॉक्स के बिना उनके साथ काम करना आसान है?
सबरीना लेगेट

1
इसे पोस्ट करने के लिए धन्यवाद। मैं उन्हीं मुद्दों को लेकर संघर्ष कर रहा हूं और आपकी पोस्ट और उत्तर को अविश्वसनीय रूप से उपयोगी पाया। अंततः मैंने फैसला किया है कि लारवेल किसी भी चीज़ के लिए एक अच्छी वास्तुकला प्रदान नहीं करता है जो एक त्वरित और गंदे रूबी-ऑन-रेल वेबसाइट से परे फैला है। हर जगह ट्रेट्स, कक्षाओं के कार्यों को खोजने में कठिनाई और हर जगह ऑटो-मैजिक कचरा। ORM ने कभी काम नहीं किया है और यदि आप इसका उपयोग कर रहे हैं, तो आपको संभवतः NoSQL का उपयोग करना चाहिए।
एलेक्स बार्कर

जवाबों:


171

मुझे लगता है कि जब तक आप ठोस सिद्धांतों का पालन करते हैं, तब तक आपके द्वारा प्रस्तुत सभी पैटर्न / आर्किटेक्चर बहुत उपयोगी होते हैं ।

के लिए जहां तर्क जोड़ने के लिए मुझे लगता है कि यह उल्लेख करने के लिए महत्वपूर्ण है एकल जिम्मेदारी सिद्धांत । इसके अलावा, मेरा जवाब मानता है कि आप एक मध्यम / बड़ी परियोजना पर काम कर रहे हैं। यदि यह एक फेंक-कुछ-पर-पृष्ठ प्रोजेक्ट है, तो इस उत्तर को भूल जाएं और इसे सभी नियंत्रकों या मॉडलों में जोड़ें।

संक्षिप्त उत्तर है: जहां यह आपको (सेवाओं के साथ) समझ में आता है

लंबे उत्तर:

नियंत्रकों : नियंत्रकों की जिम्मेदारी क्या है? ज़रूर, आप अपने सभी तर्क एक नियंत्रक में डाल सकते हैं, लेकिन क्या यह नियंत्रक की जिम्मेदारी है? मुझे ऐसा नहीं लगता।

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

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

मुझे लगता है कि मॉडल को एक इकाई का प्रतिनिधित्व करना चाहिए। Laravel के साथ, मैं केवल जैसी चीजों को जोड़ने के लिए मॉडल वर्ग का उपयोग fillable, guarded, tableऔर संबंधों (इस वजह से मैं भंडार पैटर्न का उपयोग करें, अन्यथा मॉडल भी होता है save, update, find, आदि तरीकों)।

रिपॉजिटरी (रिपोजिटरी पैटर्न) : शुरुआत में मैं इससे बहुत उलझन में था। और, आप की तरह, मैंने सोचा "अच्छी तरह से, मैं MySQL और Thats का उपयोग करता हूं।"

हालांकि, मैंने रिपॉजिटरी पैटर्न का उपयोग करने के लिए बनाम बनाम विपक्ष को संतुलित किया है और अब मैं इसका उपयोग करता हूं। मुझे लगता है कि अब , इस समय, मुझे केवल MySQL का उपयोग करने की आवश्यकता होगी। लेकिन, अगर अब से तीन साल बाद मुझे कुछ बदलने की जरूरत है जैसे MongoDB ज्यादातर काम पूरा हो गया है। सभी एक अतिरिक्त इंटरफ़ेस और ए की कीमत पर $app->bind(«interface», «repository»)

इवेंट्स ( ऑब्जर्वर पैटर्न ): इवेंट उन चीजों के लिए उपयोगी होते हैं जिन्हें किसी भी समय किसी भी क्लास में फेंका जा सकता है। उदाहरण के लिए, किसी उपयोगकर्ता को सूचनाएं भेजने के लिए सोचें। जब आपको आवश्यकता होती है, तो आप अपने आवेदन के किसी भी वर्ग में एक अधिसूचना भेजने के लिए घटना को आग लगा देते हैं। फिर, आपके पास एक वर्ग हो सकता है जो UserNotificationEventsउपयोगकर्ता सूचनाओं के लिए आपके सभी निकाल दिए गए घटनाओं को संभालता है।

सेवाएं : अब तक, आपके पास नियंत्रक या मॉडल में तर्क जोड़ने का विकल्प है। मेरे लिए, यह सेवाओं के भीतर तर्क को जोड़ने के लिए सभी समझ में आता है । आइए इसका सामना करते हैं, सेवाएँ कक्षाओं के लिए एक फैंसी नाम है। और आपके पास उतने वर्ग हो सकते हैं, जितना कि यह आपके अंदर की भावना के अनुरूप है।

इस उदाहरण को लें: कुछ समय पहले, मैंने Google फ़ॉर्म की तरह कुछ विकसित किया था। मैं एक साथ शुरू किया था CustomFormServiceऔर साथ समाप्त हो गया CustomFormService, CustomFormRender, CustomFieldService, CustomFieldRender, CustomAnswerServiceऔर CustomAnswerRender। क्यों? क्योंकि यह मेरे लिए समझ में आया। यदि आप एक टीम के साथ काम करते हैं, तो आपको अपना तर्क रखना चाहिए जहां यह टीम के लिए समझ में आता है।

सेवाओं बनाम नियंत्रकों / मॉडल का उपयोग करने का लाभ यह है कि आप किसी एकल नियंत्रक या एकल मॉडल द्वारा विवश नहीं हैं। आप अपने एप्लिकेशन के डिज़ाइन और जरूरतों के आधार पर आवश्यकतानुसार कई सेवाएँ बना सकते हैं। अपने आवेदन के किसी भी वर्ग के भीतर एक सेवा को कॉल करने का लाभ जोड़ें।

यह लंबा चलता है, लेकिन मैं आपको दिखाना चाहता हूं कि मैंने अपने आवेदन को कैसे संरचित किया है:

app/
    controllers/
    MyCompany/
        Composers/
        Exceptions/
        Models/
        Observers/
        Sanitizers/
        ServiceProviders/
        Services/
        Validators/
    views
    (...)

मैं एक विशिष्ट फ़ंक्शन के लिए प्रत्येक फ़ोल्डर का उपयोग करता हूं। उदाहरण के लिए Validatorsनिर्देशिका एक शामिल BaseValidatorवर्ग मान्यता प्रसंस्करण के लिए जिम्मेदार है, के आधार पर $rulesऔर $messages(आमतौर पर एक मॉडल के लिए एक) विशिष्ट सत्यापनकर्ता के। मैं आसानी से इस कोड को एक सेवा के भीतर रख सकता था, लेकिन यह मेरे लिए एक विशिष्ट फ़ोल्डर है, भले ही यह केवल सेवा के भीतर (अभी के लिए) उपयोग किया जाता है।

मैं आपको निम्नलिखित लेख पढ़ने की सलाह देता हूं, क्योंकि वे चीजों को आपको थोड़ा बेहतर समझा सकते हैं:

डेले रीस (CodeBright के लेखक) द्वारा मोल्ड को तोड़ना: यह वह जगह है जहां मैंने इसे सभी को एक साथ रखा, भले ही मैंने अपनी आवश्यकताओं को पूरा करने के लिए कुछ चीजें बदल दीं।

क्रिस गोज़ी द्वारा रिपोजिटरीज़ एंड सर्विसेज़ का उपयोग करके लारवेल में अपने कोड को घटाना: यह पोस्ट अच्छी तरह से समझाती है कि एक सेवा और रिपोजिटरी पैटर्न क्या है और वे एक साथ कैसे फिट होते हैं।

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


3
महान व्याख्या। यहाँ थोड़े है जहाँ मैं इस समय खड़ा हूँ - वर्तमान परियोजना में मैं अपना व्यावसायिक तर्क मॉडल में डाल रहा हूँ और यह वास्तव में बहुत अच्छा काम कर रहा है। हमें निश्चित रूप से एसओएलआईडी को थोड़ा कम करने की आवश्यकता है, लेकिन, यह वास्तव में हमें अभी तक परेशानी में नहीं डाला है। यह तेज़ है, यह थोड़े गंदा है, लेकिन अभी तक हमारी परियोजना बहुत ही कायम है क्योंकि यह इतना सूखा है। मैं निश्चित रूप से इस समय उनसे चिपके रहने के कारण ठीक हूं क्योंकि उन्हें काम मिल गया है, लेकिन किसी भी भविष्य की परियोजना में मैं बस जो भी मानक है, जो यह लगता है कि रिपॉजिटरी बन गया है, के साथ जाऊंगा।
सबरीना लेगट

2
मुझे खुशी है कि आपको एक ऐसा तरीका मिला, जो आपके लिए मायने रखता है। बस उन मान्यताओं से सावधान रहें जो आप आज बनाते हैं । मैंने 3+ वर्षों के लिए एक परियोजना पर काम किया है और कोड के 5000+ लाइनों के साथ नियंत्रकों और मॉडल के साथ समाप्त हुआ है। आपकी परियोजना के लिए शुभकामनाएं।
लुइज़ क्रूज़

थोड़े गंदे भी, लेकिन मैं मॉडल के विशाल होने से बचने के लिए लक्षणों का उपयोग करने के बारे में सोच रहा था। इस तरह मैं उन्हें थोड़ा अलग कर सकता हूं
सबरीना लेगट

यह लेख अच्छी तरह से समझ में आता है जब यह सेवाओं का उपयोग करने के लिए समझ में आता है। आपके फॉर्म उदाहरण में यह सेवाओं का उपयोग करने के लिए समझ में आता है, लेकिन वह यह बताता है कि वह इसे कैसे करता है, जो तब है जब तर्क सीधे उस मॉडल से संबंधित होता है जिसे वह उस मॉडल में रखता है। justinweiss.com/articles/where-do-you-put-your-code
सबरीना

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

24

मैं अपने ही सवाल का जवाब पोस्ट करना चाहता था। मैं दिनों के लिए इस बारे में बात कर सकता था, लेकिन मैं यह सुनिश्चित करने के लिए इस पोस्ट को तेजी से प्राप्त करने की कोशिश करने जा रहा हूं कि मैं इसे प्राप्त करूं।

मैंने उस मौजूदा संरचना का उपयोग करना समाप्त कर दिया जो लारवेल प्रदान करता है, जिसका अर्थ है कि मैंने अपनी फ़ाइलों को मुख्य रूप से मॉडल, दृश्य और नियंत्रक के रूप में रखा था। मेरे पास पुन: प्रयोज्य घटकों के लिए एक लाइब्रेरी फ़ोल्डर भी है जो वास्तव में मॉडल नहीं हैं।

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

मैंने मॉडल में व्यावसायिक तर्क रखा और सीधे अपने नियंत्रकों से अभिगम का उपयोग किया। मैं यह सुनिश्चित करने के लिए कई दृष्टिकोणों का उपयोग करता हूं कि व्यापार तर्क को दरकिनार नहीं किया जाता है:

  • एक्सेसर्स और म्यूटेटर्स: लारवेल में शानदार एक्सेसर्स और म्यूटेटर हैं। अगर मैं जब भी कोई पोस्ट ड्राफ्ट से प्रकाशित करने के लिए स्थानांतरित किया जाता है, तो मैं एक कार्य करना चाहता हूं, मैं इसे फ़ंक्शन सेट बनाकर कॉल कर सकता हूं।
  • ओवरराइडिंग क्रिएट / अपडेट आदि: आप कस्टम कार्यक्षमता को शामिल करने के लिए अपने मॉडल में एलोकेंट विधियों को हमेशा ओवरराइड कर सकते हैं। इस तरह आप किसी भी CRUD ऑपरेशन पर कार्यक्षमता कह सकते हैं। संपादित करें: मुझे लगता है कि नए Laravel संस्करणों में ओवरराइडिंग बनाने के साथ एक बग है (इसलिए मैं अब बूट में पंजीकृत घटनाओं का उपयोग करता हूं)
  • सत्यापन: मैं अपनी मान्यता को उसी तरह से हुक करता हूं, उदाहरण के लिए, यदि आवश्यक हो तो सीआरयूडी फ़ंक्शन और एक्सेसर्स / म्यूटर्स को ओवरराइड करके मैं सत्यापन चलाऊंगा। अधिक जानकारी के लिए Esensi या dwightwatson / सत्यापन देखें।
  • मैजिक मेथड्स: मैं अपने मॉडल के __get और __set तरीकों का उपयोग कार्यक्षमता में हुक करने के लिए करता हूं जहां उपयुक्त है
  • विस्तृत वाक्पटुता : यदि कोई ऐसी क्रिया है जिसे आप सभी अद्यतन पर ले जाना चाहते हैं / बनाते हैं तो आप वाक्पटुता का विस्तार भी कर सकते हैं और इसे कई मॉडलों पर लागू कर सकते हैं।
  • घटनाएँ: यह एक सीधा आगे है और आम तौर पर यह करने के लिए जगह पर सहमत है। मुझे लगता है कि घटनाओं के साथ सबसे बड़ी कमी यह है कि अपवादों का पता लगाना मुश्किल है (शायद लारवेल की नई घटनाओं प्रणाली के साथ नया मामला नहीं हो सकता है)। मुझे अपनी घटनाओं को समूह बनाने के लिए भी पसंद है, जब वे बुलाए जाने के बजाय वे क्या करते हैं ... उदाहरण के लिए, एक MailSender ग्राहक है जो मेल भेजने वाले घटनाओं के लिए सुनता है।
  • Pivot / BelongsToMany ईवेंट जोड़ना: सबसे लंबे समय तक मैंने जिन चीज़ों से संघर्ष किया, उनमें से एक है, व्यवहार को מToMany रिश्तों के संशोधन से कैसे जोड़ा जाए। उदाहरण के लिए, जब भी कोई उपयोगकर्ता किसी समूह में शामिल होता है, एक क्रिया करता है। मैं लगभग एक कस्टम पुस्तकालय इस के लिए पॉलिश कर रहा हूँ। मैंने इसे अभी तक प्रकाशित नहीं किया है लेकिन यह कार्यशील है! जल्द ही एक लिंक पोस्ट करने की कोशिश करेंगे। EDIT मैंने अपने सभी पिवोट्स को सामान्य मॉडल बनाने में समाप्त कर दिया और मेरा जीवन इतना आसान हो गया है ...

मॉडल का उपयोग करके लोगों की चिंताओं को संबोधित करना:

  • संगठन: हाँ यदि आप मॉडल में अधिक तर्क शामिल करते हैं, तो वे अधिक लंबे हो सकते हैं, लेकिन सामान्य तौर पर मैंने पाया है कि मेरे 75% मॉडल अभी भी बहुत छोटे हैं। यदि मैंने बड़े लोगों को व्यवस्थित करने के लिए चुना है, तो मैं इसे लक्षण का उपयोग करके कर सकता हूं (उदाहरण के लिए, पोस्टस्स्कोप्स, पोस्टअलाउर्स, पोस्टवैलीडेशन, आदि जैसे कुछ और फाइलों के साथ मॉडल के लिए एक फ़ोल्डर बनाएं)। मुझे पता है कि यह जरूरी नहीं है कि लक्षण क्या हैं लेकिन यह प्रणाली बिना किसी समस्या के काम करती है।

अतिरिक्त ध्यान दें: मुझे ऐसा लगता है कि सेवाओं में अपने मॉडलों को लपेटना एक स्विज़ आर्मी चाकू के समान है, जिसमें बहुत सारे उपकरण हैं, और इसके चारों ओर एक और चाकू का निर्माण करना है जो मूल रूप से एक ही काम करता है? हाँ, कभी-कभी आप एक ब्लेड को टेप करना चाहते हैं या सुनिश्चित कर सकते हैं कि दो ब्लेड एक साथ उपयोग किए जाते हैं ... लेकिन आमतौर पर इसे करने के अन्य तरीके हैं ...

सेवाओं का उपयोग करने के लिए कब : यह लेख सेवाओं का उपयोग करने के लिए बहुत अच्छे उदाहरण प्रस्तुत करता है ( संकेत: यह अक्सर नहीं होता है )। वह मूल रूप से कहता है जब आपकी वस्तु अपने जीवनचक्र के अजीब भागों में कई मॉडल या मॉडल का उपयोग करती है तो यह समझ में आता है। http://www.justinweiss.com/articles/where-do-you-put-your-code/


2
रोचक और मान्य विचार। लेकिन मैं जिज्ञासु हूं - यदि आप अपने व्यावसायिक तर्क को इकाई-परीक्षण करते हैं यदि यह उन मॉडलों से बंधा हुआ है जो एलक्वेंट से बंधा हुआ है, जो डेटाबेस से बंधा है?
जस्टअमार्टिन

code.tutsplus.com/tutorials/… या आप घटनाओं का उपयोग कर सकते हैं जैसे मैंने कहा कि अगर आप इसे और नीचे तोड़ना चाहते हैं
सबरीना लेगट

1
@JustAMartin क्या आप वाकई अपने यूनिट परीक्षणों में डेटाबेस का उपयोग नहीं कर सकते हैं? ऐसा न करने का क्या कारण है? कई लोग सहमत हैं कि अक्सर यूनिट परीक्षणों में डेटाबेस का उपयोग करना ठीक है। (मार्टिन फाउलर सहित, martinfowler.com/bliki/UnitTest.html : "मैं बाहरी संसाधनों के लिए युगल का उपयोग एक पूर्ण नियम के रूप में नहीं करता हूं। यदि संसाधन से बात करना आपके लिए स्थिर और तेज़ है तो ऐसा करने का कोई कारण नहीं है।" आपकी इकाई परीक्षणों में ")
एलेक्स पी।

@ AlexP11223 हाँ, यह समझ में आता है। मैंने अपने परीक्षण डेटाबेस के रूप में SQLite को एकीकृत करने की कोशिश की और सामान्य तौर पर यह ठीक हो गया, हालांकि SQLite की कुछ गंभीर सीमाएँ हैं जिन्हें लारावेल माइग्रेशन और कस्टम क्वेरी (यदि कोई हो) के लिए जिम्मेदार होना चाहिए। बेशक, वे तब कड़ाई से इकाई परीक्षण नहीं बल्कि कार्यात्मक परीक्षण कर रहे हैं, लेकिन यह उस तरह से भी अधिक कुशल है। फिर भी, यदि आप अपने मॉडल को पूर्ण अलगाव (एक सख्त इकाई परीक्षण के रूप में) में परीक्षण करना चाहते हैं, तो इसके लिए अतिरिक्त कोड (मोक्स इत्यादि) की आवश्यकता हो सकती है।
जस्टअमार्टिन 7

22

नियंत्रक और मॉडल के बीच तर्क बनाने के लिए मैं जो कुछ भी करता हूं, वह है सेवा परत बनाना । मूल रूप से, यह मेरे ऐप के भीतर किसी भी कार्रवाई के लिए मेरा प्रवाह है:

  1. नियंत्रक को उपयोगकर्ता की अनुरोधित कार्रवाई और भेजे गए पैरामीटर और सब कुछ एक सेवा वर्ग को सौंप देता है।
  2. सेवा वर्ग ऑपरेशन से संबंधित सभी तर्क करते हैं: इनपुट सत्यापन, इवेंट लॉगिंग, डेटाबेस संचालन, आदि ...
  3. मॉडल फ़ील्ड, डेटा परिवर्तन और विशेषताओं की परिभाषा की जानकारी रखता है।

यह मेरा इसे करने का तरीका है:

कुछ बनाने के लिए नियंत्रक की यह विधि:

public function processCreateCongregation()
{
    // Get input data.
    $congregation                 = new Congregation;
    $congregation->name           = Input::get('name');
    $congregation->address        = Input::get('address');
    $congregation->pm_day_of_week = Input::get('pm_day_of_week');
    $pmHours                      = Input::get('pm_datetime_hours');
    $pmMinutes                    = Input::get('pm_datetime_minutes');
    $congregation->pm_datetime    = Carbon::createFromTime($pmHours, $pmMinutes, 0);

    // Delegates actual operation to service.
    try
    {
        CongregationService::createCongregation($congregation);
        $this->success(trans('messages.congregationCreated'));
        return Redirect::route('congregations.list');
    }
    catch (ValidationException $e)
    {
        // Catch validation errors thrown by service operation.
        return Redirect::route('congregations.create')
            ->withInput(Input::all())
            ->withErrors($e->getValidator());
    }
    catch (Exception $e)
    {
        // Catch any unexpected exception.
        return $this->unexpected($e);
    }
}

यह सेवा वर्ग है जो ऑपरेशन से संबंधित तर्क करता है:

public static function createCongregation(Congregation $congregation)
{
    // Log the operation.
    Log::info('Create congregation.', compact('congregation'));

    // Validate data.
    $validator = $congregation->getValidator();

    if ($validator->fails())
    {
        throw new ValidationException($validator);
    }

    // Save to the database.
    $congregation->created_by = Auth::user()->id;
    $congregation->updated_by = Auth::user()->id;

    $congregation->save();
}

और यह मेरा मॉडल है:

class Congregation extends Eloquent
{
    protected $table = 'congregations';

    public function getValidator()
    {
        $data = array(
            'name' => $this->name,
            'address' => $this->address,
            'pm_day_of_week' => $this->pm_day_of_week,
            'pm_datetime' => $this->pm_datetime,
        );

        $rules = array(
            'name' => ['required', 'unique:congregations'],
            'address' => ['required'],
            'pm_day_of_week' => ['required', 'integer', 'between:0,6'],
            'pm_datetime' => ['required', 'regex:/([01]?[0-9]|2[0-3]):[0-5]?[0-9]:[0-5][0-9]/'],
        );

        return Validator::make($data, $rules);
    }

    public function getDates()
    {
        return array_merge_recursive(parent::getDates(), array(
            'pm_datetime',
            'cbs_datetime',
        ));
    }
}

इस तरह के बारे में अधिक जानकारी के लिए मैं अपने कोड को एक लारावेल ऐप के लिए व्यवस्थित करने के लिए उपयोग करता हूं: https://github.com/rmariuzzo.Pipimi


ऐसा लगता है कि सेवाओं को मैंने अपनी पोस्ट में पुस्तकालयों के रूप में संदर्भित किया है। मुझे लगता है कि यह रिपॉजिटरी से बेहतर है अगर आपको कई ओआरएमएस का उपयोग करने की आवश्यकता नहीं है, लेकिन मुद्दा यह है कि आपको अपनी पूरी परियोजना को स्थानांतरित करना होगा (जो आपको घटनाओं से नहीं करना है), और ऐसा लगता है यह थोड़े बस मॉडल संरचना को मिरर करने के लिए समाप्त होता है, इसलिए आपको इन सभी अतिरिक्त फ़ाइलों को मिला है। सिर्फ मॉडलों में इसे शामिल क्यों नहीं किया? कम से कम इस तरह से आपके पास अतिरिक्त फाइलें नहीं हैं।
सबरीना लेगट

यह एक दिलचस्प सवाल है @SabrinaGelbart, मुझे सिखाया जाता है कि मॉडल डेटाबेस संस्थाओं का प्रतिनिधित्व करें और कोई तर्क न रखें। यही कारण है कि मैंने सेवाओं के रूप में नामित उन अतिरिक्त फ़ाइलों को बनाया है: सभी तर्क और किसी भी अतिरिक्त संचालन को रखने के लिए। मुझे यकीन नहीं है कि आपके द्वारा पहले वर्णित घटनाओं का पूरा अर्थ क्या है, लेकिन मुझे लगता है कि सेवाओं और उपयोग के साथ लारवेल की घटनाओं का हम सभी सेवाओं के तरीकों को शुरू और अंत में घटनाओं को आग लगाने के लिए कर सकते हैं। इस तरह किसी भी घटना को तर्क से पूरी तरह से अलग किया जा सकता है। तुम क्या सोचते हो?
रुबेन्स मरिज़ो

मुझे सिखाया गया था कि मॉडल के बारे में भी ... (शायद निर्भरता के मुद्दों) के लिए एक अच्छी व्याख्या प्राप्त करना अच्छा होगा?
सबरीना लेगेट

मुझे यह तरीका पसंद है! मैं इंटरनेट पर खोज कर रहा हूं कि मुझे मॉडल के तर्क को कैसे संभालना चाहिए, रिपोजिटरी पर देखा, लेकिन यह बहुत जटिल और उपयोग के लिए बेकार लग रहा था। सेवाएं एक अच्छा विचार है। मेरा प्रश्न ऐप फ़ोल्डर में सेवाओं का एक फ़ोल्डर बनाने के बाद है, क्या आपको इसे बूटस्ट्रैप / start.php में या बूट करने के लिए कहीं भी शामिल करना होगा क्योंकि मैंने देखा था कि आपके git इसे ढूंढ नहीं पाए हैं? @RubensMariuzzo। क्या यह स्वचालित रूप से उपलब्ध थोरगुघट ऐप बन जाता है? इसलिए हम सिर्फ CongregationService :: getCongregations () का उपयोग कर सकते हैं; ??
ओगुजन

1
यदि आप सब कर रहे हैं $congregation->save();तो शायद आपको रिपॉजिटरी की आवश्यकता नहीं होगी। हालाँकि, आप देख सकते हैं कि समय के साथ आपकी डेटा एक्सेस की ज़रूरतें बढ़ सकती हैं। आप के लिए $congregation->destroyByUser()या $congregationUsers->findByName($arrayOfSelectedFields);इतने पर की जरूरत है शुरू कर सकते हैं । डेटा एक्सेस की जरूरतों से आपकी सेवाओं को डी-युगल क्यों नहीं। अपने बाकी ऐप को ऑब्जेक्ट्स / एरेज़ के साथ रिपोज से लौटा दें, और बस हेरफेर / फ़ॉर्मेटिंग / वगैरह को हैंडल करें ... आपका रेपो बढ़ेगा (लेकिन उन्हें अलग-अलग फाइलों में विभाजित कर देगा, अंततः एक प्रोजेक्ट की जटिलता कहीं न कहीं रहती है)।
प्राग्रामर

12

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

संक्षिप्त जवाब:

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

लंबे (एर) उत्तर:

जब आवश्यक हो, तो रिज़ॉल्यूशनरी का उपयोग करें: रिपोजिटरी को ओवरब्लो करने के लिए बाध्य किया जाता है, और अधिकांश समय, बस accessorमॉडल के रूप में उपयोग किया जाता है । मुझे लगता है कि वे निश्चित रूप से कुछ उपयोग किया है, लेकिन जब तक आप एक बड़े पैमाने पर अनुप्रयोग विकसित कर रहे हैं कि आवश्यकता होती है लिए लचीलेपन उस मात्रा की जिससे आप पूरी तरह से लार्वा को खोद सकें, रिपॉजिटरी से दूर रहें। आप बाद में खुद को धन्यवाद देंगे और आपका कोड बहुत आगे सीधे हो जाएगा।

अपने आप से पूछें कि क्या ऐसी संभावना है कि आप PHP फ्रेमवर्क या एक डेटाबेस प्रकार को बदलने जा रहे हैं जो लारवेल का समर्थन नहीं करता है।

यदि आपका उत्तर "संभवतः नहीं" है, तो रिपॉजिटरी पैटर्न को लागू न करें।

उपरोक्त के अलावा, कृपया एक शानदार ORM के शीर्ष पर पैटर्न को थप्पड़ न मारें जैसे कि एलक्वेंट। आप केवल ऐसी जटिलता जोड़ रहे हैं जिसकी आवश्यकता नहीं है और यह आपको बिल्कुल भी लाभ नहीं पहुँचाएगी।

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

मुझे लगता है कि लारवेल के लिए एक अच्छी तरह से गोल समाधान है MVC तर्क समस्या के है। यह सिर्फ एक मामला या संगठन है।

उदाहरण:

अनुरोध :

namespace App\Http\Requests;

use App\Post;
use App\Jobs\PostNotifier;
use App\Events\PostWasCreated;
use App\Http\Requests\Request;

class PostRequest extends Request
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'title'       => 'required',
            'description' => 'required'
        ];
    }

    /**
     * Save the post.
     *
     * @param Post $post
     *
     * @return bool
     */
    public function persist(Post $post)
    {
        if (!$post->exists) {
            // If the post doesn't exist, we'll assign the
            // post as created by the current user.
            $post->user_id = auth()->id();
        }

        $post->title = $this->title;
        $post->description = $this->description;

        // Perform other tasks, maybe fire an event, dispatch a job.

        if ($post->save()) {
            // Maybe we'll fire an event here that we can catch somewhere else that
            // needs to know when a post was created.
            event(new PostWasCreated($post));

            // Maybe we'll notify some users of the new post as well.
            dispatch(new PostNotifier($post));

            return true;
        }

        return false;
    }
}

नियंत्रक :

namespace App\Http\Controllers;

use App\Post;
use App\Http\Requests\PostRequest;

class PostController extends Controller
{

   /**
    * Creates a new post.
    *
    * @return string
    */
    public function store(PostRequest $request)
    {
        if ($request->persist(new Post())) {
            flash()->success('Successfully created new post!');
        } else {
            flash()->error('There was an issue creating a post. Please try again.');
        }

        return redirect()->back();
    }

   /**
    * Updates a post.
    *
    * @return string
    */
    public function update(PostRequest $request, $id)
    {
        $post = Post::findOrFail($id);

        if ($request->persist($post)) {
            flash()->success('Successfully updated post!');
        } else {
            flash()->error('There was an issue updating this post. Please try again.');
        }

        return redirect()->back();
    }
}

ऊपर दिए गए उदाहरण में, अनुरोध इनपुट स्वचालित रूप से मान्य है, और हमें बस इतना करना है कि दृढ़ता विधि को कॉल करें और एक नए पोस्ट में पास करें। मुझे लगता है कि पठनीयता और स्थिरता को हमेशा जटिल और अनावश्यक डिजाइन पैटर्न को ट्रम्प करना चाहिए।

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


लेकिन - नौकरियों "माना" कतार में नहीं हैं? कभी-कभी हम चाहते हैं कि यह कतारबद्ध हो लेकिन हर समय नहीं। इसके बजाय कमांड का उपयोग क्यों नहीं करते? क्या होगा यदि आप कुछ व्यावसायिक तर्क लिखना चाहते हैं जो एक आदेश या एक घटना या एक कतार के रूप में निष्पादित हो सकते हैं?
सबरीना लेगट

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