دروس لارافيل للمبتدئين

ما هو Laravel؟

لارافل هو إطار عمل MVC مفتوح المصدر لـ PHP. Laravel هو إطار عمل قوي يوفر تطويرًا سهلاً لتطبيقات الويب PHP مع ميزات مثل نظام التعبئة المعياري مع مدير تبعية مخصص، والوصول إلى قواعد البيانات العلائقية، والأدوات المساعدة الأخرى لنشر التطبيقات وصيانتها.

تم إنشاء Laravel بواسطة تايلور أوتويل. منذ إصداره الأولي في يونيو 2011 (الإصدار 1)، ازدادت شعبيته بشكل مطرد في قطاع إطار عمل PHP في صناعة تطوير الويب. يمكن أن يُعزى الكثير من هذه الشعبية إلى العديد من الميزات التي تركز على المطورين والتي تأتي مع المخزون.

لماذا Laravel؟

حوالي عام 2000، على الأغلب رموز PHP كانت إجرائية ويمكن العثور عليها في شكل "نصوص" تحتوي على فوضى متشابكة من رموز السباغيتي. حتى أبسط الصفحات لم يكن لها فصل المخاوف، وبالتالي كان من السهل إلى حد ما أن يتحول التطبيق بسرعة إلى كابوس للصيانة. كان العالم بحاجة إلى شيء أفضل...أدخل PHP الإصدار 5 ومجموعة متنوعة من أطر عمل PHP التي تحاول تقديم بعض الحلول التي تشتد الحاجة إليها وحلول أفضل لمختلف اهتمامات تطبيقات الويب.

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

معرفة المزيد عن الفرق بين Laravel و CodeIgniter

كيفية تنزيل Laravel وتثبيته مع Composer

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

يعد Composer مديرًا للحزم والتبعيات. لتثبيته، افتح محطة طرفية وانتقل إلى دليل جديد. قم بتشغيل هذا الأمر:

curl -Ss getcomposer.org/installer | php

ستبدو نتائج هذا الأمر كما يلي:

تنزيل وتثبيت Laravel مع Composer

ملاحظات لمزيد من التعليمات الشاملة حول إعداد Laravel، راجع وثائق Laravel هنا.

ستشاهده يقوم بتنزيل وتجميع البرنامج النصي composer.phar، وهو ما نستخدمه لتثبيت Laravel. وعلى الرغم من وجود طرق عديدة لإعداد تطبيق Laravel جديد، فسوف نقوم بذلك عبر البرنامج النصي composer Laravel. لتثبيت هذا البرنامج النصي، قم بتشغيل:

composer global require laravel/installer

والتي سوف تبدو مثل هذا:

تنزيل وتثبيت Laravel مع Composer

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

laravel new uploadApp

سوف ترى شيئًا مثل الناتج التالي:

تنزيل وتثبيت Laravel مع Composer

يقوم Composer بتثبيت جميع الحزم التي يحتاجها Laravel لتشغيله. قد يستغرق الأمر بضع دقائق لذا تحلى بالصبر. بعد الانتهاء، قم بتشغيل الأمر ls -al لإلقاء نظرة على ما تم تثبيته.

فيما يلي تفصيل موجز للأدلة في تطبيق Laravel الشائع:

  • برنامج/ : هذا هو المجلد المصدر حيث يوجد رمز التطبيق الخاص بنا. كافة وحدات التحكم والسياسات والنماذج موجودة داخل هذا المجلد
  • التمهيد/ : يحمل البرنامج النصي لبدء تشغيل التطبيق وبعض ملفات خريطة الفصل
  • التكوين/ : يحمل ملفات تكوين التطبيق. عادةً لا يتم تعديلها بشكل مباشر ولكن بدلاً من ذلك، تعتمد على القيم التي تم إعدادها في ملف .env (البيئة) في جذر التطبيق
  • قاعدة البيانات/ : يضم ملفات قاعدة البيانات بما في ذلك الهجرات والبذور ومصانع الاختبار
  • عام/ : مجلد يمكن الوصول إليه بشكل عام ويحتوي على أصول مجمعة وبالطبع ملف Index.php
  • موارد/ : يحتوي على أصول الواجهة الأمامية مثل ملفات جافا سكريبت وملفات اللغة وملفات CSS/SASS وجميع القوالب المستخدمة في التطبيق (وتسمى القوالب النصلية)
  • الطرق/ : جميع الطرق في التطبيق موجودة بالداخل هنا. هناك عدد قليل من "النطاقات" المختلفة للمسارات ولكن النطاق الذي سنركز عليه هو ملف web.php
  • تخزين/ : جميع ملفات ذاكرة التخزين المؤقت المؤقتة التي يستخدمها التطبيق، وملفات الجلسة، ونصوص العرض المجمعة، وملفات السجل
  • الاختبارات/ : يحتوي على ملفات اختبارية للتطبيق مثل اختبارات الوحدة والاختبارات الوظيفية.
  • بائع/ : جميع حزم التبعيات المثبتة باستخدام الملحن

الآن، لنبني بقية التطبيق ونشغله باستخدام أمر حرفي خاص (لتوفير على أنفسنا متاعب تثبيت وتكوين خادم ويب مثل Apache أو nginx). يحتوي ملف .env على كافة قيم التكوين التي تستخدمها الملفات الموجودة في الدليل /config لتكوين التطبيق. بداخله، ستلاحظ أن قيمة التكوين لمختلف المعلمات المستخدمة من قبل الأجزاء الداخلية للتطبيق.

تصميم التطبيق: ملخص سريع لمتطلباتنا

في هذا البرنامج التعليمي عبر الإنترنت Laravel، سنقوم ببناء تطبيق بسيط للغاية يقوم بأمرين فقط:

  1. التعامل مع تحميلات الملفات من نموذج ويب
  2. عرض الملفات التي تم تحميلها مسبقًا على صفحة مختلفة.

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

فيما يلي قائمة بالمكونات التي سنحتاجها لتشغيل التطبيق كما هو متوقع:

  • A الطريق سيسمح للعالم الخارجي (الإنترنت) باستخدام التطبيق بالإضافة إلى تحديد نقطة النهاية التي ستشير إلى المكان الذي يوجد فيه منطق حفظ الملف الذي تم تحميله
  • A مراقب الذي يتعامل مع الطلب لتدفق الاستجابة
  • A قالب والتي سيتم استخدامها لعرض قائمة بالملفات التي تم تحميلها مسبقًا ونموذج التحميل الفعلي نفسه
  • A طلب التي ستستخدمها وحدة التحكم للتحقق من صحة البيانات التي تم تمريرها من نموذج الويب

ما هو الطريق؟

المسار في Laravel هو في الأساس نقطة نهاية محددة بواسطة URI والتي تعمل بمثابة "مؤشر" لبعض الوظائف التي يقدمها التطبيق. في أغلب الأحيان، يشير المسار ببساطة إلى أسلوب ما على وحدة التحكم ويحدد أيضًا أساليب HTTP القادرة على الوصول إلى URI هذا. لا يعني المسار دائمًا طريقة التحكم أيضًا؛ يمكنه فقط تمرير تنفيذ التطبيق إلى وظيفة إغلاق محددة أو وظيفة مجهولة أيضًا.

لماذا استخدام الطريق؟

يتم تخزين المسارات داخل ملفات ضمن مجلد /routes داخل الدليل الجذر للمشروع. بشكل افتراضي، هناك عدد قليل من الملفات المختلفة المقابلة لـ "الجوانب" المختلفة للتطبيق (تأتي "الجوانب" من منهجية الهندسة المعمارية السداسية). وهي تشمل:

  • web.php الجمهور الذي يواجه الطرق المستندة إلى "المتصفح". هذه هي الأكثر شيوعًا وهي ما يتعرض له متصفح الويب. يتم تشغيلها من خلال مجموعة البرامج الوسيطة على الويب وتحتوي أيضًا على مرافق لـ حماية CSRF (مما يساعد في الدفاع ضد الهجمات والاختراقات الضارة القائمة على النموذج) ويحتوي بشكل عام على درجة من "الحالة" (وبهذا أعني أنهم يستخدمون الجلسات)
  • api.php المسارات التي تتوافق مع مجموعة واجهة برمجة التطبيقات وبالتالي يتم تمكين البرنامج الوسيط لواجهة برمجة التطبيقات بشكل افتراضي. هذه المسارات عديمة الحالة ولا تحتوي على جلسات أو ذاكرة للطلبات المتبادلة (لا يشارك طلب واحد البيانات أو الذاكرة مع أي طلب آخر - كل واحد مغلف ذاتيًا).
  • console.php تتوافق هذه المسارات مع الأوامر الحرفية المخصصة التي قمت بإنشائها لتطبيقك
  • Channels.php يسجل مسارات بث الأحداث

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

  • /upload سيكون هذا هو URI للصفحة الرئيسية التي تعرض نموذج الويب الخاص بنا لتحميل الملفات.
  • /العملية سيكون هذا هو المكان الذي ينشر فيه النموذج الموجود في /upload URI البيانات المقدمة من النموذج إلى ("إجراء" النموذج)
  • /list سيؤدي هذا إلى سرد كافة الملفات التي تم تحميلها إلى الموقع

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

//inside routes/web.php
Route::get('/upload', 'UploadController@upload')->name('upload');
Route::get('/download, 'UploadController@download)->name(‘download');
Route::post('/process', 'UploadController@process')->name('process');
Route::get('/list', 'UploadController@list')->name('list');

في هذا البرنامج التعليمي لإطار عمل Laravel، لكل مسار مرغوب، سنقوم بإدراجه بشكل واضح في ملف المسارات web.php باستخدام إحدى طرق الطلب المتاحة الخاصة بـ HTTP (get()، post()، put()،delete())، التصحيح () أو الخيارات ()). للحصول على تفاصيل كل من هذه، تحقق خارج. ما تفعله هذه الطرق هو تحديد أفعال HTTP المسموح لها بالوصول إلى هذا المسار المحدد. إذا كنت بحاجة إلى مسار لتتمكن من قبول أكثر من فعل HTTP واحد (وهو ما قد يكون عليه الحال إذا كنت تستخدم صفحة واحدة لعرض البيانات الأولية ونشر بيانات النموذج المرسل)، فيمكنك استخدام Route::any( ) طريقة.

الحجة الثانية لكل من طريقتي Route::get() و Route::post() (وأي من الطرق الأخرى المرتبطة بفعل HTTP على واجهة Route)، هي اسم وحدة تحكم محددة وطريقة موجودة داخل وحدة التحكم هذه والتي يتم تنفيذها عند الوصول إلى نقطة نهاية الطريق مع طلب HTTP المسموح به (GET، POST، PATCH، إلخ.) نحن نستخدم UploadController لجميع الطرق الثلاثة وقد حددناها بالطريقة التالية:

ما هو الطريق

الطريقة الأخيرة التي نستدعيها على كل مسار هي وظيفة name() الخاصة بها، والتي تقبل سلسلة واحدة كوسيطة وتستخدم "لوضع علامة" أكثر أو أقل على مسار معين مع سهولة تذكر الاسم (في حالاتنا، التحميل والمعالجة والقائمة). أدرك أنه لا يبدو من الرائع جدًا إعطاء كل مسار اسمه الخاص عندما يتم تسمية عنوان URL بنفس الاسم، ولكنه يكون مفيدًا حقًا عندما يكون لديك مسار محدد مثل /users/profile/dashboard/config، والتي سيكون من الأسهل تذكرها كـ Profile-admin أو user-config.

ملاحظة على الواجهات:

  • توفر الواجهات واجهة "ثابتة" للفئات المتوفرة في حاوية خدمة التطبيق.
  • إنها توفر صيغة مقتضبة وسهلة التذكر تسمح لك باستخدام ميزات Laravel دون تذكر أسماء الفئات الطويلة التي يجب إدخالها أو تهيئتها يدويًا.

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

ما هو جهاز التحكم؟

وحدة التحكم هي الحرف "C" في بنية "MVC" (Model-View-Controller)، والتي يعتمد عليها Laravel. يمكن تلخيص مهمة وحدة التحكم في هذا التعريف البسيط: يتلقى الطلب من العميل ويعيد الرد إلى العميل. هذا هو التعريف الأساسي وهو أيضًا الحد الأدنى من متطلبات أي وحدة تحكم معينة. ما يفعله بين هذين الأمرين يعتبر عمومًا "إجراء" وحدة التحكم (أو "تنفيذ المسار"). وهي بمثابة نقطة الدخول الثانية إلى التطبيق (الأولى هي الطلب) إلى العميل، الذي يرسل حمولة الطلب (والتي سنصل إليها بعد ذلك) إلى التطبيق، متوقعًا نوعًا من الاستجابة (في شكل صفحة النجاح أو إعادة التوجيه أو صفحة الخطأ أو أي نوع آخر من استجابة HTTP).

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

على سبيل المثال، ستحقق قطعتا التعليمات البرمجية التاليتان نفس الشيء:

المثال رقم 1: تعريف المسار وتنفيذه داخل استدعاء أسلوب واحد (في ملف مسارات web.php)

//inside routes/web.php
<?php
Route::get('/hello-world', function(Request $request) {
   $name = $request->name;
   return response()->make("<h1>Hello World! This is ".$name, 200);
});

المثال رقم 2: تعريف المسار موجود داخل Routes/web.php، ولكن تنفيذه موجود داخل فئة /app/Http/Controllers/HelloWorldController

//inside routes/web.php
<?php

Route::get('/hello-world', 'HelloWorldController@index')->name('hello-world');

------------------------------------------------------------------------------------
//inside app/Http/Controllers/HelloWorldController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;

class HelloWorldController extends Controller
{
   public function index(Request $request)
   {
       $name = $request->name;
       return response()->make("<h1>Hello World! This is ".$name, 200);
   }
}

على الرغم من أن مثال Laravel رقم 2 يبدو وكأنه يتطلب الكثير من العمل (وهو ليس كذلك، فقط القليل من التعليمات البرمجية هو كل شيء)، انظر إلى الفوائد التي نكتسبها من خلال وضع منطق الإجراء الخاص بنا لمسار "hello-world" المحدد داخل وحدة التحكم بدلاً من ذلك مع تعريف المسار كوظيفة رد اتصال:

  1. يتم فصل منطقنا بشكل نظيف إلى فئته الخاصة (فصل الاهتمامات)
  2. تم إعداد وحدة التحكم الخاصة بنا للتمديد لاحقًا إذا احتجنا إلى إضافة قدرات إضافية إليها... لنفترض أننا ربما أردنا إضافة ميزة "وداعًا للعالم"... في هذه الحالة، سنقوم بإعادة تسمية وحدة التحكم إلى "HelloController" أكثر عمومية ثم تحديد طريقتين منفصلتين، أهلا() مع السلامة(). سنحتاج أيضًا إلى تحديد طريقين منفصلين يرسمان خريطة /مرحبًا / مع السلامة URIs إلى طريقتها المناسبة على وحدة التحكم. يعد هذا أمرًا مرغوبًا فيه مقارنة بزيادة حجم ملف المسارات مع تحديد تنفيذ كل مسار على أنه وظائف رد اتصال.
  3. يمتلك Laravel القدرة المضمنة على تخزين جميع تعريفات المسار في التطبيق مؤقتًا بحيث يسرع الوقت المستغرق للعثور على مسار معين (يزيد من أداء التطبيق)؛ ومع ذلك، لن تتمكن من الاستفادة من ذلك إلا إذا تم تكوين جميع المسارات المحددة داخل التطبيق باستخدام تعيينات خاصة بوحدة التحكم (انظر المثال رقم 2 أعلاه)

لنقم بتشغيل هذا الأمر الذي سيؤدي إلى إنشاء وحدة تحكم جديدة لنا.

// ...inside the project's root directory:
php artisan make:controller UploadController   

بشكل أساسي، ما يفعله هذا الأمر هو إنشاء كعب روتين لوحدة تحكم تسمى "UploadController" داخل دليل وحدة التحكم الرئيسية في /app/Http/Controllers/UploadController.php. لا تتردد في فتح هذا الملف وإلقاء نظرة. الأمر بسيط جدًا لأنه مجرد إصدار متوقف من وحدة التحكم، مع مسار مساحة الاسم الصحيح والفئات المطلوبة التي يمتد منها.

توليد الطلب

قبل أن نمضي قدمًا في هذا البرنامج التعليمي PHP Laravel ونجري بعض التغييرات على ملف UploadController الذي تم إنشاؤه، أعتقد أنه سيكون من المنطقي إنشاء فئة الطلب أولاً. وذلك لأن طريقة وحدة التحكم التي تتعامل مع الطلب يجب أن تشير إلى نوع كائن الطلب في توقيعها، مما يسمح لها بالتحقق تلقائيًا من صحة بيانات النموذج الواردة (كما هو محدد في طريقة rules(). المزيد حول هذا لاحقًا...) في الوقت الحالي، دعنا نستخدم أمر artisan مرة أخرى لإنشاء ملف الطلب:

php artisan make:request UploadFileRequest

سيقوم هذا الأمر بإنشاء ملف يسمى UploadFileRequest داخل التطبيق/Http/Requests/UploadFileRequest. افتح كعب الروتين وألق نظرة خاطفة... ستجد الأمر بسيطًا جدًا، ويحتوي على طريقتين فقط، Authorize() والقواعد.

إنشاء منطق التحقق من الصحة

دعونا نعدل كعب الطلب لتلبية احتياجات تطبيقنا. قم بتعديل الملف ليصبح كما يلي:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UploadFileRequest extends FormRequest
{
   /**
    * Determine if the user is authorized to make this request.
    *
    * @return bool
    */
   public function authorize()
   {
       return true;
   }

   /**
    * Get the validation rules that apply to the request.
    *
    * @return array
    */
   public function rules()
   {
       return [
           'fileName' => 'required|string',
           'userFile' => 'required|file'
       ];
   }
}

لم يتم إجراء الكثير من التغييرات ولكن لاحظ أن طريقة Authorize()‎ تُرجع الآن صحيحًا بدلاً من خطأ. تقرر هذه الطريقة ما إذا كان سيتم السماح للطلب بالدخول إلى التطبيق أم لا. إذا تم ضبطه على خطأ، فإنه يمنع الطلب من الدخول إلى النظام (والذي عادةً ما يكون أسلوبًا في وحدة التحكم). سيكون هذا مكانًا مفيدًا جدًا لإجراء أي عمليات فحص ترخيص للمستخدم أو أي منطق آخر قد يقرر ما إذا كان يمكن نقل الطلب إلى وحدة التحكم. في الوقت الحالي، نعيد فقط القيمة true هنا للسماح لأي شيء وكل شيء باستخدام الطلب.

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

'formFieldName' => 'constraints this field has separated by pipe characters (|)'

هناك العديد من قيود التحقق المختلفة التي يدعمها Laravel فورًا. للحصول على قائمة كاملة بها، راجع الوثائق عبر الإنترنت هنابالنسبة لتطبيق التحميل الخاص بنا، سيكون هناك حقلين يتم تمريرهما عبر طلب POST من نموذج في الواجهة الأمامية. يجب تضمين معلمة fileName داخل نص النموذج (أي مطلوب) ويتم استخدامها كاسم ملف سنخزن الملف تحته في التخزين (يتم ذلك في وحدة التحكم - سنصل إليها بعد قليل). نحدد أيضًا أن اسم الملف يجب أن يكون سلسلة من خلال إضافة حرف أنبوبي (|) وكلمة "سلسلة". يتم تحديد القيود دائمًا بواسطة أنابيب، مما يسمح لك بتحديد أي معايير إضافية للحقل المحدد في سطر واحد! يا لها من قوة!

المعلمة الثانية، userFile، هي الملف الفعلي الذي يقوم المستخدم بتحميله من نموذج على صفحة ويب. ملف المستخدم مطلوب أيضًا و يجب يكون ملفا. ملحوظة: إذا كنا نتوقع أن يكون الملف الذي تم تحميله صورة، فسنستخدم قيد الصورة بدلاً من ذلك، مما سيحد من أنواع الملفات المقبولة لتكون أحد أنواع الصور الشائعة (jpeg، أو png، أو bmp، أو gif، أو svg). نظرًا لأننا نريد السماح للمستخدم بتحميل أي نوع من الملفات، فسوف نلتزم فقط بقيد التحقق من صحة الملف.

هذا هو كل ما يتعلق بكائن الطلب. وتتمثل مهمتها الرئيسية في الاحتفاظ بمجموعة المعايير (القيود) المقبولة التي يجب أن تستوفيها معلمات نص النموذج من أجل المضي قدمًا بشكل أعمق في التطبيق. شيء آخر يجب ملاحظته هو أن هذين الحقلين (ملف المستخدم واسم الملف) يجب أيضًا تحديدهما داخل كود HTML في شكل حقول إدخال (مع اسم الحقل المطابق للاسم الموجود داخل كائن الطلب).

قد تتساءل: من المؤكد أن هذا يحدد خصائص ما يجب أن يحتوي عليه طلب النموذج، ولكن أين يتم التحقق الفعلي من هذه القيود؟ سوف ندخل في ذلك بعد ذلك.

تعديل وحدة التحكم

افتح التطبيق/Http/Controllers/UploadController وقم بإجراء التغييرات التالية عليه:

<?php

namespace App\Http\Controllers;

use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Http\Request;
use App\Http\Requests\UploadFileRequest; //our new request class
use Illuminate\Support\Facades\Storage; 

class UploadController extends Controller
{
   /**
    * This is the method that will simply list all the files uploaded by name and provide a
    * link to each one so they may be downloaded
    *
    * @param $request : A standard form request object
    * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
    * @throws BindingResolutionException
    */
   public function list(Request $request)
   {
       $uploads = Storage::allFiles('uploads');

       return view('list', ['files' => $uploads]);
   }

   /**
    * @param $file
    * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
    * @throws BindingResolutionException
    */
   public function download($file)
   {
       return response()->download(storage_path('app/'.$file));
   }

   /**
    * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
    * @throws BindingResolutionException
    */
   public function upload()
   {
       return view('upload');
   }

   /**
    * This method will handle the file uploads. Notice that the parameter's typehint
    * is the exact request class we generated in the last step. There is a reason for this!
    *
    * @param $request : The special form request for our upload application
    * @return array|\Illuminate\Http\UploadedFile|\Illuminate\Http\UploadedFile[]|null
    * @throws BindingResolutionException
    */
   public function store(UploadFileRequest $request)
   {
       //At this point, the parameters passed into the $request (from form) are
       //valid--they satisfy each of the conditions inside the rules() method

       $filename = $request->fileName;    //parameters have already been validated
       $file = $request->file('userFile'); //that we don't need any additional isset()

       $extension = $file->getClientOriginalExtension(); //grab the file extension
       $saveAs = $filename . "." . $extension; //filename to save file under

       $file->storeAs('uploads', $saveAs, 'local'); //save the file to local folder

       return response()->json(['success' => true]); //return a success message
   }
}

لذلك يعد هذا أسلوبًا مباشرًا إلى حد ما لحفظ الملفات التي تم تحميلها على القرص. فيما يلي تفاصيل طريقة التحميل () أعلاه:

  • اكتب تلميحًا لفئة الطلب في طريقة التحكم التي تقوم بوظيفة "اللحوم والبطاطس" حتى نتمكن من التحقق تلقائيًا من صحة البيانات الواردة
  • احصل على الملف من كائن الطلب (الذي تم التحقق من صحته الآن) داخل طريقة وحدة التحكم (في هذه الحالة قمنا بتسميته upload() ولكن من الممكن أيضًا تسميته باسم أكثر توحيدًا مثل store()).
  • احصل على اسم الملف من الطلب
  • قم بإنشاء اسم الملف النهائي الذي سيتم استخدامه لحفظ الملف تحته. تقوم طريقة getClientOriginalExtension() ببساطة بالحصول على الامتداد الأصلي للملف الذي تم تحميله.
  • قم بتخزين الملف في نظام الملفات المحلي باستخدام طريقة storeAs() الخاصة به، مع تمرير المسار المسمى داخل دليل /storage باعتباره الوسيط الأول واسم الملف الذي سيتم حفظه فيه باعتباره الوسيط الثاني.
  • قم بإرجاع استجابة JSON تشير إلى نجاح الطلب

قالب الشفرة

القطعة الرئيسية الأخيرة في هذا اللغز هي قالب الشفرة، الذي سيحتوي على كل من HTML وCSS وjavascript لتطبيقنا البسيط. هذا هو الكود - وسنشرحه لاحقًا.

<body>
   <h1>Upload a file</h1>
   <form id="uploadForm" name="uploadForm" action="{{route('upload')}}" enctype="multipart/form-data">
       @csrf
       <label for="fileName">File Name:</label>
       <input type="text" name="fileName" id="fileName" required /><br />
       <label for="userFile">Select a File</label>
       <input type="file" name="userFile" id="userFile" required />
       <button type="submit" name="submit">Submit</button>
   </form>
   <h2 id="success" style="color:green;display:none">Successfully uploaded file</h2>
   <h2 id="error" style="color:red;display:none">Error Submitting File</h2>
   <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
   <script>
        $('#uploadForm').on('submit', function(e) {
            e.preventDefault();
            var form = $(this);
            var url = form.attr('action');
            $.ajax({
                url: url,
                type: "POST",
                data: new FormData(this),
                processData: false,
                contentType: false,
                dataType: "JSON",
                success: function(data) {
                    $("#fileName").val("");
                    $("#userFile").val("");
                }
            }).done(function() {
                $('#success').css('display', 'block');
                window.setTimeout(()=>($("#success").css('display', 'none')), 5000);
            }).fail(function() {
                $('#error').css('display', 'block');
                window.setTimeout(()=>($("#error").css('display', 'none')), 5000);
            });
        });
   </script>
</body>
</html>

هنا هو ما لدينا / تحميل الصفحة تبدو مثل:

قالب الشفرة

هذا مثال نموذجي للغاية لملف شفرة يحتوي على نموذج HTML وjavascript/jQuery لإضافة وظيفة غير متزامنة (لذا لا يتم تحديث الصفحة). هناك طريقة أساسية علامة بدون سمة طريقة (سأشرحها بعد ثانية واحدة فقط) وسمة إجراء غريبة بقيمة {{route('file.upload')}}. في blade، هذا ما يُعرف باسم التوجيه. التوجيه هو مجرد اسم فاخر للوظيفة - فهي وظائف خاصة بقوالب blade التي تؤدي عمليات مختلفة شائعة في إنشاء صفحات الويب وتطبيقات الويب. للحصول على فهم أفضل لكل الأشياء الرائعة التي يمكن أن يقوم بها blade، راجع الوثائق هنا. في الحالة المذكورة أعلاه، نستخدم توجيه المسار لإنشاء عنوان URL لإرسال النموذج الخاص بنا.

تذكر أننا قمنا بتعريف مساراتنا مسبقًا في التطبيق داخل ملف web.php، مع تحديد طريقة سهلة لتذكر اسم كل منها. يقبل التوجيه {{route()}} اسم المسار، ويبحث عنه داخل قائمة المسارات المخزنة مؤقتًا داخليًا، وينشئ عنوان URL كاملًا استنادًا إلى تعريف هذا المسار في ملف web.php. بالنسبة لهذه الحالة الأولى، نحدد أننا نريد أن يرسل النموذج بياناته المرسلة إلى عنوان URL /العملية لتطبيقنا، والذي تم تعريفه على أنه سأعين الطريق.

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

بعد ذلك، نحدد نموذجنا كالمعتاد، ومع ذلك، لاحظ أن أسماء معلمات النموذج، userFile وfileName، هي بالضبط نفس كما هو محدد داخل كائن الطلب الخاص بنا. إذا نسينا تضمين إدخال لمعلمة معينة تم تعريفها في كائن الطلب (أو أخطأنا في كتابتها)، فسيفشل الطلب وسيتم إرجاع خطأ، مما يمنع طلب النموذج الأصلي من الوصول إلى طريقة وحدة التحكم الموجودة في UploadController@ عملية .

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

قالب الشفرة

الصورة الأكبر

دعونا نرجع خطوة إلى الوراء ونلقي نظرة على ما قمنا به في هذا البرنامج التعليمي الخاص بـ Laravel.

يوضح هذا الرسم البياني التطبيق كما هو عليه الآن (باستثناء التفاصيل عالية المستوى):

مخطط تعليمي لارافيل

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

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

تقوم طريقة التحكم بعد ذلك بسحب المعلمات التي تم التحقق من صحتها من كائن الطلب، وإنشاء اسم ملف كامل عن طريق تسلسل المعلمة التي تم تمريرها في fileName مع الامتداد الأصلي لـ userFile، وتخزين الملف داخل دليل في تطبيقنا، ثم إرجاع ملف JSON مشفر بسيط استجابة التحقق من نجاح الطلب. يتم تلقي الاستجابة من خلال منطق jQuery، الذي يقوم ببعض المهام الأخرى المتعلقة بواجهة المستخدم مثل عرض رسالة النجاح (أو الخطأ) لمدة 5 ثوانٍ ثم إخفائها بالإضافة إلى مسح إدخالات النموذج السابقة... وذلك حتى يعرف المستخدم للتأكد من أن الطلب كان ناجحًا ويمكنهم تحميل ملف آخر إذا رغبوا في ذلك.

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

لقد قمنا بتغطية ما يقرب من 90+ من الأسئلة المهمة المتداولة أسئلة المقابلة ذات الصلة بـ Laravel و PHP للطلاب الجدد وكذلك المرشحين ذوي الخبرة للحصول على الوظيفة المناسبة.