लारवेल में संबंधों का प्रबंधन, रिपॉजिटरी पैटर्न का पालन करना


120

लारवेल में अच्छे डिजाइन पैटर्न पर टी। ओटवेल की पुस्तक पढ़ने के बाद लारावेल 4 में एक ऐप बनाते हुए मैंने खुद को एप्लिकेशन पर हर तालिका के लिए रिपोजिटरी बनाते हुए पाया।

मैं निम्नलिखित तालिका संरचना के साथ समाप्त हुआ:

  • छात्र: आईडी, नाम
  • पाठ्यक्रम: आईडी, नाम, शिक्षक_एड
  • शिक्षक: आईडी, नाम
  • असाइनमेंट: आईडी, नाम, कोर्स_आईडी
  • स्कोर (छात्रों और असाइनमेंट के बीच एक धुरी के रूप में कार्य करता है): student_id, असाइनमेंट_id, स्कोर

मेरे पास इन सभी तालिकाओं के तरीकों को खोजने, बनाने, अद्यतन करने और हटाने के साथ रिपॉजिटरी कक्षाएं हैं। प्रत्येक रिपॉजिटरी में एलोकेंट मॉडल होता है जो डेटाबेस के साथ इंटरैक्ट करता है। मॉडल प्रति लारवेल के प्रलेखन में परिभाषित हैं: http://laravel.com/docs/eloquent#relationships

एक नया पाठ्यक्रम बनाते समय, मैं जो कुछ करता हूं, वह कोर्स रिपॉजिटरी पर क्रिएट मेथड है। उस पाठ्यक्रम में असाइनमेंट हैं, इसलिए एक बनाते समय, मैं पाठ्यक्रम में प्रत्येक छात्र के लिए स्कोर तालिका में एक प्रविष्टि बनाना चाहता हूं। मैं यह असाइनमेंट रिपोजिटरी के माध्यम से करता हूं। इसका अर्थ है असाइनमेंट रिपॉजिटरी, दो एलोक्वेंट मॉडल के साथ असाइनमेंट और स्टूडेंट मॉडल के साथ संचार करता है।

मेरा प्रश्न है: जैसा कि यह ऐप संभवतः आकार में बढ़ेगा और अधिक रिश्तों को पेश किया जाएगा, क्या रिपॉजिटरी में अलग-अलग एलोक्वेंट मॉडल के साथ संवाद करने के लिए यह अच्छा अभ्यास है या इसके बजाय अन्य रिपॉजिटरी का उपयोग करना चाहिए (मेरा मतलब असाइनमेंट रिपॉजिटरी से अन्य रिपॉजिटरी को कॉल करना है) ) या इसे एलोकेन्ट मॉडल में एक साथ किया जाना चाहिए?

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

जवाबों:


71

ध्यान रखें कि आप राय पूछ रहे हैं: डी

ये मेरा:

TL; DR: हाँ, यह ठीक है।

आपका काम बढ़िया चल रहा है!

मैं वही करता हूं जो आप अक्सर कर रहे हैं और पाते हैं कि यह बहुत अच्छा काम करता है।

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

एक कोर्स एक "इकाई" है, जिसमें विशेषताओं (शीर्षक, आईडी, आदि) और यहां तक ​​कि अन्य इकाइयां (असाइनमेंट भी हैं, जिनकी अपनी विशेषताओं और संभवतः इकाइयां हैं)।

आपका "कोर्स" रिपॉजिटरी एक पाठ्यक्रम और पाठ्यक्रम की विशेषताओं / असाइनमेंट (असाइनमेंट सहित) को वापस करने में सक्षम होना चाहिए।

आप इसे एलोकेंट के साथ, सौभाग्य से पूरा कर सकते हैं।

(मैं अक्सर प्रति तालिका एक रिपॉजिटरी के साथ समाप्त होता हूं, लेकिन कुछ रिपॉजिटरी का उपयोग दूसरों की तुलना में बहुत अधिक किया जाता है, और इसलिए कई और अधिक तरीके हैं। उदाहरण के लिए, आपके "पाठ्यक्रम" रिपॉजिटरी आपके असाइनमेंट रिपॉजिटरी की तुलना में बहुत अधिक पूर्ण हो सकते हैं, उदाहरण के लिए, यदि आपके। पाठ्यक्रम के आसपास आवेदन केंद्र अधिक और पाठ्यक्रम के संग्रह के बारे में कम)।

मुश्किल हिस्सा है

कुछ डेटाबेस क्रियाओं को करने के लिए मैं अक्सर अपनी रिपॉजिटरी के अंदर रिपॉजिटरी का उपयोग करता हूं।

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

व्यावहारिक दृष्टिकोण से, यह समझ में आता है। हम डेटा स्रोतों को किसी चीज़ में बदलने की संभावना नहीं रखते हैं। एलोकेंट (एक गैर-वर्ग डेटा स्रोत के लिए) को संभाल नहीं सकता है।

ORMS

इस सेटअप का सबसे पेचीदा हिस्सा, मेरे लिए कम से कम, यह निर्धारित कर रहा है कि एलोकेंट वास्तव में हमारी मदद कर रहा है या नुकसान पहुंचा रहा है। ORM एक मुश्किल विषय है, क्योंकि जब वे व्यावहारिक दृष्टिकोण से हमारी बहुत मदद करते हैं, तो वे डेटा पुनर्प्राप्ति करने वाले कोड के साथ आपके "व्यापार तर्क संस्थाओं" को भी जोड़ते हैं।

इस प्रकार की गड़गड़ाहट होती है कि क्या आपकी रिपॉजिटरी की जिम्मेदारी वास्तव में डेटा को संभालने या संस्थाओं की पुनर्प्राप्ति / अद्यतन (व्यावसायिक डोमेन संस्थाओं) को संभालने के लिए है।

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

वैसे भी, ये कुछ अधूरे विचार हैं। जैसा कि कहा गया है, केवल मेरी राय, जो पिछले साल के भीतर रूबी मिडवेस्ट में "चाचा बॉब के" प्रमुख जैसे डोमेन ड्रिवेन डिज़ाइन पढ़ने और वीडियो देखने का परिणाम है ।


1
आपकी राय में, क्या यह एक अच्छा विकल्प होगा यदि रिपॉजिटरी, एलोकेंट ऑब्जेक्ट्स के बजाय डेटा ट्रांसफर ऑब्जेक्ट्स लौटाते हैं? बेशक यह वाक्पटु से डोटो के लिए एक अतिरिक्त रूपांतरण होगा, लेकिन इस तरह, कम से कम, आप अपने नियंत्रकों / विचारों को वर्तमान ऑर्म कार्यान्वयन से अलग करते हैं।
फेडरिवो सेप

1
मैंने उस पर थोड़ा प्रयोग किया है और इसे अव्यावहारिक पक्ष पर थोड़ा सा पाया है। कहा जा रहा है, मैं उस विचार को अमूर्त में पसंद करता हूं। हालाँकि, Illuminate का डेटाबेस कलेक्शन ऑब्जेक्ट सिर्फ सरणियों की तरह काम करता है और मॉडल ऑब्जेक्ट्स स्टैडक्लास ऑब्जेक्ट्स की तरह ही कार्य करते हैं ताकि हम, व्यावहारिक रूप से बोल सकें, एलक्वेंट के साथ रहें और फिर भी भविष्य में हमें सरणियों / वस्तुओं का उपयोग करना चाहिए।
फिदेल्पर

4
@ फिडेलॉपर मुझे लग रहा है कि अगर मैं रिपॉजिटरी का उपयोग करता हूं तो मैं ओआरएम की पूरी सुंदरता खो देता हूं जो एलोक्वेंट प्रदान करता है। जब $a = $this->account->getById(1)मैं अपनी रिपॉजिटरी विधि के माध्यम से किसी खाता वस्तु को पुनः प्राप्त कर रहा हूं तो मैं केवल श्रृंखला विधियों को पसंद नहीं कर सकता $a->getActiveUsers()। ठीक है, मैं उपयोग कर सकता हूं $a->users->..., लेकिन फिर मैं एक एलोकेंट संग्रह और कोई stdClass ऑब्जेक्ट वापस कर रहा हूं और फिर से एलक्क्वस से बंधा हुआ हूं। इसका क्या उपाय है? उपयोगकर्ता रिपॉजिटरी में एक और तरीका घोषित करना जैसे $user->getActiveUsersByAccount($a->id);? यह सुनना अच्छा लगेगा कि आप इसे कैसे हल करते हैं ...
santacruz

1
ORM एंटरप्राइज़ (ish) -level आर्किटेक्चर के लिए भयानक हैं क्योंकि वे इस तरह के मुद्दों का कारण बनते हैं। अंत में, आपको यह तय करना होगा कि आपके आवेदन के लिए सबसे अधिक समझ में क्या आता है। निजी तौर पर एलोकेंट के साथ रिपॉजिटरी का उपयोग करते समय (90% समय!) मैं एलोकेंट का उपयोग करता हूं और मॉडल और संग्रह जैसे कि स्टडक्लासेस एंड एरेज़ (क्योंकि आप कर सकते हैं) का इलाज करने के लिए अपने सबसे कठिन प्रयास करें (यदि आप कर सकते हैं!) तो अगर मुझे ज़रूरत है, तो कुछ और पर स्विच करना संभव है।
फिदेल्पर

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

224

मैं लारवेल 4 का उपयोग करके एक बड़ी परियोजना को पूरा कर रहा हूं और आपको उन सभी सवालों का जवाब देना होगा जो आप अभी पूछ रहे हैं। लीनपब पर उपलब्ध लारवेल की सभी पुस्तकों और टॉगल ऑफ गोग्लिंग को पढ़ने के बाद, मैं निम्नलिखित संरचना के साथ आया।

  1. एक योग्य मॉडल वर्ग प्रति खाने योग्य तालिका
  2. एलोकेंट मॉडल प्रति एक रिपॉजिटरी वर्ग
  3. एक सेवा वर्ग जो कई रिपॉजिटरी कक्षाओं के बीच संवाद कर सकता है।

तो मान लीजिए कि मैं एक मूवी डेटाबेस बना रहा हूं। मेरे पास कम से कम निम्नलिखित स्पष्ट मॉडल वर्ग होंगे:

  • चलचित्र
  • स्टूडियो
  • निदेशक
  • अभिनेता
  • समीक्षा

एक रिपॉजिटरी वर्ग प्रत्येक एलोकेंट मॉडल वर्ग को अतिक्रमण करेगा और डेटाबेस पर CRUD संचालन के लिए जिम्मेदार होगा। रिपॉजिटरी वर्ग इस तरह दिख सकते हैं:

  • MovieRepository
  • StudioRepository
  • DirectorRepository
  • ActorRepository
  • ReviewRepository

प्रत्येक रिपॉजिटरी वर्ग एक बेस रिपॉजिटरी वर्ग का विस्तार करेगा जो निम्नलिखित इंटरफ़ेस को लागू करता है:

interface BaseRepositoryInterface
{
    public function errors();

    public function all(array $related = null);

    public function get($id, array $related = null);

    public function getWhere($column, $value, array $related = null);

    public function getRecent($limit, array $related = null);

    public function create(array $data);

    public function update(array $data);

    public function delete($id);

    public function deleteWhere($column, $value);
}

एक सेवा वर्ग का उपयोग कई रिपॉजिटरी को एक साथ करने के लिए किया जाता है और इसमें एप्लिकेशन का वास्तविक "व्यावसायिक तर्क" होता है। नियंत्रक केवल क्रिएट, अपडेट और डिलीट कार्यों के लिए सेवा वर्गों के साथ संवाद करते हैं।

इसलिए जब मैं डेटाबेस में एक नया मूवी रिकॉर्ड बनाना चाहता हूं, मेरे मूवीकंट्रोलर वर्ग के निम्नलिखित तरीके हो सकते हैं:

public function __construct(MovieRepositoryInterface $movieRepository, MovieServiceInterface $movieService)
{
    $this->movieRepository = $movieRepository;
    $this->movieService = $movieService;
}

public function postCreate()
{
    if( ! $this->movieService->create(Input::all()))
    {
        return Redirect::back()->withErrors($this->movieService->errors())->withInput();
    }

    // New movie was saved successfully. Do whatever you need to do here.
}

यह निर्धारित करना आपके लिए है कि आप अपने नियंत्रकों को कैसे POST डेटा देते हैं, लेकिन मान लीजिए कि पोस्टक्रीट में इनपुट :: all () विधि द्वारा दिया गया डेटा कुछ इस प्रकार है:

$data = array(
    'movie' => array(
        'title'    => 'Iron Eagle',
        'year'     => '1986',
        'synopsis' => 'When Doug\'s father, an Air Force Pilot, is shot down by MiGs belonging to a radical Middle Eastern state, no one seems able to get him out. Doug finds Chappy, an Air Force Colonel who is intrigued by the idea of sending in two fighters piloted by himself and Doug to rescue Doug\'s father after bombing the MiG base.'
    ),
    'actors' => array(
        0 => 'Louis Gossett Jr.',
        1 => 'Jason Gedrick',
        2 => 'Larry B. Scott'
    ),
    'director' => 'Sidney J. Furie',
    'studio' => 'TriStar Pictures'
)

चूंकि MovieRepository को डेटाबेस में अभिनेता, निर्देशक या स्टूडियो रिकॉर्ड बनाने का तरीका नहीं पता होना चाहिए, हम अपने MovieService क्लास का उपयोग करेंगे, जो कुछ इस तरह दिख सकता है:

public function __construct(MovieRepositoryInterface $movieRepository, ActorRepositoryInterface $actorRepository, DirectorRepositoryInterface $directorRepository, StudioRepositoryInterface $studioRepository)
{
    $this->movieRepository = $movieRepository;
    $this->actorRepository = $actorRepository;
    $this->directorRepository = $directorRepository;
    $this->studioRepository = $studioRepository;
}

public function create(array $input)
{
    $movieData    = $input['movie'];
    $actorsData   = $input['actors'];
    $directorData = $input['director'];
    $studioData   = $input['studio'];

    // In a more complete example you would probably want to implement database transactions and perform input validation using the Laravel Validator class here.

    // Create the new movie record
    $movie = $this->movieRepository->create($movieData);

    // Create the new actor records and associate them with the movie record
    foreach($actors as $actor)
    {
        $actorModel = $this->actorRepository->create($actor);
        $movie->actors()->save($actorModel);
    }

    // Create the director record and associate it with the movie record
    $director = $this->directorRepository->create($directorData);
    $director->movies()->associate($movie);

    // Create the studio record and associate it with the movie record
    $studio = $this->studioRepository->create($studioData);
    $studio->movies()->associate($movie);

    // Assume everything worked. In the real world you'll need to implement checks.
    return true;
}

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


8
यह टिप्पणी अब तक क्लीनर, अधिक स्केलेबल और रखरखाव योग्य दृष्टिकोण है।
एंड्रियास

4
+1! इससे मुझे बहुत मदद मिलेगी, हमारे साथ साझा करने के लिए धन्यवाद! आश्चर्य है कि आप सेवाओं के अंदर चीजों को कैसे वैध बनाने में कामयाब रहे, यदि संभव हो, तो आप संक्षेप में बता सकते हैं कि आपने क्या किया? वैसे भी धन्यवाद! :)
पाउलो फ्रीटास

6
जैसे @PauloFreitas ने कहा, यह देखना दिलचस्प होगा कि आप सत्यापन वाले हिस्से को कैसे संभालते हैं, और मैं अपवाद हिस्से में भी दिलचस्पी लूंगा (क्या आप अपवाद, घटनाओं का उपयोग करते हैं या आप इसे संभालते हैं जैसे कि आप अपने सुझाव देते हैं आपकी सेवाओं में बूलियन रिटर्न के माध्यम से नियंत्रक?)। धन्यवाद!
निकोलस

11
अच्छा लिखिए, हालाँकि मुझे यकीन नहीं है कि आप MovieRepository को MovieController में इंजेक्ट कर रहे हैं क्योंकि नियंत्रक सीधे रिपॉजिटरी के साथ कुछ भी नहीं कर रहा है, और न ही आपकी पोस्टक्रिएट विधि MovieRepository का उपयोग कर रही है, इसलिए मैं आपको इसे गलती से मानता हूं। ?
डेविडकनइट

15
इस बारे में प्रश्न: आप इस उदाहरण में रिपॉजिटरी का उपयोग क्यों कर रहे हैं? यह एक ईमानदार सवाल है - मेरे लिए, ऐसा लगता है कि आप रिपॉजिटरी का उपयोग कर रहे हैं, लेकिन कम से कम इस उदाहरण में रिपॉजिटरी वास्तव में कुछ भी नहीं कर रहा है, लेकिन एलोकेंट के समान इंटरफ़ेस प्रदान कर रहा है, और अंत में आप अभी भी एलोक्वेंट से बंधे हैं क्योंकि आपका सेवा वर्ग इसमें सीधे ( $studio->movies()->associate($movie);) का उपयोग कर रहा है ।
केविन मिशेल

5

मुझे यह सोचना पसंद है कि मेरा कोड क्या कर रहा है और इसके लिए क्या जिम्मेदार है, बजाय इसके कि वह "सही या गलत" है। इस तरह मैं अपनी जिम्मेदारियों से अलग हो जाता हूं:

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

इसे ध्यान में रखते हुए, यह हर बार एक रिपॉजिटरी का उपयोग करने के लिए समझ में आता है (चाहे आप interfaces.etc बनाते हैं। एक संपूर्ण अन्य विषय है)। मुझे यह दृष्टिकोण पसंद है, क्योंकि इसका मतलब है कि मुझे पता है कि मुझे कुछ काम करने की आवश्यकता होने पर कहाँ जाना है।

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


क्या आप अपने BaseRepository का अपना कार्यान्वयन दिखा सकते हैं? मैं वास्तव में भी ऐसा करता हूं और मैं उत्सुक हूं कि आपने क्या किया।
ओडिसी

GetById, getByName, getByTitle, प्रकार के तरीके सहेजें ।etc के बारे में सोचें। - आम तौर पर विधियां जो विभिन्न डोमेन के भीतर सभी रिपॉजिटरी पर लागू होती हैं।
Oddman

5

अपने डेटा के लगातार फाइलिंग कैबिनेट के रूप में रिपॉजिटरी के बारे में सोचें (न केवल आपके ओआरएम)। विचार यह है कि आप एपीआई का उपयोग करने के लिए लगातार सरल में डेटा हड़पना चाहते हैं।

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

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

  1. माता-पिता मॉडल (एक-एक या एक-कई) से एक नए बच्चे के मॉडल को लटकाते हुए, मैं बच्चे के रिपॉजिटरी में कुछ createWithParent($attributes, $parentModelInstance)इस तरह से एक विधि जोड़ूंगा और यह सिर्फ विशेषताओं और कॉल बनाने $parentModelInstance->idके parent_idक्षेत्र में जोड़ देगा ।

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

  3. एक रन में संबंधित मॉडल बनाते हुए, मैं कुछ ऐसा बनाता हूं जिसे मैं गेटवे कहता हूं (यह फाउलर की परिभाषाओं से थोड़ा हटकर हो सकता है)। जिस तरह से मैं $ गेटवे-> createParentAndChild ($ parentAttributes, $ childAttributes) को तर्क के एक गुच्छा के बजाय कॉल कर सकता हूं जो कि नियंत्रक या कमांड में लगे तर्क को जटिल कर सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.