مولد القطعة CRUD لـ Yii

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



من وجهة نظر نمذجة البيانات ، كلاهما كيانان "متداخلان" ليس لهما أهمية مستقلة بمعزل عن الكائن الأصل.

في Yii ( إطار عمل php ) ، يوجد Gii - وهو مُنشئ كود مدمج يسمح لك بإنشاء واجهات CRUD أساسية باستخدام نموذج بيانات بنقرات قليلة من الفأرة ، والتي تسرع عملية التطوير بشكل كبير ، ولكنها تنطبق فقط على الكيانات المستقلة ، مثل المقالة أو الجهاز في الأمثلة أعلاه.

سيكون من الرائع أن تكون قادرًا على إنشاء شيء مشابه لكائنات البيانات "المتداخلة" ، أليس كذلك؟ الآن - يمكنك ، مرحبا بكم في كات للحصول على التفاصيل.

للأكثر نفاد الصبر في نهاية المقالة ، يتم إعطاء تعليمات لبداية سريعة.

للراغبين في المقال ، يتم النظر في الجوانب من تطبيق الأعمال إلى جهاز داخلي:

  • حالة العمل: نشر حسب الموضوع
    • قائمة المواضيع على الرئيسية
    • قائمة الوظائف ذات الصلة
  • تحت الغطاء: مولد gii على أساس CRUD
    • غي مولد القالب
    • الطبقة الأساسية القطعة
    • تحكم واجهة متكاملة
  • بداية سريعة
    • حول الدعم والتطوير

حالة العمل: نشر حسب الموضوع


ربما تعليقات على habr ومثالا سيئا منذ ذلك الحين غالبًا ما يكون مفيدًا أكثر من المقالة نفسها ، ولكن على أي حال ، عند تطوير تطبيق ما ، تكون هناك حالات غالبًا ما يكون فيها كائن معين من نموذج البيانات ذا فائدة قليلة للمستخدم ككيان مستقل.

فكر في مهمة أعمال مبسطة: لإنشاء موقع ويب لنشر الرسائل التي تم تجميعها حسب مواضيع مختلفة.

يجب أن يحتوي الموقع على الواجهات التالية:

  1. يجب أن تدعم الصفحة الرئيسية - عناصر واجهة مستخدم متعددة في المستقبل ، ولكن في المرحلة الحالية للتنفيذ ، هناك واحد فقط: قائمة بالموضوعات التي تمت تصفيتها بواسطة بعض المعايير.
  2. قائمة كاملة بالمواضيع - قائمة كاملة بالمواضيع في شكل جدول ؛
  3. صفحة الموضوع - معلومات حول الموضوع وقائمة المنشورات المنشورة فيه.

جميلة القياسية ، أليس كذلك؟

لنلقِ نظرة على نموذج البيانات:



أيضا لا مفاجآت. ستحتوي فئتان من النماذج على منطق أعمالنا:

  • فئة الموضوع - بيانات عن الموضوع ، والتحقق من الصحة ، وقائمة المنشورات فيه ، فضلاً عن طريقة منفصلة تُرجع قائمة بالموضوعات التي تمت تصفيتها وفقًا لمعايير عنصر واجهة المستخدم في الصفحة الرئيسية.
  • فئة المشاركة هي فقط البيانات والتحقق من الصحة.

سيتم تقديم الطلب من قبل جهازي تحكم:

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

من المحتمل ، يمكنك أيضًا إنشاء PostController - لأغراض الإدارة و / أو نسخ لصق أجزاء من التعليمات البرمجية في عناصر واجهة مستخدم مخصصة ، ولكن اترك هذا خارج نطاق هذه المقالة.
حتى الآن ، يمكن إنشاء معظم الشفرة باستخدام gii ، مما يسرع عملية التطوير ويقلل المخاطر (أقل رمز يدوي = فرصة أقل لارتكاب خطأ).

يبقى سؤالان:

  1. كيف يتم عرض قائمة مصفاة بالموضوعات على الصفحة الرئيسية؟
  2. كيفية عرض قائمة المنشورات حسب الموضوع؟

إذا تمكنت من حلها باستخدام مولد تلقائي - فسيكون ذلك إنجازًا قويًا.

قائمة المواضيع على الرئيسية


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

للعرض ، هناك العديد من خيارات التنفيذ.

الأول ، القذر والسريع ، هو القيام بكل شيء مباشرةً في ملف العرض ( طرق العرض / الموقع / index.php ):

  1. إنشاء ActiveDataProvider ؛
  2. املأها ببيانات من نموذج Topic ؛
  3. العرض باستخدام عنصر واجهة مستخدم ListView / GridView قياسي ، مع تحديد الحقول المطلوبة يدويًا.

يمكنك الانتقال إلى أبعد من ذلك وتعبئته جميعًا في ملف عرض منفصل ، مثل طريقة العرض / site / _topic-list-widget.php ، مع استدعاء العرض الخاص به من الملف الرئيسي. سيعطي ذلك المزيد من القابلية للإدارة والتوسعة ، ولكنه لا يزال يبدو قذرًا جدًا.

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

ولكن هل يبدو أن التعليمات البرمجية لهذه الأداة ستكرر رمز TopicController كثيرًا من حيث التعامل مع actionIndex () ؟ ومن المزعج جدًا كتابة هذا الرمز يدويًا.

سيكون من الأفضل كثيرًا إنشاء هذا الرمز تلقائيًا ثم استدعاء الأداة المصغّرة:

<?= \app\widgets\TopicControllerWidget::widget([ 'action' => 'index', 'params' => [ 'query' => app\models\Topic::findBySomeSpecificCriteria() ], ]) ?> 

قائمة الوظائف ذات الصلة

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

عن طريق القياس مع قائمة الموضوعات التي تمت تصفيتها ، لدينا نفس الخيارات تقريبًا.

الأول هو عمل كل شيء في رمز ملف العرض لعرض الموضوع ( المشاهدات / الموضوع / view.php ):

  1. إنشاء ActiveDataProvider ؛
  2. املأه ببيانات من النموذج $ model-> getPosts () ؛
  3. العرض باستخدام عنصر واجهة مستخدم ListView / GridView قياسي ، مع تحديد الحقول المطلوبة يدويًا.

والثاني هو عزل هذا الرمز في ملف عرض تقديمي منفصل: طرق العرض / الموضوع / _posts-list-widget.php ، حتى لا تكون عينًا - إعادة استخدامها في مكان ما ستفشل.

والثالث عبارة عن عنصر واجهة مستخدم كامل يعمل على تكرار رمز PostController الشرطي إلى حد كبير في الجزء actionIndex () ، ولكن كتابته يدويًا.

أو قم بإنشاء الشفرة تلقائيًا واتصل بالبرنامج المصغّر النهائي:

 <?= app\widgets\PostControllerWidget::widget([ 'action' => 'index', 'params' => [ 'query' => $model->getPosts(), ], ]) ?> 

تحت الغطاء: مولد gii على أساس CRUD


يتم تعريف مهمة العمل ، ويتم تحديد متطلبات عنصر واجهة التعامل الذي تم إنشاؤه ، وسنعرف كيف سننشئها بالضبط. يحتوي Gii بالفعل على مولد لوحدة التحكم CRUD. بالنسبة إلى عنصر واجهة تعامل المستخدم (CRUD) ، نحتاج إلى إنشاء مولد جديد استنادًا إلى المكون الحالي.

بضعة روابط للوثائق قبل البدء - سيكون مفيدًا أيضًا إذا قررت كتابة ملحقك الخاص:


من الواضح أن جميع الوظائف يتم تعبئتها في ملحق Yii ، الذي يتم تثبيته من خلال الملحن ويدخل في مجلد البائع في مشروعك.

يتكون التمديد من ثلاثة أجزاء:

  1. دليل القوالب / الخام الذي يحتوي على قالب مولد gii ؛
  2. Controller.php file - المدمج في واجهة تحكم للمكالمات القطعة.
  3. ملف Widget.php هو الفئة الأساسية لجميع عناصر واجهة المستخدم المنشأة.



غي مولد القالب


يجب أن ينشئ الامتداد رمزًا ، لذلك يكون الجزء المركزي هو مولد Gii.

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

يتكون مولد gii من الأجزاء التالية (كلها داخل دليل القوالب / الخام):

  • الدليل الافتراضي هو قالب يحدث فيه كل السحر: سيتوافق كل ملف في هذا الدليل مع ملف تم إنشاؤه في مشروعك ؛
  • File form.php - كما قد تخمن من الاسم ، هذا نموذج لإدخال معلمات الجيل (أسماء الفئات ، وما إلى ذلك) ؛
  • File Generator.php - أوركسترا جيل تتلقى البيانات من النموذج ، تقوم بالتحقق من صحتها ، ثم تقوم باستدعاء ملفات القوالب بالتسلسل لإنشاء النتيجة.

تحتوي ملفات Generator.php و form.php على تغييرات تجميلية في الغالب بالنسبة لتلك الأصلية من مولد CRUD: أسماء الملفات ، التحقق من الصحة ، نصوص تلميح الأدوات ، إلخ.

ملفات القوالب هي المسؤولة عن طريقة العرض التي تم إنشاؤها ورمز القطعة نفسه. بادئ ذي بدء ، تعد قوالب الملفات / crud / default / controller.php مهمة ، وهي المسؤولة عن إنشاء فئة عنصر واجهة المستخدم مباشرةً ، والتي تتوافق مع فئة وحدة التحكم من المولد الأصلي.

يجب أن يكون لعنصر واجهة المستخدم نفس الإجراءات مثل وحدة التحكم CRUD ، ولكن يتم إنشاؤها بشكل مختلف قليلاً. توضح الأمثلة أدناه نتيجة الجيل مع التعليقات:

  • actionIndex - بدلاً من الإخراج غير المشروط لجميع النماذج ، تقبل الطريقة معلمة استعلام $؛

     public function actionIndex($query) { $dataProvider = new ActiveDataProvider([ 'query' => $query, ]); return $this->render('index', [ 'dataProvider' => $dataProvider, ]); } 
  • actionCreate و actionUpdate - في حالة النجاح ، فبدلاً من إعادة التوجيه ، يقومون ببساطة بإرجاع رمز النجاح ، ويتم توفير مزيد من المعالجة بواسطة وحدة تحكم الواجهة المدمجة ؛

     public function actionCreate() { $model = new Post(); if ($model->load(Yii::$app->request->post()) && $model->save()) { return 'success'; } return $this->render('create', [ 'model' => $model, ]); } 

  • actionDelete - يدعم طريقة GET لعرض أداة الحذف (افتراضيا - زر واحد) و POST لأداء الإجراء ؛ إذا نجحت ، فإنه لا يؤدي أيضًا عملية إعادة توجيه ، ولكنه يعرض رمزًا.

     public function actionDelete($id) { $model = $this->findModel($id); if (Yii::$app->request->method == 'GET') { return $this->render('delete', [ 'model' => $model, ]); } else { $model->delete(); return 'success'; } } 

أخيرًا ، تحتوي ملفات العرض على التعديلات الأساسية التالية:

  • تمت ترجمة جميع الرؤوس إلى h2 بدلاً من h1 ؛
  • أزلت الكود المسؤول عن عرض عنوان الصفحة وعن فتات التنقل - يجب ألا تؤثر الأداة على هذه الأشياء ؛
  • يتم إنشاء النماذج وتحريرها باستخدام نافذة مشروطة (أداة Modal مدمجة) ؛
  • وأضاف حذف قالب القطعة - مع زر واحد أحمر كبير.

الطبقة الأساسية القطعة


عندما ينتهي المولد من عمله ، سينشئ فئة عنصر واجهة مستخدم في مساحة اسم التطبيق. تبدو سلسلة الميراث كما يلي: يتم توريث عناصر واجهة المستخدم التي تم إنشاؤها للتطبيق من عنصر واجهة المستخدم الأساسي ، الفئة \ ianikanov \ wce \ Widget ، والتي بدورها تُورث من عنصر واجهة المستخدم الأساسي الأساسي ، الفئة \ yii \ base \ Widget .

تحل الفئة الأساسية لعنصر واجهة المستخدم المهام التالية:

  1. يحدد مجالين رئيسيين: $ action و $ params ، يتم من خلاله نقل السيطرة إلى عنصر واجهة المستخدم من مشاهدة الاتصال ؛
  2. يحدد عددًا من المعلمات القياسية التي يمكن تجاوزها في الفئة التي تم إنشاؤها ، مثل المسار إلى ملفات عرض عنصر واجهة المستخدم والاسم والمسار إلى وحدة تحكم الواجهة (حولها أدناه) ورسائل الخطأ ؛
  3. يعرّف المعلمات القياسية عند تقديم طرق العرض: render and renderFile؛
  4. يوفر بنية أساسية لحدث يشبه بنية التحكم الأساسية بحيث تعمل عوامل التصفية القياسية مثل AccessControl و VerbFilter ؛
  5. يحدد طريقة التشغيل التي تجمع كل هذا معًا.

تحكم واجهة متكاملة

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

وحدة التحكم هذه مسجلة في خريطة التطبيق من خلال ملف التكوين وتحتوي على طريقة واحدة فقط - actionIndex ، والتي تنفذ الإجراءات التالية:

  1. يقبل طلبًا من عميل ؛
  2. ينقل التحكم إلى فئة القطعة المقابلة ؛
  3. يتعامل مع أخطاء العمل نتيجة لعنصر واجهة المستخدم ؛
  4. يعيد التوجيه مرة أخرى إلى التطبيق الرئيسي.

ربما يكون من المهم الإشارة إلى ما لا تفعله وحدة التحكم هذه:

  1. لا يتحقق من مستويات الوصول - هذا المنطق ينتمي إلى عناصر واجهة تعامل محددة.
  2. لا يؤدي أي معالجة الإدخال - يتم تمرير المعلمات إلى القطعة كما هي ؛
  3. لا يعالج الإخراج إلا للتحقق من رمز نجاح محدد مسبقًا.

يتيح لك هذا النهج الحفاظ على براعة الواجهة ، تاركًا تنفيذ متطلبات العمل ، بما في ذلك متطلبات الأمان ، رمز تطبيق التطبيق.

بداية سريعة

تحدي الأعمال واضح وجاهز للبدء؟ استخدام الملحق له أربع خطوات:

  1. تركيب.
  2. التكوين.
  3. جيل.
  4. التطبيق.

يتم تثبيت الامتداد باستخدام الملحن:

 php composer.phar require --prefer-dist ianikanov/yii2-wce "dev-master" 

بعد ذلك ، تحتاج إلى إجراء العديد من التغييرات على ملف تكوين التطبيق.

أولاً ، أضف إشارة إلى مولد gii:

 if (YII_ENV_DEV) { $config['modules']['gii'] = [ 'class' => 'yii\gii\Module', 'allowedIPs' => ['127.0.0.1', '::1', '192.168.0.*', '192.168.178.20'], 'generators' => [ //here 'widgetCrud' => [ 'class' => '\ianikanov\wce\templates\crud\Generator', 'templates' => [ 'WCE' => '@vendor/ianikanov/yii2-wce/templates/crud/default', // template name ], ], ], ]; } 

ثانياً ، أضف وحدة التحكم في الواجهة المدمجة إلى الخريطة:

 $config = [ ... 'controllerMap' => [ 'wce-embed' => '\ianikanov\wce\Controller', ], ... ]; 

هذا يكمل التثبيت والتكوين.

لإنشاء عنصر واجهة مستخدم:

  1. فتح gii.
  2. حدد "القطعة تحكم CRUD" ؛
  3. ملء حقول النموذج ؛
  4. عرض وإنشاء رمز.

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

القطعة لعرض قائمة النماذج:

 <?= app\widgets\PostControllerWidget::widget([ 'action' => 'index', 'params' => [ 'query' => $otherModel->getPosts(), ], ]) ?> 

القطعة لمشاهدة نموذج واحد:

 <?= app\widgets\PostControllerWidget::widget(['action' => 'view', 'params' => ['id' => $post_id]]) ?> 

عنصر واجهة إنشاء النموذج (زر + نموذج ملفوف في Modal):

 <?= app\widgets\PostControllerWidget::widget(['action' => 'create']) ?> 

تغيير نموذج القطعة (زر + نموذج ملفوف في مشروط):

 <?= app\widgets\PostControllerWidget::widget(['action' => 'update', 'params'=>['id' => $post_id]]) ?> 

القطعة إزالة النموذج (زر):

 <?= app\widgets\PostControllerWidget::widget(['action' => 'delete', 'params'=>['id' => $post_id]]) ?> 

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

حول الدعم والتطوير


بضع كلمات حول كيفية دعم التوسع وتطويره. لديّ العمل الرئيسي وبعض مشاريعي "الجانبية" (مشاريع الحيوانات الأليفة). لذلك ، هذا الامتداد هو مشروع جانبي من مشاريعي الجانبية ، لذلك سأقوم بتطوير تحسينات عليه لتلبية احتياجات مشاريعي فقط.

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

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


All Articles