المحتوى عن 'تطبيق ويب'.



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

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

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

نوع المُحتوى


التصنيفات

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

التصنيفات

  • PHP
    • Laravel
    • ووردبريس
  • جافاسكريبت
    • Node.js
    • jQuery
    • AngularJS
    • Cordova
  • HTML
    • HTML5
  • CSS
  • SQL
  • سي شارب #C
    • منصة Xamarin
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • Sass
    • إطار عمل Bootstrap
    • إطار العمل 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

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

  1. نحن نصبح اليوم أكثر وأكثر انشغالًا باللحاق بوتيرة عالمنا المتسارعة، ونتلقى على الدوام كمًا كبيرًا من المعلومات المختلفة بأنواعها ومصادرها مضافة إليها الأفكار المتنوعة المتعلّقة بحياتنا العملية والشخصية والتي تراودنا يوميًا. ومع هذا الكم من المعلومات والأفكار، يصعب على عقولنا استيعابها وتذكرها، مما يجعلنا بحاجة إلى وسيلة لخزنها وتنظيمها. لحسن الحظ، هناك العديد من الأدوات والتطبيقات لحفظ الملاحظات مثل OneNote ،Google Keep ،Simplenote، إلخ. يتميّز من بين هذه الأدوات تطبيق Evernote الذي يستخدم لتسجيل الملاحظات، تخزينها وتنظيمها. يمكن أن تكون الملاحظات أي شيء من النصوص إلى الصور إلى الملفات الصوتية، كما يمكن أن تكون صفحات ويب أو رسائل بريد إلكتروني. ويمكن إنشاء هذه الملاحظات والوصول إليها من مختلف الأجهزة كأجهزة سطح المكتب، الهواتف، أو الأجهزة اللوحية. حيث يدعم التطبيق أنظمة Windows، Mac ،iOS Android، وكذلك الويب. وبالإضافة إلى حفظ الملاحظات وتنظيمها، يتيح التطبيق أيضًا إمكانية التعاون بين الزملاء والأصدقاء من خلال خاصية المشاركة والنشر. سنساعدك من خلال هذا الدرس، والدروس القادمة، على التعرّف على Evernote والخصائص التي يوفّرها لتدوين كل ملاحظاتك وأفكارك والاحتفاظ بها على منصة سهلة البحث والوصول. ملاحظة: توجد ثلاثة إصدارات من Evernote: Basic وهو مجاني Plus بسعر 25$/السنة Premium بسعر 50$/السنة ويمكنك الاطلاع على الخصائص المُتاحة مع كل إصدار بزيارة الصفحة الخاصة بالتطبيق Evernote. تنصيب Evernote كما ذكرنا أعلاه، يعمل Evernote على مختلف الأجهزة، ولتنصيبه على حاسوبك اذهب إلى صفحة تنزيل Evernote: اختر نوع الجهاز من القائمة، وسيتم تنزيل البرنامج على جهازك. قم بتنصيبه ثم التسجيل بإدخال عنوان بريدك الإلكتروني والكلمة السرية: بإمكانك أيضًا تنصيب التطبيق على أجهزتك المحمولة من متجر App Store أو متجر Google Play. كما بإمكانك استخدام التطبيق دون تنصيبه من خلال إصدار الويب. واجهة Evernote واضحة وسهلة، وهي تحتوي على شريط قوائم، شريط أدوات، بالإضافة إلى الجزء الأيسر Left Pane، قائمة الملاحظات Note List، ولوحة معاينة الملاحظات Note Panel التي تُعرض بشكل افتراضي عند فتح البرنامج لأول مرّة: بإمكانك التحكّم في عرض وإخفاء هذه الأجزاء من قائمة View: يضم الجزء الأيسر مجموعات دفاتر الملاحظات Notebooks والوسوم Tags التي تستخدم لتصنيف وتنظيم الملاحظات، بالإضافة إلى دفتر الملاحظات المحذوفة Trash. كيفية إنشاء الملاحظات الملاحظة هي عبارة عن أي شيء تريد حفظه من أجل الرجوع إليه لاحقًا عند الحاجة. بإمكانك حفظ ملاحظات نصية أو صوتية. كما بإمكانك حفظ صور، ملفات PDF، جداول بيانات، مستندات وورد، وغيرها من أنواع الملفات. وبذلك يصبح الوصول إليها سهلا من على أي جهاز. لإنشاء ملاحظة انقر على زر New Note من شريط الأدوات (أو اضغط على مفتاحي Ctrl+N): ستُفتح نافذة مستقلة تحتوي على مجموعة خيارات وأدوات خاصة بإنشاء وتنسيق ملاحظتك: ابدأ بإدخال عنوان للملاحظة في حقل Title، واختر دفتر الملاحظات الذي تريد حفظ الملاحظة فيه ثم قم بإضافة وسم لتصنيف الملاحظة بالنقر على Add Tag. إذا لم تقم بتحديد دفتر ملاحظات معيّن، سيتم حفظ الملاحظة تلقائيًا في دفتر الملاحظات الافتراضي الذي يُنشأ عند تنصيب البرنامج. ملاحظة: تستخدم الوسوم ودفاتر الملاحظات لتنظيم الملاحظات، وسنخصص لها درسًا إن شاء الله. أدوات تنسيق النصوص مثل نوع الخط، حجمه، سمكه، إلخ. يمكنك استخدام أداة التمييز اللوني Highlight إذا كنت تريد التركيز على عنصر معيّن في الملاحظة، أو استخدام Code Block لاحتواء الشيفرات إذا كانت ملاحظتك تحتوي على نصوص برمجية. أدوات تخطيط ومحاذاة نصوص الملاحظة. يمكنك استخدام التعداد النقطي أو التعداد الرقمي. وإذا كانت لديك مجموعة من العناصر تريد التركيز على إنهائها، قم بإنشاء قائمة تدقيق/مراجعة checklist ثم قم بتأشير العنصر الذي انتهيت منه. هناك أيضًا أدوات التحكم في محاذاة النص والمسافات البادئة. أدوات إدراج جدول بعدد صفوف وأعمدة محدد، أو إدراج خط فاصل. أدوات إرفاق ملفات متنوّعة أو تسجيل ملف صوتي. بإمكانك إرفاق الملفات بالنقر على زر مشبك الورق واختيار الملف، أو سحبه مباشرة من مجلد الحفظ وإفلاته في حقل تحرير الملاحظة. ولتسجيل ملاحظة صوتية انقر على أيقونة الميكروفون ثم على زر Record. أداة تكرار الأمر الأخير؛ أي تنفيذ آخر أمر تم استخدامه. إذا كانت ملاحظتك تتطلب الرجوع إليها في وقت محدّد، بإمكانك إضافة تذكير بوقت وتاريخ معيّنين بالنقر على زر السهم أمام عنوان الملاحظة ثم اختيار Reminder > Add Date لتحديد الوقت والتاريخ المرغوبين: لا يوجد هناك أمر لحفظ الملاحظة، لأنّها تُحفظ تلقائيًا كلّما قمت بتعديل محتوياتها. عند الانتهاء من إنشاء الملاحظة أغلق النافذة. تتم مزامنة الملاحظات مع الأجهزة الأخرى التي تستخدمها بشكل تلقائي أيضًا وكل فترة زمنية معيّنة. مع ذلك بإمكانك عمل المزامنة يدويًا بالنقر على أيقونة المزامنة Sync: إذا كنت ترغب في تغيير فترة المزامنة التلقائية للملاحظات بصورة عامة اذهب إلى: Tools > Options من تبويب Sync تأكّد من تأشير الخيار Synchronize automatically ثم اختر الفترة الزمنية المرغوبة من القائمة: بإمكانك تغيير طريقة عرض الملاحظات في قائمة الملاحظات، أو تغيير طريقة ترتيبها (حسب تاريخ الإنشاء أو التحديث أو حسب العنوان) وفرزها (حسب العنوان، دفتر الملاحظات، الوسم، إلخ) بالنقر على أيقونة المربعات واختيار الخيار المرغوب: تحرير الملاحظات بإمكانك تحرير الملاحظات التي قمت بإنشائها بنفسك أو التي قام أحد زملائك بمشاركتها معك (بشرط أن يكون نوع الترخيص عند المشاركة "Can Edit" أو "Can Edit and Invite"). انقر على الملاحظة بشكل مزدوج لفتحها. قم بإجراء التغييرات المرغوبة على النصوص، وبإمكانك استخدام الأوامر في قائمة Edit كالنسخ Copy، اللصق Paste، التراجع والإلغاء Undo & Redo أو الحذف Delete. تأكد من تحديد النص أو العنصر قبل أن تقوم بتطبيق الأمر: وكذلك لديك خيار البحث والاستبدال Find and Replace والتدقيق اللغوي Check Spelling. تتوفّر أيضًا مجموعة أدوات لتحرير الصور والتأشير عليها بإضافة أسهم، خطوط، تعليقات، أشكال، إلخ. مرر مؤشر الفأرة فوق الصورة التي تريد تحريرها ثم انقر على أيقونة تحرير الصورة (حرف a داخل دائرة): قم بإضافة ما يلزمك من تأشيرات على الصورة ثم أغلق النافذة. وإذا رغبت في إزالة جميع التأشيرات التي قمت بإضافتها افتح محرر الصورة ثم اذهب إلى: Edit > Clear Annotations بنفس الطريقة يمكنك التأشير على ملفات PDF. حذف الملاحظات لحذف ملاحظة من قائمة الملاحظات حدد الملاحظة ثم اذهب إلى: Edit > Delete (أو انقر على مفتاح Delete): لن يتم حذف الملاحظة نهائيًا، بل سيتم نقلها إلى دفتر الملاحظات المحذوفة Trash. يتم مزامنة مجلد Trash عبر جميع الأجهزة التي تستخدم Evernote عليها، لكن إذا قمت بحذف ملاحظة من دفتر ملاحظات محلي* لن يتم مزامنة تلك الملاحظة المحذوفة. *دفتر الملاحظات المحلي Local Notebook: هو دفتر الملاحظات الذي يحفظ على الجهاز الذي أنشأته عليه فقط ولا تتم مزامنته مع Evernote Service. ويُنشأ عبر المسار File> New Local Notebook. إذا رغبت في استرجاع الملاحظة المحذوفة، انقر عليها بزر الفأرة الأيمن واختر Restore Note: أمّا إذا رغبت في حذف الملاحظة من سلة المحذوفات بشكل نهائي، انقر عليها بزر الفأرة الأيمن واختر Expunge Note. كن حذرًا عن استخدام هذا الخيار لأنّك لن تتمكن من استرجاع الملاحظات المحذوفة بهذه الطريقة: بإمكانك أيضًا حذف جميع الملاحظات في مجلد Trash بشكل شامل ونهائي بالنقر عليه بزر الفأرة الأيمن واختيار Empty Trash: عرض الملاحظات باستخدام وضع العرض يعتبر وضع العرض Presentation Mode من الأدوات الرائعة التي تفيد في توفير الوقت إذا كنت ترغب في مشاركة المعلومات التي قمت بحفظها في ملاحظاتك مع زملائك أو أصدقائك. بإمكانك عرض الملاحظة على جهازك أو على شاشة عرض. هذه الخاصية تتوفر لمستخدمي الإصدار المدفوع Evernote Premium أو إصدار الشركات Evernote Business من التطبيق، لكنها تُتاح للمستخدمين الجدد كتجربة مجانية لمدة 30 يوم. لعرض ملاحظة معينة باستخدام وضع العرض انقر على زر السهم أمام عنوان الملاحظة واختر Present: سيقوم التطبيق بتعديل الخط ليناسب حجم الشاشة كما سيقسّم الملاحظة (إن اقتضت الحاجة) إلى عدة صفحات يمكنك تصفّحها بالضغط على مفتاح Space: بإمكانك اختيار نوع المؤشر وتشغيل الوضع الليلي من الأزرار في الزاوية العليا اليمنى. ولإغلاق وضع العرض انقر على أيقونة ×.
  2. بعد أن تعرّفنا على أساسيات لغة بايثون حان الوقت للانتقال إلى مرحلة جديدة. في هذه السّلسلة من الدّروس سنتعرّف على أساسيات تطوير تطبيقات الويب بلغة بايثون، وذلك بالاستعانة بإطار العمل Flask، يعتبر Flask إطارا مُصغّرا Micro-Framework أي أنّه يُقدّم للمُبرمج أدوات مُساعدة بسيطة، وبعكس إطار Django فهو مُناسب للمُبتدئين الذين تعرّفوا على لغة بايثون حديثا. متطلبات هذه السلسلة لمتابعة هذه الدّروس وفهمها، ستحتاج إلى معرفة بسيطة بلغة بايثون. ستحتاج كذلك إلى معرفة بسيطة بلغة HTML الهيكلية، وكذلك القليل من لغة CSS لتنسيق الصّفحات إذ لن أشرح ما يتعلق بلغة HTML وCSS لأنّ ذلك ليس من اختصاص السّلسلة. يمكنك مراجعة الدروس التالية على أكاديمية حسوب لتعلم أساسيات هذه اللغات: سلسلة دروس تعلم لغة بايثون تعلّم لغة HTML ولغة CSS ما هو تطبيق الويب؟ تطبيق الويب، هو كل تطبيق يُمكن الوصول إليه عن طريق مُتصفّح للويب (Firefox ،Chrome ،Safari) ويقوم بتقديم صفحات مرئية حسب طلب الزّائر. يُمكن اعتبار موقع الأكاديمية هذا تطبيق ويب، إذ يتفاعل مع الزائر بتقديم المقالات بشكل متناسق، ويوفّر إمكانية المُشاركة للمُستخدمين عبر صندوق التّعليقات وغير ذلك من الخصائص. الصفحة التي تقرأ منها هذا المقال حاليا أصلها شيفرات لغة HTML وهي لغة أساسية في الويب. وتُستعمل لغات البرمجة مثل لغة Python لتقديم شيفرة HTML من الخادوم إلى المُتصفّح الذي يعرضها بدوره للمُستخدم. ما يعني أنّ الهدف النهائي من برمجة التّطبيق هو تقديم ملفات HTML من الخادوم إلى العميل (المُستخدم). خلاصة القول أنّك عندما تدخل إلى موقع الأكاديمية عن طريق رابط academy.hsoub.com، يرسل المُتصفّح طلبا للخادوم الخاص بالأكاديمية، عندما يستقبل الخادوم الطلب يقوم مُباشرة بتنفيذ الشيفرة المكتوبة بلغة برمجية، الشيفرة البرمجيّة تُجيب بملفات HTML ويعرضها لك المُتصفّح فور استقبالها. ما سنتعلّمه في هذه السّلسلة هو كيفيّة التعامل مع طلبات المُستخدم وكيفيّة تقديم ملفات HTML للمُتصفّح باستخدام لغة بايثون. ما هو إطار العمل؟ إطار العمل هو مجموعة من المكتبات والوحدات التي تحتوي على دوال مُساعدة تُمكّن المُبرمج من كتابة تطبيقات دون الاضطرار إلى التعامل مع التفاصيل الدقيقة التي تتطلب وقتا وجهدا كبيرين. يُمكن أن يكون إطار العمل خاصا بتطوير تطبيقات الويب مثل Flask أو Django، ويُمكن كذلك أن يكون مُخصّصا لمجالات أخرى كبناء تطبيقات سطح المكتب مثلا. تتوفّر لغة بايثون على العديد من أطر العمل الخاصّة بتطوير الويب، والتالي قائمة ببعض الأطر مع وصف مختصر لكلّ إطار. Django: إطار عمل ضخم، يتوفّر على عدد هائل من الدوال المُساعدة، كما يعتبر أنسب خيار لمن يرغب بتطوير تطبيقات كبيرة ومُعقّدة متعدّدة الوظائف، يتميّز بشهرته الواسعة وهو سهل التّعلم، يعتبر مناسبا كذلك لمن يرغب بإنشاء تطبيق بسرعة وهو شائع بين الشّركات النّاشئة. Flask: إطار عمل مُصغّر/صغير، يتوفّر على عدد لا بأس به من الدوال المُساعدة، شهرته تقريبا بنفس شهرة Django، مُناسب لتطوير تطبيقات صغيرة ومُتوسّطة (مُدونة، منتدى، موقع شخصي… ). Tornado: إطار عمل مُخصّص للتطبيقات التي تتطلب سرعة في مُعالجة الطّلبات وسرعة في التجاوب كتطبيقات الدّردشة مثلا. Bottle: إطار عمل صغير جدا، يوفّر أدنى المُتطلبات لتطوير تطبيق بسرعة، ويعتبر أصغر من إطار Flask. سبق وأن نشرنا درسا عنه. TurboGears: خصائصه تقترب من خصائص إطار Django، الاختلاف الرئيسي يكمن في الأدوات والمكتبات التي يعتمد عليها كالاتصال بقواعد البيانات وما إلى ذلك ويُعتبر خيارا آخر لمن يرغب بتطوير تطبيقات كبيرة. صحيح أن هناك أطر عمل أخرى لكنّ ما تقدّم ذكره يعتبر أبرزها. لماذا Flask؟ وقع الاختيار على إطار العمل Flask لسهولة تعلّمه بالنّسبة للمبتدئ، إذ سيبدو مألوفا لمن تعرّف حديثا على لغة بايثون، وبما أنّه إطار عمل مُصغّر فسيسهل عليك فهم خطوات إنشاء تطبيق كامل، خاصّة أنّك تستطيع أن تبني تطبيقا في ملفّ بايثون واحد. يتميّز إطار Flask كذلك بإتاحة إمكانيّة ربط تطبيقك بمُختلف مكتبات لغة بايثون، والتي يُمكنك تنصيبها بسهولة بأداة pip، وهي أداة لإدارة الحزم (مثل Gem بالنّسبة للغة روبي و Composer بالنّسبة للغة PHP). يُمكن كذلك الاعتماد على إضافات لجعل الإطار أقرب إلى الأطر الكبيرة مثل Django إذ يمتلك إطار العمل Flask العديد من الإضافات التي يُمكنك تنصيبها واستعمالها في مشروعك، ما يُمكن أن يُساعدك على إنشاء مشاريع كبيرة. Flask أم Django؟ يعتبر الاختيار بين إطار Flask وإطار Django من القرارات الصّعبة على المُبتدئ، لكنّ عليك فهم الفرق بين الإطارين لتختار ما يُناسبك، فكما قلنا سابقا فإطار Django يُوفّر عددا هائلا من الدوال والأدوات المُساعدة، أما إطار Flask فيُوفّر أدوات بسيطة وعددا أقلّ من الدوال المُساعدة. يُمكنك اختيار تعلّم إطار Django إذا كانت لديك خبرة مُسبقة بأحد أطر العمل في اللغات الأخرى مثل Laravel أو Ruby On Rails، كما يُنصح به إذا كان المشروع الذي ستعمل عليه كبيرا كتطبيق تواصل اجتماعي أو تطبيق خدمي. أما إذا لم تكن تملك أية خبرة مُسبقة فأنصح بتعلّم إطار Flask أولا، وبعد التمكن من التعامل معه وإتقان ذلك يُمكنك الانتقال إلى استعمال Django متى ما دعت الحاجة إلى ذلك، وستجد حينها بأنّ الوقت الذي استثمرته في تعلّم Flask قد أتى أكله، وسيسهل عليك تعلّم إطار Django وفهم كيفيّة عمله. كيف تستفيد من هذه السلسلة من الدروس؟ سلسلة الدروس هذه ستكون موزعة حسب المُخطّط التالي: إعداد بيئة التّطوير وإنشاء تطبيقك الأول تقديم ملفات HTML وملفات CSS والصور استخدام قاعدة بيانات مع تطبيق Flask كل درس سيكون شبه مُستقل عن الدّرس الذي يسبقه، وذلك لتكون الدروس مرجعا لك في حالة نسيان أي جزئية. في نهاية السّلسلة ستكون قادرا على استعمال لغة بايثون لتطوير تطبيق يعمل على المُتصفّح ويتصل بقاعدة بيانات. ختاما في الدّرس المُقبل سنقوم بإعداد بيئة التّطوير بتنصيب الأدوات المطلوبة، كما سننشئ تطبيقا بسيطا لعرض صفحة ويب على المُتصفّح.
  3. هذا الدرس جزء من سلسلة تعلم 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 لتوليد بيانات وهمية قصدَ الاختبار. نكمل بناء متجرنا الإلكتروني بإضافة خاصية سلة المشتريات. سنستخدم حزمة Laravel ShoppingCart لإضافة هذه الخاصية إلى المشروع. يغطي الدرس المواضيع التالية: تثبيت حزمة Laravel Shopping Cart بـComposer. إعداد Laravel 5 لاستخدام الحزمة.إضافة عناصر إلى سلة المشتريات.العثور على العناصر الموجودة في سلة المشتريات.تحديث عنصر في سلة المشتريات.حذف عنصر من سلة المشتريات.استخدام Composer لتثبيت Laravel Shopping Cartنفتح ملف composer.json لإضافة اعتمادية جديدة للمشروع. نبحث عن فقرة require: "require": { "php": ">=5.5.9", "laravel/framework": "5.2.*", "doctrine/dbal": "v2.4.2" },نضيف حزمة ShoppingCart على النحو التالي: "require": { "php": ">=5.5.9", "laravel/framework": "5.2.*", "doctrine/dbal": "v2.4.2", "gloudemans/shoppingcart": "~1.3" },ملحوظة: انتبه للفواصل في نهاية الأسطر. نعلم Composer أننا نريد تثبيت الإصدار 1.3 من الحزمة gloudemans/shoppingcart؛ ثم نحدّث المشروع بتنفيذ الأمر التالي: composer updateإعداد Laravel لاستخدام حزمة ShoppingCartنحتاج بعد تثبيت حزمة ShoppingCart لإعداد Laravel للعمل معها. نفتح ملف الإعداد config/app.php ونضيف السطر التالي إلى مصفوفة providers: Gloudemans\Shoppingcart\ShoppingcartServiceProvider::class,يسجل الإعداد أعلاه مزوّد خدمة Provider لسلة المشتريات. ملحوظة: يتيح مزود الخدمة Service Provider في Laravel تحميل صنف (في الذاكرة) مع بدء عمل التطبيق، كما أنه يمكِّن من إضافة عناصر جديدة إلى حاويات الخدمة Service container وهي أداة تدير الاعتمادات بين مختلف الأصناف في إطار العمل. سنضيف الآن كنية Alias لصنف سلة المشتريات. افتح ملف الإعداد config/app.php وأضف العنصر التالي إلى مصفوفة aliases: 'Cart' => Gloudemans\Shoppingcart\Facades\Cart::class,ملحوظة: الكنى Aliases هي أسماء مختصرة للأصناف تُكتب بدلا من الاسم الكامل للصنف. يسجّل التطبيقُ عند بدئه هذه الأصنافَ لكنه لا يحملها إلا عند الحاجة. إضافة عناصر لسلة المشترياتسنضيف في هذه الفقرة إمكانية إضافة عنصر إلى سلة المشتريات في صفحة المنتج. تُجرى العملية على ثلاث خطوات: إنشاء مسار لإجراء HTTP POST الذي يضيف العناصر إلى سلة المشتريات.التعديل على القالب products.blade.php من أجل تضمين استمارة لإرسال البيانات مع معرّف المنتَج.التعديل على المتحكم Front.php لكي يتبقى بيانات الاستمارة ويضيفها إلى السلة.مسار إجراء HTTP POSTافتح ملف المسارات routes.php وأضف المسار التالي: Route::post('/cart', 'Front@cart');يعرف السطر السابق مسارات لتلقي إجراءات POST على رابط سلة المشتريات. سيُستخدَم هذا المسار لإضافة عناصر إلى سلة المشتريات. استمارة صفحة المنتجالخطوة التالية هي التعديل على قالب صفحة المنتج وإضافة استمارة form لإرسال معرّف المنتج إلى سلة المشتريات من أجل إضافته إليها. افتح ملف العرض products.blade.php وعدّله ليصبح محتواه التالي: @extends('layouts.layout') @section('content') <section id="advertisement"> <div class="container"> <img src="{{asset('images/shop/advertisement.jpg')}}" alt="" /> </div> </section> <section> <div class="container"> <div class="row"> <div class="col-sm-3"> <div class="left-sidebar"> @include('shared.sidebar') </div> </div> <div class="col-sm-9 padding-right"> <div class="features_items"><!--features_items--> <h2 class="title text-center">Features Items</h2> @foreach ($products as $product) <div class="col-sm-4"> <div class="product-image-wrapper"> <div class="single-products"> <div class="productinfo text-center"> <img src="{{asset('images/shop/product9.jpg')}}" alt="" /> <h2>${{$product->price}}</h2> <p>{{$product->name}}</p> <a href="{{url('cart')}}" class="btn btn-default add-to-cart"><i class="fa fa-shopping-cart"></i>Add to cart</a> <a href='{{url("products/details/$product->id")}}' class="btn btn-default add-to-cart"><i class="fa fa-info"></i>View Details</a> </div> <div class="product-overlay"> <div class="overlay-content"> <h2>${{$product->price}}</h2> <p>${{$product->name}}</p> <form method="POST" action="{{url('cart')}}"> <input type="hidden" name="product_id" value="{{$product->id}}"> <input type="hidden" name="_token" value="{{ csrf_token() }}"> <button type="submit" class="btn btn-fefault add-to-cart"> <i class="fa fa-shopping-cart"></i> Add to cart </button> </form> <a href='{{url("products/details/$product->id")}}' class="btn btn-default add-to-cart"><i class="fa fa-info"></i>View Details</a> </div> </div> </div> <div class="choose"> <ul class="nav nav-pills nav-justified"> <li><a href=""><i class="fa fa-plus-square"></i>Add to wishlist</a></li> <li><a href=""><i class="fa fa-plus-square"></i>Add to compare</a></li> </ul> </div> </div> </div> @endforeach <ul class="pagination"> <li class="active"><a href="">1</a></li> <li><a href="">2</a></li> <li><a href="">3</a></li> <li><a href="">»</a></li> </ul> </div><!--features_items--> </div> </div> </div> </section> @endsection التغيير الأساسي هنا هو إضافة استمارة form مع إجراء post: <form method="POST" action="{{url('cart')}}">...</form>تُرسل الاستمارة معرف المنتج إلى سلة المشتريات الذي يعرفه حقل product_id: <input type="hidden" name="product_id" value="{{$product->id}}">تحتوي الاستمارة أيضا على عنصر أمني هو: <input type="hidden" name="token" value="{{ csrftoken() }}">الذي يعرف رمز أمان Security token للحماية ضد هجمات تزوير الطلب عبر الموقع Cross-site request forgery (تُكتب CSRF أو XCRF اختصارا). احفظ التعديلات. ملحوظة: تقوم هجمات تزوير الطلب عبر الموقع على البحث عن روابط تمكن إعادة استخدامها لتنفيذ إجراءات معينة تحتاج لصلاحيات خاصة، تتوفر عادة عند المستخدمين المسجلين، ثم الاحتيال عليهم لكي يفتحوا هذه الروابط - غالبا دون علمهم - وتنفيذ الإجراءات الطلوبة. تحمي رموز الأمان المستخدمين من هذه الهجمات. التعديل على المتحكم Frontنحتاج، ليمكن لنا استخدام سلة المشتريات، التعديل على دالة cart لاستيرد فضاء الأسماء Cart. افتح ملف المتحكم Front.php وأضف الأسطر التالية لاستيراد فضاءات الأسماء Redirect، Request وCart على التوالي: يُستخدَم Request للوصول إلى بيانات إجراءات HTTP. يُستخدَم Redirect لتوجيه المستخدم بعد تنفيذ عملية لا تحتاج لإظهار بيانات في الصفحة.للوصول إلى عناصر سلة المشتريات نستخدم Cart.اعثُر على الدالة cart في المتحكم Front.php وحدّثها كالتالي: public function cart() { if (Request::isMethod('post')) { $product_id = Request::get('product_id'); $product = Product::find($product_id); Cart::add(array('id' => $product_id, 'name' => $product->name, 'qty' => 1, 'price' => $product->price)); } $cart = Cart::content(); return view('cart', array('cart' => $cart, 'title' => 'Welcome', 'description' => '', 'page' => 'home')); }نفحص أولا نوع إجراء HTTP الذي أتى منه الطلب إلى الدالة: if if (Request::isMethod(‘فإن كان الإجراء من نوع POST ننفذ الشفرة الموالية. نعثر علي معرف المنتج المُرسَل في الطلب: $productid = Request::get('productid');دالة Request::get لا تتعلق بنوعية إجراء HTTP ويتساوى عندها POST وGET. تُستخدَم هذه الدالة للعثور على متغيرات مرسلة في الطلب. نستخدم نموذج المنتج Product للعثور على المنتج في قاعدة البيانات: $product = Product::find($product_id);نستخدم كائن المنتج في التعليمة السابقة للحصول على بيانات المنتج وإضافتها إلى سلة المشتريات بإرسال نداء إلى الدالة Cart::add: Cart::add(array('id' => $product_id, 'name' => $product->name, 'qty' => 1, 'price' => $product->price));ننادي الدالة Cart::content للحصول على محتوى سلة المشتريات ونضيفه إلى المتغيرات الممررة إلى العرض cart.blade.php: $cart = Cart::content(); return view('cart', array('cart' => $cart, 'title' => 'Welcome', 'description' => '', 'page' => 'home'));العثور على العناصر الموجودة في سلة المشترياتبقيت لنا خطوة واحدة قبل أن نستطيع تجربة سلة المشتريات. نحتاج لتعديل العرض cart لكي يُظهر محتويات السلة. نفتح ملف العرض cart.blade.php لتحريره. نعدّل الملف على النحو التالي: @extends('layouts.layout') @section('content') <section id="cart_items"> <div class="container"> <div class="breadcrumbs"> <ol class="breadcrumb"> <li><a href="#">Home</a></li> <li class="active">Shopping Cart</li> </ol> </div> <div class="table-responsive cart_info"> @if(count($cart)) <table class="table table-condensed"> <thead> <tr class="cart_menu"> <td class="image">Item</td> <td class="description"></td> <td class="price">Price</td> <td class="quantity">Quantity</td> <td class="total">Total</td> <td></td> </tr> </thead> <tbody> @foreach($cart as $item) <tr> <td class="cart_product"> <a href=""><img src="images/cart/one.png" alt=""></a> </td> <td class="cart_description"> <h4><a href="">{{$item->name}}</a></h4> <p>Web ID: {{$item->id}}</p> </td> <td class="cart_price"> <p>${{$item->price}}</p> </td> <td class="cart_quantity"> <div class="cart_quantity_button"> <a class="cart_quantity_up" href=""> + </a> <input class="cart_quantity_input" type="text" name="quantity" value="{{$item->qty}}" autocomplete="off" size="2"> <a class="cart_quantity_down" href=""> - </a> </div> </td> <td class="cart_total"> <p class="cart_total_price">${{$item->subtotal}}</p> </td> <td class="cart_delete"> <a class="cart_quantity_delete" href=""><i class="fa fa-times"></i></a> </td> </tr> @endforeach @else <p>You have no items in the shopping cart</p> @endif </tbody> </table> </div> </div> </section> <!--/#cart_items--> <section id="do_action"> <div class="container"> <div class="heading"> <h3>What would you like to do next?</h3> <p>Choose if you have a discount code or reward points you want to use or would like to estimate your delivery cost.</p> </div> <div class="row"> <div class="col-sm-6"> <div class="chose_area"> <ul class="user_option"> <li> <input type="checkbox"> <label>Use Coupon Code</label> </li> <li> <input type="checkbox"> <label>Use Gift Voucher</label> </li> <li> <input type="checkbox"> <label>Estimate Shipping & Taxes</label> </li> </ul> <ul class="user_info"> <li class="single_field"> <label>Country:</label> <select> <option>United States</option> <option>Bangladesh</option> <option>UK</option> <option>India</option> <option>Pakistan</option> <option>Ucrane</option> <option>Canada</option> <option>Dubai</option> </select> </li> <li class="single_field"> <label>Region / State:</label> <select> <option>Select</option> <option>Dhaka</option> <option>London</option> <option>Dillih</option> <option>Lahore</option> <option>Alaska</option> <option>Canada</option> <option>Dubai</option> </select> </li> <li class="single_field zip-field"> <label>Zip Code:</label> <input type="text"> </li> </ul> <a class="btn btn-default update" href="">Get Quotes</a> <a class="btn btn-default check_out" href="">Continue</a> </div> </div> <div class="col-sm-6"> <div class="total_area"> <ul> <li>Cart Sub Total <span>$59</span></li> <li>Eco Tax <span>$2</span></li> <li>Shipping Cost <span>Free</span></li> <li>Total <span>${{Cart::total()}}</span></li> </ul> <a class="btn btn-default update" href="{{url('clear-cart')}}">Clear Cart</a> <a class="btn btn-default check_out" href="{{url('checkout')}}">Check Out</a> </div> </div> </div> </div> </section><!--/#do_action--> @endsection نستخدم الدالة count لتحديد ما إذا كان المتغير cart يحوي أي عناصر، فإن كان أنشأنا جدولا لعرض عناصر سلة المشتريات ديناميكيا: @if(count($cart)) <table class="table table-condensed">نستخدم الحلقة التكرارية foreach لعدّ عناصر سلة المشتريات: @foreach(item) لكل منتج في سلة المشتريات نعرض اسم المنتج، معرّفه، ثمنه ومجموعا فرعيا Subtotal لتكلفة المنتج على التوالي: {{$item->name}} {{$item->id}} {{$item->price}} {{$item->subtotal}}المجموع الفرعي هو حاصل ضرب ثمن المنتج بكميّته. في الأسفل نعرض الثمن الكلي للمنتجات الموجودة في سلة المشتريات: {{Cart::total()}}تحديث العناصر الموجودة في سلة المشترياتنضيف في هذه الفقرة إمكانية تحديث كمية المنتج في سلة المشتريات بالنقر على زر الزيادة + أو النقصان - بجانب الكمية. سنستخدم لهذا الغرض الاستعلام عن طريق رابط URL. افتح ملف العرض cart.blade.php واعثر على السطرين: <a class="cart_quantity_up" href=""> + </a> <a class="cart_quantity_down" href=""> - </a>حدّث الشفرة المصدرية لكل منهما حتى تصبح على النحو التالي: <a class="cart_quantity_up" href='{{url("cart?product_id=$item->id&increment=1")}}'> + </a> <a class="cart_quantity_down" href='{{url("cart?product_id=$item->id&decrease=1")}}'> - </a>تولد الشفرة: {{url("cart?productid=$item->id&increment=1")}}رابطا بالهيئة http://larashop.dev/cart?productid=1&increment=1. يعيّن الرابط معرّف المنتج الذي نريد تحديث كميته واتجاه التحديث. إذا كان المتسوق يريد زيادة الكمية (نقر على +) نعطي القيمة 1 للمعطى increment؛ أما إذا كان المتسوق يريد نقص الكمية (نقر على -) فنعطي القيمة 1 للمتغير decrease. يجب الآن تعديل المتحكم للتعاطي مع رغبة المتسوق في تحديث الكمية. نعدل الدالة cart لتصبح على النحو التالي: public function cart() { // إضافة منتج جديد إلى سلة المشتريات if (Request::isMethod('post')) { $product_id = Request::get('product_id'); $product = Product::find($product_id); Cart::add(array('id' => $product_id, 'name' => $product->name, 'qty' => 1, 'price' => $product->price)); } // زيادة كمية منتج في سلة المشتريات if (Request::get('product_id') && (Request::get('increment')) == 1) { $rowId = Cart::search(array('id' => Request::get('product_id'))); $item = Cart::get($rowId[0]); Cart::update($rowId[0], $item->qty + 1); } // نقص كمية منتج في سلة المشتريات if (Request::get('product_id') && (Request::get('decrease')) == 1) { $rowId = Cart::search(array('id' => Request::get('product_id'))); $item = Cart::get($rowId[0]); Cart::update($rowId[0], $item->qty - 1); } $cart = Cart::content(); return view('cart', array('cart' => $cart, 'title' => 'Welcome', 'description' => '', 'page' => 'home')); } في الشيفرة أعلاه نتحقق من تعيين المتغيّرين product_id وincrement. if (Request::get('product_id') && (Request::get('increment')) == 1)إذا كان المتغيران معيَّنيْن وقيمة المتغيّر increment تساوي 1 فهذا يعني أن المتسوق أراد زيادة الكمية. يستخدم السطر الموالي معرّف المنتج product_id للبحث بين عناصر سلة المشتريات ويرجع مصفوفة بمعرّفات أسطُر rowId موافقة للبحث: $rowId = Cart::search(array('id' => Request::get('product_id')));معرّف السطر هو معرّف وحيد لعنصُر في السلة يُولّد تلقائيا، ويُستخدَم لتحديث العناصر في السلة. نستخدم معرف العنصر للعثور على كائن يمثل المنتج في سلة المشتريات: $item = Cart::get($rowId[0]);نحتفظ بالعنصر الأول من المصفوفة التي ترجعها الدالة Cart::get، في حالتنا لا يوجد سوى عنصر واحد. نبحث عن كائن المنتج لمعرفة الكمية الموجودة في السلة وبالتالي يمكن لنا زيادتها أو نقصها. نستدعي الدالة Cart::update ونمرر لها معرف المنتج ونزيد الكمية بـ1: Cart::update($rowId[0], $item->qty + 1); السطر الموالي يتحقق من تعيين المتغيرين product_id وdecrease: if (Request::get('productid') && (Request::get('decrease')) == 1)وفي حال كانت الإجابة نعم يفحص قيمة المتغير decrease وإذا كانت 1 ينقص كمية المنتج بـ1 في سلة المشتريات: Cart::update($rowId[0], $item->qty 1); افتح رابط صفحة المنتجات http://larashop.dev/products، اختر أحدها بتمرير المؤشر فوقه وأضفه إلى سلة المشتريات بالنقر على زر Add to cart. ستحصل على النتيجة التالية (تتغير النتيجة حسب المنتج الذي اخترته في الخطوة السابقة). اضغط على الزر + لزيادة كمية منتج في سلة المشتريات. لاحظ تغير المجموع الفرعي مع تغير الكمية. حذف عناصر من سلة المشترياتحذفُ عنصُر من سلة المشتريات مشابه لتحديثه: $rowId = Cart::search(array('id' => Request::get('product_id'))); Cart::remove($rowId[0]); تحذف الدالة Cart::remove عنصرا من سلة المشتريات اعتمادا على معرف السطر الممرَّر إليها. لحذف جميع عناصر سلة المشتريات دفعة واحدة نستخدم الدالة Cart::destroy. خاتمةكان الهدف من هذا الدرس شرح كيفية تثبيت حزمة Laravel ShoppingCart واستخدامها في مشروع Laravel الخاص بك للحصول على ميزة سلة مشتريات. استعملنا خلال هذا الدرس الحزمة في صفحة المنتج، يمكنك التوسع في استخدام الحزمة في صفحات الموقع الأخرى إن أردت. ترجمة -وبتصرّف- لمقال Laravel 5 Shopping Cart لصاحبه Rodrick Kazembe.
  4. كثُر الحديث في السنوات الأخيرة عن إطار العمل Laravel وانتشر بين مطوّري PHP حتى إنه أصبح إطار العمل الأكثر استخداما بينهم، سواء للمشاريع الشخصية أو المهنية، حسب استبيان أجراه موقع SitePoint الشهير. كما أنه من أكثر المشاريع التي يُساهَم فيها على GitHub. سنتعرّف في سلسلة الدّروس هذه، التي يمثّل هذا المقال مقدّمة لها، على إطار العمل Laravel وأهم المبادئ التي يعمل وفقا لها. لماذا Laravel؟توجد الكثير من الأسباب التي تدعو لاختيار Laravel منها ماهو نفعيّ (انتشار أكبر يعني فرصًا أكثر للحصول على فرص توظيف) ومنها ماهو تقني بحت. قبل الإجابة على السؤال "لماذا Laravel؟" قد يكون من المفيد محاولة الإجابة عن "لماذا إطار عمل؟" بمعنى آخر ألا يمكنك كمطوّر PHP البدء من الصفر وبناء تطبيقك حسب الحاجة؟ يمكننا القول -باختصار- أن أطر العمل تجعلك تتخلص من ضرورة الاعتناء بتفاصيل كثيرة، ترفع كثيرا من إنتاجيتك وتقيك من أخطاء التعامل المباشر مع بيئة لغة البرمجة من قبيل أخطاء التعامل مع استعلامات قواعد البيانات التي قد تنتج عنها هجمات الحقن بتعليمات SQL المعروفة بــSQL injection. تفرِض أطر العمل الجيدة على مستخدميها الفصل بين أجزاء التطبيق وتنفيذ بنية Architecture مجرَّبة تؤدي في النهاية إلى الرفع من تصميم التطبيق وجعل الشفرة المصدرية أيسر في القراءة وأسهل في الصيانة والاختبار. نجمل في ما يلي أهم الأسباب التي تجعل من اختيار Laravel مناسبًا: سهولة الاستخدام.الفصل بين عناصر التطبيق مما يسهل عمل فريق من المطوّرين وتقاسم المهامّ بينهم.دعم التطوير السريع للتطبيقات Rapid Application Developing, RAD: توفر أداة Artisan وسيلة سريعة لإنشاء شفرة مصدرية نمطية للتعديل المباشر عليها. كما أنها تُستخدَم لمهامّ أخرى مثل تشغيل الاختبارات الأحادية Unit tests، تهجير قواعد البيانات، وغيرها.التضمين الافتراضي لوظائف شائعة الاستخدام في تطبيقات الويب، مثل الاستيثاق Authentication، التوجيه Routing، إدارة قواعد البيانات، إرسال البريد الإلكتروني.متحكمات RESTful: يعني هذا أنه يمكن الاستفادة من أفعال HTTP القياسية مثل PUT، POST، GET وDELETE.إدارة الاعتماديات Dependencies باستخدام Composer وهو ما يعني إمكانية استخدام الحزم والمكتبات الموجودة على الموقع www.packagist.com بيُسر ضمن مشاريعك.استخدام إطار العمل Eloquent وهو إطار للربط بين الكائنات في قاعدة البيانات والتصنيفات في شفرة التطبيق Object Relational Mapper.بنية MVCتتبع المشاريع في إطار العمل Laravel بنية Model-View-Controller (تُختصر بـMVC) التي تقسّم التطبيق إلى ثلاثة أجزاء متصلة في ما بينها، وتُفرّق بين التمثيل الداخلي للمعلومة والطرق التي تُقدَّم بها المعلومة إلى المستخدم. يقع جزء النموذج Model في قلب بنية التطبيق؛ تُعالَج في هذا القسم البيانات وتُنفَّذ عليها القواعد (في تطبيق محاسبة تنتمي الفواتير والعمليات عليها إلى هذا الجزء). يتولى الجزء الثاني في البنية وهو العرض View مهمة تقديم البيانات إلى المستخدم. يمكن أن تأخذ نفس البيانات أشكالا عدّة للعرض (مخطّط بياني، جدول، … إلخ). أما الجزء الثالث (المتحكِّم Controller) فيأخذ مُدخلات ويحوّلها إلى أوامر يرسلها للنموذج والعرض. يمكن شرح الأمر على النحو التالي: يرسل المتحكّم أمرا إلى النموذج لتعديل حالته (تحرير فاتورة). كما يمكنه إرسال أمر إلى العرض بتغيير طريقة تقديم البيانات (الانتقال بين أسطر الفاتورة).يخزّن النموذج البيانات المعثور عليها وفقا لأوامر المتحكّم وتلك المعروضة في العرض.يولّد العرض مخرجات للمستخدم حسب البيانات الخزّنة في النموذج.يجمل المخطط البياني التالي آلية العمل. سلسلة دروس Laravel: إنشاء تطبيق ويب للتسوقننطلق في سلسلة الدروس هذه من مبدأ أن أفضل وسيلة للتعلم هي الممارسة، لذا سنبدأ خطوة خطوة بإنشاء تطبيق ويب للتسوق مع ميزة سلة المشتريات. تعطي الصورة التالية فكرة عن شكل الموقع الذي نريد إنشاءه. تشمل السلسلة المواضيع التالية: تثبيت Laravel وإعداده على كلّ من Windows وUbuntu.أساسيات بناء تطبيق باستخدام Laravel.إنشاء روابط محسنة لمحركات البحث (SEO) في إطار عمل Laravel.نظام Blade للقوالب.تهجير قواعد البيانات في Laravel.استخدام Eloquent ORM لإدخال البيانات في قاعدة البيانات، تحديثها أو حذفها.إنشاء سلة مشتريات في Laravel.الاستيثاق في Laravel.إنشاء واجهة لبرمجة التطبيقات API في Laravel.إنشاء مدوّنة باستخدام Laravel.استخدام AngularJS واجهةً أمامية Front end لتطبيق Laravel.الدوّال المساعدة المخصّصة في Laravel.استخدام مكتبة Faker في تطبيق Laravel لتوليد بيانات وهمية قصدَ الاختبار.ترجمة -بتصرّف- لمقال Laravel 5 Tutorial لصاحبه Rodrick Kazembe.
  5. يهدف هذا الدرس إلى بناء تطبيق CRUD (إدراج بيانات في قاعدة بيانات، القراءة منها، تحديثها وحذفها؛ اختصار لـUpdate، Read، Create وDelete). التطبيق عبارة عن واجهة لإدارة لائحة من الموظفين: إضافة موظّف، تحرير بياناته أو حذفها. سنستخدم Laravel 5 للنهاية الخلفية Backend و AngularJS للنهاية الأمامية Frontend. سنستخدم أيضا Bootstrap لإضافة لمسة جمالية إلى التطبيق. هذا الدرس جزء من سلسلة تعلم 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 لتوليد بيانات وهمية قصدَ الاختبار. AngularJS هو إطار عمل جافاسكريبت قويّ وفعّال، يتبنى مبدأ النموذج-العرض-المتحكم MVC ويعمل لدى العميل (المتصفّح). للاطلاع على المزيد عن AngularJS تابع سلسلة دروس مدخل إلى تعلم AngularJS . يفترض هذا الدرس معرفة أساسيات Laravel 5، تثبيت كلّ من PHP، MySQL، ِApache وComposer. يغطي الدرس المواضيع التالية: إنشاء نهاية خلفية في Laravel 5، ستكون عبارة عن واجهة برمجية API.بنية تطبيق AngularJS.واجهة برمجية باستخدام Laravel 5ننشئ في هذه الفقرة النهاية الخلفية للتطبيق الذي نعمل عليه. سيتولى Laravel هذه المهمة. نبدأ بإنشاء تطبيق Laravel ثم نعدّه لتوفير الواجهة البرمجية. الخطوة الأولى: إنشاء تطبيق Laravelننفذ الأمر التالي في أصل المستند Document root لإنشاء مشروع Laravel باسم angulara: composer create-project laravel/laravel angularaراجع درس تثبيت Laravel 5 وإعداده على Windows وUbuntu للمزيد حول تثبيت Laravel وإعداده. سنفترض في بقية هذا الدرس تثبيت Laravel على المنصة المفضلة لديك وإنشاء مضيف افتراضي باسم angulara.dev. الخطوة التالية هي إعداد تهجير قاعدة البيانات. الخطوة الثانية: إعداد قاعدة البياناتستحتاج لقاعدة بيانات للعمل مع التطبيق. استخدم برنامج إدارة قاعدة البيانات المفضل لديك أو نفذ الأمر التالي في سطر أوامر MySQL لإنشاء قاعدة بيانات للمشروع: CREATE DATABASE `angulara`;ننتقل الآن لإعداد Laravel لكي يعمل مع قاعدة البيانات. افتح ملف env. في مجلد تطبيق Laravel وعدل القيم التالية بما يناسب: DB_HOST=localhost // اسم قاعدة البيانات DB_DATABASE=angulara // اسم مستخدم في MySQL لديه صلاحيات الكتابة والقراءة في القاعدة أعلاه DB_USERNAME=root // كلمة سر المستخدم DB_PASSWORD=melodyاحفظ التعديلات. نستغل أداة Artisan لإنشاء ملف تهجير خاص بجدول يحوي بيانات الموظفين employees. نفذ الأمر التالي لإنشاء ملف التهجير: php artisan make:migration create_employees_tableستحصُل على الرسالة التالية التي تعرض اسم الملف المنشأ: Created Migration: 2016_01_05_203637_create_employees_tableينشئ الأمر ملفا في المجلد database/migrations، نفتحه للتعديل عليه. عدّل المحتوى كالتالي: <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateEmployeesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('employees', function (Blueprint $table) { $table->increments('id'); $table->string('name')->unique(); $table->string('email')->unique(); $table->string('contact_number'); $table->string('position'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('employees'); } }احفظ التعديلات ثم نفذ أمر ِArtisan التالي: php artisan migrateينفذ الأمر التهجيرات وينشئ جدول بيانات الموظفين. تظهر الرسائل التالية بعد تنفيذ الأمر: Migration table created successfully. Migrated: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_100000_create_password_resets_table Migrated: 2016_01_05_203637_create_employees_tableتحقق من قاعدة بيانات MySQL، ستجد أن جدولا جديدا أُدرِج في القاعدة. الخطوة الثالثة: إنشاء واجهة برمجيةننشئ متحكما Controller للتطبيق، سنسميه Employees: php artisan make:controller Employeesثم يأتي دور النموذج Model: php artisan make:model Employeeسنضيف مصفوفة في النموذج لتفعيل الإسناد الشامل؛ افتح ملف النموذج وعدّله على النحو التالي: <?php namespace App; use Illuminate\Database\Eloquent\Model; class Employee extends Model { protected $fillable = array('id', 'name', 'email','contact_number','position'); }احفظ التعديلات. ننتقل للتعديل على المتحكم. افتح ملف المتحكم Employees وعدله ليصبح كالتالي <?php namespace App\Http\Controllers; use App\Employee; use Illuminate\Http\Request; use App\Http\Requests; use App\Http\Controllers\Controller; class Employees extends Controller { /** * Display a listing of the resource. * * @return Response */ public function index($id = null) { if ($id == null) { return Employee::orderBy('id', 'asc')->get(); } else { return $this->show($id); } } /** * Store a newly created resource in storage. * * @param Request $request * @return Response */ public function store(Request $request) { $employee = new Employee; $employee->name = $request->input('name'); $employee->email = $request->input('email'); $employee->contact_number = $request->input('contact_number'); $employee->position = $request->input('position'); $employee->save(); return 'Employee record successfully created with id ' . $employee->id; } /** * Display the specified resource. * * @param int $id * @return Response */ public function show($id) { return Employee::find($id); } /** * Update the specified resource in storage. * * @param Request $request * @param int $id * @return Response */ public function update(Request $request, $id) { $employee = Employee::find($id); $employee->name = $request->input('name'); $employee->email = $request->input('email'); $employee->contact_number = $request->input('contact_number'); $employee->position = $request->input('position'); $employee->save(); return "Sucess updating user #" . $employee->id; } /** * Remove the specified resource from storage. * * @param int $id * @return Response */ public function destroy($id = null) { if ($id == null) { } else { $employee = Employee::find($id); $employee->delete(); return "Employee record successfully deleted #" . $id; } } }يعرِّف المتحكم الدوالّ index لسرد قائمة بالموظفين، store لإضافة موظف جديد، show لعرض موظف بناء على معرّفه، update لتحديث بيانات موظّف وdestroy لحذف موظّف. تبقى لنا إعداد المسارات Routes في Laravel. افتح ملف المسارات routes.php وعدله كالتالي: <?php /* |-------------------------------------------------------------------------- | Application Routes |-------------------------------------------------------------------------- | | Here is where you can register all of the routes for an application. | It's a breeze. Simply tell Laravel the URIs it should respond to | and give it the controller to call when that URI is requested. | */ Route::get('/', function () { return view('index'); }); Route::get('/api/v1/employees/{id?}', 'Employees@index'); Route::post('/api/v1/employees', 'Employees@store'); Route::post('/api/v1/employees/{id}', 'Employees@update'); Route::delete('/api/v1/employees/{id}', 'Employees@destroy');لاحظ استخدام إجراءات HTTP وفقا للمبدأ المشروح في درس إنشاء واجهة برمجية API في Laravel 5. يختلف التعامل مع المسار api/v1/employees حسب إجراء HTTP المستخدم: get يُستخدم للحصول على معلومات موظف أو قائمة بالموظفين، post لإضافة موظف جديد، put لتحديث بيانات موظّف وdelete لحذف موظّف. أكملنا الآن جانب النهاية الخلفية بإنشاء واجهة برمجية. ننتقل للواجهة الأمامية التي ستستخدم الواجهة البرمجية للحصول على بيانات الموظفين وتنسيقها قبل عرضها في المتصفح. بنية تطبيق AngularJSسيأخذ مجلد public (الواجهة الأمامية لتطبيق Laravel) الشكل التالي: يحوي المجلّد الفرعي app ملفات جافاسكريبت التابعة لـAngularJS.توجد متحكمات AngularJS في المجلّد app/controllers.توجد ملفات نواة AngularJS في المجلّد app/lib. توجد أيضا إمكانية استخدام شبكة توصيل محتوى Content delivery network, CDN.توجد ملفات CSS في المجلد css.ملفات جافاسكريبت غير التابعة لـAngularJS توجد في المجلد js.توجد ملفات الواجهة الأمامية في الملف المرفق، سنشرح ما يحتاج لشرح منها. الملف app.jsسنستخدم الملف public/app/app.js لتعريف التطبيق الخاص بنا: var app = angular.module('employeeRecords', []) .constant('API_URL', 'http://angulara.dev/api/v1/');ننشئ وحدة Module في AngularJS ونسند الكائن إلى المتغير app. سيُستخدم هذا المتغير في جميع ملفات AngularJS؛ ثم نعرّف ثابتا Constant لرابط الواجهة البرمجية API_URL. ملحوظة: إن كنت اخترت اسما مختلفا للمضيف فضعه مكان angulara.dev. المتحكم Employees.jsسيكون هذا الملف مسؤولا عن التفاعل مع عروض تطبيق AngularJS: app.controller('employeesController', function($scope, $http, API_URL) { // الحصول على لائحة الموظفين $http.get(API_URL + "employees") .success(function(response) { $scope.employees = response; }); // عرض نافذة منبثقة $scope.toggle = function(modalstate, id) { $scope.modalstate = modalstate; switch (modalstate) { case 'add': $scope.form_title = "Add New Employee"; break; case 'edit': $scope.form_title = "Employee Detail"; $scope.id = id; $http.get(API_URL + 'employees/' + id) .success(function(response) { console.log(response); $scope.employee = response; }); break; default: break; } console.log(id); $('#myModal').modal('show'); } //save new record / update existing record $scope.save = function(modalstate, id) { var url = API_URL + "employees"; var request_method = 'POST'; //append employee id to the URL if the form is in edit mode if (modalstate === 'edit'){ url += "/" + id; request_method = 'PUT'; } $http({ method: request_method, url: url, data: $.param($scope.employee), headers: {'Content-Type': 'application/x-www-form-urlencoded'} }).success(function(response) { console.log(response); location.reload(); }).error(function(response) { console.log(response); alert('This is embarassing. An error has occured. Please check the log for details'); }); } //delete record $scope.confirmDelete = function(id) { var isConfirmDelete = confirm('Are you sure you want this record?'); if (isConfirmDelete) { $http({ method: 'DELETE', url: API_URL + 'employees/' + id }). success(function(data) { console.log(data); location.reload(); }). error(function(data) { console.log(data); alert('Unable to delete'); }); } else { return false; } } });نعرِّف متحكما باسم employeesController في المتغيّر app الذي أنشأناه في الملف app.js. حدّدنا الاعتماديات بـ $http، scope$ وAPI_URL. نستدعي خدمة http$ في AngularJS لإرسال طلب إلى الواجهة البرمجية، مع تمرير المعطى API_URL + "employees": $http.get(API_URL + "employees").success(function(response) {$scope.employees = response;});عند نجاح الطلب نُسنِد الإجابة إلى المتغير scope.employees$ الذي سيصبح متاحا في العرض View لإظهار محتواه. تعرض الدالة: $scope.toggle = function(modalstate, id) {…}نافذة منبثقة تحوي استمارة لإضافة موظّف جديد أو تعديل بيانات موظّف موجود حسب الحالة. نستخدم الدالة: $scope.save = function(modalstate, id){…}في حالتيْ الإضافة والتعديل. بالنسبة لإضافة موظّف نستخدم إجراء POST؛ وفي حالة التعديل نستخدم الإجراء PUT. تحذف الدالة: $scope.confirmDelete = function(id){…}بيانات موظّف من جدول الموظفين. عرض البيانات المتحصل عليها من الواجهة البرمجية بـAngularJSسننشئ عرضا لإظهار البيانات التي نتحصل عليها من الواجهة البرمجية؛ يستخدم كل من angularJS وBlade الحاضنات المزدوجة {{}} لعرض البيانات، لذا لن نحفظ عرض AngularJS بلاحقة blade.php حتى لا يعدّ نظام Blade العرض موجها له. محتوى العرض هو التالي، نحفظ الملف index.php في ملف العروض resources/views حتى يُحمّل عند طلبه من المسار / (الصفحة الرئيسية للموقع): <!DOCTYPE html> <html lang="en-US" ng-app="employeeRecords"> <head> <title>Laravel 5 AngularJS CRUD Example</title> <!-- Load Bootstrap CSS --> <link href="<?= asset('css/bootstrap.min.css') ?>" rel="stylesheet"> </head> <body> <h2>Employees Database</h2> <div ng-controller="employeesController"> <!-- Table-to-load-the-data Part --> <table class="table"> <thead> <tr> <th>ID</th> <th>Name</th> <th>Email</th> <th>Contact No</th> <th>Position</th> <th><button id="btn-add" class="btn btn-primary btn-xs" ng-click="toggle('add', 0)">Add New Employee</button></th> </tr> </thead> <tbody> <tr ng-repeat="employee in employees"> <td>{{ employee.id }}</td> <td>{{ employee.name }}</td> <td>{{ employee.email }}</td> <td>{{ employee.contact_number }}</td> <td>{{ employee.position }}</td> <td> <button class="btn btn-default btn-xs btn-detail" ng-click="toggle('edit', employee.id)">Edit</button> <button class="btn btn-danger btn-xs btn-delete" ng-click="confirmDelete(employee.id)">Delete</button> </td> </tr> </tbody> </table> <!-- End of Table-to-load-the-data Part --> <!-- Modal (Pop up when detail button clicked) --> <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel">{{form_title}}</h4> </div> <div class="modal-body"> <form name="frmEmployees" class="form-horizontal" novalidate=""> <div class="form-group error"> <label for="inputEmail3" class="col-sm-3 control-label">Name</label> <div class="col-sm-9"> <input type="text" class="form-control has-error" id="name" name="name" placeholder="Fullname" value="{{name}}" ng-model="employee.name" ng-required="true"> <span class="help-inline" ng-show="frmEmployees.name.$invalid && frmEmployees.name.$touched">Name field is required</span> </div> </div> <div class="form-group"> <label for="inputEmail3" class="col-sm-3 control-label">Email</label> <div class="col-sm-9"> <input type="email" class="form-control" id="email" name="email" placeholder="Email Address" value="{{email}}" ng-model="employee.email" ng-required="true"> <span class="help-inline" ng-show="frmEmployees.email.$invalid && frmEmployees.email.$touched">Valid Email field is required</span> </div> </div> <div class="form-group"> <label for="inputEmail3" class="col-sm-3 control-label">Contact Number</label> <div class="col-sm-9"> <input type="text" class="form-control" id="contact_number" name="contact_number" placeholder="Contact Number" value="{{contact_number}}" ng-model="employee.contact_number" ng-required="true"> <span class="help-inline" ng-show="frmEmployees.contact_number.$invalid && frmEmployees.contact_number.$touched">Contact number field is required</span> </div> </div> <div class="form-group"> <label for="inputEmail3" class="col-sm-3 control-label">Position</label> <div class="col-sm-9"> <input type="text" class="form-control" id="position" name="position" placeholder="Position" value="{{position}}" ng-model="employee.position" ng-required="true"> <span class="help-inline" ng-show="frmEmployees.position.$invalid && frmEmployees.position.$touched">Position field is required</span> </div> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-primary" id="btn-save" ng-click="save(modalstate, id)" ng-disabled="frmEmployees.$invalid">Save changes</button> </div> </div> </div> </div> </div> <!-- Load Javascript Libraries (AngularJS, JQuery, Bootstrap) --> <script src="<?= asset('app/lib/angular/angular.min.js') ?>"></script> <script src="<?= asset('js/jquery.min.js') ?>"></script> <script src="<?= asset('js/bootstrap.min.js') ?>"></script> <!-- AngularJS Application Scripts --> <script src="<?= asset('app/app.js') ?>"></script> <script src="<?= asset('app/controllers/employees.js') ?>"></script> </body> </html>نربط تطبيق AngularJS بوسم html حتى يكون له كامل التحكّم في العناصر الموجودة في الصفحة: <html lang="en-US" ng-app="employeeRecords"> نفس الشيء بالنسبة للمتحكم employeesController الذي نربطه بعنصر div حتى نجعل جميع دوال المتحكم متاحة في هذا العنصر: <div ng-controller="employeesController">نستخدم تعليمة ng-repeat للمرو على جميع عناصر المجموعة employees: <tr ng-repeat="employee in employees">تعمل ng-repeat بطريقة مشابهة لعمل الحلقة التكرارية foreach. التحقق من بيانات استمارات AngularJSاستخدمنا في استمارات الموظفين طرقا للتحقق من المُدخلات. اعثر على الشفرات التالية في ملف العرض index.php ولاحظ استخدامها: <form name="frmEmployees" class="form-horizontal" novalidate="">تعرّف هذه الشفرة استمارة باسم frmEmployees وتضيف إليها خاصيّة novalidate للطلب من HTML 5 الامتناع عن تدقيق الاستمارة، سنتولى الأمر. <input type… ng-model="employee.name" ng-required="true">تستخدم تعليمة ng-model لربط حقول الاستمارة ببيانات النموذج Employee. ربطنا الحقل أعلاه بخاصية name في النموذج. بهذه الطريقة يكون محتوى الحقل متاحا للنموذج، والعكس أيضا. تدل التعليمة ng-required أن الحقل مطلوب. إن لم تذكر قيمة لهذا الحقل فلن يمكن إرسال الاستمارة. <span class="help-inline" ng-show="frmEmployees.name.$invalid && frmEmployees.name.$touched">لا يظهر هذا العنصُر إلا إذا أخفق التحقق من حقل name قبله. تظهر رسالة تفيد أن قيمة الحقل مطلوبة. ng-disabled="frmEmployees.$invalid" تعطّل هذه التعليمة إمكانية إرسال الاستمارة عند إخفاق التحقق من أحد الحقول المطلوبة. حان الآن وقت تجربة ما عملناه في الخطوات السابقة، افتح الموقع (بالنسبة لي اخترتُ إنشاء مضيف افتراضي angulara.dev): http://angulara.dev/ستحصُل، إن اتبعت الخطوات السابقة، على الواجهة التالية: اضغط على زر Add New Employee لإضافة موظّف. ستظهر نافذة منبثقة لإضافة بيانات الموظّف. تصبح الواجهة بعد إضافة موظفين على النحو التالي: تمكّن الأزرار edit و delete الموجودة في كل سطر تحديثَ أو حذف بيانات موظّف. الملف المرفق: مجلد public. ترجمة -وبتصرّف- لمقال Laravel 5 AngularJS Tutorial لصاحبه Rodrick Kazembe.
  6. أكملنا في الجزء السابق من هذه السّلسلة إعداد التطبيق المثال؛ يجب علينا الآن تصميم خطة استرداد Recovery plan. خطة الاسترداد (أو الاستعادة) عبارة عن مجموعة موثقة من العمليات التي يجب تنفيذها لتصحيح إعدادات بيئة العمل بعد حدوث مشاكل مزمنة أو عند حصول أخطاء إدارية. يساعد إنشاء خطة استرداد أيضا على تحديد العناصر والبيانات الأساسية ضمن إعدادات خادوم التطبيق. يمكن أن تتمثل خطة استرداد قاعدية من إخفاق بيئة العمل في لائحة بالخطوات الواجب اتباعها لإنجاز النشر الابتدائي للخادوم؛ إلى جانب عمليات إضافية لاستعادة بيانات التطبيق من النسخ الاحتياطية. للحصول على خطة استرداد أفضل يجب، إضافة للتوثيق الجيد، استغلال سكربتات النشر وأدوات إدارة الإعدادات مثل Chef، Ansible وPuppet؛ للمساعدة في أتممة وتسريع الاسترداد. سنوضح في هذا الجزء من السّلسلة كيفية إنشاء خطة استرداد قاعدية لتطبيق ووردبريس الذي أعددناه. سيساعدك الشرح في البدء بتصميم خطة استرداد خاصة بك حتى ولو كانت احتياجاتك مختلفة. متطلبات خطة الاستردادمطلبنا الأساسي هو إمكانية استرداد بيئة العمل بعد فقدان واحد من الخواديم المكوّنة لها، واستعادة وظيفة التطبيق وبياناته؛ إلى حد زمني مقبول. سننشئ جردًا لإعدادات كل خادوم نحدد من خلاله البيانات التي نحتاج لنسخ احتياطية منها؛ ثم نكتب خطة استرداد اعتمادا على ما يوجد في الخادوم. يجب أن نتحقق بعد تنفيذ أي واحدة من خطط الاسترداد أن التطبيق استُرِدّ بطريقة صحيحة. سنخرج بخطة استرداد لكل نوع من الخواديم التي يتكون منها التطبيق: خادوم قاعدة البيانات.خواديم التطبيق.خادوم توزيع الحمل.نبدأ بخادوم قاعدة البيانات. خادوم قاعدة البياناتبإعادة تتبع خطواتنا (وإعادة النظر في الدرس السابق) نجد أن خادوم قاعدة البيانات أنشئ وفقا للخطوات التالية: تثبيت MySQL.إعداد MySQL.إعادة تشغيل MySQL.إنشاء قاعدة البيانات والمستخدمين.خطة استرداد خادوم قاعدة البياناتنعرف، بالنظر لطريقة إنشاء خادوم قاعدة البيانات، أنه تمكن إعادة إنشائه من الصفر ما عدا محتوى قاعدة البيانات. تُخزَّن أغلب بيانات تطبيق ووردبريس (التدوينات مثلا) في قاعدة البيانات. يعني هذا أنه يجب علينا الاحتفاظ بنسخة احتياطية من قاعدة البيانات إن أردنا توفير القدرة على استرداد خادوم قاعدة البيانات. سنحتفظ أيضا بنسخ احتياطية من ملف إعدادات MySQL الذي غيرنا فيه قليلا. في ما يلي ملخَّص لخطة الاسترداد الخاصة بخادوم قاعدة البيانات: يجب الآن التدرب على تنفيذ خطة الاستعادة هذه، والتأكد من الاحتفاظ بالنسخ الاحتياطية الضرورية. خواديم التطبيقنعرف بالنظر في طريقة إنشاء خواديم التطبيق (ومراجعة الدرس السابق)؛ أنّ الخطوات المتَّبعة كانت على النحو التالي: تثبيت كل من PHP وApache وإعدادهما.تنزيل التطبيق (ووردبريس) وإعداده.نسخ ملفات التطبيق إلى جذر المستند Document root.تكرار ملفات التطبيق على جميع خواديم التطبيق.خطة الاسترداد لخادوم التطبيقتمكن إعادة إنشاء خادوم التطبيق من الصفر، ما عدا ملفات التطبيق. تتضمن ملفات التطبيق في المثال ملفات إعداد ووردبريس (التي تحتوي على معلومات الاتصال بقاعدة البيانات)، إضافات ووردبريس المثّبَّتة، والملفات المحمَّلة. أي أنه يجب علينا الاحتفاظ بنسخة احتياطية من ملفات التطبيق إن أردنا إمكانية استرداد خادوم التطبيق. أعددنا الخواديم بحيث تُكرَّر الملفات على خواديم التطبيق؛ يعني هذا أننا لا نحتاج لاستعادة البيانات من النسخ الاحتياطية إلا إذا أخفقت خواديم التطبيق جميعها أو تلَفتْ البيانات بطريقة أو بأخرى. إن بقي خادوم تطبيق واحد على الأقل يعمل جيدا، مع ملفات التطبيق الصحيحة؛ فإن إعادة ضبط تكرار الملفات مرة أخرى سيعيد الملفات الصحيحة إلى خادوم التطبيق الجديد. في ما يلي ملخَّص لخطة الاسترداد الخاصة بخواديم التطبيقات، اعتمادا على الجرد أعلاه: اكتمل إعداد خطة الاسترداد لخواديم التطبيق. يجب الآن التدرب على تنفيذ خطة الاسترداد، والتأكد من الاحتفاظ بالنسخ الاحتياطية الضرورية. خادوم توزيع الحملالمبدأ هو نفسه، ننظر إلى خطوات إنشاء موزع الحمل في الدرس السابق؛ فنخرج بالتالي: الحصول على شهادة SSL والملفات المتعلقة بها.تثبيت HAProxy.إعداد HAProxy.إعادة تشغيل HAProxy.خطة الاسترداد لخادوم توزيع الحملنعرف من الخطوات أعلاه، أنه تمكن إعادة إنشاء موزع الحمل انطلاقا من صفر، ما عدا الملفات المتعلقة بشهادة SSL. يعني هذا أنه يتوجب علينا الاحتفاظ بنسخ احتياطية من الملفات المتعلقة بشهادة SSL إن أردنا توفير القابلية لاسترداد خادوم توزيع الحمل. سنضيف أيضا ملف إعداد HAProxy ضمن النسخ الاحتياطية. نضع - مثل ما فعلنا مع العناصر السابقة، ملخصا لخطة الاسترداد الخاصة بخادوم توزيع الحمل: اكتمل إعداد خطة الاسترداد لخادوم توزيع الحمل. يجب الآن التدرب على تنفيذ خطة الاسترداد، والتأكد من الاحتفاظ بالنسخ الاحتياطية الضرورية. اعتبارات أخرىإن تطلب استرداد أحد العناصر إعادة ضبط عنصر آخر (تغير عنوان IP الخاص بخادوم قاعدة البيانات مثلا)؛ فعليك التأكد من إدراج الخطوات الضرورية في خطط الاسترداد. ستحتاج أيضا لكتابة خطط استرداد للعناصر الأخرى المكوِّنة للتطبيق مثل خادوم النطاقات؛ وكذلك جميع العناصر التي يمكن أن تضيفها في المستقبل مثل خواديم النسخ الاحتياطي، المراقبة والسجلات. يجب، مع تطور إعداداتك، إعادة النظر في خطط الاستعادة الموجودة وإجراء التغييرات اللّازمة. لم نتطرق لحد الساعة إلى كيفية إنشاء ثم استعادة النسخ الاحتياطية؛ لذا سنحتاج للنظر في هذه التفاصيل لاحقا. سيكون النسخ الاحتياطي موضوع الجزء الموالي من هذا الدليل. خاتمةيجب الاحتفاظ بخطط الاستعادة الخاصة بالخواديم المختلفة في مكان آمن يمكن لمن أراد تنفيذ الخطوات الموجودة فيها الوصولُ إليه. احتفظ بها في مكان منفصل تماما عن بيئة العمل. ترجمة -وبتصرّف- لمقال Building for Production: Web Applications — Recovery Planning لصاحبه Mitchell Anicas. حقوق الصورة البارزة: Designed by Freepik.