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

ما هو Laravel؟
لارافل هو إطار عمل MVC مفتوح المصدر لـ PHP. Laravel هو إطار عمل قوي يوفر تطويرًا سهلاً لتطبيقات الويب PHP مع ميزات مثل نظام التعبئة المعياري مع مدير تبعية مخصص، والوصول إلى قواعد البيانات العلائقية، والأدوات المساعدة الأخرى لنشر التطبيقات وصيانتها.
تم تطوير Laravel بواسطة تايلور أوتويل. ومنذ إصداره الأول في يونيو 2011 (الإصدار 1)، ازداد انتشاره بشكل مطرد في قطاع أطر عمل PHP ضمن صناعة تطوير الويب. ويعود جزء كبير من هذا الانتشار إلى العديد من الميزات التي تراعي احتياجات المطورين بشكل أساسي، والتي تأتي مُدمجة افتراضيًا.
لماذا Laravel؟
حوالي عام 2000، على الأغلب كود PHP كانت إجرائية ويمكن العثور عليها في شكل "نصوص" تحتوي على فوضى متشابكة من رموز السباغيتي. حتى أبسط الصفحات لم يكن لها فصل المخاوفوبالتالي، كان من السهل نسبيًا أن يتحول أي تطبيق بسرعة إلى كابوس صيانة. كان العالم بحاجة إلى حل أفضل. هنا ظهر الإصدار الخامس من لغة PHP ومجموعة متنوعة من أطر عمل PHP التي سعت إلى توفير بنية ضرورية وحلول أفضل لمختلف مشاكل تطبيقات الويب.
منذ ذلك الحين، شهدنا إطلاق العديد من أطر العمل التي مهدت الطريق لأطر العمل الشائعة المستخدمة اليوم. في رأينا، تُعدّ Zend Framework وSymfony، وبالطبع Laravel، أفضل ثلاثة أطر عمل. مع أن كل إطار عمل من هذه الأطر تأسس على مبادئ متشابهة ويهدف إلى حلّ (بشكل أساسي) نفس المشاكل الشائعة، إلا أن الاختلافات الرئيسية بينها تكمن في طريقة تنفيذها. لكل منها خصائصها المميزة في كيفية حلّ المشاكل. عند النظر إلى الشيفرة البرمجية الناتجة عن كل منها، ستلاحظ وجود فرق واضح بينها. في رأينا المتواضع، يُعدّ إطار عمل Laravel الأفضل.
تعرف على المزيد حول الفرق بين Laravel و Codeأنبوب.
كيفية تنزيل Laravel وتثبيته مع Composer
ملاحظة: كُتب هذا الدليل التعليمي لـ Laravel 5.8، لكن مفاهيم التوجيه، والمتحكم، والطلبات، وBlade تبقى كما هي في الإصدارات الحالية. اعتبارًا من عام 2026، كان أحدث إصدار هو Laravel 13 (صدر في مارس 2026)، والذي يتطلب PHP 8.3 أو أحدث، بينما يتطلب Laravel 12 الإصدار PHP 8.2.
ملاحظة: يُفترض أن لديك نسخة من PHP مثبتة بالفعل على نظامك المحلي. إذا لم يكن الأمر كذلك، يمكنك قراءة كيفية تثبيتها. اضغط هنا.
يعد Composer مديرًا للحزم والتبعيات. لتثبيته، افتح محطة طرفية وانتقل إلى دليل جديد. قم بتشغيل هذا الأمر:
curl -Ss getcomposer.org/installer | php
ستبدو نتائج هذا الأمر كما يلي:
ملاحظة: للحصول على تعليمات أكثر تفصيلاً حول إعداد Laravel، يُرجى الرجوع إلى وثائق Laravel. اضغط هنا.
ستلاحظ عملية تنزيل وتجميع سكربت composer.phar، وهو السكربت الذي نستخدمه لتثبيت Laravel. على الرغم من وجود طرق عديدة لإعداد تطبيق Laravel جديد، سنستخدم سكربت Composer الخاص بـ Laravel. لتثبيت هذا السكربت، شغّل الأمر التالي:
composer global require laravel/installer
والتي سوف تبدو مثل هذا:
سيؤدي هذا إلى تنزيل وتثبيت جميع ملفات إطار العمل، بالإضافة إلى جميع التبعيات اللازمة. سيتم حفظ الحزم داخل مجلد vendor. بمجرد اكتمال التنزيل والتثبيت، يصبح الأمر بسيطًا للغاية، كل ما عليك فعله هو تنفيذ الأمر التالي:
laravel new uploadApp
سوف ترى شيئًا مثل الناتج التالي:
يقوم Composer بتثبيت جميع الحزم التي يحتاجها Laravel للتشغيل. قد يستغرق الأمر بضع دقائق، لذا يُرجى التحلي بالصبر. بعد الانتهاء، شغّل الأمر ls -al للاطلاع على ما تم تثبيته.
فيما يلي تفصيل موجز للأدلة في تطبيق Laravel الشائع:
- برنامج/ : هذا هو مجلد المصدر الذي يحتوي على كود التطبيق الخاص بنا. جميع وحدات التحكم والسياسات والنماذج موجودة داخل هذا المجلد.
- التمهيد/ : يحتوي على برنامج بدء تشغيل التطبيق وبعض ملفات خريطة الفئات.
- التكوين/ : يحتوي على ملفات تكوين التطبيق. عادةً لا يتم تعديل هذه الملفات مباشرةً، بل تعتمد على القيم المُحددة في ملف .env (البيئة) الموجود في جذر التطبيق.
- قاعدة البيانات/ : يحتوي على ملفات قاعدة البيانات بما في ذلك عمليات الترحيل، والبذور، ومصانع الاختبار.
- عام/ : مجلد متاح للعامة يحتوي على الأصول المجمعة، وبالطبع، ملف index.php.
- موارد/ : يحتوي على أصول الواجهة الأمامية مثل Javaملفات البرمجة النصية، وملفات اللغة، وملفات CSS/SASS، وجميع القوالب المستخدمة في التطبيق (تسمى قوالب Blade).
- الطرق/ : جميع المسارات في التطبيق موجودة هنا. هناك عدة "نطاقات" مختلفة للمسارات، لكننا سنركز على ملف web.php.
- تخزين/ : جميع ملفات التخزين المؤقت المؤقتة التي يستخدمها التطبيق، وملفات الجلسة، ونصوص العرض المجمعة، وملفات السجل.
- الاختبارات/ : يحتوي على ملفات اختبار للتطبيق، مثل اختبارات الوحدة والاختبارات الوظيفية.
- بائع/ : تم تثبيت جميع حزم التبعية باستخدام Composer.
والآن، لنقم ببناء بقية التطبيق وتشغيله باستخدام أمر Artisan خاص (لتوفير عناء تثبيت وتكوين خادم ويب مثل Apache أو nginx). يحتوي ملف .env على جميع قيم التكوين التي تستخدمها الملفات الموجودة في مجلد /config لتكوين التطبيق.
تصميم التطبيق: ملخص سريع لمتطلباتنا
في هذا البرنامج التعليمي عبر الإنترنت Laravel، سنقوم ببناء تطبيق بسيط للغاية يقوم بأمرين فقط:
- التعامل مع تحميلات الملفات من نموذج ويب
- عرض الملفات التي تم تحميلها مسبقًا على صفحة مختلفة.
في هذا المشروع، سيكون تطبيقنا للكتابة فقط، أي أن المستخدم سيتمكن فقط من كتابة الملفات وعرض قائمة الملفات التي قام بتحميلها. هذا التطبيق بسيط للغاية، ولكنه يُعدّ تدريبًا جيدًا لبناء مهاراتك ومعرفتك في Laravel. تجدر الإشارة إلى أننا، اختصارًا للوقت، لم نتطرق إلى نمذجة قواعد البيانات، أو عمليات الترحيل، أو المصادقة، ولكن في التطبيقات العملية، ستكون هذه أمورًا إضافية عليك مراعاتها.
فيما يلي قائمة بالمكونات التي سنحتاجها لتشغيل التطبيق كما هو متوقع:
- A الطريق سيسمح ذلك للعالم الخارجي (الإنترنت) باستخدام التطبيق، بالإضافة إلى تحديد نقطة النهاية التي ستشير إلى مكان وجود منطق حفظ الملف الذي تم تحميله.
- A مراقب الذي يتولى عملية نقل البيانات من الطلب إلى الاستجابة.
- A قالب سيتم استخدام ذلك لعرض قائمة بالملفات التي تم تحميلها مسبقًا ونموذج التحميل الفعلي نفسه.
- A طلب والتي سيستخدمها المتحكم للتحقق من صحة البيانات التي تم تمريرها من نموذج الويب.
ما هو الطريق؟
المسار في Laravel هو في الأساس نقطة نهاية مُحددة بواسطة مُعرّف موارد موحد (URI)، تعمل كمؤشر إلى وظيفة معينة يُقدمها التطبيق. في أغلب الأحيان، يُشير المسار ببساطة إلى دالة في وحدة تحكم، ويُحدد أيضًا طرق HTTP التي يُمكنها الوصول إلى مُعرّف الموارد الموحد هذا. ولا يعني المسار بالضرورة دالة في وحدة التحكم، فقد يُمرر تنفيذ التطبيق إلى دالة مُعرّفة (Closure) أو دالة مجهولة.
لماذا نستخدم مسارًا؟
يتم تخزين المسارات داخل ملفات ضمن مجلد /routes داخل الدليل الجذر للمشروع. بشكل افتراضي، هناك عدد قليل من الملفات المختلفة المقابلة لـ "الجوانب" المختلفة للتطبيق (تأتي "الجوانب" من منهجية الهندسة المعمارية السداسية). وهي تشمل:
- ملف web.php: المسارات العامة التي يستخدمها المتصفح. وهي الأكثر شيوعًا، وهي التي يتم الوصول إليها بواسطة متصفح الويب. تعمل هذه المسارات من خلال مجموعة برامج وسيطة للويب، وتحتوي أيضًا على وظائف لـ حماية من هجمات تزوير الطلبات عبر المواقع (CSRF) (مما يساعد في الدفاع ضد الهجمات الخبيثة القائمة على النماذج) وتحتوي عمومًا على درجة من "الحالة" (ونعني بذلك أنها تستخدم الجلسات).
- ملف api.php: يحتوي على مسارات تتوافق مع مجموعة واجهات برمجة التطبيقات (API)، وبالتالي يتم تفعيل برمجيات الوسيطة الخاصة بواجهة برمجة التطبيقات (API) افتراضيًا. هذه المسارات عديمة الحالة، ولا تحتوي على جلسات أو ذاكرة مشتركة بين الطلبات (لا يتشارك أي طلب البيانات أو الذاكرة مع أي طلب آخر؛ كل طلب مغلف ذاتيًا).
- console.php: تتوافق هذه المسارات مع أوامر Artisan المخصصة التي قمت بإنشائها لتطبيقك.
- channels.php: يسجل مسارات بث الأحداث.
الملف الرئيسي الذي يجب التركيز عليه الآن هو ملف web.php الخاص بالمتصفح. يوجد مسار افتراضي مُعرّف مسبقًا، وهو المسار الذي ستختاره عند الانتقال إلى جذر موقع تطبيقك (يقع جذر الموقع في المجلد العام). سنحتاج إلى ثلاثة مسارات مختلفة لكي يعمل تطبيق الرفع الخاص بنا:
- /upload: سيكون هذا هو عنوان URI للصفحة الرئيسية التي تعرض نموذج الويب الخاص بنا لتحميل الملفات.
- /process: سيكون هذا هو المكان الذي يقوم فيه النموذج الموجود في /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()، patch()، أو options()). للاطلاع على شرح مفصل لكل منها، راجع تُحدد هذه الطرق أفعال HTTP المسموح لها بالوصول إلى مسار معين. إذا كنتَ بحاجة إلى مسار يقبل أكثر من فعل HTTP واحد (كما هو الحال عند استخدام صفحة واحدة لعرض البيانات الأولية وإرسال بيانات النموذج المُرسَل)، فيمكنك استخدام طريقة Route::any().
الوسيط الثاني لكل من دالتي `Route::get()` و`Route::post()` (وأي دوال أخرى متعلقة بأفعال HTTP في واجهة `Route`) هو اسم وحدة تحكم محددة والدالة الموجودة داخلها والتي تُنفَّذ عند الوصول إلى نقطة نهاية المسار باستخدام طلب HTTP المسموح به (GET، POST، PATCH، إلخ). نستخدم وحدة التحكم `UploadController` لجميع المسارات، وقد حددناها على النحو التالي:
آخر طريقة نستدعيها على كل مسار هي دالة name() الخاصة به، والتي تقبل سلسلة نصية واحدة كوسيط، وتُستخدم لتمييز مسار معين باسم يسهل تذكره (في حالتنا، upload وprocess وlist). قد لا يبدو إعطاء كل مسار اسمًا خاصًا به ميزة رائعة عندما... URL يتم تسميته بنفس الاسم تمامًا، ولكنه مفيد حقًا عندما يكون لديك مسار محدد مثل /users/profile/dashboard/config، والذي سيكون من الأسهل تذكره باسم profile-admin أو user-config.
ملاحظة حول الواجهات:
- توفر الواجهات واجهة "ثابتة" للفئات المتوفرة في حاوية خدمة التطبيق.
- إنها توفر صيغة مقتضبة وسهلة التذكر تسمح لك باستخدام ميزات Laravel دون تذكر أسماء الفئات الطويلة التي يجب إدخالها أو تهيئتها يدويًا.
في تعريفات المسارات المذكورة أعلاه، نستخدم واجهة Route بدلاً من إنشاء كائن Illuminate/Routing/Router جديد يدويًا واستدعاء الطرق المقابلة عليه. إنها مجرد طريقة مختصرة توفر الوقت والجهد.pingتُستخدم الواجهات بكثرة في إطار عمل 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" المحدد داخل وحدة تحكم بدلاً من تعريف المسار كدالة رد نداء:
- منطقنا منفصل تمامًا في فئته الخاصة (فصل الاهتمامات).
- تم تصميم وحدة التحكم لدينا لتكون قابلة للتوسيع لاحقًا إذا احتجنا إلى إضافة إمكانيات إضافية إليها. لنفترض أننا أردنا إضافة ميزة "وداعًا للعالم". في هذه الحالة، سنعيد تسمية وحدة التحكم إلى اسم أكثر عمومية "HelloController"، ثم نُعرّف طريقتين منفصلتين. أهلا() و مع السلامة(). سنحتاج أيضًا إلى تحديد طريقين منفصلين يرسمان خريطة /مرحبًا و / مع السلامة يتم توجيه عناوين URI إلى الطريقة المناسبة لها في وحدة التحكم. وهذا أفضل من إضافة المزيد من التفاصيل إلى ملف التوجيهات، حيث يتم تعريف كل مسار كدالة رد نداء.
- يمتلك Laravel القدرة المضمنة على تخزين جميع تعريفات المسار في التطبيق مؤقتًا بحيث يسرع الوقت المستغرق للعثور على مسار معين (يزيد من أداء التطبيق)؛ ومع ذلك، لن تتمكن من الاستفادة من ذلك إلا إذا تم تكوين جميع المسارات المحددة داخل التطبيق باستخدام خريطة خاصة بوحدة التحكمping(انظر المثال رقم 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 داخل المسار app/Http/Requests/UploadFileRequest. افتح الملف وألقِ نظرة عليه. ستجده بسيطًا للغاية، إذ يحتوي على دالتين فقط: authorize() و rules().
إنشاء منطق التحقق من الصحة
لنقم بتعديل نموذج الطلب ليناسب احتياجات تطبيقنا. عدّل الملف بحيث يبدو كالتالي:
<?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 بدلاً من false. تُحدد هذه الدالة ما إذا كان سيتم السماح للطلب بالدخول إلى التطبيق أم لا. إذا كانت قيمتها false، فسيتم منع الطلب من دخول النظام. سيكون هذا مكانًا مناسبًا جدًا لإجراء أي فحوصات ترخيص للمستخدم أو أي منطق آخر قد يُحدد ما إذا كان الطلب سيُرسل إلى وحدة التحكم. حاليًا، نُرجع القيمة true هنا للسماح لأي شيء باستخدام الطلب.
أما الطريقة الأخرى، rules()، فهي التي تُحدث فرقًا كبيرًا في عملية التحقق من الصحة. الفكرة بسيطة: إرجاع مصفوفة تحتوي على مجموعة من القواعد على النحو التالي:
'formFieldName' => 'constraints this field has separated by pipe characters (|)'
هناك العديد من قيود التحقق المختلفة التي يدعمها Laravel فورًا. للحصول على قائمة كاملة بها، راجع الوثائق عبر الإنترنت اضغط هنافي تطبيق التحميل الخاص بنا، سيتم تمرير حقلين عبر طلب POST من نموذج في واجهة المستخدم. يجب تضمين مُعامل fileName داخل نص النموذج (أي أنه إلزامي)، ويُستخدم كاسم الملف الذي سنخزنه في وحدة التخزين (يتم ذلك في وحدة التحكم، وسنتناوله لاحقًا). كما نُحدد أن اسم الملف يجب أن يكون نصًا بإضافة رمز الأنبوب (|) وكلمة "نص". تُفصل القيود دائمًا برموز الأنبوب، مما يسمح لك بتحديد أي معايير إضافية للحقل المحدد في سطر واحد.
المعامل الثاني، userFile، هو الملف الفعلي الذي يقوم المستخدم بتحميله من نموذج على صفحة ويب. userFile مطلوب أيضًا. يجب يكون ملفا. ملاحظة: لو كنا نتوقع أن يكون الملف المرفوع صورة، لاستخدمنا قيد الصورة، الذي سيحصر أنواع الملفات المقبولة في أحد أنواع الصور الشائعة (jpeg، png، bmp، gif، أو svg). ولأننا نريد السماح للمستخدم برفع أي نوع من الملفات، سنكتفي بقيد التحقق من صحة الملف.
هذا كل ما يتعلق بكائن الطلب. وظيفته الأساسية هي ببساطة الاحتفاظ بمجموعة المعايير المقبولة (القيود) التي يجب أن تستوفيها معلمات نص النموذج للمتابعة إلى مراحل متقدمة في التطبيق. تجدر الإشارة أيضًا إلى أنه يجب تحديد هذين الحقلين (userFile و fileName) داخل كود 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 process(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'); //so 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
}
}
لذا، تُعدّ هذه طريقةً بسيطةً لحفظ الملفات المرفوعة على القرص. إليك شرحٌ مُفصّلٌ لطريقة process() المذكورة أعلاه:
- قم بتحديد نوع فئة الطلب في طريقة وحدة التحكم التي تقوم بالوظيفة الرئيسية حتى نتمكن من التحقق التلقائي من صحة البيانات الواردة.
- استخرج الملف من كائن الطلب (الذي تم التحقق من صحته الآن) داخل طريقة وحدة التحكم.
- استخرج اسم الملف من الطلب.
- قم بإنشاء اسم الملف النهائي الذي سيتم استخدامه لحفظ الملف تحته. تقوم طريقة getClientOriginalExtension() ببساطة بالحصول على الامتداد الأصلي للملف الذي تم تحميله.
- قم بتخزين الملف في نظام الملفات المحلي باستخدام طريقة storeAs() الخاصة به، مع تمرير المسار المسمى داخل دليل /storage باعتباره الوسيط الأول واسم الملف الذي سيتم حفظه فيه باعتباره الوسيط الثاني.
- قم بإرجاع استجابة JSON تشير إلى نجاح الطلب.
قالب الشفرة
آخر قطعة رئيسية في هذه الأحجية هي قالب الشفرة، الذي سيحتوي على جميع ملفات HTML وCSS و Javaنص برمجي لتطبيقنا البسيط. إليكم الكود؛ سنشرحه لاحقاً.
<body>
<h1>Upload a file</h1>
<form id="uploadForm" name="uploadForm" action="{{route('process')}}" 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>
هنا هو ما لدينا / تحميل الصفحة تبدو مثل:
هذا مثال نموذجي جدًا لملف Blade يحتوي على نموذج HTML و Javaسكربت/jQuery لإضافة وظائف غير متزامنة (بحيث لا يتم تحديث الصفحة). يوجد أساس عنصر `tag` بدون سمة `method` (والتي سنشرحها بعد قليل) وبسمة `action` غريبة بقيمة `{{route('process')}}`. في Blade، يُعرف هذا باسم ` التوجيه. التوجيه ليس إلا اسمًا مُنمّقًا للدالة؛ وهي دوال خاصة بقوالب Blade تُنفّذ عمليات مُختلفة شائعة في بناء صفحات الويب وتطبيقاتها. لفهم أفضل لجميع الميزات المفيدة التي يُمكن لـ Blade القيام بها، راجع الوثائق. اضغط هنافي المثال أعلاه، نستخدم توجيه المسار لإنشاء URL لتقديم النموذج الخاص بنا.
تذكر أننا حددنا مساراتنا سابقًا في التطبيق داخل ملف web.php، مع تحديد اسم يسهل تذكره لكل منها. يقبل التوجيه {{route()}} اسم المسار، ويبحث عنه داخل قائمة المسارات المخزنة مؤقتًا داخليًا، ثم يُنشئ مسارًا كاملاً. URL استنادًا إلى تعريف هذا المسار في ملف web.php. في هذه الحالة الأولى، نحدد أننا نريد من النموذج إرسال البيانات المُرسلة إلى /process URL من تطبيقنا، والذي يُعرَّف بأنه سأعين الطريق.
قد تكون لاحظتَ أيضًا وجود وسم @csrf أسفل وسم النموذج الرئيسي مباشرةً. في Blade، يُنشئ هذا الوسم مُعاملًا _token في النموذج، والذي يتم التحقق منه داخل التطبيق قبل السماح بمعالجة بيانات النموذج. يضمن هذا أن تكون البيانات داخل النموذج من مصدر صحيح ويمنع هجمات تزوير الطلبات عبر المواقع. لمزيد من المعلومات حول هذا الموضوع، راجع مستندات.
بعد ذلك، نُعرّف نموذجنا كالمعتاد؛ ومع ذلك، تجدر الإشارة إلى أن أسماء معلمات النموذج لدينا، userFile و fileName، هي بالضبط نفس كما هو مُحدد داخل كائن الطلب. إذا نسينا تضمين مُدخل لمعامل مُحدد في كائن الطلب (أو أخطأنا في كتابته)، فسيفشل الطلب وسيتم إرجاع خطأ، مما يمنع طلب النموذج الأصلي من الوصول إلى دالة وحدة التحكم الموجودة في UploadController@process.
تفضل وجرّب ذلك، وأرسل بعض الملفات إلى التطبيق باستخدام هذا النموذج. بعد ذلك، انتقل إلى /قائمة صفحة لرؤية محتويات مجلد التحميل، مع إدراج الملفات التي قمت بتحميلها في جدول:
الصورة الأكبر
دعونا نعود خطوة إلى الوراء ونلقي نظرة على ما قمنا به في هذا الدرس التعليمي عن Laravel.
يوضح هذا الرسم التخطيطي التطبيق كما هو عليه الآن (باستثناء التفاصيل العامة):
يجب أن تتذكر أن كائن الطلب الذي أنشأناه في بداية هذا الدرس التعليمي لـ Laravel يجب أن يحتوي على نفس المعلمات المُعرّفة في دالة القواعد الخاصة به كما هي موجودة في النموذج الموجود في قالب Blade (وإلا، فأعد قراءة قسم "إنشاء منطق التحقق"). يُدخل المستخدم النموذج على صفحة ويب يتم عرضها بواسطة محرك قالب Blade، ثم يُرسل النموذج. يقوم كود jQuery الموجود أسفل القالب بإيقاف الإرسال الافتراضي (الذي كان سيُعيد التوجيه تلقائيًا إلى صفحة منفصلة)، ويُنشئ طلب AJAX، ويُحمّل الطلب ببيانات النموذج والملف المُحمّل، ثم يُرسل كل ذلك إلى الطبقة الأولى من تطبيقنا: طبقة الطلب.
يتم ملء كائن الطلب بربط المعلمات داخل دالة rules() بمعلمات النموذج المُرسَل، ثم يتم التحقق من صحة البيانات وفقًا لكل قاعدة مُحددة. إذا استُوفيت جميع القواعد، يُمرَّر الطلب إلى دالة وحدة التحكم المُناسبة للقيم المُعرَّفة في ملف التوجيه web.php. في هذه الحالة، تقوم دالة process() الخاصة بوحدة التحكم UploadController بهذه المهمة. بمجرد الوصول إلى وحدة التحكم، نكون قد تأكدنا من نجاح الطلب، لذا لسنا بحاجة إلى إعادة اختبار ما إذا كان اسم الملف المُعطى سلسلة نصية أم أن مُعامل userFile يحتوي على نوع ملف. يُمكننا المتابعة كالمعتاد.
تقوم دالة التحكم باستخلاص المعاملات المُدققة من كائن الطلب، ثم تُنشئ اسم ملف كاملاً بدمج معامل fileName المُمرر مع الامتداد الأصلي لملف المستخدم، وتخزن الملف في مجلد ضمن تطبيقنا، ثم تُعيد استجابة JSON بسيطة تُؤكد نجاح الطلب. تستقبل دالة jQuery هذه الاستجابة، وتُنفذ بعض المهام الإضافية المتعلقة بواجهة المستخدم، مثل عرض رسالة النجاح (أو الخطأ) لمدة 5 ثوانٍ، ثم إخفائها، بالإضافة إلى مسح جميع إدخالات النموذج السابقة. هذا يُتيح للمستخدم التأكد من نجاح الطلب، وإمكانية تحميل ملف آخر إذا رغب في ذلك.
لاحظ أيضًا في الرسم التوضيحي أعلاه مكان الخط الفاصل بين العميل والخادم. هذا المفهوم بالغ الأهمية لفهمك، وسيساعدك على حل المشكلات التي قد تواجهها مستقبلًا عند التعامل مع طلبات غير متزامنة متعددة، على سبيل المثال، والتي قد تحدث في أي وقت. يقع هذا الفصل عند حدود كائن الطلب. يمكن اعتبار كائن الطلب بمثابة "بوابة" لبقية التطبيق، حيث يقوم بالتحقق الأولي من صحة قيم النموذج المُمررة من متصفح الويب وتسجيلها. إذا كانت القيم صحيحة، ينتقل الطلب إلى وحدة التحكم. كل ما يسبق ذلك يتم في واجهة المستخدم (العميل هنا يعني حرفيًا "على جهاز المستخدم"). تُعاد الاستجابة من التطبيق إلى جانب العميل، حيث يستمع كود jQuery الخاص بنا بصبر لوصولها، ثم يقوم ببعض مهام واجهة المستخدم البسيطة فور استلامها.
لقد غطينا أيضًا العديد من الأسئلة المهمة والمتكررة أسئلة المقابلة ذات الصلة بـ Laravel و PHP للطلاب الجدد وكذلك المرشحين ذوي الخبرة للحصول على الوظيفة المناسبة.







