MVC + سيناريو مقابل تحكم الدهون

سيناريو MVC + مقابل وحدات التحكم السميكة


تظهر أطر PHP الحديثة (Symphony ، Laravel ، من الآن فصاعدًا في كل مكان) بشكل مقنع أن تطبيق نموذج Model-View-Controller ليس بهذه البساطة. جميع عمليات التنفيذ لسبب ما تكون عرضة للتحكم في fat controllers ( fat controllers ) ، والتي يتم إدانتها من قبل الجميع ، والمطورين ، والأطر نفسها.


لماذا هذا؟ وهل من طريقة للتعامل مع هذا؟ دعنا نحصل على حق.


المصطلحات


  • نموذج - نموذج (شكل البيانات المطلوبة)
  • عرض - عرض (مصمم بيانات النموذج)
  • تحكم - تحكم (منسق عرض النموذج على النحو المطلوب)
  • قالب - قالب عرض
  • التقديم - التقديم (تشكيل وتصميم صورة العرض التقديمي)
  • Renderer - العارض (المشكل ، مصمم صورة العرض التقديمي)

تحكم سميك


هنا وحدة تحكم الدهون النموذجية:


 class UserController { /** *   *      ID */ public function actionUserHello($userId) { //         ( ) $user = UserModel::find($userId); //       -   $name = $user->firstName.' '.$user->lastName; //         $view = new View('hello', ['name' => $name]); //  ( )     return $view->render(); } } 

ماذا نرى؟ نرى صلصة الخل! كل شيء ممكن في وحدة التحكم مختلط - كل من النموذج والعرض التقديمي ، وفي الواقع ، وحدة التحكم نفسها!


نرى أسماء النموذج والقالب موصولين بإحكام في وحدة التحكم. هذه ليست ضجة. نرى التلاعب ببيانات النموذج في وحدة التحكم - تشكيل اسم كامل من الاسم الأول والأخير. وهذه ليست ضجة.


وشيء آخر: لا نرى هذا المثال صراحة ، ولكنه ضمني. وهي: هناك طريقة واحدة فقط لتقديم (تكوين الصورة)! واحد فقط: وفقًا للنموذج الموجود في ملف php! وإذا كنت تريد قوات الدفاع الشعبي؟ وإذا كنت لا تريد في ملف ، ولكن في خط php؟ كان لدي تصميمات ذات تصميمات معقدة على مئات النماذج الصغيرة. اضطررت إلى مسح العارض لقوالب الأوتار بنفسي. لم أقم بارتفاع درجة الحرارة بالطبع ، لكن الأمر من حيث المبدأ.


ملخص قصير:


الأطر الحديثة لها عيوب مشتركة في تنفيذ MVC للجميع:
  1. التفسير الضيق لعرض MVC (عرض) فقط على أنه "عرض مع قالب في ملف PHP" بدلاً من "عرض مع أي عارض" .
  2. تفسير ضيق لنموذج MVC فقط كـ "مجال طراز قاعدة البيانات" بدلاً من "أي مترجم بيانات للعرض التقديمي" .
  3. إنهم يثيرون استخدام ما يسمى "وحدات التحكم السميكة" التي تحتوي على كل المنطق في نفس الوقت: الأعمال والعرض والتفاعل. هذا يدمر تمامًا الهدف الرئيسي لـ MVC - تقسيم المسؤوليات بين مكونات ثالوث.

لمعالجة هذه العيوب ، سيكون من الجيد إلقاء نظرة فاحصة على مكونات MVC.


العرض عارض


ألق نظرة على العيب الأول:


  1. التفسير الضيق لعرض MVC (عرض) فقط على أنه "عرض مع قالب في ملف PHP" بدلاً من "عرض مع أي عارض" .

هنا ، كل شيء بسيط للغاية - يشار إلى حل المشكلة بالفعل في صياغة المشكلة. علينا فقط أن نقول أن أي عارض يمكنه استخدام العرض. لتنفيذ ذلك ، ما عليك سوى إضافة خاصية renderer الجديدة إلى فئة العرض:


 class View { public $template, $data, $renderer; public function __costruct($template, $data, $renderer = NULL) {} } 

لذا ، قمنا بتحديد خاصية renderer جديدة للعرض. في الحالة العامة ، يمكن أن تكون قيمة هذه الخاصية أي وظيفة callable تشكل صورة للبيانات المنقولة إليها باستخدام القالب المرسل.


تستخدم معظم التطبيقات عارضًا واحدًا فقط ، وحتى إذا كانت تستخدم عدة عارضات ، فمن المفضل استخدام أحدها. لذلك ، يتم تعريف وسيطة renderer على أنها اختيارية ، بافتراض وجود بعض العارض الافتراضي.


هل هي بسيطة؟ بسيط. في الواقع ليس بهذه البساطة. والحقيقة هي أن View الموجود في MVC ليس هو بالضبط View الموجود في الإطارات. لا يمكن للعرض الموجود في الإطار العيش بدون قالب. لكن View ، الذي في MVC ، لسبب ما لا يعرف أي شيء عن هذه القوالب نفسها. لماذا؟ نعم ، لأن MVC View ، هذا هو أي محول لبيانات النموذج إلى صورة ، وليس مجرد محرك قالب. عندما نكتب شيئًا كهذا في معالج الطلب:


 $name = ' '; return "Hello, {$name}!"; 

أو حتى:


 $return json_encode($name); // Ajax response 

ثم نحدد حقًا View الموجود في MVC ، دون لمس أي View موجود في الأطر!


ولكن الآن كل شيء بسيط حقًا: تلك View ، والتي في الأطر - هذه مجموعة فرعية من تلك View ، الموجودة في MVC. علاوة على ذلك ، فإن مجموعة فرعية ضيقة للغاية ، وهي فقط محرك قالب يعتمد على ملفات PHP.


ملخص: هو ، أي أي مصمم لصورة البيانات هو View الموجود في MVC. وتلك View ، الموجودة في الأطر ، هي مجرد نوع من .


نموذج المجال / عرض النموذج (ViewModel / DomainModel)


انظر الآن إلى العيب الثاني:


  1. تفسير ضيق لنموذج MVC فقط كـ "مجال طراز قاعدة البيانات" بدلاً من "أي مترجم بيانات للعرض التقديمي" .

من الواضح للجميع أن نموذج MVC هو شيء معقد يتكون من قطع أخرى. يوافق المجتمع على تحليل النموذج إلى مكونين: نموذج المجال (DomainModel) ونموذج العرض التقديمي (ViewModel).


نموذج المجال هو ما يتم تخزينه في قواعد البيانات ، أي بيانات النموذج المقيسة. اكتب "الاسم الأول" و "الاسم الأخير" في حقول مختلفة. الإطارات مشغولة بهذا الجزء المعين من النموذج ببساطة لأن تخزين البيانات هو كونه الخاص ، مدروس جيدًا.


ومع ذلك ، يحتاج التطبيق إلى بيانات مجمعة بدلاً من البيانات العادية. يجب تجميع بيانات المجال في صور مثل: "Hello، Ivan!" أو "Dear Ivan Petrov!" أو حتى "For Ivan a Petrov a !". تتم إحالة هذه البيانات المحولة إلى نموذج آخر - نموذج عرض. لذا فإن هذا الجزء من النموذج لا يزال يتم تجاهله من قبل الأطر الحديثة. يتم تجاهلها لأنه لا يوجد اتفاق حول كيفية التعامل معها. وإذا كانت الأطر لا توفر حلاً ، فإن المبرمجين يسلكون أبسط طريقة - حيث يرمون نموذج العرض في وحدة التحكم. ويحصلون على تحكم الدهون الكراهية ولكن لا مفر منه!


الإجمالي: من أجل تنفيذ MVC ، تحتاج إلى تنفيذ نموذج عرض. لا توجد خيارات أخرى. بالنظر إلى أن التمثيلات وبياناتها يمكن أن تكون أي شيء ، فإننا نقول أن لدينا مشكلة.


السيناريو مقابل تحكم الدهون


هناك عيب أخير في الأطر:


  1. إنهم يثيرون استخدام ما يسمى "وحدات التحكم السميكة" التي تحتوي على كل المنطق في نفس الوقت: الأعمال والعرض والتفاعل. هذا يدمر تمامًا الهدف الرئيسي لـ MVC - تقسيم المسؤوليات بين مكونات ثالوث.

هنا نصل إلى أساسيات MVC. لنكن واضحين. لذلك ، تفترض MVC التوزيع التالي للمسؤوليات بين مكونات ثالوث:


  • وحدة التحكم هي منطق التفاعل ، أي التفاعل مع كل من العالم الخارجي (طلب - استجابة) وداخلي (نموذج - عرض) ،
  • النموذج هو منطق الأعمال ، أي توليد البيانات لطلب محدد ،
  • التمثيل هو منطق التمثيل ، أي زخرفة البيانات الناتجة عن النموذج.

المضي قدما. يظهر مستويان من المسؤوليات بوضوح:


  • المستوى التنظيمي هو المراقب ،
  • المستوى التنفيذي هو النموذج والتمثيل.

بعبارات بسيطة ، فإن وحدة التحكم توجه ، المحراث النموذجي والعرضي. هذا إذا بطريقة بسيطة. وإذا لم يكن بطريقة بسيطة ، ولكن بشكل أكثر تحديدًا؟ كيف بالضبط توجيه وحدة تحكم؟ وكيف بالضبط يحرث النموذج وطريقة العرض؟


تحكم توجيه مثل هذا:


  • يتلقى طلبًا من تطبيق ،
  • يقرر أي نموذج وأي عرض سيتم استخدامه لهذا الطلب ،
  • استدعاء النموذج المحدد واستلام البيانات منه ،
  • استدعاء العرض المحدد مع البيانات المستلمة من النموذج ،
  • إرجاع البيانات المزخرفة بواسطة طريقة العرض إلى التطبيق.

شيء من هذا القبيل. الشيء الأساسي في هذا المخطط هو أن النموذج والتمثيل يتحولان إلى روابط في سلسلة تنفيذ الاستعلام. علاوة على ذلك ، من خلال الروابط المتتالية: أولاً ، يحول النموذج الطلب إلى بعض البيانات ، ثم يتم تحويل بيانات النموذج هذه بواسطة العرض إلى إجابة مزينة حسب الحاجة لطلب محدد. مثل ، تم تصميم طلب بشري بصريًا باستخدام قوالب ، تم تزيين طلب Android بتشفيرات JSON.


الآن دعونا نحاول معرفة كيف يحرث فناني الأداء بالضبط - النموذج والعرض التقديمي. قلنا أعلاه أن هناك إجماع على تحلل النموذج إلى مكونين فرعيين: نموذج المجال ونموذج العرض التقديمي. هذا يعني أنه يمكن أن يكون هناك المزيد من الفنانين - ليس اثنين ، ولكن ثلاثة. بدلا من سلسلة التنفيذ


>>

قد تكون هناك سلسلة


>> >>

السؤال يطرح نفسه: لماذا اثنان أو ثلاثة فقط؟ وإذا كنت بحاجة إلى المزيد؟ الجواب الطبيعي ، في سبيل الله ، خذ بقدر ما تحتاج!


الفنانون المفيدون الآخرون مرئيون على الفور: المصادقون ، المعيدون ، العارضون المختلفون ، وعمومًا كل شيء غير متوقع ، ولكنه ممتع.


دعونا نلخص:


  • يمكن تنفيذ المستوى التنفيذي MVC ( - ) كسلسلة من الروابط ، حيث يقوم كل ارتباط بتحويل إخراج الارتباط السابق إلى الإدخال الخاص باللاحقة.
  • إدخال الرابط الأول هو طلب التطبيق.
  • ناتج الارتباط الأخير هو استجابة التطبيق للطلب.

دعوت هذه السلسلة Scenario ، لكن لارتباطات السلسلة لم أقرر بعد الاسم. الخيارات الحالية هي مشهد (كجزء من برنامج نصي) ، ومرشح (كمحول بيانات) ، وعمل برنامج نصي. بشكل عام ، اسم الارتباط ليس مهمًا جدًا ، هناك شيء أكثر أهمية.


عواقب ظهور السيناريو كبيرة. وهي: يفترض السيناريو المسؤولية الرئيسية للمراقب - لتحديد النموذج والعرض الضروري للطلب وإطلاقهما. وبالتالي ، يتحكم جهاز التحكم في مسؤوليتين فقط: التفاعل مع العالم الخارجي (طلب-استجابة) وتشغيل البرنامج النصي. وهذا أمر جيد بمعنى أن جميع مكونات ثالوث MVC متحللة بشكل متسلسل وتصبح أكثر تحديدًا وإدارتها. ولا تزال جيدة من ناحية أخرى - تصبح وحدة التحكم في MVCS فئة ثابتة داخلية بحتة ، وبالتالي ، حتى من حيث المبدأ ، لا يمكن أن تصبح سمينة.


يؤدي استخدام السيناريوهات إلى اختلاف آخر في نمط MVC ؛ دعوت هذا الاختلاف MVCS - Model-View-Controller-Scenario .


واثنين من الخطوط حول تحلل MVC. الأطر الحديثة ، حيث تتحلل جميع الوظائف النموذجية إلى أقصى حد ، أخذت بشكل طبيعي تمامًا من جزء MVC المفاهيمي من مسؤوليات التفاعل مع العالم الخارجي. لذا ، تعمل الفصول المدربة بشكل خاص مثل HTTP في معالجة طلب المستخدم. ونتيجة لذلك ، لا يتلقى المتحكم طلب المستخدم الأولي ، ولكن بعض المحسنة ، وهذا يسمح بعزل وحدة التحكم عن تفاصيل الطلب. وبالمثل ، يتم إجراء عزل عن تفاصيل استجابة HTTP ، مما يسمح لوحدة MVC بتحديد نوع الاستجابة الخاص بها. بالإضافة إلى ذلك ، قامت الأطر بتنفيذ عنصري MVC بالكامل - نموذج المجال ونموذج العرض التقديمي ، ومع ذلك ، فقد ناقشنا هذا بالفعل. أنا كل هذا إلى حقيقة أن تحسين وتثبيت MVC مستمر ومستمر ، وهذا أمر صاخب.


مثال MVCS


الآن دعونا نرى كيف يمكن تنفيذ مثال Fat Cortroller في بداية هذه المقالة في MVCS.


نبدأ بإنشاء وحدة تحكم MVCS:


 $mvcs = new MvcsController(); 

يتلقى جهاز تحكم MVCS طلبًا من جهاز توجيه خارجي. دع جهاز التوجيه يحول URI للنموذج 'user / hello / XXX' إلى مثل هذا الإجراء ومعلمات الطلب:


 $requestAction = 'user/hello'; //   $requestParams = ['XXX']; //   -   

بالنظر إلى أن وحدة تحكم MVCS تقبل النصوص البرمجية بدلاً من عناوين URI ، نحتاج إلى تعيين بعض النصوص النصية إلى إجراء الطلب. من الأفضل القيام بذلك في حاوية MVCS:


 //   MVCS  URI  $mvcs->set('scenarios', [ 'user/hello' => 'UserModel > UserViewModel > view, hello', ..., ]); 

دعونا نلقي نظرة فاحصة على هذا السيناريو. هذه سلسلة من ثلاثة محولات بيانات مفصولة بعلامة ">":


  • "UserModel" هو اسم نموذج المجال "المستخدم" ، ومدخلات النموذج ستكون معلمات الطلب ، وسيكون الناتج البيانات الفعلية للنموذج ،
  • "UserViewModel" هو اسم نموذج العرض الذي يحول بيانات المجال إلى بيانات العرض ،
  • "view، hello" هو "قالب" عرض النظام لقالب PHP يسمى "hello".

الآن نحن بحاجة فقط إلى إضافة محولين متضمنين في البرنامج النصي كدالة إغلاق إلى حاوية MVCS:


 //   UserModel $mvcs->set('UserModel', function($id) { $users = [ 1 => ['first' => '', 'last' => ''], 2 => ['first' => '', 'last' => ''], ]; return isset($users[$id]) ? $users[$id] : NULL; }); //   UserViewModel $mvcs->set('UserViewModel', function($user) { //    PHP  : 'echo "Hello, $name!"'; return ['name' => $user['first'].' '.$user['last']]; }); 

هذا كل ما في الأمر! لكل طلب ، من الضروري تحديد البرنامج النصي المقابل وجميع مشاهده (باستثناء النظام ، مثل "عرض"). ولا أكثر.


والآن نحن جاهزون لاختبار MVCS للطلبات المختلفة:


 //        $scenarios = $mvcs->get('scenarios'); $scenario = $scenarios[$requestAction]; //      ... //   'user/hello/1'  ' '   'hello' $requestParams = ['1']; $response = $mvcs->play($scenario, $requestParams); //   'user/hello/2'  ' '   'hello' $requestParams = ['2']; $response = $mvcs->play($scenario, $requestParams); 

تمت استضافة تطبيق PHP MVCS على github.com.
هذا المثال موجود في example دليل MVCS.

Source: https://habr.com/ru/post/ar424595/


All Articles