المحتوى عن 'mvc'.



مزيد من الخيارات

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المُحتوى


التصنيفات

  • التخطيط وسير العمل
  • التمويل
  • فريق العمل
  • دراسة حالات
  • نصائح وإرشادات
  • التعامل مع العملاء
  • التعهيد الخارجي
  • التجارة الإلكترونية
  • مقالات ريادة أعمال عامة

التصنيفات

  • PHP
    • Laravel
    • ووردبريس
  • جافاسكريبت
    • Node.js
    • jQuery
    • AngularJS
    • Cordova
  • HTML5
  • CSS
    • Sass
    • إطار عمل Bootstrap
  • SQL
  • سي شارب #C
    • منصة Xamarin
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • برمجة أندرويد
  • لغة Swift
  • لغة R
  • لغة TypeScript
  • سير العمل
    • Git
  • صناعة الألعاب
    • Unity3D
  • مقالات برمجة عامة

التصنيفات

  • تجربة المستخدم
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
    • كوريل درو
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • مقالات تصميم عامة

التصنيفات

  • خواديم
    • الويب HTTP
    • قواعد البيانات
    • البريد الإلكتروني
    • DNS
    • Samba
  • الحوسبة السّحابية
    • Docker
  • إدارة الإعدادات والنّشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • مقالات DevOps عامة

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • استسراع النمو
  • المبيعات

التصنيفات

  • إدارة مالية
  • الإنتاجية
  • تجارب
  • مشاريع جانبية
  • التعامل مع العملاء
  • الحفاظ على الصحة
  • التسويق الذاتي
  • مقالات عمل حر عامة

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
  • أندرويد
  • iOS
  • macOS
  • ويندوز

التصنيفات

  • شهادات سيسكو
    • CCNA
  • شهادات مايكروسوفت
  • شهادات Amazon Web Services
  • شهادات ريدهات
    • RHCSA
  • شهادات CompTIA
  • مقالات عامة

أسئلة وأجوبة

  • الأقسام
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة البرمجة
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات
    • أسئلة الشهادات المتخصصة

التصنيفات

  • ريادة الأعمال
  • العمل الحر
  • التسويق والمبيعات
  • البرمجة
  • التصميم
  • DevOps

تمّ العثور على 10 نتائج

  1. تجهيز قاعدة البيانات بما أنّنا سنستخدم قاعدة البيانات PostgreSQL لهذا التّطبيق، عليك أولا أن تقوم بتنصيبها، إن كنت تستخدم Ubuntu فيُمكنك مُراجعة درس كيفيّة تنصيب PostgreSQL على Ubuntu، أمّا إن كنت على نظام Windows أو نظام Mac OS فتستطيع تحميلها من الموقع الرّسمي وتنصيبها، يُمكنك كذلك استخدام برنامج pgAdmin لإدارة قواعد بياناتك عن طريق برنامج رسومي. يُمكنك استعمال البرنامج الرّسومي لإنشاء قاعدة البيانات إن أردت ذلك، لكنّنا سنستعمل أداة psql لتنفيذ أوامر PostgreSQL واستعمال لغة SQL مباشرة من سطر الأوامر، لذا تأكّد من أنّك تستطيع الوصول إلى أداة psql. إنشاء قاعدة البيانات لإنشاء قاعدة البيانات، يكفي أن ننفّذ الأمر التّالي على سطر أوامر psql : CREATE DATABASE kalima; بعد تنفيذ الأمر، سيكون المُخرج كما يلي: CREATE DATABASE كلمة المرور للاتّصال بقاعدة البيانات، سنحتاج إلى كلمة مرور، إن سبق لك وأن خصّصت كلمة مرور أثناء التّنصيب، تستطيع تخطي هذه الخطوة، أمّا إن لم تمتلك كلمة مرور أو أنّك نسيتها، فيُمكنك ببساطة تغييرها في سطر أوامر psql بالأمر التّالي: \password بعد تنفيذ الأمر سيُطلب منك كتابة كلمة مرور جديدة وإعادة كتابتها للتّأكد من أنّك لم تُخطئ. كلمة المرور هذه مُهمّة جدا للاتّصال بقاعدة البيانات من تطبيق فلاسك باستخدام أداة SQLAlchemy لذا تأكّد من أنّها مُتاحة. ما معنى ORM؟ ORM اختصار Object-Relational Mapper أي رابط الكائنات بالعلاقات (الجداول)، الهدف منه ببساطة التّعامل مع قواعد بيانات SQL باستعمال الكائنات Objects والأصناف Classes عوضا عن تعليمات SQL، فعوضا عن إنشاء البيانات وجلبها وتعديلها وحذفها عن طريق تعليمات SQL التّي ستتكرّر كثيرا في الشّفرة يُمكن ببساطة استخدام لغة بايثون للوصول إلى نفس الهدف، كما أنّ استعمالها مع لغة برمجة يخلق شيئا من عدم التّناسق. لو تابعت سلسلة دروس Flask للمُبتدئين، للاحظت بأنّنا استعملنا ملفّا باسم manage_db للتّعامل مع قواعد البيانات عن طريق الدّوال عوضا عن كتابة تعليمات SQL عند الرّغبة في إجراء كل عمليّة، ولو استعملنا SQL الخام لكان تكرار الشّفرة كثيرا. بالإضافة إلى ميّزة تعريف الأصناف التّي تُمثّل الجداول والتّعامل معها عن طريق التّوابع (الدوال) لتجنّب تكرار الشّفرة، يقوم الـORM بالكثير من الأشياء المُملّة خلف الكواليس، فعوضا عن الاهتمام بالتّفاصيل الصّغيرة بأنفسنا، يقوم الـORM بالاهتمام بها من أجلنا لنهتمّ بالأمور الأكثر أهميّة، وفي النّهاية، مُعظمنا لا يتقن لغة SQL كثيرا لذا من المُفضّل استعمال مكتبة للتّعامل مع قواعد البيانات باللغة التّي نُجيدها. وبما أنّ استعمال الـORM يُتيح لنا عزل الشّفرة المسؤولة عن التّعامل مع قاعدة البيانات في معزل عن التّطبيق فهذا يُتيح لنا تعديل الخصائص وإضافة الميّزات للتّطبيقات دون التّأثير على تطبيق معيّن بحد ذاته، ومن الشّائع جمع الشّفرة المسؤولة عن التّعامل مع قاعدة البيانات في ملف باسم models.py في مجلّد المشروع. يُساعدنا الـORM كذلك على تحقيق مبدأ MVC أو Model-View-Controller أي “نموذج، عرض، مُتحكّم ” وهو مبدأ يقوم على عزل جزء العرض، المُتحكّمات، والنّماذج في تطوير التّطبيقات لمرونة أكثر في التّطوير، أي أنّ كلّا من العرض (الذي يُمثّل القوالب في تطبيقنا) والمُتحكّم (الذي يُمثّل دوال الموجّهات في ملفّات views.py) والنّموذج (أي الجزء الذي يتعامل مع البيانات) أجزاء منفصلة حسب الوظيفة متّصلة في التّطبيق ويُمكن أن تنتقل البيانات بينها ببساطة، ورغم أنّ إطار Flask يمنحك الحريّة الكاملة في طريقة تسميّة أجزاء تطبيقك، إلّا أن أطر عمل أخرى مثل Django و Rails تفرض عليك تسميّات محدّدة. ما هو SQLAlchemy؟ بعد أن عرّفنا معنى الـORM بقي تعريف مكتبة SQLAlchemy، وهي مكتبة تُسهّل علينا التّعامل مع قواعد البيانات المُختلفة، كما أنّها تحتوي على ORM قوي ومُعتمد عليه من طرف المشاريع الكبيرة. تحتوي SQLAlchemy على الكثير من الدّوال المُساعدة والكائنات التّي تُسهّل عليك كتابة SQL بلغة بايثون، والORM المبني فيه يُستعمل لربط الكائنات بالبيانات في قاعدة البيانات. سنستعمل في غالب هذا المشروع الـORM الخاص بـSQLAlchemy ولن نتطرّق إلى بقيّة ميّزات المكتبة، لذا إن أردت معرفة المزيد عن المكتبة فعليك بالتّوثيق الرّسمي. إضافات Flask Flask Extensions أو إضافات فلاسك عبارة عن مكتبات وأطر عمل Frameworks مبنيّة لتُسهّل على المُطوّر القيام بالأشياء المُفصّلة وتجنّب التّعامل مع كل شيء بأنفسنا، فمثلا، يُمكننا أن نستعمل مكتبة SQLAlchemy مع تطبيق Flask مُباشرة، إلّا أن في هذه الطّريقة الكثير من الأمور غير المُهمّة والكثير من الإعدادات، وبما أنّنا في مسيرة تعلّم إطار فلاسك لا كيفيّة استعمال SQLAlchemy، ولتسهيل استعمال SQLAlchemy مع المشاريع المبنيّة بإطار العمل فلاسك، قام كاتب الإطار Armin Ronacher بتطوير إضافة للإطار باسم Flask-SQLAlchemy التّي أصبحت أحد أشهر الإضافات على موقع Github. بالإضافة إلى Flask-SQLAlchemy هناك الكثير من الإضافات التّي يُمكننا استعمالها لتطوير تطبيقات فلاسك، وإليك بعضا من هذه الإضافات: Flask-Login إضافة لتسهيل التّعامل مع جلسات المُستخدمين Sessions، تُتيح إمكانيّة تسجيل دخول مُستخدم وتسجيل خروجه، لكنّها لا تقوم بالتّحقق من صحّة البيانات (اسم المُستخدم وكلمة المرور مثالا) وتترك المُطوّر للاهتمام بالأمر. Flask-Bcrypt إضافة لتشفير كلمات المرور باستعمال خوارزميّة Bcrypt قبل حفظها بقاعدة البيانات لحماية أكثر، هذا لمنع المُخترق من سرقة كلمات المرور حتى بعد وصوله إلى قاعدة البيانات، وكلّما كانت خوارزميّة التّشفير أعقد كلّما كان من الصّعب فك التّشفير عن كلمة المرور ما يُوفّر حماية أكثر. Flask-WTF بما أنّ مُعظم التّطبيقات تعتمد على نماذج HTML (حقول النّصوص، كلمات المرور و مساحة النّص TextArea) وبما أنّها تُسبّب الكثير من الثّغرات الأمنيّة في التّطبيقات والتّي يُمكن أن يُساء استغلالها، فلا بد من توفير طريقة آمنة وبسيطة للتأكّد من أنّ ما يُدخله المُستخدم في هذه الحقول آمن. يُمكنك بالطّبع التّأكد من مُدخلات المُستخدم بنفسك، لكنّ الأمر يأخذ وقتا، كما أنّه ممل في الحقيقة، إذ عليك تكرار نفس الشّيء كلّ مرّة. عوضا عن الاعتماد على مهاراتك البرمجيّة للتأكّد من سلامة المُدخلات، يُمكنك أن تترك إضافة Flask-WTF للاهتمام بالأمر في تطبيقاتك المبنيّة بإطار فلاسك، الإضافة مبنيّة على مكتبة WTForms التّي يُمكنك استعمالها مع أطر عمل أخرى، وأنصحك بالاطلاع على توثيق المكتبة الرّسمي للمزيد من المعلومات عن كيفيّة مُعالجة النّماذج. Flask-Migrate ببساطة، Flask-Migrate إضافة تُتيح لك تهجير البيانات Migrations عند تطوير تطبيقك. هذه الإضافة مهمّة جدّا إن كنت تطوّر تطبيقا سبق وأن نشرته على نحو مُتواصل، إذ تُتيح لك تهجير البيانات في كل مرّة تُضيف جدولا جديدا أو علاقة بين الجداول إلى قاعدة البيانات. تخيّل أنّك تمتلك تطبيقا يحتوي جدول المُستخدمين فيه على أكثر من ألف مُدخل، إن أردت إتاحة إمكانيّة إضافة تاريخ ازدياد للمُستخدمين فستضطر إلى حذف كلّ شيء في هذا الجدول وإضافة العمود الجديد ثمّ إعادة البيانات من جديد، الأمر مُعقّد بعض الشّيء وفقدان البيانات أمر غير مرغوب فيه بتاتا. مُجدّدا عوضا عن القيام بكل شيء بنفسك، دع إضافة Flask-Migrate لتهتمّ بكل هذا التّعقيد من أجلك، فبسطر أو سطرين تستطيع تطبيق الميّزة الجديدة لتطبيقك وتهجير البيانات القديمة بكل بساطة. Flask-Testing إضافة لتسهيل إجراء اختبارات وحدة Unit tests لتطبيقك، إذ أنّ اختبار التّطبيق مُهمّ جدّا للتأكّد من أنّ كلّ شيء بخير وأنّ المُستخدمين لا يواجهون أية مشاكل، خاصّة إذا كان مشروعك كبيرا، فاختبار كل وظيفة يدويّا قد يأخذ منك وقتا طويلا، وإن لم تختبره آليا فنسبة الخطأ كبيرة جدّا. إذا أضفت خاصيّة جديدة لتطبيقك فأنت بذلك تُعرّض أجزاء أخرى من التّطبيق إلى الخطأ، وستُسهّل عليك الاختبارات معرفة ما إذا كان التّطبيق لا يزال يعمل كما ينبغي له أو لا، وبما أنّ اختبارات الوحدة تختبر كلّ وظيفة على نحو مُستقل، فسيسهل عليك معرفة أي جزء يجب عليك الاهتمام به لإصلاح التّطبيق. Flask-Gravatar هذه الإضافة تُسهّل لنا استعمال خدمة Gravatar لتمكين المُستخدمين من إضافة صورة شخصيّة لهم، إذ تكون الصّورة الشّخصيّة مُرتبطة بالبريد الإلكتروني للمُستخدم وتُستعمل هذه الخدمة في الكثير من التّطبيقات في وقتنا الحالي. هناك مئات الإضافات الخاصّة بإطار Flask لذا لا يُمكنني ذكرها كلّها، إن أردت الاطّلاع على إضافات أخرى، تستطيع البحث عنها عن طريق أداة pip كما يلي: pip search flask سنتعرّف على معظم هذه الإضافات في قادم الدّروس مع التّقدم في المشروع، وهذا الهدف الأساسي من هذه الإضافات، كلّما تقدّمت أكثر وكبر المشروع كلّما احتجت إلى التّعامل مع الكثير من المهام المُملّة كالتّأكد من أنّ ما يرسله المُستخدم إلى قاعدة بياناتك آمن، وكالتّعامل مع الجلسات لتوفير نظام تسجيل دخول آمن دون الاضطرار للقيام بكل التّفاصيل؛ كما أنّ الإضافات تُقلّل من حجم الخطأ في التّطوير، فالاعتماد على إضافة لتسجيل دخول المُستخدمين بشكل آمن أفضل من مُحاولة إنشاء طريقة خاصّة بك قد تكون مليئة بالثّغرات الأمنيّة. وبما أنّ فلاسك إطار عمل مُصغّر، فبإضافاته يُمكنك أن تستخدمه كما تُستخدم أطر العمل الضّخمة كـDjango و Rails و Laravel وغيرها من الأطر المشهورة. خاتمة بعد أن أنشأنا قاعدة البيانات وتعرّفنا على بعض المفاهيم المُهمّة في تطوير تطبيقات الويب مع إطار فلاسك، حان الوقت لإنشاء الجداول الأساسيّة في قاعدة البيانات لنتمكّن من التّعامل معها عن طريق إضافة Flask-SQLAlchemy وهذا بالضّبط ما سنقوم به في الدّرس القادم.
  2. رغم أنّ شركة مايكروسوفت كانت تعتمد بشكل كلّي على نماذج ويب ASP.NET Forms في تطوير تطبيقات الويب، إلّا أنّه وفي الأعوام القليلة الماضيّة بدا أنّ تركيز الشركة منصبًّا بشكل واضح على تطوير تطبيقات الويب باستخدام ASP.NET MVC. وعلى الرغم مع عدم تخلّي عن تقنيّة Forms إلّا أنّ دورها على ما يبدو يتضاءل يومًا بعد يوم. طرحت مايكروسوفت هذا الامتحان للمرّة الأولى عام 2012. وباعتبار أنّ مصدر هذه التقنيّة هو مايكروسوفت فلا غنى لأيّ مطوّر عن الحصول على هذا الامتحان والنجاح فيه كوثيقة لإثبات المعرفة والمقدرة أمّام أيّ شركة أو جهة يطمح بالعمل لديها. فالشركات التقنيّة عمومًا تفضّل أصحاب الشهادات المعتمدة من كبريات الشركات العالميّة في توظيف الكادر للعمل لديها. وفي الحقيقة أنّه حتى بالنسبة للموظّفين الحاليين فإنّهم يفضّلون الحصول على مثل هكذا شهادات لتحسين وضعهم الحالي في شركاتهم. نبذة عن الامتحان يقيس هذا الامتحان مهاراتك كمطوّر ويب في استخدام هذه التقنيّة الرائعة بشكل صحيح وسليم. حيث أنّ هناك خمسة مجالات رئيسيّة يغطيها الامتحان. تنصح مايكروسوفت أن يتقدّم للامتحان كلّ مطوّر له خبرة برمجيّة عمرها خمسة سنوات أو ثلاثة أعوام في مجال الأعمال باستخدام هذه التقنيّة. يكلّف الامتحان حاليًّا مبلغًا قدره 150 دولارًا أمريكيًّا ويمكنك أن تحجز لإجراء هذا الامتحان عن طريق الإنترنت وذلك في أيّ مركز معتمد من مايكروسوفت. يمكنك مراجعة الصفحة الرسميّة للامتحان. يجري الامتحان ضمن المركز المعتمد في توقيت مُحدّد تلتزم به. تكون القاعة التي سيجري فيها الامتحان مراقبة، وبعد أن يقوم الموظّف المختص بتحميل أسئلة الامتحان على الحاسوب يبدأ التوقيت. من الضروري التنبّه إلى أنّ النقاط الواردة في هذا المقال لا تمثّل بالضرورة المصدر الوحيد لأسئلة الامتحان، ويجب الانتباه أيضًا إلى وجود بعض المواقع التي تزوّدك بأسئلة مسرّبة لامتحانات سابقة مع الحلول لهذه الأسئلة، وفي الغالب تكون مدفوعة وليست مجّانيّة. المشكلة هنا (بصرف النظر عن كونها مسألة غير قانونيّة) في أنّه قد تكون هذه الأسئلة غير صحيحة بمعنى أنّ مصدرها ليس امتحانات مايكروسوفت، وهناك احتمال أن يكون مصدرها امتحانات مايكروسوفت بالفعل ولكن قد تكون الإجابات المقترحة لها خاطئة، وفي جميع الأحوال لا تستطيع أن تضمن أن تتكرّر هذه الأسئلة في امتحانات قادمة. ومن الجدير ذكره أنّ هذا الامتحان يدخل ضمن متطلّبات الحصول على عدّة شهادات تمنحها مايكروسوفت أيضًا (تتطلّب كلّ شهادة عادةً النجاح في أكثر من امتحان)، فهو يدخل مثلًا ضمن شهادة مايكروسوفت في تطوير تطبيقات شير بوينت MCSD: SharePoint Applications. وشهادة مايكروسوفت في تطوير تطبيقات ويب MCSD: Web Applications ويجب ملاحظة أنّه اعتبارًا من 30 أبريل (نيسان) عام 2014 أصبحت أسئلة الامتحان تغطّي Visual Studio 2013 مع MVC5 بالإضافة إلى التحديثات الخاصة بـ Microsoft Azure. على ماذا سأحصل بعد النجاح في الامتحان؟ بعد النجاح في الامتحان ستحصل على وثيقة نجاح موقّعة من المدير التنفيذي لمايكروسوفت تحمل اسمك، واسم الامتحان الذي اجتزته بدون ذكر المعدّل الّذي حصلت عليه. وهناك شكلان لهذه الوثيقة: إلكترونيّ مجّاني، ومطبوع غير مجّاني. يمكنك تحميل النسخة الإلكترونيّة من موقع يتبع مايكروسوفت مخصّص لهذا الغرض، كما يمكنك طلب النسخة المطبوعة من هذه الشهادة لتصلك بالبريد لقاء رسمٍ رمزيّ. الملفت في الموضوع أنّ مايكروسوفت تسمح لك بمشاركة النسخة الإلكترونيّة مع أيّ جهة عن طريق رابط مخصّص لهذا الغرض، مما يسمح لك بإثبات امتلاكك لهذه الوثيقة بيسر وموثوقيّة عاليّة. فعلى سبيل المثال لا الحصر، يتطلّب موقع upwork.com الشهير للعمل المستقل مثل هذا الإثبات، في حال صرّحت حول امتلاكك لمثل هذه الشهادات. المجالات الرئيسيّة لأسئلة الامتحان فيما يلي المجالات الرئيسيّة للامتحان، والنسبة المئويّة لمساهمة كلّ منها في أسئلة الامتحان: تصميم بنية التطبيق (من 15% إلى 20%) تصميم واجهة المستخدم (من 20% إلى 25%) تطوير تجربة المستخدم (من 15% إلى 20%) اصطياد الأخطاء وتنقيح تطبيقات الويب (من 20% إلى 25%) تصميم وتطبيق النواحي الأمنيّة (من 20% إلى 25%) 1. تصميم بنية التطبيق ستحتاج في هذا المجال إلى معرفة كيفيّة التخطيط لطبقات layers التطبيق وذلك عن طريق التخطيط لفصل الأجزاء الرئيسيّة concerns main والاستخدام المناسب للنماذج models والمشاهد views والمتحكّمات controllers. والاختيار بين المعالجة من طرف العميل client-side أو من طرف الخادم server-side، والتخطيط من أجل قابليّة التوسّع scalability. كما ستحتاج لمعرفة كيفيّة تصميم تطبيق موزّع distributed application، وما يتضمّن ذلك من تصميم تطبيقات هجينة hybrid applications، والتخطيط والتنفيذ لدورة حياة تطبيق سحابيّ على Azure، وإعداد إدارة الحالة state management، وتصميم استراتيجيّة خاصّة باستخدام الذاكرة المؤقّتة cache والـ WebSockets، وتصميم وحدات (HTTP (HTTP Modules ومعالجات (HTTP (HTTP Handlers. 2. تصميم واجهة المستخدم يتطلّب هذا المجال تصميم واجهة مستخدم UI على تطبيق ويب ودراسة سلوكها، واستجابة التطبيق للمزايا الخاصّة بكلّ متصفّح عن طريق ميّزة تحديد نوع المتصفّح، والتخطيط لإنشاء تصميم متجاوب responsive design. 3. تطوير تجربة المستخدم في هذا المجال يجب على المتقدّم أن يكون ملمًّا بكيفيّة التخطيط لقابليّة الوصول والأمثَلَة لمحرّكات البحث SEO، والتخطيط لتوطين (ترجمة وما إلى ذلك) التّطبيق localization، وتصميم وتطبيق المتحكّمات controllers وطرائق action ضمن تطبيق MVC، وتصميم وتطبيق المسالك routes، والتحكّم بسلوك التطبيق باستخدام نقاط التوسعة extensibility points الخاصّة بـ MVC، والتقليل من عرض الحزمة المستخدم عن طريق ميزّتي التحزيم bundle والتصغير minify واستخدام شبكات توصيل المحتوى CDN. 4. اصطياد الأخطاء وتنقيح تطبيقات الويب بالنسبة إلى هذا المجال، يتوجّب معرفة كيفيّة منع الأخطاء أثناء التشغيل واصطيادها، وتصميم استراتيجيّة متكاملة لمعالجة الاستثناءات exception handling، وإجراء اختبارات ممنهجة لتطبيق ويب عن طريق إنشاء وتشغيل وحدات الاختبار unit tests وإنشاء كائنات اختبار زائفة mocks، وتنقيح تطبيق الويب ضمن عدّة متصفّحات، واستخدام محاكيات الأجهزة المحمولة mobile emulators، وتنقيح تطبيق Azure عن طريق جمع معلومات تشخيصيّة باستخدام الواجهة السحابيّة لأدوات تنقيح (Azure (Azure Diagnostics API، وغيرها من التقنيّات التي تتيحها Windows Azure لتنقيح الأخطاء. 5. تصميم وتطبيق النواحي الأمنية ستحتاج إلى معرفة كيفيّة إعداد وضبط عمليّة الاستيثاق authentication للمستخدمين، والاختيار بين الاستيثاق باستخدام ويندوز أو النماذج Forms أو الاستيثاق المخصّص، وضبط وإعداد التخويل authorization للمستخدمين بواسطة الأدوار roles، وإنشاء مزوّد أدوار مخصّص custom membership provider، وتصميم وتطبيق التوثيق باستخدام claims وذلك عبر مستودعات federated identity stores، وإدارة سلامة البيانات data integrity، وإنشاء موقع محميّ باستخدام ASP.NET وذلك بتطبيق شهادات SSL، وتشفير كلمات المرور باستخدام الحماية الإضافيّة salt password قبل تخزينها في قاعدة البيانات، وترميز المحتوى في HTML لمنع هجمات cross-site، ومنع هجمات حقن (SQL (SQL Injection بتمرير الوسائط إلى الاستعلام بشكل كائنيّ وليس بشكل نصّي مباشر، ومنع الهجمات من النوع XSRF.
  3. يقدّم هذا الدرس كيفية إنشاء نموذج Model قاعدي في Laravel ومن ثم استخدامه. النماذج هي الجزء من بنية MVC الذي تُعالَج فيه البيانات وتُنفَّذ عليها قواعد التطبيق. يتطلّب الدرس تثبيت Laravel وإعداده مع قاعدة البيانات. نبدأ بإنشاء النموذج باستخدام أمر artisan على النحو التالي: php artisan make:model Widget -m سمّينا النموذج بـWidget وأضفنا خيار m- لإنشاء التهجير في نفس الوقت. يختزل الأمر بهذه الطريقة الكثير من الوقت ويجعلنا نركّز على الأهم: عمل النموذج. ستجد بعد اكتمال تنفيذ الأمر ملفا باسم Widget.php في مجلّد app المتفرّع عن مجلّد المشروع، وملفًّا للتهجير في المجلّد database/migrations. يظهر اسما الملفّيْن في مخرجات تنفيذ الأمر السّابق. نفتح ملفّ Widget.php للنظر في محتواه: <?php namespace App; use Illuminate\Database\Eloquent\Model; class Widget extends Model { // } هذا كلّ ما يوجد الملف! هيكل نموذج يمكننا الاستفادة منه لإنشاء ما نريد. بالانتقال إلى مجلّد database/migrations نجد ملفًّا يشبه التالي: 2016_03_19_163722_create_widgets_table.php يظهر في بداية اسم الملف ختم زمني بتاريخ إنشائه. يفترض Laravel أن اسم النموذج كلمة مفردة (Widget مثلا) تبدأ بحرف كبير Uppercase، في حين يتوقّع أن يكون اسم الجدول Table جمعًا (widgets) يبدأ بحرف صغير. يمكن تفسير الأمر بأن النموذج يُرجِع نظيرا واحدا لتسجيلات الجدول. إذا نظرنا إلى ملفّ التهجيرات فسنجد أن لدينا قاعدة يمكننا البناء عليها لأمور أكثر تقدّما: use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateWidgetsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('widgets', function (Blueprint $table) { $table->increments('id'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('widgets'); } } ينشئ Laravel تلقائيا حقل المعرّف في قاعدة البيانات id ويجعله يتقدّم تلقائيا فور إدراج تسجيلة جديدة في الجدول (autoincrement) وذلك باستخدام الدّالة increments. يضيف Laravel كذلك ختمين زمنيّين لتاريخَيْ إنشاء التسجيلة وتحديثها timestamps. سنضيف عمودا Column جديدا إلى قاعدة البيانات؛ لذا نضيف التعليمة التالية إلى دالّة up ضمن ملفّ التهجير: $table->string('widget_name')->unique(); يضيف السّطر أعلاه عمودا جديدا للجدول باسم widget_name من نوع string ويقيّده بـunique لكي لا توجد تسجيلتان في الجدول بنفس الاسم. تصبح دالّة up في ملف التهجير بعد إضافة العمود على النحو التالي: public function up() { Schema::create('widgets', function (Blueprint $table) { $table->increments('id'); $table->string('widget_name')->unique(); $table->timestamps(); }); } ثم ننفّذ التهجير: php artisan migrate ستلاحظ بعد تنفيذ الأمر إنشاءَ جدول جديد في قاعدة البيانات لديك. بما أننا نخطّط لإدراج تسجيلات إلى قاعدة البيانات بالتطبيق فيجب أن نضيف الخاصيّة التالية إلى النموذج Widget: /** * The attributes that are mass assignable. * * @var array */ protected $fillable = ['widget_name']; تخبر هذه التعليمة Laravel أن العمود widget_name يدعم الإسناد الشّامل Mass assignment (تحديد قيم معطياتٍ عدّةٍ مرة واحدة). إن لم نضف هذه التعليمة فلن يمكننا باستخدام التطبيق إدراجُ تسجيلات جديدة في الجدول. سنستخدم في الدرس التالي النموذج الذي أنشأناه أعلاه مع معمل النماذج Model factory في Laravel لملْء تسجيلات في جدول widgets. ترجمة -وبتصرّف- للمقال How to Make a Model in Laravel 5.1 لصاحبه Bill Keck.
  4. أساسيات angularjs

    أقدّم بين أيديكم هذه السلسلة التي استلهمت فكرتها من كتب برمجة صغيرة مجّانيّة ومحبّبة، مثل كتاب The Little Book on CoffeeScript لمؤلّفه Alex MacCaw. لقد ألّفت هذه السلسلة لتعليم Angular بالطّريقة التي تمنّيت أن أتعلمها بها، ولذلك فهذه السلسلة معينك للانطلاق السريع مع Angular واستخدام هذه المكتبة الرائعة في عملك كمطوّر ويب. أسلوب هذه السلسلة مستلهم من مبدأ باريتو Pareto فهي تعلّمك جزءًا كبيرًا من نقاط قوّة Angular دون أن تثقل كاهلك بالكثير من تعقيداتها، وستتمكّن بعد إنهائك لهذه السلسلة من كتابة تطبيقات واجهة front-end قويّة، وستدهشك سهولة ذلك، بالرّغم من أنّ السلسلة لا تقدّم إلا جزءًا محدودًا ممّا عليك تعلّمه لاحتراف Angular بشكل كامل، لكنها ستمنحك الثّقة الكافية للقيام بذلك لأنّ خبرتك ستكون مبنيّة على التّجربة العمليّة أثناء قراءتك لدروسها، فهي بحدّ ذاتها صفحات ويب ديناميكيّة تحوي آخر نسخة من Angular وتستخدمها لتنفيذ جميع الأمثلة بشكل مباشر، وجميع الشّيفرات البرمجيّة تتيح التّعديل المباشر عليها ممّا يغيّر المخرجات مباشرة، وأتمنّى لو تقوم بكلّ التّجارب والتّعديلات التي تخطر على بالك عند كل مثال. إذا كنت ترغب في معرفة سبب كتابتي لهذه السلسلة يمكنك قراءة هذه المقدّمة إلى نهايتها فهي تتضمّن بعضًا من ذكرياتي مع Angular، ثم سنناقش أفضليّة استخدام Angular في مشاريعك. هل هي صعبة أم سهلة؟لقد عملت من قبل على تطبيقات معتمدة على Web MVC لما يزيد عن عشر سنوات، واستعملت الكثير من الأدوات بدءًا من Struts وانتهاءً بـSpring MVC مرورًا بـRuby on Rails وBackbone، حتّى أنّني قمت بكتابة كتاب Backbone and CoffeeScript لذا كان من الطّبيعي بالنّسبة لي أن أفترض أنّ تعلّم ِAngular سيكون بسيطًا بالنسبة لي، إلّا أنّ تقدّمي في تعلّمها واجه سدًّا كبيرًا من المصطلحات غير المألوفة بعد غوصي في توثيق هذه المكتبة، مصطلحاتٌ مثل transclusion، توجيه directive والمجال المعزول isolate scope، وكلّما قرأت أكثر في التّوثيق الرّسمي للّغة ودروسها تأكّدت أكثر بأنّني كنت أتوهّم عندما ظننت بأنّ Angular أداةٌ سهلة، وأتذكّر بشكل خاصّ مروري على العبارة التّالية: لن تجد العبارة السابقة هذه الأيام داخل توثيق اللّغة، والشّكر يعود للجهود الجادّة التي بذلها فريق ِAngluar لتحسين التّوثيق، وعلى أيّ حال فالاقتباس السّابق جعلني أشعر بالجهل وبدأت الشّكوك تراودني والقلق يساورني: هل هذه المكتبة مجال جديد كلّيّا عليّ؟ كانت الإجابة تأتيني من كلّ الجهات تقريبًا: إنّ ِAngular تقنيّة معقدّة، ولا مجال للعبث معها، ففي ملتقيات المبرمجين على Stack Overflow ومجموعة AngularJS على Google وفي كلّ مكان آخر، كانت تفاصيل هذه المكتبة محلّ النّقاشات المطوّلة، مع توثيقات مرعبة للمشاكل والأفخاخ والحيل فيها، فشمّرت عن ساعد الجد كأي محترف يحترم نفسه وقبلت هذا التّحدّي، ومع مرور الوقت أصبحت أكثر ألفة مع هذه المفاهيم والمصطلحات، وتقبّلت أنّ تعلّمي هذه الأداة سيكون بطيئًا، إلى أن جاء ذلك اليوم الذي شاهدت فيه مقابلة مع Miško Hevery مخترع Angular، وبعد ذلك اكتشفت حقيقة بسيطةً إلّا أنّها كانت شديدة الأهمّيّة: الهدف الأصليّ من Angular هو سهولة الاستخدام. لقد بيّن Hevery بأنّه أراد أن تكون Angular أداة ليستخدمها غير المبرمجين، ليتمكّنوا من بناء صفحات ويب ديناميكيّة باستخدامهم لنصوص تصريحية بسيطة، لقد اكتشفت بأنّني قد تعمّقت في الكثير من تفاصيل Angular دون أن أجني منها فائدة مكافئة للوقت والجهد المبذول، ورغم أنّ مشروع Angular ومجتمع Angular أصبحا معتمدين على بعضهما بشكل وثيق حيث تقدّم المكتبة التّحديات والتّعقيدات التي تشبع شغف هؤلاء، إلّا أنّه كان هناك طريق أفضل لاستخدام المكتبة كما أراد مخترعها، بعيدا عن مبدأ عملها المصنوع بعناية، وقد كان الصّواب بالنسبة إليّ الابتعاد عن هذه الأمور الدّاخليّة الدّقيقة وتركها آمنة لتقود كلّ شيء دون المساس بها، وبعد أن اعتمدت هذا المبدأ في التعامل معها وبالرّغم من وجود العديد من الأدوات الأخرى إلّا أنّ شمس Angular صارت تشرق لي عند مواجهة العديد من الحالات. هل تناسبك؟تعتمد إجابة هذا السّؤال على معرفتك لمشروعك بدقّة، فعليك معرفة فيما إن كان يحتاج بالفعل لمعالجة البيانات وإخراج HTML في طرف الزّبون، أم أنّك تخدع نفسك ببعض المتطلّبات الإضافيّة لتعطيها دافعًا لتعلّم أداة جميلة وجذّابة، فقد لا تلزمك Angular إن كان بإمكانك الاعتماد على بعض المعالجة من طرف الخادوم مع "رشّةٍ" من التّفاعل المعتمد على jQuery. ضع في حسابك أنّ Angular واسعة وتدعو للتشبّث بها، فبالرّغم من أنّنا ندعوها "مكتبة" إلا أنّ دعمها الذّاتي للـوحدات modules ولـحقن التّبعيّة dependency injection سيفرض على المطوّر طريقة إدارة مشروعه، وقد يُفضّل حلًّا آخر على Angular، ربّما سيختار أداة أقدم منها ومتميزةً بكونها الأفضل في وقتها، لكنّه قد يجد أنّه من الصّعب أو المستحيل أن تحلّ محلّ Angular، أضف إلى ذلك أنّك لن تحتاج إلى الدّعم الفنّي من فريق تطوير Angular إن لم تكن تنوي أن يصبح مشروعك كبيرًا بالقدر الّذي يعتبره مهندسو Google مثاليًّا. هناك مشكلة أخرى تظهر عندما تحاول دمج شيفرات Angular مع شيفرات غير Angular وتريدها أن تعمل إلى جانب تغليف Angular للبيانات أو آلية إخراج الصفحة فيها، سيكون عليك عندها الغوص في تفاصيل غامضة في Angular غوصًا عميقا، قارن ذلك مع Backbone التي تعد طبقة رقيقة فوق jQuery فهي أصغر وأقرب للفهم، وإن كان تطبيقك معتمدًا بشكل كبير على ملحقات jQuery فسيكون عليك استخدام Backbone لتزيد من التّحسين في تصميم تطبيقك. أخيرًا، إنّ لطريقة Angular الأساسيّة للرّبط ثنائي الاتجاه بين عناصر واجهة المستخدم وكائنات النمذجة حدودًا تعتمد على مدى تعقيد التّطبيق، وقد تشارك المطوّرون في Facebook خيبة أملهم بربط البيانات ثنائيّ الاتجاه فقالوا: وبالرّغم من كون مكتبة React الخاصة بـFacebook بالكاد تهتمّ بالإخراج ومن ثمّ فهي تعدّ حلّا جزئيًّا بالمقارنة مع Angular، إلّا أنّ تطبيقات طرف الزّبون التي تعتمد عليها تستحقّ التقدير حقًّا. أسباب هامة تدفعك لاستخدام Angularلا شك أنّ Angular هي أشهر مكتبات JavaScript المختصّة بحلول النّمذجة والعرض عالميًّا في هذه الأيام، فقد حصلت على أكثر من 33000 نجمة على GitHub، وربّما ازدادت أكثر من ذلك بكثير منذ وقت كتابة هذه السلسلة إلى اليوم، فقد تربّعت على قمّة قائمة الحلول المطروحة التي تمّت دراستها ومقارنتها بواسطة مشروع TodoMVC وسنناقش الآن بعض أسباب نجاح Angular. الإنتاجية الآنيةإذا كان مشروعك بحاجة إلى واجهة مستخدم معقّدة إلى حدّ ما لتقوم بعمليات إدارة البيانات CRUD على البيانات من طرف الزّبون، فإنّ Angular ستفي بوعدها لك بتحقيق إنتاجيّة شبه آنيّة، فبإضافتك لرشّةٍ من بعض الخصائص المميّزة غلى نصّ HTML الأصلي، والقليل من شيفرات Javascript، ستتمكّن من جعل صفحتك تتفاعل مع المستخدم، في حين كنت ستحتاج إلى الكثير من المهارات وبذل الجهود لتقوم بذلك باستخدام مكتبة أدنى مستوى. الألفةتعتمد Angular على كتابة شيفرات JavaScript السّهلة ونصوص مطابقة تقريبًا لتعليمات HTML، لقد قلت "تقريبًا" لأنّ Angular تقدّم عناصر وخصائص جديدة وبعض الشيفرات المستغربة، إلّا أنها بالمقارنة مع أنظمة القوالب الأخرى تبقى قريبةً جدًّا إلى HTML النّقيّة، وهذا يجعلها سهلة الفهم لأغلبية مطوري الويب. المرونةتتبنّى Angular التّوجّه الحالي نحو التكيف مع واجهات المستخدم في أطر عمل JavaScript، دون الكثير من التّضحية بإنتاجيّتها، فإن كنت تحبّ العمل مع أحد أطر العمل الشهيرة المختصة بواجهة المستخدم مثل Bootstrap فستتمكّن من الاستفادة من الإضافة المقدّمة من مشاريع طرف ثالث مثل AngularUI لتقوم بتكامل سهل. لذا سواء كنت تريد زخرفة صفحة ويب تقليديّة ببعض التّطبيقات التفاعلية هنا وهناك، أو كنت تريد تطوير تطبيقٍ كاملٍ وحيد الصّفحة فإن Angular ستكون الأفضل للعمل ضمن شروطك ومحدداتك. المعايير المستقبليةلا أدري أيّهما أكثر صحّة، إن كانت Angular متبصّرة بالمستقبل أو أنّ Google والدةَ Angular ستصنع المستقبل، إلا أنّه من الواضح أنّ استخدامك لـAngular سيكون طريقة ناجحة لتألف المعايير المقترحة مثل Web Components وأضف إلى ذلك أنّني أتوقّع بقاء Angular واستمرارها لأنّها تواكب ميزات JavaScript المرتقبة مثل Object.observe. مجتمع Angularلابدّ أنّ أحد أقوى الأسباب لاختيار Angular بدلًا من منافساتها هو أنّها الأكثر شيوعًا، فهي تُستخدم الآن في عدد غير محدود من مواقع الويب كثيرة الزيارة، ولكن تذكّر بأنّ الجري وراء الأغلبية ليس الصّواب دومًا وليس لكلّ النّاس ولا في كلّ الأحيان، وعليك أن تدرس متطلّبات مشروعك الحقيقيّة بعناية. عن هذه السلسلةلقد جاءتني فكرة الكتب التفاعلية منذ عدّة سنوات أثناء قراءتي لكتاب إلكترونيّ عن البرمجة باستخدام JavaScript على حاسوبي المحمول، فقد توجّب عليّ لتجربة أحد أمثلة الكتاب أن أقوم بتحميله من موقع النّاشر، ثم البحث عن موضع الملفّ الذي تم تحميله وإيجاد مكان لفكّ ضغطه، ثم الإبحار عبر الكثير من الملفّات إلى أن أعثر على الشّيفرة المطلوبة، وأفتحها أخيرًا في أحد المحرّرات، ثمّ أكتشف بأنّ عليّ إنشاء ملف HTML ليُشغّل السكربت، وبعد كلّ هذا لا تعمل الشيفرة وأكون قد ضيّعت وقتي في مطاردة أماكن الملفّات والارتباطات. لم كلّ هذا؟ إن كنت أقرأ كتابًا عن تقنية front-end على الحاسوب فهل عليّ أن أعاني كلّ تلك المعاناة لأشغّل المثال؟ لقد اكتشفت بعد مدّة قصيرة من ذلك النّسخةَ الأولى لكتاب Marijn Haverbeke المسمّى Eloquent JavaScript واكتشفت بأنّه بإمكاني استخدام مشروعه CodeMirror لأنشر رؤيتي الخاصّة: كتاب إلكترونيّ رائع المظهر، أنيق الحروف وجميل التّصميم، ولكن مع أمثلة حية قابلة للتّعديل والتّشغيل مباشرة من الدّرس ذاته، ولهذا ستجد جميع أمثلة السلسلة داخل محرّرات حيّة تفاعليّة، وستجد مخرجات هذه الشيفرات مباشرة تحت المثال داخل صندوق iframe. <div ng-app=""> <strong>The lucky number {{11+12}}</strong> </div> See the Pen angular-intro by Hsoub Academy (@HsoubAcademy) on CodePen. هيّا حاول تغيير المثال أعلاه الآن، رغم أنك لم تتعلم شيئًا بعد عن Angular، قم ببعض التغييرات على المثال وراقب التّغييرات. ماذا بعد؟سيأخذك الفصل الأوّل من هذه السلسلة في رحلة لطيفة للتّعرف على مبادئ Angular في القولبة templating من طرف الزّبون وفي الرّبط ثنائيّ الاتّجاه، وقد أقرّ العديد من المطوّرين المحترفين في ِAngular بأنهم استفادوا من هذا الفصل رغم أنّ جميع أمثلته بسيطة ويمكن فهمها بلمحة سريعة. ترجمة وبتصرّف للجزء الأول من كتاب: Angular Basics لصاحبه: Chris Smith.
  5. أنشأنا في الدرس السابق مسارات تكتفي بكتابة عبارات في صفحة الويب. سننشئ في هذا الدرس عروضا لتقديمها إلى الزوار حسب الرابط الذي يختارونه؛ نستخدم لهذا الغرض قوالب Blade. هذا الدرس جزء من سلسلة تعلم Laravel والتي تنتهج مبدأ "أفضل وسيلة للتعلم هي الممارسة"، حيث ستكون ممارستنا عبارة عن إنشاء تطبيق ويب للتسوق مع ميزة سلة المشتريات. يتكون فهرس السلسلة من التالي: مدخل إلى Laravel 5.تثبيت Laravel وإعداده على كلّ من Windows وUbuntu.أساسيات بناء تطبيق باستخدام Laravel.إنشاء روابط محسنة لمحركات البحث (SEO) في إطار عمل Laravel.نظام Blade للقوالب. (هذا الدرس)تهجير قواعد البيانات في Laravel.استخدام Eloquent ORM لإدخال البيانات في قاعدة البيانات، تحديثها أو حذفها.إنشاء سلة مشتريات في Laravel.الاستيثاق في Laravel.إنشاء واجهة لبرمجة التطبيقات API في Laravel.إنشاء مدوّنة باستخدام Laravel.استخدام AngularJS واجهةً أمامية Front end لتطبيق Laravel.الدوّال المساعدة المخصّصة في Laravel.استخدام مكتبة Faker في تطبيق Laravel لتوليد بيانات وهمية قصدَ الاختبار. تعرِّف القوالب Templates إطارا عامًّا للعرض، يحدّد أجزاءه والعناصر التي تكوّنه. Blade هو نظام إدارة القوالب والتعامل معها المضمَّن في Laravel. نحصُل بنهاية هذا الدرس على الواجهة التالية. يشمل الدرس المواضيع التالية: توريث القالب.المخطّط الرئيس Master layout.تمديد المخطّط الرئيس.عرض المتغيرات.التعبيرات الشرطية Conditional statements في Blade.الحلقات التكراراية Loops في Blade.تنفيذ تعليمات PHP في Blade,تنتهي جميع ملفات العروض في Blade بالامتداد blade.php. توريث القوالبيمكن تعريف توريث القوالب بأنه تلك الخاصيّة التي تسمح بجمع عناصر مشتركة بين عدة عروض ضمن عرض تعيد استخدامه عند الحاجة مع إضافة العناصر الخاصة بالصفحة؛ مما يجنب تكرار العناصر المشتركة في كلّ مرة. المخطط الرئيستُجمع العناصر المشتركة في عرض يُطلَق عليه المخطّط الرئيس تعيد العروض الأخرى استخدامه وتضيف إليه العناصر الخاصة بها. سننشئ في ما يلي مخطّطا رئيسا نضمنه عناصر مشتركة بين العروض.ننشئ مجلدا جديدا باسم layouts على المسار resources/views/. ثم ننشئ ملفا باسم master.blade.php ضمن المجلد layouts.نضيف الشفرة التالية إلى الملف master.blade.php:<html> <head> <title>@yield('title')</title> </head> <body dir="rtl"> @section('sidebar') هنا يوجد محتوى المقطع sidebar في المخطط الرئيس. @show <div class="container"> @yield('content') </div> </body> </html>قالب Blade عبارة عن وسوم HTML مع تعليمات خاصة بنظام القوالب. يستخدم القالب أعلاه ثلاث تعليمات هي section ،@yield@ و show@. تُستخدم التعليمة section@ لتعريف مقطع (عنصر) من القالب.بينما تستخدم التعليمة yield@ لعرض محتوى مقطع معطى (مقطع باسم title في أول استخدام للتعليمة yield@ في المخطّط السابق).أما التعليمة show@ فتستخدم لعرض محتوى مقطع.تمديد المخطط الرئيسننشئ الآن قالبا يمدّد القالب الرئيس السابق. أنشئ ملفا باسم page.blade.php في المسار resources/views وأضف إليه الشفرة التالية: @extends('layouts.master') @section('title', 'عنوان الصفحة') @section('sidebar') @parent <p>هذا المحتوى ملحق بمحتوى المقطع sidebar الموجود في المخطط الرئيس</p> @endsection @section('content') <p>جسم الصفحة.</p> @endsectionتشير التعليمة ('extends('layouts.master إلى أننا في صدد تمديد المخطّط الرئيس master.blade.php الموجود ضمن المجلد layouts.تعيّن التعليمة ('section('title', 'Page Title قيمة المقطع title المعرّف في المخطّط الرئيس. ثم نعرّف مقطع جديدا باسم sidebar ضمن العرض page. داخل المقطع sidebar نطبع محتوى المقطع الذي يحمل نفس الاسم في المخطّط الرئيس باستخدام التعليمة parent@، نضيف فقرة HTML باستخدام الوسم <p>...</p> ثم ننهي المقطع sidebar بالتعليمة endsection@.تعرّف التعليمة ('section('content محتوى المقطع content وهو في هذا المثال الفقرة <p>جسم الصفحة.</p>.في المخطط الرئيس توجد ثلاثة مقاطع وهي، حسب ترتيب الاستخدام، sidebar ،title و content. بالنسبة للمقطعين title و content فقد اكتفينا بتحديد أماكنهما (التعليمة yield@)؛ أما المقطع sidebar فقد عرفنا محتواه وعرضناه (التعليمتان section@ و show@). في القالب page أعدنا استخدام المخطّط الرئيس ثم أعطينا قيمتي المقطعين title و content المعرّفين سابقا. بالنسبة للمقطع sidebar فقد أعدنا تعريفه مع إعادة استخدام محتوى المقطع المماثل له في الاسم ضمن القالب الرئيس (تعليمة parent@) وإضافة فقرة نصية أخرى. سنضيف مسارا خاصًّا لتجربة عمل نظام القوالب. افتح ملف المسارات routes.php وأضف المسار التالي: Route::get('blade', function () { return view('page'); });احفظ التعديلات. الآن أدخل الرابط في المتصفح: http://larashop.dev/bladeستحصل على الصفحة التالية: استخدام متغيرات في قوالب bladeنعرّف متغيرا باسم name ونمرره إلى قالب blade. افتح ملف المسارات وغيره بحيث يصبح على النحو التالي: Route::get('blade', function () { return view('page',array('name' => 'حسوب')); });احفظ التعديلات. نحدّث القالب page.blade.php لإظهار المتغير الذي يمرره المسار: @extends('layouts.master') @section('title', 'عنوان الصفحة') @section('sidebar') @parent <p>هذا المحتوى ملحق بمحتوى المقطع sidebar الموجود في المخطط الرئيس</p> @endsection @section('content') <h2>{{$name}}</h2> <p>جسم الصفحة</p> @endsectionتستخدم التعليمة {{name$}} لطباعة قيمة المتغير name$. احفظ التعديلات ثم أعد تحميل الصفحة http://larashop.dev/blade. ستلاحظ وجود عنوان h2 جديد هو حسوب التي هي قيمة المتغير الممرًّر لقالب page.blade.php. التعبيرات الشرطية في Bladeيدعم نظام Blade التعبيرات الشرطية التي تحدّد ما يُعرض حسب شرط معرَّف مسبقا. سنمرر متغيرا إلى القالب ثم نختبر قيمته (الشرط) وحسب نتيجة الاختبار يكون العرض. افتح ملف routes.php وعدل المسار بحيث يصبح ما يلي: Route::get('blade', function () { return view('page',array('name' => 'حسوب','day' => 'Friday')); });أضفنا هنا متغيرا جديد باسم day وأعطيناه القيمة Friday. احفظ التعديلات. افتح ملف القالب وعدله على النحو التالي: @extends('layouts.master') @section('title', 'عنوان الصفحة') @section('sidebar') @parent <p>هذا المحتوى ملحق بمحتوى المقطع sidebar الموجود في المخطط الرئيس</p> @endsection @section('content') <h2>{{$name}}</h2> <p>جسم الصفحة</p> <h2>تعبير if الشرطي</h2> @if ($day == 'Friday') <p>إنه يوم الجمعة</p> @else <p>اليوم ليس يوم الجمعة</p> @endif @endsectionإذا كانت قيمة المتغير day هي Friday نعرض الجملة <p>إنه يوم الجمعة</p> وإلا فإن الفقرة المعروضة تصبح <p>اليوم ليس يوم الجمعة</p>. احفظ التعديلات ثم أعد تنزيل الصفحة ولاحظ الفرق. الحلقات التكرارية في Bladeيدعم Blade كل الحلقات التكرارية التي يدعمها PHP. سنرى مثالا لاستخدام الحلقة التكرارية foreach لعرض محتويات مصفوفة Array في قالب Blade. عدل ملف المسارات routes.php على النحو التالي: Route::get('blade', function () { $foods = array('Barbecue','Couscous','Fish'); return view('page',array('name' => 'حسوب', 'day' => 'Friday', 'foods' => $foods)); });عرّفنا مصفوفة تحوي ثلاثة عناصر ومررناها إلى قالب Blade. احفظ التعديلات ثم افتح ملف القالب وعدّله على النحو التالي: @extends('layouts.master') @section('title', 'عنوان الصفحة') @section('sidebar') @parent <p>هذا المحتوى ملحق بمحتوى المقطع sidebar الموجود في المخطط الرئيس</p> @endsection @section('content') <h2>{{$name}}</h2> <p>جسم الصفحة</p> <h2>تعبير if الشرطي</h2> @if ($day == 'Friday') <p>إنه يوم الجمعة</p> @else <p>اليوم ليس يوم الجمعة</p> @endif <h2>حلقة foreach التكرارية</h2> @foreach ($foods as $food) {{$food}} <br> @endforeach @endsectionاحفظ التعديلات ثم أعد تحميل الصفحة ولاحظ طباعة محتوى المصفوفة. تضمين شفرة PHP في قالب Bladeافتح ملف القالب وعدّله بإضافة سطر يستخدم إحدى دوالّ PHP (اخترنا الدالة date). يصبح ملف القالب كما يلي: @extends('layouts.master') @section('title', 'عنوان الصفحة') @section('sidebar') @parent <p>هذا المحتوى ملحق بمحتوى المقطع sidebar الموجود في المخطط الرئيس</p> @endsection @section('content') <h2>{{$name}}</h2> <p>جسم الصفحة</p> <h2>تعبير if الشرطي</h2> @if ($day == 'Friday') <p>إنه يوم الجمعة</p> @else <p>اليوم ليس يوم الجمعة</p> @endif <h2>حلقة Loop التكرارية</h2> @foreach ($foods as $food) {{$food}} <br> @endforeach <h2>شفرة PHP</h2> <p>تاريخ اليوم {{date(' D M, Y')}}</p> @endsectionوضعنا دالة PHP داخل معكوفين مزدوجين لتنفيذها. أعد تنزيل الصفحة http://laravel.dev/blade بعد حفظ التعديلات. العروض المكونة لمشروع Larashopذكرنا في بداية السلسلة أننا نهدف إلى إنشاء موقع للتسوق الإلكتروني. سنستخدم ما تعلمناه في هذا الدرس والدروس السابقة لبناء اللبنة الأولى من هذا المشروع وهي الجانب المرئي. لإعطاء وجه لائق لمشروعنا بحثنا عن تصميم HTML جاهز ووجدنا أن قالب Eshopper من موقع shapebootstrap.net مناسب لما نريد. الخطوة التالية للحصول على تصميم HTML هي تحويله إلى قالب Blade يعمل مع Laravel. سنبدأ أولا بمحتوى الملف المرفق وكيفية استخدامه للحصول على واجهة الموقع المعروضة في أول الدرس، ثم نشرح بعد ذلك تعليمات Blade التي لم نتطرق إليها حتى الآن. محتوى الملف المرفقيحوي الملف المرفق: عروض المشروع larashop.ملف المتحكم Front الذي حدثناه ليحمّل عروض المشروع.ملف المسارات.الموارد المستخدمة في القالب: ملفات CSS، الصور، ملفات Js والخطوط.العروضيحوي المشروع العروض التالية: layout: وهو المخطط الرئيس ويوجد في المجلد الفرعي layouts.sidebar: وهو عرض مشترك بين صفحاتٍ عدة، يوجد في مجلد فرعي باسم shared.blog: صفحة المدونة.blog_post: صفحة منشور على المدونة.cart: صفحة سلة المشتريات.checkout: صفحة الدفع.contact_us: صفحة الاتصال.home: الصفحة الرئيسية.login: صفحة تسجيل الدخول.products: صفحة المنتجات.product_details: تفاصيل منتج.يجب أن توضع العروض في المجلد resources/views. تبدو بنية هذا المجلد كالتالي بعد إضافة العروض إليها. المتحكم Front وملف المساراتأنشأنا في الدرس السابق متحكم Front لكنه يكتفي بعرض نص في المتصفح. سنحتاج لتعديله ليحمِّل العروض. عدّلنا قليلا على ملف المسارات routes.php لتعريف مسار لكل تصنيف أو علامة تجارية. مجلد publicيحوي الموارد (صور، css، js) التي تحتاجها واجهة الموقع للعمل. يجب وضع هذه الموارد في مجلد public في المشروع. ملحوظة: تأكد بعد نقل الملفات من المرفق إلى أماكنها في المشروع من أن الأذون ما زالت على الحال التي ضبطناها بها في درس الإعداد (لينكس). الآن وبعد التأكد من نقل الملفات من المرفق إلى أماكنها الصحيحة، اذهب إلى الصفحة الرئيسية http://larashop.dev وستظهر واجهة الموقع. نأخذ وقتا لشرح المشروع. تحويل صفحات HTML إلى قالب Bladeقوالب Blade هي، كما رأينا، وسوم HTML مع تعليمات خاصّة بنظام القوالب؛ لذا نحافظ على البنية العاملة لملفات HTML المكوِّنة للموقع مع إجراء تغييرين أساسيين: جمع العناصر المشتركة بين مختلف الصفحات ضمن صفحة خاصة.إبدال الروابط في صفحة HTML بتعليمات Blade.يُترجَم تحويل صفحات HTML إلى قوالب Blade بالخطوات التالية: إنشاء مخطّط رئيس تُمدده جميع الصفحات. يحوي المخطط الرئيس العناصر المشتركة بين الصفحات.إنشاء صفحة (عرض) لكل مسار من المسارات المعرَّفة في الدرس السابق.تحديث المتحكم Front.php لتحميل العروض.إضافة الموارد (الصور، ملفات css وjs) إلى مجلد public في تطبيق Laravel.يحوي الملف المرفق بهذا المقال عروض Blade الناتجة عن تحويل صفحات HTML إلى قوالب Blade، إضافة إلى ملف المسارات الخاص بمشروع Larahop، المتحكم Front.php والموارد مثل الصور وملفات css (مجلد public). المخطط الرئيسأنشأنا ملفا لمخطط رئيس باسم layout.blade.php على المسار resources/views/layouts. في هذا الملف توجد وسوم HTML مع تعليمات Blade؛ بعضها لم نتطرق له بعد: تعليمة {{url}}:{{url('products')}}تنشئ التعليمة {{url}} رابط URL بالنسبة للمجلدpublic. في المثال أعلاه فإن الرابط الذي ترجعه التعليمة هو http://larashop.dev/products؛ وهو الرابط الذي تتعامل معه دالة المسار products/. لإنشاء رابط إلى الصفحة الرئيسية فالتعليمة تكون: {{url('')}}نأخذ أيضا المثال التالي الموجود في المخطط الرئيس: <li><a href="{{url('products')}}" {{$page == 'products' ? 'class=active' : ''}}>Products</a></li>نلاحظ استخدام التعليمة url لإعطاء قيمة الرابط ضمن وسم <a>. في نفس السطر توجد تعليمة تشبه تعليمةً مألوفة في PHP وهي {{$page == 'products' ? 'class=active' : ''}}هنا نتحقق من قيمة المتغير page فإذا كانت تساوي products نضيف صنف CSS يسمّى active إلى الوسم. تعليمة {{asset}}:{{asset('css/bootstrap.min.css')}}تُرجع الدالة asset مسار مجلد public (أي عنوان الموقع) وتلحق به المعطى الممرَّر إليها. في السطر أعلاه ترجِع الدالةُ القيمةَ http://larashop.dev/css/bootstrap.min.css. تُستخدم هذه الدالة كثيرا لإضافة ملفات CSS، الصور وملفات JavaScript كما في الأمثلة التالية المأخدوذة من المخطط الرئيس. <!-- CSS --> <link href="{{asset('css/bootstrap.min.css')}}" rel="stylesheet"> <!-- صورة --> <img src="{{asset('images/home/iframe1.png')}}" alt="" /> <!-- JavaScript --> <script src="{{asset('js/jquery.js')}}"></script>يمكن من خلال المعطيات الممرَّرة إلى الدالة asset في الأمثلة أعلاه اسنتاجُ أننا نستخدم مجلدًّا فرعيا في public لكل نوع من الموارد (CSS، الصور، JS إضافة للخطوط fonts). إن نظرت جيدا في ملف المخطط الرئيس فستميز ثلاثة أجزاء فارقة: الجزء الأول ويحوي الوسوم المؤسِّسة للجزء الأعلى المشترك بين مختلف صفحات الموقع، ويحوي ترويسة الموقع وقائمته الرئيسية.الجزء الثاني تمثله التعليمة ('yield('content@ وتلعب دور ماسك مكان Place holder. ستحدّد العروض الأخرى الممدّدة للمخطط الرئيس محتوى ماسك المكان.الجزء الثالث وبه التذييل المشترك بين صفحات الموقع.إن فهمت جيدا آلية عمل نظام القواعد فستعرف أن الجزأين الأول والثالث لا يتغيران بتغير الصفحة التي يطلبها الزائر. ما يتغير هو فقط الجزء الثاني الذي يعبئه نظام القوالب بمحتوى مختلف حسب الصفحة. الصفحات المشتقةننتقل الآن للعروض الخاصة بكل صفحة. يمدّد كل عرض المخطّط الرئيس. في ما يلي المنحى العام للعروض: @extends('layouts.layout') @section('content') <!--وسوم HTML --> @include('shared.sidebar') <!--وسوم HTML --> @endsectionيمدد العرض المخطط الرئيس بتنفيذ التعليمة التالية:@extends('layouts.layout')يعرّف مقطعا باسم content:@section('content')يُحمَّل محتوى المقطع content في المكان المعرّف بنفس الاسم في المخطّط الرئيس. ينتهي المقطع عند التعليمة endsection@. نضمِّن محتوى العرض sidebar الموجود في المجلد resources/views/shared:@include('shared.sidebar')تستخدم التعليمة include لتحميل محتوى عرض ضمن آخر. عرض sidebar الذي يمثل شريطا جانبيا للموقع موجود في أغلب الصفحات. نضيف وسوم HTML المأخوذة من قالب E-Shopper لتكوين الصفحة.تحديث المتحكم Frontنحدّث المتحكم Front.php ليحمل العروض بدلا من الاكتفاء بطباعة نص في الصفحة. يصبح محتوى المتحكم بعد التحديث على النحو التالي. تحمل كل دالّة العرض الموافق لها حسب جدول الدرس السابق. <?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; class Front extends Controller { public function index() { return view('home', array('page' => 'home')); } public function products() { return view('products', array('page' => 'products')); } public function product_details($id) { return view('product_details', array('page' => 'products')); } public function product_categories($name) { return view('products', array('page' => 'products')); } public function product_brands($name, $category = null) { return view('products', array('page' => 'products')); } public function blog() { return view('blog', array('page' => 'blog')); } public function blog_post($id) { return view('blog_post', array('page' => 'blog')); } public function contact_us() { return view('contact_us', array('page' => 'contact_us')); } public function login() { return view('login', array('page' => 'home')); } public function logout() { return view('login', array('page' => 'home')); } public function cart() { return view('cart', array('page' => 'home')); } public function checkout() { return view('checkout', array('page' => 'home')); } public function search($query) { return view('products', array('page' => 'products')); } } جرب تصفح الموقع والتنقل بين صفحاته. إذا اتبعت خطوات الدرس على النحو المشروع فستكون قادرا على التنقل بين صفحات الموقع دون مشاكل. يمكنك أيضا فتح الشفرة المصدرية لصفحات موقع الويب ومقارنتها بما كتبناه في قوالب Blade. خاتمةنحصل بنهاية الدرس على تصميم أنيق لصفحات الموقع، استخدمنا لإنشائه Blade الذي يوفر نظاما فعّالا لكتابة قوالب العروض في Laravel مما يتيح تجنب تكرار العناصر المشتركة. بانتهاء هذا الدرس نكون قد أنهينا أساس جزء العرض من بنية MVC. الدروس التالية من السلسلة تتناول بقية الأجزاء. ترجمة -وبتصرّف- لمقال Laravel 5 Blade Template لصاحبه Rodrick Kazembe.
  6. بايثون (Python) لغة ممتازة لبرمجة الويب نظرا لمرونتها وأدائها العالي. أطُرُ الويب يمكن أن تجعل برمجة تطبيقات الويب أبسط بكثير لأنها توصل العديد من المكونات الضرورية مع بعضها للحصول على تطبيق قوي. في حين تهدف بعض أطر الويب إلى توفير كل شيء يمكن أن يرغب به المستخدم لتطوير تطبيق ما، هناك أطر أخرى تحاول البقاء بعيدا والاهتمام بالأهم، Bottle إطار للغة بايثون يندرج ضمن النوع الثاني. إنه بالفعل خفيف ومصغر، لكنه يجعل تطوير التطبيقات سهلا وسريعا. في هذا المقال، سنعرض طريقة ضبط واستعمال إطار العمل المصغّر Bottle لإنشاء تطبيقات ويب بسيطة وباستعمال لغة Python. كيفية تثبيت Bottleتثبيت Pythonإطار Bottle مبني على لغة Python وهي مثبتة مسبقا على أنظمة لينكس وOS X، أما بالنسبة لنظام Windows فيمكن تنصيب Python 2 عبر تحميلها من موقعها الرسمي. الجدير بالذّكر أن هذا الدّرس خاصّ بالإصدار الثاني من بايثون (Python 2.x). تثبيت وتفعيل بيئة وهميةسنثبت حزمة virtualenv لعزل مشروع بايثون الخاص بنا من بيئة بايثون الخاصة بالنظام. يمكننا فعل هذا بسهولة عبر تنصيب أداة إدارة الحزم الخاصة ببايثون واسمها pip. لتنصيب pip على Ubuntu يكفي تنصيب virtualenv مباشرة، فهي إحدى اعتمادياته: sudo apt-get update sudo apt-get install python-virtualenv بالنسبة لأنظمة OS X و Windows يمكن تنصيبه بتنصيب pip ثم تنصيب virtualenv عبرها: أو احفظ هذا الملف على جهازك، ثم نفذ الأمر التالي على نافذة الأوامر بالنسبة لـ Windows أو Terminal بالنسبة لـِ Mac OS X، في كلا النظامين، ستحتاج أن تنفذ الأمر التالي بصلاحيات المدير: python get-pip.pyبرنامج virtualenv عبارة عن بيئة وهمية لبايثون لتنصيب مكتبات بايثون في معزل عن بيئة بايثون الحقيقية على النظام، هذا مهم جدا لعزم اعتماديات مشروع الويب الخاص بك وما يحتاجه من حزم عن الحزم العامة المنصبة على كافة النظام، تحتوي بيئة مشاريع بايثون الخاصة بنا على حزمنا فقط، لكي لا تؤثر على نظام التشغيل ككل. سننشئ مجلد المشاريع projects في مجلد Home أو ماشابه، ثم نقوم بإنشاء بيئة وهمية في هذا المجلد، بالنسبة لـ Windows يمكن تنفيذ هذه الأوامر باستخدام طرفية PowerShell: mkdir ~/projects cd ~/projects virtualenv --no-site-packages venv هذا سينشئ مجلدا باسم venv داخل مجلد المشاريع. لقد تُبِّتت بعض أدوات بايثون داخل هذا المجلد وأنشِئَت بنية مجلد لتثبيت أدوات إضافية. يجب علينا تفعيل البيئة الوهمية قبل بداية العمل على مشروعنا : source venv/bin/activateالأمر المُخرَج سيتغير لعكس حقيقة أننا نقوم بعمليات داخل بيئة وهمية الآن. وسيكون كالتالي: (venv)user@Hostname:~/projects$إذا أردت الخروج من البيئة الوهمية، يمكنك في أي وقت كتابة الأمر التالي : deactivateملاحظة: لا تخرج من البيئة الوهمية حاليا. تثبيت Bottleأداة pip تُمكنك من تثبيت حزم بايثون بسهولة من دليل حزم بايثون Python package index، وهو مستودع مُفهرس لمكتبات بايثون. إذا أردنا البحث عن حزم بايثون المتعلقة بـِ Bottle، يمكن تنفيذ: pip search bottleسنبدأ بتثبيت حزمة Bottle فقط: pip install bottleبعد إنتهاء العملية، سنتمكن من استخدام إطار Bottle داخل تطبيقاتنا. إنشاء أول تطبيق باستخدام Bottleكمعظم الأطر، Bottle يطبق نسخة من النمط البرمجي MVC .MVC اختصار لـِ Model, view, controller نموذج،عرض،هيكل؛ وهو أمر للفصل بين عوامل مختلفة بين واجهة المستخدم والمنطق البرمجي. النموذج model تمثيل لمجموعة من البيانات وهو مسؤول عن تخزين، استعلام، وتحديث البيانات.العرض view مسؤول عن كيفية تقديم المعلومة للمستخدم. ويُستخدم لتشكيل وضبط عرض البيانات.الهيكل controller هو مركز العمليات الرئيسي للتطبيق، والذي يقرر كيفية الإجابة لطلبات المستخدم.تطبيقات bottle يمكنها أن تكون بسيطة للغاية. في شكلها البسيط يمكنها تنفيذ جميع المكونات في ملف واحد. سنقوم بإنشاء تطبيق "مرحبا بالعالم" لعرض كيفية العمل. باستعمال محررك المفضل (في هذه الحالة سنستعمل محرر سطر الأوامر nano، بالنسبة لنظام Windows يمكنك استعمال محرر مرئي)، أنشئ تطبيق بايثون باسم hello.py: nano hello.pyفي هذا الملف، سنقوم أولا باستدعاء بعض الوظائف من حزمة Bottle. الأمر الذي سيمكننا من استخدام أدوات الإطار داخل تطبيقنا: from bottle import route, runهذا السطر يخبر برنامجنا بأننا نحتاج إلى استيراد المسار route وتشغيل النماذج modules من حزمة Bottle. نموذج run الذي قمنا باستيراده يمكن أن يُستعمل لتشغيل التطبيق في خادوم التطوير، الشيء الذي يعتبر جيداً لرؤية نتائج برنامجك بسرعة. نموذج route مسؤول عن إخبار التطبيق بالتعامل مع أي من طلباتURL باستخدام أي من دوال بايثون.تطبيقات Bottle تنفّذ التوجيه routing باستدعاء دالّة بايثون واحدة لكلّ طلب من طلبات URL. وتقوم بعد ذلك بإرجاع نتائج الدالة للمُستخدم. نستطيع إضافة توجيه سيُوافق رابط URL /hello from bottle import route, run @route('/hello')هذا التوجيه سيوافق رابط URL /hello عندما يتمّ طلب هذا المسار على الخادوم. ستُنفّذ الدّالة التّابعة مباشرة: # -*- coding: utf-8 -*- from bottle import route, run @route('/hello') def hello(): return u"<h1>مرحباً بالعالم</h1>"ملاحظات: السطر # -*- coding: utf-8 -*- مسؤولٌ عن دعم اليونيكود وبالتالي اللغة العربية، فهو يخبر مفسر بايثون أن هذا الملف به أحرف unicode غير الأحرف الانجليزية.حرف u (اختصارًا لـ unicode) قبل النص العربي مهم أيضا لإخبار بايثون أن هذه السلسلة النصية بالضبط تحتوي على أحرف يونيكود وبالتالي يعامل السلسلة النصية بطريقة خاصة.هذه الدّالة بسيطة جدّاً، لكنّها كافية لإكمال المتطلّب الوحيد لدالّة توجيه: تقوم بإرجاع قيمة يُمكن عرضها على المتصفّح. في هذه الحالة، القيمة عبارة عن نص HTML. يمكننا حذف وسم h1 وستُعرض نفس القيمة بشكل غير منسّق. أخيراً، نحتاج إلى تشغيل تطبيقنا باستعمال خادوم التّطوير development server: # -*- coding: utf-8 -*- from bottle import route, run @route('/hello') def hello(): return u"<h1>مرحباً بالعالم</h1>" run(host='0.0.0.0', port=8080)هذا السطر سيُشغل الخادوم. بتمرير المعامل 'host='0.0.0.0 الأمر سيقوم بإرجاع المحتوى لأي حاسوب، وليس فقط الحاسوب المحليّ. هذا مهم بما أن تطبيقنا مستضاف عن بعد. معامل port يقوم بتحديد المنفذ الذي سنستخدمه. يُمكننا تشغيل التطبيق بتنفيذ الأمر: python hello.pyيمكنك زيارة التطبيق بمتصفح الويب عن طريق الذهاب إلى عنوان IP الخاصّ بك (إن كنت تعمل على خادوم) أو localhost إن كنت تعمل محليا، متبوعاً برقم المنفذ الذي قمنا باختياره (8080)، متبوعا بالتوجيه الذي أنشأناه (hello/): http://localhost:8080/helloسيظهر لك التالي: يُمكن إيقاف الخادوم في أي وقت بالضغط على CTRL-C في نافذة الطرفيّة أو سطر الأوامر. تطبيق مبدأ MVCلقد نفّذنا الآن تطبيقنا الأول. لقد كان بسيطاً بالتأكيد، ولكنّه لا ينفّذ مبادئ MVC، أو لا يقوم بشيء مثير للاهتمام. لنحاول جعله تطبيقاً أكثر تعقيداً هذه المرّة. إنشاء النموذجلنبدأ بنموذجنا، هذا هو الجزء الخاص بالتّعامل مع تخزين البيانات في برنامجنا. يمكن لـ Bottle بسهولة استخدام مجموعة من الواجهات الخلفية backends للبيانات باستعمال الإضافات. سنستخدم ملف SQLite لقاعدة بيانات التطبيق. هذه قاعدة بيانات بسيطة للغاية مُصمّمة للعمليّات الخفيفة التي يُمكن أن يقوم بها برنامجنا. ثبّت أولا SQLite، على Ubuntu يمكن ذلك عبر الأمر التالي: sudo apt-get install sqliteبالنسبة لـ Windows و OS X يمكن تثبيتها من على موقعها الرسمي. نحتاج كذلك إلى تحميل وتثبيت إضافة Bottle التي تُخوّلنا لاستعمال قواعد البيانات هذه: pip install bottle-sqliteالآن نحن نمتلك المكوّنات الأساسية، نستطيع أن ننشئ قاعدة بيانات بسيطة لتخزين بياناتنا فيها. سنقوم بإنشاء ملفّ بايثون لتوليد قاعدة بيانات SQLite مع بعض البيانات بداخلها عندما ننفّذ الملفّ. يُمكننا فعل الأمر على مترجم بايثون، لكنّ هذه الطريقة تجعل الأمر أسهل للتكرار. سننشئ ملفا باسم picnic_data.py. nano picnic_data.pyهنا نقوم باستيراد حزمة SQLite. بعد ذلك، يمكننا تنفيذ أمر يُنشئ جدولا ويدخل بيانات فيه. وفي الأخير، ننّفذ التغييرات: # -*- coding: utf-8 -*- import sqlite3 db = sqlite3.connect('picnic.db') db.execute("CREATE TABLE picnic (id INTEGER PRIMARY KEY, item CHAR(100) NOT NULL, quant INTEGER NOT NULL)") db.execute("INSERT INTO picnic (item,quant) VALUES ('خبز' , 4')") db.execute("INSERT INTO picnic (item,quant) VALUES ('جبن', 2)") db.execute("INSERT INTO picnic (item,quant) VALUES ('عنب', 30)") db.execute("INSERT INTO picnic (item,quant) VALUES ('كعك', 1)") db.execute("INSERT INTO picnic (item,quant) VALUES ('مشروبات', 4)") db.commit()احفظ الملفّ وأغلقه يُمكننا تنفيذ الملفّ، الشيء الذي سينشئ ملفّ قاعدة بيانات باسم نزهة.db داخل المُجلّد: python picnic_data.py نموذج تطبيقنا الآن مكتمل. يمكننا الآن استنتاج أن النموذج يملي على التطبيق كيفية تعامل جزء التحكم مع البيانات. إنشاء هيكل التّطبيقبعد أن أنشأنا قاعدة بيانات التّطبيق، يمكننا البدء في تطوير تطبيقنا الرئيسي. هذه العمليّة ستكون وظيفة الهيكل بشكل أساسي. وسيكون الملفّ الأكثر شبها بتطبيقنا الأول. أنشئ ملفّا باسم picnic.py لحفظ تطبيقنا الرئيسي: nano picnic.pyداخل هذا الملفّ، نحتاج إلى استيراد بعض الأشياء من حزمة Bottle، تماما كما سبق. نحتاج إلى بعض النّماذج الإضافية التي لم يسبق لنا أن استخدمناها. إضافة إلى ذلك، نحتاج إلى استيراد وظيفة SQLite: # -*- coding: utf-8 -*- import sqlite3 from bottle import route, run, templateتالياً، سنقوم بتعريف توجيه يوافق مسار URL على الشكل التالي picnic/: # -*- coding: utf-8 -*- import sqlite3 from bottle import route, run, template @route('/picnic')سنضيف دالّة للاتصال بقاعدة البيانات، لتحضر البيانات من الجدول، والاتصال مع العرض View لتقديم الصفحة. وفي الأخير، ستُرجع المخرج إلى المُستخدم. # -*- coding: utf-8 -*- import sqlite3 from bottle import route, run, template @route('/picnic') def show_picnic(): db = sqlite3.connect('picnic.db') c = db.cursor() c.execute("SELECT item,quant FROM picnic") data = c.fetchall() c.close() output = template('bring_to_picnic', rows=data) return outputبعد ذلك سنضيف أمر run لكي نقوم بتشغيل التطبيق: # -*- coding: utf-8 -*- import sqlite3 from bottle import route, run, template @route('/picnic') def show_picnic(): db = sqlite3.connect('picnic.db') c = db.cursor() c.execute("SELECT item,quant FROM picnic") data = c.fetchall() c.close() output = template('bring_to_picnic', rows=data) return output run(host='0.0.0.0', port=8080)احفظ وأغلق الملفّ. نقوم بالاتصال مع قاعدة البيانات باستعمال: db = sqlite3.connect('picnic.db')نقوم باستعلام قاعدة البيانات وجلب جميع القيم بالأسطر الأربعة الموالية. السطر الذي نقوم فيه بالإتصال إلى "العرض" لتشكيل البيانات هو: output = template('bring_to_picnic', rows=data)السطر يقوم بالاتصال بقالب (عرض) باسم bringtopicnic.tpl لتشكيل البيانات وتقديمها. حيث يقوم بتمرير المتغير data لمتغير القالب rows. سنقوم بإنشاء ملفّ القالب هذا في المرحلة التالية. إنشاء العرضالآن نحن نمتلك كلّا من النموذج والهيكل، الشيء الوحيد المتبقّي هو إنشاء العرض. يُمكن القيام بهذا بسهولة بالاستعانة بمحرك القوالب المُدمج مع Bottle. سيبحث التطبيق عن قالب موافق للاسم الذي عرّفناه في الدّالة السابقة، الملفّ يجب أن ينتهي ب .tpl يُمكن للملفّ أن يكون إمّا في مجلّد المشروع، أو داخل مجلّد باسم "view”. أنشئ ملفّا باسم يوافق الاسم الذي عرّفناه في دالّة القالب: nano bring_to_picnic.tplفي هذا الملفّ، يُمكننا دمج HTML والبرمجة معاً. سيكون ملفّنا بسيطا جدّاً. سنقوم باستعمال حلقة تكرار لإنشاء جدول يقوم بعرض بيانات النّموذج: <html dir="rtl" style="font:droid arabic naskh"> <body> <h1>أشياء لإحضارها إلى النّزهة</h1> <table> <tr><th>المكوّن</th><th>الكميّة</th></tr> %for row in rows: <tr> %for col in row: <td>{{col}}</td> %end </tr> %end </table> </body> </html>هذه الأسطر ستقوم بتقديم صفحتنا بصيغة HTML. لغة القالب التي رأينها هي ببساطة لغة بايثون. متغيّر row الذي قمنا بتمريره إلى القالب مُتاح للاستخدام عند تصميم المُخرجات. يُمكننا كتابة أسطر بايثون بتقديم علامة "%". يُمكننا الوصول إلى المُتغيّرات بداخل HTML باستخدام "{{var}}". احفظ الملفّ وأغلقه. مشاهدة النتائجتطبيقنا مكتملٌ الآن ويمكننا تشغيل الملفّ الرئيسي: python picnic.pyيمكننا رؤية النتائج بزيارة عنوان IP متبوعا برقم المنفذ، متبوعاً بالتوجيه picnic/ http://localhost:8080/picnic ختاماًإلى هذه النقطة، يجب أن تكون قادراً على رؤية كيف يُمكنك بناء تطبيقات معقّدة باستخدام الإطار المُصغر والبسيط Bottle. رغم أنّ أمثلتنا بسيطة، إلا أنّك الآن تستطيع بسهولة أن تطوّر تطبيقات إلى القيام بوظائف متقدّمة. نظام إضافات Bottle يعدّ أيضاً أصلاً مهمّاً. الإضافات مُشارَكةُ بنشاط في المجتمع وإضافة وظائف أكثر تعقيداً لتطبيقك يُمكن أن يُنفّذ بسهولة باستخدام الإضافات. هناك طريقة سهلة للبحث عن الإضافات وهي عن طريق استعمال الأمر: pip search bottleهذا سيُعطيك فكرة عن بعض الإضافات الأكثر شعبية. ترجمة -وبتصرّف- للمقال: How To Use the Bottle Micro Framework to Develop Python Web Apps.
  7. بعد أن انتهينا من إعداد قواعد البيانات والطرق (routes)، سوف نتحدث في هذا الجزء عن المتحكِّمات (Controllers)، النماذج (مع العلاقات)، والعروض views. (بما في ذلك نظام blade ومخططات المحتوى). مساعدات النماذج Form Helpers في Laravelبعد كل هذه الإعدادات، إذا ذهبنا الآن (في المتصفح) إلى projects/ فسوف نحصل على صفحة فارغة فما هو السبب؟ حسنا، لنكتشف ذلك، قم بتنفيذ الأمر php artisan route:list على سطر الأوامر مرة أخرى وأنظر إلى هذا السطر: +--------+----------+----------------------------------------+------------------------+-------------------------------------------------+------------+ | Domain | Method | URI | Name | Action | Middleware | +--------+----------+----------------------------------------+------------------------+-------------------------------------------------+------------+ | | GET|HEAD | projects | projects.index | App\Http\Controllers\ProjectsController@index | | +--------+----------+----------------------------------------+------------------------+-------------------------------------------------+------------+يبدو أن رابط projects/ يقوم بتحميل الوظيفة Index الخاصة بـ ProjectsController، لذلك سنقوم بفتح app/Http/controllers/ProjectsController.php/ وسنقوم بتحديث التابع (method) لنقوم بربطه إلى عرض سوف نقوم بإنشائه. قم بإضافة السطر ;('return view('projects.index إلى الوظيفة ()index كالتالي: public function index() { return view('projects.index'); }بما أننا نستخدم في هذا الدرس نظام Blade للقَوْلَبة سنقوم بإنشاء ملف resources/views/projects/index.blade.php/ وسنكتب نص قصير داخله، ثم سنقوم مرة أخرى بالذهاب إلى projects/ في المتصفح، إذا كان كل شيء يعمل جيدا فسوف تجد النص الذي كتبته بالأعلى. والآن قُم بنفس الشيء لتابع المتحكِّم create عن طريق إضافة السطر ;('return view('projects.create إلى التابع ()create كالتالي: public function create() { return view('projects.create'); }إن إظهار محتويات العرض view هو أمر رائع، لكن ماذا لو كنا نملك أكثر من صفحة واحدة في موقعنا ؟ في هذه الحالة، سوف نحتاج إلى قالب ثابت لجميع الصفحات، أي أننا نحتاج إلى عرض محتويات العرض view داخل قالب HTML بسيط، وسنقوم بهذا عن طريق مخططات المتحكِّمات. من أجل عمل مخططات المتحكِّمات سنقوم بالخطوات التالية: إنشاء مخطط العرض، وبما أن Laravel توفر لنا واحدة جيدة تدعى app.blade.php لذلك سنوفر الوقت وسنقوم بإستخدامها. لاحظ أن قرب أسفل المخطط هنالك سطر ('@yield('content وهذه دالة ستقوم بتحميل محتوانا الحالي.الإشارة إلى مخططك في عرضك view باستخدام ('extends('app@ ولفها عن طريق كتلة ('section('content@، مثل التالي: @extends('app') @section('content') This is my /resources/views/projects/index.blade.php file! @endsection سنقوم الآن بتنفيذ هذه الخطوات بإنشاء عروض show.blade.php و create.blade.php و index.blade.php في مجلد resources/views/projects/ مع الشيفرات (markup) المذكورة أعلاه وقُم بتغيير اسم الملف إذا كان الأمر ضروريا، ثم قُم بعمل تحديث للصفحة projects/ في متصفحك، وسوف ترى هيكل app.blade.php حول محتويات عرضك (view). الربط بين الطريق (route) والنموذجسيوفر Laravel بشكل افتراضي معرف رقمي ID للعديد من توابع متحكِّمات الموارد مثل ()show و ()edit و ()update و ()destroy، وهذا الأمر سيضيف العديد من الشيفرات الجاهزة (boilerplate) التي نحتاج إلى كتابتها، مثل الحصول على مثيل النموذج والتأكد من وجودها وغيرها. ولهذا سوف نستخدم إحدى مميزات Laravel والتي تدعى الربط بين الطريق و النموذج route model binding، فبدل من توفير متغير id$، سوف نقوم بإعطاء الوظيفة (method) كائن project$ أو task$. قُم بفتح app/Http/routes.php/ وأضف هذين السطرين (أول سطرين بعد التعليق): // Provide controller methods with object instead of ID Route::model('tasks', 'Task'); Route::model('projects', 'Project'); // Use slugs rather than IDs in URLs Route::bind('tasks', function($value, $route) { return App\Task::whereSlug($value)->first(); }); Route::bind('projects', function($value, $route) { return App\Project::whereSlug($value)->first(); }); Route::resource('projects', 'ProjectsController'); Route::resource('projects.tasks', 'TasksController'); وفي TasksController و ProjectsController (ملفات app/Http/Controllers/ProjectsController.php/ و app/Http/Controllers/TasksController.php/) قُم باستبدال كل وظيفة (method) مُعرف بمرجع id$ بـ task$ أو project$ مثل التالي: // public function edit($id) public function edit(Project $project)لا تنسَ إضافة use App\Task و use App\Project في أعلى المتحكِّمات حتى نشير إلى هذه النماذج. لا تقلق إذا لم تفهم هذه التغييرات، فسنقوم بعرض الشيفرة البرمجة الكاملة لـ TasksController و ProjectsController لاحقا. وفي هذه المرحلة يمكنك تمرير الكائن (object) إلى عرضه في كل متحكِّم لوظيفة (method) الإظهار والتعديل والتحديث حتى نستطيع استخدامهم لاحقا: public function edit(Project $project) { return view('projects.show', compact('project')); }سوف يحتاج TasksController إلى بضعة تعديلات طفيفة أخرى، وبما أننا نستخدم الموارد المضمّنة nested resources، سيخبرنا php artisan route:list أن جميع طرق task تحتوي على قناع {projects} بالإضافة إلى أن بعضها يستقبل قناع {tasks} أيضا. و كنتيجة لذلك، سيتم تمرير مثيل Project كمُعامل أول لتوابع المتحكِّمات (controller methods)، لذلك قُم بتحديثها وقٌم بتمرير متغير project$ الجديد. إذا لم تفهم خطوات الإضافة لـ TasksController و ProjectsController فهذه هي الشيفرة الكاملة للملفين بعد كل التعديلات: // /app/Http/Controllers/ProjectsController.php <?php namespace App\Http\Controllers; use App\Project; use App\Http\Requests; use App\Http\Controllers\Controller; use Illuminate\Http\Request; class ProjectsController extends Controller { /** * Display a listing of the resource. * * @return Response */ public function index() { $projects = Project::all(); return view('projects.index', compact('projects')); } /** * Show the form for creating a new resource. * * @return Response */ public function create() { return view('projects.create'); } /** * Store a newly created resource in storage. * * @return Response */ public function store() { // } /** * Display the specified resource. * * @param \App\Project $project * @return Response */ public function show(Project $project) { return view('projects.show', compact('project')); } /** * Show the form for editing the specified resource. * * @param \App\Project $project * @return Response */ public function edit(Project $project) { return view('projects.edit', compact('project')); } /** * Update the specified resource in storage. * * @param \App\Project $project * @return Response */ public function update(Project $project) { // } /** * Remove the specified resource from storage. * * @param \App\Project $project * @return Response */ public function destroy(Project $project) { // } } // /app/Http/Controllers/TasksController.php <?php namespace App\Http\Controllers; use App\Project; use App\Task; use App\Http\Requests; use App\Http\Controllers\Controller; use Illuminate\Http\Request; class TasksController extends Controller { /** * Display a listing of the resource. * * @param \App\Project $project * @return Response */ public function index(Project $project) { return view('tasks.index', compact('project')); } /** * Show the form for creating a new resource. * * @param \App\Project $project * @return Response */ public function create(Project $project) { return view('tasks.create', compact('project')); } /** * Store a newly created resource in storage. * * @param \App\Project $project * @return Response */ public function store(Project $project) { // } /** * Display the specified resource. * * @param \App\Project $project * @param \App\Task $task * @return Response */ public function show(Project $project, Task $task) { return view('tasks.show', compact('project', 'task')); } /** * Show the form for editing the specified resource. * * @param \App\Project $project * @param \App\Task $task * @return Response */ public function edit(Project $project, Task $task) { return view('tasks.edit', compact('project', 'task')); } /** * Update the specified resource in storage. * * @param \App\Project $project * @param \App\Task $task * @return Response */ public function update(Project $project, Task $task) { // } /** * Remove the specified resource from storage. * * @param \App\Project $project * @param \App\Task $task * @return Response */ public function destroy(Project $project, Task $task) { // } }لاحظ أنه إذا قمت بتحديث صفحة projects/project-1/ سيبقى كل شيء يعمل. عرض نماذجناصفحة عرض قائمة المشاريع، حان الآن وقت البدء بعرض المشاريع والمهام، قٌم بفتح projects/ في متصفحك. وبالاعتماد على php artisan route:list، ستكون هذه الصفحة هي صفحة عرض المشاريع، لذلك قُم بفتح resources/views/projects/index.blade.php/ وأضف التالي: @extends('app') @section('content') <h2>Projects</h2> @if ( !$projects->count() ) You have no projects @else <ul> @foreach( $projects as $project ) <li><a href="{{ route('projects.show', $project->slug) }}">{{ $project->name }}</a></li> @endforeach </ul> @endif @endsectionسوف أشرح بعض النقاط في هذه الشفرة البرمجية: استخدمنا في هذه الشفرة لغة Blade للقَوْلَبة، لذلك فإن if و foreach تتحكم في تدفق flow الدوال بإضافة إلى أنها دالة طباعة (الأقواس المعقوفة المزدوجة).تأكدنا إن كان هنالك أي مشروع لعرضه، إن كان هنالك أية مشاريع فسيقوم بعرضها وإن لم يكن تظهر رسالة تخبرك بذلك.استدعينا مساعد ()route مع طريق ذا اسم (يمكنك رؤية قائمة الطرق ذات الاسم عن طريق php artisan route:list) لربط كل مشروع مع صفحة تفاصيله.سوف تحتاج أيضا إلى تمرير متغير projects$ لهذا العرض view وإلا ستحصل على خطأ متغير غير معرف undefined variable error. قُم بفتح app/Http/controllers/ProjectsController.php/ وقُم بتحديث الوظيفة ()index إلى: public function index() { $projects = Project::all(); return view('projects.index', compact('projects')); }قُم بتحديث الصفحة (Refresh) وستجد قائمة من مشاريعك. علاقات النموذج - صفحة تفاصيل المشروعفي صفحة تفاصيل المشروع نحتاج إلى عرض قائمة من مهام المشاريع، وللقيام بذلك نحتاج إلى تعريف علاقة "واحد إلى الكثير one-to-many" في نموذج Project للسماح له بالحصول على المهام tasks. قُم بفتح app/Project.php/ وأضف التابع ()tasks كالتالي: public function tasks() { return $this->hasMany('App\Task'); }بشكل عكسي، يمكننا إضافة علاقة "الكثير إلى واحد many-to-one" لنموذج المهام Task: public function project() { return $this->belongsTo('App\Project'); }للتأكد من أنها تعمل اكتب الأمر: $ php artisan tinkerوستكون النّتيجة كالتي حسب المدخلات: >App\Project::whereSlug('project-1')->first()->tasks->count(); 5 >App\Project::whereSlug('project-2')->first()->tasks->count(); 2 >App\Task::first()->project->name; Project 1ممتاز، يمكننا الآن تحديث عرض resources/views/projects/show.blade.php/: @extends('app') @section('content') <h2>{{ $project->name }}</h2> @if ( !$project->tasks->count() ) Your project has no tasks. @else <ul> @foreach( $project->tasks as $task ) <li><a href="{{ route('projects.tasks.show', [$project->slug, $task->slug]) }}">{{ $task->name }}</a></li> @endforeach </ul> @endif @endsectionاضغط على أي مشروع في صفحة عرض قائمة المشاريع في متصفحك وسوف يتم عرض المشروع مع جميع المهام المرتبطة به. وأخير تَبقى لدينا صفحة عرض المهام (resources/views/tasks/show.blade.php/)، وهذه سهلة للغاية: @extends('app') @section('content') <h2> {!! link_to_route('projects.show', $project->name, [$project->slug]) !!} - {{ $task->name }} </h2> {{ $task->description }} @endsectionملاحظة: كُن حذرا عندما تستخدم علاقات النماذج (models)، فإنه من السهل إنشاء عدد كبير من استعلامات SQL، وتسمى هذه المشكلة بـ "مشكلة N+1". الخاتمةاليوم تعلمنا الكثير من الأشياء الجديدة مثل: الربط بين الطريق (route) و النموذجالنماذج (مع علاقة واحد إلى الكثير one-to-many)المتحكِّمات (مع الربط بين الطريق و النموذج)العروض (مع لغة blade للقَوْلَبة والمخططات)أصبحت الصفحة تعرض لنا قائمة من المشاريع والمهام، وفي الدرس القادم سوف نركز على تعديل وإضافة وحذف المشاريع والمهام. ترجمة -وبتصرّف- للمقال Creating a Basic ToDo Application in Laravel 5 – Part 2. حقوق الصورة البارزة: Designed by Freepik.
  8. حتى الآن تعلمنا كيفية تثبيت وإعداد Laravel، بالإضافة إلى إعداد بعض المشاريع والمهام والموارد المضمّنة و عرضهم على المستخدم، كما أنشأنا وظائف الإنشاء والتعديل والحذف، وفي هذا الفصل سوف نختم الدرس عن طريق إضافة استمارة التحقق. استمارة التحقق من جانب الخادمعلى الرغم من أن استمارات الإنشاء والتعديل تعمل إلا أننا لم نقم بالتحقق من ما يتم إدخاله، وهذا ما سنقوم بعمله اليوم. هنالك طرق متعددة للتعامل مع استمارة التحقق، بعضها أفضل من الآخر، ولهذا التطبيق الصغير نقترح أن نستخدم وظيفة المتحكِّمات ()validate مع كائن Illuminate\Http\Request مثل هذا، في ملف app/Http/Controllers/ProjectsController.php/: // /app/Http/Controllers/ProjectsController.php use Illuminate\Http\Request; class ProjectsController extends Controller { protected $rules = [ 'name' => ['required', 'min:3'], 'slug' => ['required'], ]; /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return Response */ public function store(Request $request) { $this->validate($request, $this->rules); $input = Input::all(); Project::create( $input ); return Redirect::route('projects.index')->with('message', 'Project created'); } /** * Update the specified resource in storage. * * @param \App\Project $project * @param \Illuminate\Http\Request $request * @return Response */ public function update(Project $project, Request $request) { $this->validate($request, $this->rules); $input = array_except(Input::all(), '_method'); $project->update($input); return Redirect::route('projects.show', $project->slug)->with('message', 'Project updated.'); }وأما في ملف app/Http/Controllers/TasksController.php/: // /app/Http/Controllers/TasksController.php use Illuminate\Http\Request; class TasksController extends Controller { protected $rules = ['name' => ['required', 'min:3'], 'slug' => ['required'], 'description' => ['required'], ]; /** * Store a newly created resource in storage. * * @param \App\Project $project * @param \Illuminate\Http\Request $request * @return Response */ public function store(Project $project, Request $request) { $this->validate($request, $this->rules); $input = Input::all(); $input['project_id'] = $project->id; Task::create( $input ); return Redirect::route('projects.show', $project->slug)->with('Task created.'); } /** * Update the specified resource in storage. * * @param \App\Project $project * @param \App\Task $task * @param \Illuminate\Http\Request $request * @return Response */ public function update(Project $project, Task $task, Request $request) { $this->validate($request, $this->rules); $input = array_except(Input::all(), '_method'); $task->update($input); return Redirect::route('projects.tasks.show', [$project->slug, $task->slug])->with('message', 'Task updated.'); }سوف نحتاج أيضا إلى مكان لعرض أية أخطاء، لذلك قُم بفتح resources/views/app.blade.php/ وأضف السطور التالية أسفل ('yield('content@: <div class="content"> @if (Session::has('message')) <div class="flash alert-info"> <p>{{ Session::get('message') }}</p> </div> @endif @if ($errors->any()) <div class='flash alert-danger'> @foreach ( $errors->all() as $error ) <p>{{ $error }}</p> @endforeach </div> @endif @yield('content') </div>إذا أردت قائمة كاملة من قواعد التحقق، أنصحك بزيارة التوثيق الرسمي. من المفترض أن يعمل كل شيء الآن، وإذا كان عكس ذلك، فسوف تقوم ()this->validate$ بتوجيهك إلى الصفحة الحالية مع الأخطاء التي سوف تظهر على الصفحة. خاتمةلقد قمنا في هذه الدورة بتعلم الكثير من الأشياء حول Laravel، مثل كيفية تثبيت وإعداد Laravel 5 بالإضافة إلى بعض المفاهيم المتقدمة مثل الربط بين الطريق والنموذج route model binding والحماية من CSRF، وعلى الرغم من بساطة التطبيق الذي قمنا به إلا أنه بداية جيدة لكل من يريد احتراف Laravel. ترجمة -وبتصرّف- للمقال Creating a Basic ToDo Application in Laravel 5 – Part 4. حقوق الصورة البارزة: Designed by Freepik.
  9. حتى الآن تعلمنا كيفية تثبيت وإعداد Laravel، بالإضافة إلى أننا قمنا بـإعداد بعض موارد المشاريع والمهام وعرضهم للمستخدم. في هذا الدرس، سنتعلم كيفية إنشاء وتعديل وحذف الصفحات والإجراءات. إضافة روابط التصفحقبل أن نفعل أي شيء، سنقوم بإضافة روابط create/edit/delete/back إلى صفحات المشاريع والمهام: <!-- /resources/views/projects/index.blade.php --> @extends('app') @section('content') <h2>Projects</h2> @if ( !$projects->count() ) You have no projects @else <ul> @foreach( $projects as $project ) <li> {!! Form::open(array('class' => 'form-inline', 'method' => 'DELETE', 'route' => array('projects.destroy', $project->slug))) !!} <a href="{{ route('projects.show', $project->slug) }}">{{ $project->name }}</a> ( {!! link_to_route('projects.edit', 'Edit', array($project->slug), array('class' => 'btn btn-info')) !!}, {!! Form::submit('Delete', array('class' => 'btn btn-danger')) !!} ) {!! Form::close() !!} </li> @endforeach </ul> @endif <p> {!! link_to_route('projects.create', 'Create Project') !!} </p> @endsection <!-- /resources/views/projects/show.blade.php --> @extends('app') @section('content') <h2>{{ $project->name }}</h2> @if ( !$project->tasks->count() ) Your project has no tasks. @else <ul> @foreach( $project->tasks as $task ) <li> {!! Form::open(array('class' => 'form-inline', 'method' => 'DELETE', 'route' => array('projects.tasks.destroy', $project->slug, $task->slug))) !!} <a href="{{ route('projects.tasks.show', [$project->slug, $task->slug]) }}">{{ $task->name }}</a> ( {!! link_to_route('projects.tasks.edit', 'Edit', array($project->slug, $task->slug), array('class' => 'btn btn-info')) !!}, {!! Form::submit('Delete', array('class' => 'btn btn-danger')) !!} ) {!! Form::close() !!} </li> @endforeach </ul> @endif <p> {!! link_to_route('projects.index', 'Back to Projects') !!} | {!! link_to_route('projects.tasks.create', 'Create Task', $project->slug) !!} </p> @endsectionهذه الشفرة البرمجية مفهومة، الصعوبة تكمن في رابط الحذف، متحكِّمات الموارد تتطلب إرسال وظيفة HTTP DELETE، وهذا لا يمكن أن يتم مع رابط عادي، لذلك يتطلب نموذج يتم تقديمه إلى طريق route محدد. للمزيد من المعلومات قُم بزيارة إجراءات يتم التحكم بها عن طريق متحكِّمات الموارد. إنشاء صفحات الإضافة والتعديلبعد الانتهاء من صفحات عرض قائمة المشاريع، نحتاج إلى إمكانية إضافة وحذف المشاريع والمهام. استمارات الإضافة والحذف ستكون متشابهة كثيرا، لذلك بدلا من تكرارهم، سنقوم بوراثتهم من نموذج واحد. سوف نبدأ مع عروض create/edit للمشروع: <!-- /resources/views/projects/create.blade.php --> @extends('app') @section('content') <h2>Create Project</h2> {!! Form::model(new App\Project, ['route' => ['projects.store']]) !!} @include('projects/partials/_form', ['submit_text' => 'Create Project']) {!! Form::close() !!} @endsection <!-- /resources/views/projects/edit.blade.php --> @extends('app') @section('content') <h2>Edit Project</h2> {!! Form::model($project, ['method' => 'PATCH', 'route' => ['projects.update', $project->slug]]) !!} @include('projects/partials/_form', ['submit_text' => 'Edit Project']) {!! Form::close() !!} @endsectionقُم بعمل نفس الشيء مع المهام لكن لا تنسَ تحديث الطرق (routes): <!-- /resources/views/tasks/create.blade.php --> @extends('app') @section('content') <h2>Create Task for Project "{{ $project->name }}"</h2> {!! Form::model(new App\Task, ['route' => ['projects.tasks.store', $project->slug], 'class'=>'']) !!} @include('tasks/partials/_form', ['submit_text' => 'Create Task']) {!! Form::close() !!} @endsection <!-- /resources/views/tasks/edit.blade.php --> @extends('app') @section('content') <h2>Edit Task "{{ $task->name }}"</h2> {!! Form::model($task, ['method' => 'PATCH', 'route' => ['projects.tasks.update', $project->slug, $task->slug]]) !!} @include('tasks/partials/_form', ['submit_text' => 'Edit Task']) {!! Form::close() !!} @endsectionالآن توجد عدة مفاهيم جديدة: إضافة جزئيةالاستمارة تتطلب عدة وسوم، وبدلا من ذلك سنقوم بتقسيمها من جزئية _form ونضعها مباشرة في العرض، استمارة Add هي من نوع POST ترسل البيانات إلى طريق projects.store واستمارة Edit هي من نوع PATCH وترسل البيانات إلى projects.update. قد يبدوا هذا معقدا ومبهم لكن هذه هي الطريقة التي تعمل بها المتحكِّمات. لاحظ أننا استخدمنا ()Form::model، وتسمى هذه نموذج الاستمارة الملزمة و ليس لدى هذه أهمية كبيرة الآن، فهي تُستخدم للتعبئة التلقائية وسوف نحتاجها في وقت لاحقا عندما نضيف الحقول باستخدام ()Form::input.الحماية من CSRF:مساعدي الاستمارة (Form helpers) توفر العديد من الوظائف مجانا، فإذا ذهبت إلى projects/create/ ورأيت مصدر الصفحة ستجد شيئا مشابها لهذا: <form method="POST" action="http://l4todo.localhost.com/projects" accept-charset="UTF-8"> <input name="_token" type="hidden" value="Y8uOo7SeD5tQZExezDf5a7UwiYR4P6qIHEUKJNxI"> </form>هل ترى حقل token_ ؟ هذا هو الرمز المميز لـ CSRF مُنشئ تِلقائيا بواسطة استدعاء {{ ()Form::model }} الذي يمنع ثغرة CSRF. يكفي أن نقول أن هذا شيئ مفيد وأننا لم نقم بأي شيئ للحصول عليه. إنشاء استمارة التعديلنحن بحاجة إلى ترميز (markup) الاستمارة للمشاريع والمهام، وبفضل نموذج الاستمارة الملزمة يمكننا فقط استخدام مساعدي الاستمارة في Laravel لإخراج كافة الحقول التي نحتاجها. <!-- /resources/views/projects/partials/_form.blade.php --> <div class="form-group"> {!! Form::label('name', 'Name:') !!} {!! Form::text('name') !!} </div> <div class="form-group"> {!! Form::label('slug', 'Slug:') !!} {!! Form::text('slug') !!} </div> <div class="form-group"> {!! Form::submit($submit_text, ['class'=>'btn primary']) !!} </div> <!-- /resources/views/tasks/partials/_form.blade.php --> <div class="form-group"> {!! Form::label('name', 'Name:') !!} {!! Form::text('name') !!} </div> <div class="form-group"> {!! Form::label('slug', 'Slug:') !!} {!! Form::text('slug') !!} </div> <div class="form-group"> {!! Form::label('completed', 'Completed:') !!} {!! Form::checkbox('completed') !!} </div> <div class="form-group"> {!! Form::label('description', 'Description:') !!} {!! Form::textarea('description') !!} </div> <div class="form-group"> {!! Form::submit($submit_text) !!} </div>هذا كل شيئ، سوف تستطيع الأن التصفح في صفحات الإضافة والتعديل، الأمر كان سهلا للغاية. جعل الاستمارات تعمللدينا استمارات الإضافة والتعديل للمشروع و المهام، بالإضافة إلى استمارة مُضللة لحذفهم، الآن يجب علينا أن نجعلهم يعملون لأداء مهامهم. أولا، أضف هذا في أعلى المتحكِّمات: use Input; use Redirect;والآن لوظائف store و update و destroy: // ProjectsController public function store() { $input = Input::all(); Project::create( $input ); return Redirect::route('projects.index') ->with('message', 'Project created'); } public function update(Project $project) { $input = array_except(Input::all(), '_method'); $project->update($input); return Redirect::route('projects.show', $project->slug) ->with('message', 'Project updated.'); } public function destroy(Project $project) { $project->delete(); return Redirect::route('projects.index')->with('message', 'Project deleted.'); } // TasksController public function store(Project $project) { $input = Input::all(); $input['project_id'] = $project->id; Task::create( $input ); return Redirect::route('projects.show', $project->slug) ->with('message', 'Task created.'); } public function update(Project $project, Task $task) { $input = array_except(Input::all(), '_method'); $task->update($input); return Redirect::route('projects.tasks.show', [$project->slug, $task->slug]) ->with('message', 'Task updated.'); } public function destroy(Project $project, Task $task) { $task->delete(); return Redirect::route('projects.show', $project->slug)->with('message', 'Task deleted.'); }الشفرة البرمجية في الأعلى مفهومة ولا داعي لشرحها. إذا قمت الآن بتقديم إحدى الاستمارات فسوف تحصل على خطأ MassAssignmentException: _token، فالإحالة الكتلية تحدث عندما تقوم بتمرير مصفوفة بيانات إلى ()Model::create أو ()Model::update من المتحكِّمات بدل من وضع حقل واحد في نفس الوقت، ولإصلاح هذا، قم ببساطة بإضافة خاصية guarded إلى كل نموذج. class Project extends Model { protected $guarded = []; class Task extends Model { protected $guarded = [];رسائل الفلاشسوف تلاحظ من الشفرة السابقة أننا استخدمنا دالة ()with، وهذه الدالة تقوم بتمرير متغير فلاش (يستخدم لمرة واحدة) للجلسة session والتي يمكن قراءتها عند تحميل الصفحة التالية. والآن نحتاج إلى التأكد من تلك الرسالة وعرضها على المستخدم. قُم بفتح resources/views/app.blade.php/ وأضف التالي: ... <div class="content"> @if (Session::has('message')) <div class="flash alert-info"> <p>{{ Session::get('message') }}</p> </div> @endif @yield('content') </div> ...حاول إنشاء مشروع، هذه الرسالة ستظهر مهما حدّثت الصفحة وستذهب بعد فترة. خاتمةاليوم قمنا بأشياء مثيرة للغاية، فلقد أضفنا استمارات الإضافة والتعديل والحذف وتعلمنا حول CSRF و نموذج الاستمارة الملزمة بالإضافة إلى تعلمنا المزيد حول blade و الدوال. كل شيئ الآن يعمل، يمكن تجربة التطبيق وإنشاء وتعديل وحذف المهام والمشاريع، وفي أي وقت يمكنك كتابة الأمر: php artisan migrate:refresh –seed وسوف يتم إعادة تعيين قواعد البيانات. في المرحلة القادمة والتي ستكون النهائية سوف نقوم بالتحقق من الاستمارات. ترجمة -وبتصرّف- للمقال Creating a Basic ToDo Application in Laravel 5 – Part 3. حقوق الصورة البارزة: Designed by Freepik.
  10. يعتبر Laravel أشهر إطار ويب بلغة PHP، ولقد شهد إصداره الخامس العديد من التغييرات وتمت إضافة الكثير من المميزات الجديدة، ولذلك لتعلم أساسيات هذا الإطار سوف نقوم بإنشاء تطبيق Todo List، وسوف نتعلم من خلال هذا التطبيق الكثير من المفاهيم والطرق البرمجية حتى نتمكن من التعامل والتوسع مع إطار Laravel 5. ملاحظة: هذا الدرس طويل للغاية لذلك سوف يتم تقسيمه إلى أجزاء أصغر، ويمكنك الحصول على الكود المصدري لكل جزء من GitHub. في هذا الدرس سوف نتحدث عن تثبيت Laravel 5 وإعداده وعن بعض التقنيات الجديد كالتهجير migration والبذر seeding. قبل أن نبدأ أهم المصطلحات التي ستصادفنا في هذه الدروس: التهجير migration: نظام لإدارة قواعد البيانات، فهو يسمح للفريق بتعديل مخطط قواعد البيانات لجميع الأعضاء. البذر seeding: يقصد بها إدخال البيانات الأولية لتجربة التطبيق، أي أنه سيقوم بإدخال بيانات لمساعدتك على التطوير واكتشاف الأخطاء. هدف المشروع سوف يتكون تطبيقنا من مشروع أو أكثر، كل واحد لديه قائمة مهام خاصة به، وسوف تتمكن من إنشاء وعرض وتعديل وحذف المهام والمشاريع. في هذا الدرس سوف نقوم بـ: إعداد وتنصيب Laravel. تركيب حزم إضافية لتسهيل عملية التطوير. استخدام التهجير migration والبذر seeds. تعلم كيفية استخدام متحكِّمات الموارد resourceful controllers. تعلم كيفية استخدام العروض views. (بما في ذلك نظام blade ومخططات المحتوى) التعامل مع علاقات النماذج. التثبيت إن عملية تثبيت Laravel سهلة للغاية بفضل Composer، لذلك سوف نستخدمه في تثبيته. استخدام Composer والآن نقوم بتشغيل مثبت Laravel (سوف تحتاج إلى عمل هذا لمرة واحدة فقط): composer global require "laravel/installer=~1.1" والآن نقوم بعمل مشروعنا: laravel new l5todo الإعداد يستخدم Laravel 5 حزمة تدعى DotEnv تقوم بتخزين المعلومات الحساسة في ملفات ذات صيغة .env والتي يتم تحميلها كمتغيرات PHP عند التشغيل. قد يبدوا لك هذا معقدا لكن بكلمات أخرى، هذا يعني أن فقط الإعدادات الحسّاسة credentials يتم تخزينها في هذه الملفات وأما بقية إعداداتك فيتم تخزينها في ملفات الإعداد العادية. قاعدة البيانات سوف نحتاج إلى قاعدة بيانات، لذلك سنقوم بعمل واحدة ثم سنقوم بنسخ .env.example إلى .env وتحديث البيانات على الشكل التالي: DB_HOST=localhost DB_DATABASE=homestead DB_USERNAME=homestead DB_PASSWORD=secret في النهاية إذا لم تكن تستخدم MySQL فقُم بفتح config/database.php/ ثم قٌم بتغيير السطر الافتراضي: 'default' => 'mysql', تذكر أن تضيف ملفات بيئة عملك إلى .gitignore عن طريق إضافة سطر .env. خطواتنا الأولى كما ذكرنا في الأعلى، سوف يتكون تطبيق قائمة المهام على مشروع أو أكثر كل واحد مع قائمة المهام الخاصة به، ولذلك سوف نحتاج إلى مشروع، نماذج مهام، متحكِّمات، عروض views، التهجير migration، البذور seeds والطرق routes، ولقد قمنا بشرح بعض هذه المصطلحات في بداية الدرس. لنبدأ بالتعامل معهم كل واحد على حدة. التهجير migration أولا نريد أن نرى مخطط جدولنا، سوف يبدو مثل هذا: Projects +------------+------------------+------+-----+ | Field | Type | Null | Key | +------------+------------------+------+-----+ | id | int(10) unsigned | NO | PRI | | name | varchar(255) | NO | | | slug | varchar(255) | NO | | | created_at | timestamp | NO | | | updated_at | timestamp | NO | | +------------+------------------+------+-----+ Tasks +-------------+------------------+------+-----+ | Field | Type | Null | Key | +-------------+------------------+------+-----+ | id | int(10) unsigned | NO | PRI | | project_id | int(10) unsigned | NO | MUL | | name | varchar(255) | NO | | | slug | varchar(255) | NO | | | completed | tinyint(1) | NO | | | description | text | NO | | | created_at | timestamp | NO | | | updated_at | timestamp | NO | | +-------------+------------------+------+-----+ ثم سوف نقوم بعمل التهجير migration: php artisan make:migration create_projects_and_tasks_tables --create="projects" سوف نقوم بعمل كِلا الجدولين بتهجير migration واحد حتى نتمكن من حذفها بترتيب عكسي لتجنب سلامة خرق القيد integrity constraint violation، قُم بفتح: /database/migrations/createprojectsandtasks_tables.php وقُم بتحديث المعلومات حسب الآتي: <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateProjectsAndTasksTables extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('projects', function(Blueprint $table) { $table->increments('id'); $table->string('name')->default(''); $table->string('slug')->default(''); $table->timestamps(); }); Schema::create('tasks', function(Blueprint $table) { $table->increments('id'); $table->integer('project_id')->unsigned()->default(0); $table->foreign('project_id')->references('id')->on('projects')->onDelete('cascade'); $table->string('name')->default(''); $table->string('slug')->default(''); $table->boolean('completed')->default(false); $table->text('description')->default(''); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('tasks'); Schema::drop('projects'); } } قم بتنفيذ الهجرة migration: php artisan migrate إذا قمت الآن بمراجعة قاعدة البيانات، يجب أن تكون الجداول مكتملة. البذور Seeds سوف نحتاج إلى بذر المشاريع/المهام ليكون لديك شيء للعمل معه عندما نصل إلى المتصفح، لذلك قم بإنشاء: /database/seeds/ProjectsTableSeeder.php و TasksTableSeeder.php كالتالي: // /database/migrations/seeds/ProjectsTableSeeder.php <?php use Illuminate\Database\Seeder; class ProjectsTableSeeder extends Seeder { public function run() { // Uncomment the below to wipe the table clean before populating DB::table('projects')->delete(); $projects = array( ['id' => 1, 'name' => 'Project 1', 'slug' => 'project-1', 'created_at' => new DateTime, 'updated_at' => new DateTime], ['id' => 2, 'name' => 'Project 2', 'slug' => 'project-2', 'created_at' => new DateTime, 'updated_at' => new DateTime], ['id' => 3, 'name' => 'Project 3', 'slug' => 'project-3', 'created_at' => new DateTime, 'updated_at' => new DateTime], ); // Uncomment the below to run the seeder DB::table('projects')->insert($projects); } } // /database/migrations/seeds/TasksTableSeeder.php <?php use Illuminate\Database\Seeder; class TasksTableSeeder extends Seeder { public function run() { // Uncomment the below to wipe the table clean before populating DB::table('tasks')->delete(); $tasks = array( ['id' => 1, 'name' => 'Task 1', 'slug' => 'task-1', 'project_id' => 1, 'completed' => false, 'description' => 'My first task', 'created_at' => new DateTime, 'updated_at' => new DateTime], ['id' => 2, 'name' => 'Task 2', 'slug' => 'task-2', 'project_id' => 1, 'completed' => false, 'description' => 'My first task', 'created_at' => new DateTime, 'updated_at' => new DateTime], ['id' => 3, 'name' => 'Task 3', 'slug' => 'task-3', 'project_id' => 1, 'completed' => false, 'description' => 'My first task', 'created_at' => new DateTime, 'updated_at' => new DateTime], ['id' => 4, 'name' => 'Task 4', 'slug' => 'task-4', 'project_id' => 1, 'completed' => true, 'description' => 'My second task', 'created_at' => new DateTime, 'updated_at' => new DateTime], ['id' => 5, 'name' => 'Task 5', 'slug' => 'task-5', 'project_id' => 1, 'completed' => true, 'description' => 'My third task', 'created_at' => new DateTime, 'updated_at' => new DateTime], ['id' => 6, 'name' => 'Task 6', 'slug' => 'task-6', 'project_id' => 2, 'completed' => true, 'description' => 'My fourth task', 'created_at' => new DateTime, 'updated_at' => new DateTime], ['id' => 7, 'name' => 'Task 7', 'slug' => 'task-7', 'project_id' => 2, 'completed' => false, 'description' => 'My fifth task', 'created_at' => new DateTime, 'updated_at' => new DateTime], ); //// Uncomment the below to run the seeder DB::table('tasks')->insert($tasks); } } ولا تنسَ إضافة أصناف البذور(seed classes) إلى database/seeds/DatabaseSeeder.php/ : use Illuminate\Database\Seeder; use Illuminate\Database\Eloquent\Model; class DatabaseSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { Model::unguard(); $this->call('ProjectsTableSeeder'); $this->call('TasksTableSeeder'); } } الآن نقوم بالبذر: composer dump-autoload ثم: php artisan db:seed # أو php artisan migrate:refresh --seed يجب الآن أن تكون قاعدة البيانات قد تم بذرها. mysql> select * from projects; +----+-----------+-----------+---------------------+---------------------+ | id | name | slug | created_at | updated_at | +----+-----------+-----------+---------------------+---------------------+ | 1 | Project 1 | project-1 | 2015-02-05 01:25:43 | 2015-02-05 01:25:43 | | 2 | Project 2 | project-2 | 2015-02-05 01:25:43 | 2015-02-05 01:25:43 | | 3 | Project 3 | project-3 | 2015-02-05 01:25:43 | 2015-02-05 01:25:43 | +----+-----------+-----------+---------------------+---------------------+ mysql> select * from tasks; +----+------------+--------+--------+-----------+----------------+---------------------+---------------+ | id | project_id | name | slug | completed | description | created_at | updated_at | +----+------------+--------+--------+-----------+----------------+---------------------+---------------+ | 1 | 1 | Task 1 | task-1 | 0 | My first task | 2015-02-05 01:25:43 | 2015-02-05 01:25:43 | 2 | 1 | Task 2 | task-2 | 0 | My first task | 2015-02-05 01:25:43 | 2015-02-05 01:25:43 | 3 | 1 | Task 3 | task-3 | 0 | My first task | 2015-02-05 01:25:43 | 2015-02-05 01:25:43 | 4 | 1 | Task 4 | task-4 | 1 | My second task | 2015-02-05 01:25:43 | 2015-02-05 01:25:43 | 5 | 1 | Task 5 | task-5 | 1 | My third task | 2015-02-05 01:25:43 | 2015-02-05 01:25:43 | 6 | 2 | Task 6 | task-6 | 1 | My fourth task | 2015-02-05 01:25:43 | 2015-02-05 01:25:43 | 7 | 2 | Task 7 | task-7 | 0 | My fifth task | 2015-02-05 01:25:43 | 2015-02-05 01:25:43 +----+------------+--------+--------+-----------+----------------+---------------------+---------------+ النماذج Models للعمل مع جداول المشاريع والمهام نحتاج إلى نماذج مماثلة، سوف نقوم بإنشائها الآن: php artisan make:model Project php artisan make:model Task كان هذا سهلا استخدام Artisan – Tinker الآن لدينا المعلومات في قاعدة البيانات وسيكون من الرائع أن نتعلم حول واحدة من أهم ميزات artisan وهي Tinker الذي يوفر لك سطر أوامر للتعامل مع Laravel، وكمثال، لنستخدمه في معرفة عدد المشاريع في قاعدة البيانات الحالية: $ php artisan tinker > App\Project::count(); 3 > App\Task::count(); 7 وكما ترى يمكن أن يكون Tinker مفيدا للغاية، لذلك سوف نستخدمه عدة مرات في هذه السّلسلة. المُتحكِّمات Controllers الآن وصلنا إلى النقطة التي سوف نبدأ بعرض ما صنعناه على المتصفح، وسوف نحتاج إلى إنشاء بعض المتحكِّمات Controllers والطرق Routes. سنبدأ أولا بالمتحكِّمات: php artisan make:controller ProjectsController php artisan make:controller TasksController الموارد المُضمّنة نبدأ بإضافة موارد Project و Task إلى app/Http/routes.php/ : Route::get('/', 'WelcomeController@index'); //Route::get('home', 'HomeController@index'); // //Route::controllers([ // 'auth' => 'Auth\AuthController', // 'password' => 'Auth\PasswordController', //]); Route::resource('projects', 'ProjectsController');Route::resource('tasks', 'TasksController'); والآن دعونا نرى إحدى مميزات artisan والمُتمثّلة في route:list، في سطر الأوامر أكتب التالي: php artisan route:list لتكون النّتيجة +--------+----------+--------------------------+------------------+-------------------------------------------------+------------+ | Domain | Method | URI | Name | Action | Middleware | +--------+----------+--------------------------+------------------+-------------------------------------------------+------------+ | | GET|HEAD | / | | App\Http\Controllers\WelcomeController@index | | | | GET|HEAD | projects | projects.index | App\Http\Controllers\ProjectsController@index | | | | GET|HEAD | projects/create | projects.create | App\Http\Controllers\ProjectsController@create | | | | POST | projects | projects.store | App\Http\Controllers\ProjectsController@store | | | | GET|HEAD | projects/{projects} | projects.show | App\Http\Controllers\ProjectsController@show | | | | GET|HEAD | projects/{projects}/edit | projects.edit | App\Http\Controllers\ProjectsController@edit | | | | PUT | projects/{projects} | projects.update | App\Http\Controllers\ProjectsController@update | | | | PATCH | projects/{projects} | | App\Http\Controllers\ProjectsController@update | | | | DELETE | projects/{projects} | projects.destroy | App\Http\Controllers\ProjectsController@destroy | | | | GET|HEAD | tasks | tasks.index | App\Http\Controllers\TasksController@index | | | | GET|HEAD | tasks/create | tasks.create | App\Http\Controllers\TasksController@create | | | | POST | tasks | tasks.store | App\Http\Controllers\TasksController@store | | | | GET|HEAD | tasks/{tasks} | tasks.show | App\Http\Controllers\TasksController@show | | | | GET|HEAD | tasks/{tasks}/edit | tasks.edit | App\Http\Controllers\TasksController@edit | | | | PUT | tasks/{tasks} | tasks.update | App\Http\Controllers\TasksController@update | | | | PATCH | tasks/{tasks} | | App\Http\Controllers\TasksController@update | | | | DELETE | tasks/{tasks} | tasks.destroy | App\Http\Controllers\TasksController@destroy | | +--------+----------+--------------------------+------------------+-------------------------------------------------+------------+ ستلاحظ أن كل من projects و tasks هي روابط ذات مستوى عالي، وفي تطبيقنا، المهام تتبع المشاريع، لذلك سيكون من الأفضل للروابط أن تكون مُضمّنة مثل /projects/1/tasks/3 بدلا من /tasks/، وهذا يمكن فعله باستخدام شيء اسمه الموارد المُضمّنة nested resources، وكما هو الحال مع أغلب الأشياء في Laravel، التعديل المطلوب سريع وبسيط، فقط قٌم بفتح /app/Http/routes.php وقٌم بالتعديلات التالية: // Route::resource('tasks', 'TasksController'); Route::resource('projects.tasks', 'TasksController'); هذا كل شيء، قُم بكتابة php artisan route:list لنعلم ماذا لدينا لحد الآن: php artisan route:list +--------+----------+----------------------------------------+------------------------+-------------------------------------------------+------------+ | Domain | Method | URI | Name | Action | Middleware | +--------+----------+----------------------------------------+------------------------+-------------------------------------------------+------------+ | | GET|HEAD | / | | App\Http\Controllers\WelcomeController@index | | | | GET|HEAD | projects | projects.index | App\Http\Controllers\ProjectsController@index | | | | GET|HEAD | projects/create | projects.create | App\Http\Controllers\ProjectsController@create | | | | POST | projects | projects.store | App\Http\Controllers\ProjectsController@store | | | | GET|HEAD | projects/{projects} | projects.show | App\Http\Controllers\ProjectsController@show | | | | GET|HEAD | projects/{projects}/edit | projects.edit | App\Http\Controllers\ProjectsController@edit | | | | PUT | projects/{projects} | projects.update | App\Http\Controllers\ProjectsController@update | | | | PATCH | projects/{projects} | | App\Http\Controllers\ProjectsController@update | | | | DELETE | projects/{projects} | projects.destroy | App\Http\Controllers\ProjectsController@destroy | | | | GET|HEAD | projects/{projects}/tasks | projects.tasks.index | App\Http\Controllers\TasksController@index | | | | GET|HEAD | projects/{projects}/tasks/create | projects.tasks.create | App\Http\Controllers\TasksController@create | | | | POST | projects/{projects}/tasks | projects.tasks.store | App\Http\Controllers\TasksController@store | | | | GET|HEAD | projects/{projects}/tasks/{tasks} | projects.tasks.show | App\Http\Controllers\TasksController@show | | | | GET|HEAD | projects/{projects}/tasks/{tasks}/edit | projects.tasks.edit | App\Http\Controllers\TasksController@edit | | | | PUT | projects/{projects}/tasks/{tasks} | projects.tasks.update | App\Http\Controllers\TasksController@update | | | | PATCH | projects/{projects}/tasks/{tasks} | | App\Http\Controllers\TasksController@update | | | | DELETE | projects/{projects}/tasks/{tasks} | projects.tasks.destroy | App\Http\Controllers\TasksController@destroy | | +--------+----------+----------------------------------------+------------------------+-------------------------------------------------+------------+ جعل روابط ذات اسم لطيف الطرق routes الحالية ممتازة لكنها ذات عناوين يمكن تحسينها، مثل هذا العنوان /projects/1/tasks/2، فسيكون من الرائع للزوار أن يتم تغيير المعرف الرقمي ID بالاسم اللطيف للحقول، فمثلا سوف نحصل على /projects/my-first-project/tasks/buy-milk بدلا من /projects/1/tasks/2. قم بفتح ملف /app/Http/routes.php وضع به التالي: Route::bind('tasks', function($value, $route) { return App\Task::whereSlug($value)->first(); }); Route::bind('projects', function($value, $route) { return App\Project::whereSlug($value)->first(); }); هذه الشيفرة سوف تغير السلوك الافتراضي لـ tasks و projects في artisan routes وجعل الروابط ذات إسم لطيف slug. خاتمة اليوم لقد قمنا بعمل عدة أشياء وهي: تثبيت وإعداد Laravel. إضافة موردان اثنان resources. إنشاء التهجيرات migrations. إضافة بعض بيانات البذور seeds. تكوين هيكل الروابط. بكلمات أخرى، قمنا اليوم بوضع الأساس التي سوف نعتمد عليه في الدروس القادمة من خلال إنشاء جميع العناصر اللازمة حتى تعمل الواجهة الأمامية، ولدينا الآن بعض البيانات في قاعدة البيانات بالإضافة إلى الطرق، في الدرس القادم سوف نبدأ في الواجهة الأمامية للموقع. هنالك بضعة مواقع أخرى لتحصل على المزيد من المعلومات وآخر الأخبار: The Laravel Twitter feed: أخر الأخبار حول تطورات Laravel. Taylor Otwell’s Twitter feed: حساب تويتر لمُؤسّس Laravel. Laravel.io: لمتابعة آخر الأخبار و الدورات من مختلف مواقع الويب، بالإضافة إلى بودكاست أسبوعي يتحدث عن الأفكار والاهتمامات ذات علاقة إلى المنصة. Laravel Packages Registry: مكان جيد لإيجاد أفضل حزم Laravel. Code Bright: كتاب إلكتروني مجاني من المؤلف دايلي ريس Dayle Rees. ترجمة وبتصرف للمقال: Creating a Basic ToDo Application in Laravel 5 – Part 1. حقوق الصورة البارزة: Designed by Freepik.