اذهب إلى المحتوى

البحث في الموقع

المحتوى عن 'laravel 5'.

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

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

نوع المحتوى


التصنيفات

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

التصنيفات

  • مقالات برمجة عامة
  • مقالات برمجة متقدمة
  • PHP
    • Laravel
    • ووردبريس
  • جافاسكربت
    • لغة TypeScript
    • Node.js
    • React
    • Vue.js
    • Angular
    • jQuery
    • Cordova
  • HTML
  • CSS
    • Sass
    • إطار عمل Bootstrap
  • SQL
  • لغة C#‎
    • ‎.NET
    • منصة Xamarin
  • لغة C++‎
  • لغة C
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • لغة Rust
  • برمجة أندرويد
  • لغة R
  • الذكاء الاصطناعي
  • صناعة الألعاب
  • سير العمل
    • Git
  • الأنظمة والأنظمة المدمجة

التصنيفات

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

التصنيفات

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

التصنيفات

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

التصنيفات

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

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
    • بريستاشوب
    • أوبن كارت
    • دروبال
  • الترجمة بمساعدة الحاسوب
    • omegaT
    • memoQ
    • Trados
    • Memsource
  • برامج تخطيط موارد المؤسسات ERP
    • تطبيقات أودو odoo
  • أنظمة تشغيل الحواسيب والهواتف
    • ويندوز
    • لينكس
  • مقالات عامة

التصنيفات

  • آخر التحديثات

أسئلة وأجوبة

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

التصنيفات

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

ابحث في

ابحث عن


تاريخ الإنشاء

  • بداية

    نهاية


آخر تحديث

  • بداية

    نهاية


رشح النتائج حسب

تاريخ الانضمام

  • بداية

    نهاية


المجموعة


النبذة الشخصية

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

  1. إدارة الصور هي واحدة من الأشياء التي غالبا ما أجدها صعبة، فأنا معتاد على التعامل مع النماذج وجداول قواعد البيانات، لكن التعامل مع الملفات ليس سهلا بالنسبة لي، فإذا كنت قد بدأت للتو مع Laravel وبدأت تشعر بالصعوبة والضيق، فأنا أشعر بألمك. لحسن الحظ، أساسيات إدارة الصور في Laravel لن تكون صعبة إذا فهمت بعض الأمور الأساسية. ملاحظة: إذا كنت جديدا في Laravel، فلا أنصحك بالبدء بهذا الدرس، أنصحك بقراءة بعض الدروس والدورات حول Laravel قبل المتابعة. سوف تلاحظ أن الدرس طويل لذلك قمت بتقسيمه إلى 3 أجزاء، وسوف تلاحظ أيضا أنني لست بارعا في تصميم الواجهة الأمامية (front-end)، فلذلك فالواجهات التي سنقوم بعملها لن تكون جميلة جدا، يمكنك تزيينها بنفسك لاحقا، فالهدف الأساسي هنا هو تعلم أساسيات إدارة الصور. لذلك على أية حال، ماهي هذه الأساسيات ؟ فكرتُ بالمتطلبات التي قد تحتاجها في تطبيقك وكتبتها في هذه القائمة: إنشاء الصورتخزين الصورتعديل الصورتحديث الصورإنشاء صور مصغرةتعديل صور مصغرةإنشاء وتعديل صور الهواتف بشكل منفصلبالنسبة للذين اعتادوا على إجراءات المتحكِّمات (controller actions) المريحة، ستظهر الاستمارات عند إجراءات (actions) الإنشاء create والتعديل edit وأما إجراءات التخزين store والتحديث update فوظيفتهم إنشاء وتعديل السجلات والملفات. سنتعامل مع شيئين مهمين عند تعاملنا مع الصور، الشيء الأول هو النموذج الذي يعمل على البيانات مثل اسم الصورة و مسارها، وأما الشيء الثاني فهو ملف الصورة نفسه الذي سوف يتم تخزينه في مجلد الذي سنقوم بإسناده له. تثبيت Interventionسوف نبدأ بتثبيت حزمة Intervention/image، فإذا لم تقُم بذلك، عدل على ملف composer.json وأضف التعليمة التالية في جزء الاستدعاء (require) : "intervention/image": "~2.2"ثم أضف السطر التالي ضمن مصفوفة Providers في ملف app\config\app.php (انتبه للفواصل) : Intervention\Image\ImageServiceProvider::class,في نفس الملف أضف السطرين التاليين لمصفوفة Aliases: Intervention\Image\ImageServiceProvider::class,أنصحك بالإطلاع على صفحة Intervention للتأكد من الإصدار الأخير للحزمة. في آخر مرة تأكدتُ فيها،كانت تعليمات التَدَخّل تستخدم النمط القديم للإشارة إلى المرجع: 'Intervention\Image\ImageServiceProvider'يمكنك أن تلاحظ في الأعلى أننا في كلتا الحالتين استخدمنا ::class والتي هي ممارسة جيدة تعلمتها من Laracasts.com، فإذا كنت تستخدم على سبيل المثال PHP Storm، فسيكون باستطاعتك الوصول إلى الفئة class الأساسية. إن حزمة Intervention تقوم بإعطائنا صياغة (syntax) وطريقة سهلة لصناعة الصور المصغرة بالإضافة إلى الكثير من التوابع (method) الأخرى الرائعة، لذلك سوف نستخدمها في هذا الدرس، ولمزيد من المعلومات حول هذه الحزمة أنصحك بالإطلاع على التوثيق الرسمي. لاحظ أيضا أننا سنقوم باستخدام حزمة laravelcollective/html وحزمة patricktalmadge/bootstrapper، ولذلك قم بتثبيتهم قبل أن تتابع الدرس. إنشاء نموذجسوف نبدأ بإنشاء نموذج Marketingimage، يمكننا فعل ذلك عن طريق artisan من سطر الأوامر بكتابة السطر التالي: php artisan make:model Marketingimage -mسوف تلاحظ علم m- الذي سيخبر Laravel أنك تريد إنشاء تهجير migration في نفس الوقت، لذلك فهذه الميزة مفيدة للغاية. حسنا، قم بتنفيذ الأمر السابق وستحصل على ملف النموذج والمسمى Marketingimage.php مباشرة تحت دليل تطبيقك وستحصل أيضا على ملف التهجير في مجلد database/migrations. دعونا نقوم بتعديل التابع في أعلى ملف التهجير إلى ما يلي: public function up() { Schema::create('marketing_images', function(Blueprint $table) { $table->increments('id'); $table->boolean('is_active')->default(false); $table->boolean('is_featured')->default(false); $table->string('image_name')->unique(); $table->string('image_path'); $table->string('image_extension', 10); $table->string('mobile_image_name')->unique(); $table->string('mobile_image_path'); $table->string('mobile_extension', 10); $table->timestamps(); }); }أول شيئ يمكنك رؤيته أنني قد غيرت اسم الجدول، فأنا افضل فصل الكلمات في جدول الأسماء بسطر سفلي underscore. أنت حر في اختيار الطريقة التي تعجبك، لكن يجب أن نختار صيغة الجمع لإتباع قواعد Laravel بشكل صحيح. ففي Laravel، النموذج يكتب بصيغة المفرد وأما اسم الجدول فيكتب بصيغة الجمع. بعد عمود المعرف الرقمي، قمنا باستخدام عمودين من نوع المنطقي boolean والتي سوف تسمح لنا بمعرفة هل الصورة نشطة أو مميزة، هذه القيود المفيدة سوف تساعد على العمل مع الصور في وقت لاحق. ثم قمنا بإضافة أعمدة الاسم، المسار والامتدادات للصور وصور الهاتف، وهذا سيسمح لنا بالمرونة الكافية إذا أردت حفظ صورة مختلفة للهاتف، وهذا الأمر ضروري لأن تغيير حجم الصورة قد لا ينتج لنا النتائج المرجوة. وبما أننا سوف نقوم بإنشاء صور مصغرة من الصور الأصلية، لن نحتاج إلى حفظ أية بيانات لذلك. عن طريق حفظ مسار وإمتداد الصورة، سيكون لدينا مرجع سهل نستطيع استخدامه لإظهار الصورة في تطبيقنا، بالإضافة إدارة الصورة في قائمة الصور. عدل على التابع ليبدو على النحو التالي: public function down() { Schema::drop('marketing_images'); }بمجرد أن تقوم بذلك، قم بتنفيذ أمر php artisan migrate من سطر الأوامر وتأكد من أن الجدول قد تم إنشاءه. بعد هذا، سوف نقوم بتعديل نموذج Marketingimage كما يلي: <?php namespace App; use Illuminate\Database\Eloquent\Model; class Marketingimage extends Model { protected $table = 'marketing_images'; protected $fillable = ['is_active', 'is_featured', 'image_name', 'image_path', 'image_extension', 'mobile_image_name', 'mobile_image_path', 'mobile_extension' ]; }سوف تلاحظ أننا قمنا بإخبار النموذج الجدول الذي سيتخذه كمرجع، بالإضافة إلى توفير أعمدة مملوءة تلقائيا، حتى لا نواجه مشكلة الإحالة الكتلية mass-assignment. المتحكمجيد، نحن الآن مستعدين للاستمرار للخطوة القادمة، سنقوم بإنشاء المتحكِّم بإستخدام artisan: php artisan make:controller MarketingImageControllerوبهذا سوف تحصل على متحكِّم في app/Http/Controllers مع التوابع التالية: indexcreatestoreshoweditupdatedestroyوسوف نستخدم جميع هذه التوابع. وكنصيحة مفيدة للمبتدئين، قُم بوضع السطر التالي في تابع index: return 'Here is the index method.';فهذا سوف يعطيك فرصة لتجربة هذا الطريق route. (يستطيع بقية المبرمجين المحترفين تجاوز هذه الخطوة إذا أرادوا) وبعد ذلك، سنقوم بتثبيت الطرق routes. عدل على ملف app/Http/routes.php وأضف التعليمة التالية: Route::resource('marketingimage', 'MarketingImageController');سوف ترى أننا قد قمنا بإضافة مورد resource، والذي سوف يقوم بإعطائنا الطرق routes لجميع الإجراءات actions بطريقة مريحة للغاية. حسنا، سوف تستطيع الآن الذهاب إلى yourproject.com/marketingimage وسوف تحصل على النتيجة التالية: Here is the index method.الخطوة المنطقية التالية هي إعداد العروض views، أنشئ مجلدا باسم marketingimage أسفل resources/views، ثم أنشئ الملفات الفارغة التالية داخل مجلد marketingimages: create.blade.phpedit.blade.phpindex.blade.phpshow.blade.phpإعداد المجلداتسوف نعود إلى تلك الملفات في وقت لاحق، في الوقت الحالي، سنقوم بإنشاء مكان لتخزين صورنا الحالية، سوف أجعل هذا الأمر سهلا، أنشئ مجلدا باسم imgs مباشرة تحت مجلدك العام (public folder)، وبداخل مجلد imgs، أنشئ مجلد marketing، وبداخله أنشئ مجلدا باسم mobile وآخر بإسم thumbnails. الآن قمنا بإنشاء جميع المجلدات للصور. عرض الإنشاء The Create Viewحسنا، دعونا الآن نتعامل مع عرض الإنشاء The Create View. أضف الأسطر التالية داخل ملف `create.blade.php`: @extends('layouts.master') @section('content') {!! Breadcrumb::withLinks(['Home' => '/', 'marketing images' => '/marketingimage', 'create']) !!} <h1>Upload a Photo </h1> <hr/> @if (count($errors) > 0) <div class="alert alert-danger"> <strong>Whoops! </strong> There were some problems with your input. <br> <br> <ul> @foreach ($errors->all() as $error) <li>{{ $error }} </li> @endforeach </ul> </div> @endif {!! Form::open(array('route' => 'marketingimage.store', 'class' => 'form', 'files' => true)) !!} <!-- image name Form Input --> <div class="form-group"> {!! Form::label('image name', 'Image name:') !!} {!! Form::text('image_name', null, ['class' => 'form-control']) !!} </div> <!-- mobile_image_name Form Input --> <div class="form-group"> {!! Form::label('mobile_image_name', 'Mobile Image Name:') !!} {!! Form::text('mobile_image_name', null, ['class' => 'form-control']) !!} </div> <!-- is_something Form Input --> <div class="form-group"> {!! Form::label('is_active', 'Is Active:') !!} {!! Form::checkbox('is_active') !!} </div> <!-- is_featured Form Input --> <div class="form-group"> {!! Form::label('is_featured', 'Is Featured:') !!} {!! Form::checkbox('is_featured') !!} </div> <!-- form field for file --> <div class="form-group"> {!! Form::label('image', 'Primary Image') !!} {!! Form::file('image', null, array('required', 'class'=>'form-control')) !!} </div> <!-- form field for file --> <div class="form-group"> {!! Form::label('mobile_image', 'Mobile Image') !!} {!! Form::file('mobile_image', null, array('required', 'class'=>'form-control')) !!} </div> <div class="form-group"> {!! Form::submit('Upload Photo', array('class'=>'btn btn-primary')) !!} </div> {!! Form::close() !!} @endsectionلاحظ أن الشيفرة في الأعلى ليست صعبة ويمكنك فهمها بسهولة دون أن تضطر إلى قراءة الشرح، ولاحظ أيضا أننا نقوم بتوسيع صفحتنا الرئيسية master page، التي بداخلها مجلد المخططات في مجلد العروض. والتي قمنا باستدعائها عن طريق هذه التعليمة: @extends('layouts.master')إذا كانت لديك صفحة رئيسية أخرى أو أنها موجودة في مكان مختلف، قم بتعديل ذلك حسب الحاجة، وإذا كنت لا تعرف مفهوم الصفحة الرئيسية master page، قُم بالبحث عن دروس حوله وتعلمه قبل أن تتابع الدرس. إذا كنت لا تستخدم حزمة `Bootstrapper`، قم بحذف السطر التالي: {!! Breadcrumb::withLinks(['Home' => '/', 'marketing images' => '/marketingimage', 'create']) !!}لاحظ أيضا، لهذا الدرس، قمت بتضمين `if` لطباعة أخطاء الإدخال، لكن في العادة، يجب وضع هذا الجزء في جزئية العرض view partial ومن ثم الإشارة إليه بشيء مثل هذا: @include('errors.errors')يمكنك أيضا ملاحظة أننا نستخدم مساعد الاستمارة Form helper من حزمة `laravelcollective/html`، فلقد وجدت أن مساعد الاستمارة مفيد جدا خاصة عند استخدامه لفتح الاستمارة: {!! Form::open(array('route' => 'marketingimage.store', 'class' => 'form', 'files' => true)) !!}تستطيع أن ترى أننا قمنا بتضمين 'files => 'true والتي تسمح لنا برفع ملفات متعددة. إذا كنت جديدا في استخدام مساعد الاستمارة، فيمكنك ملاحظة أننا لا نحتاج إلى استخدام POST خاصة وأننا لا نحتاج إلى استدعاء رمز CSFR لأنه يتم ذلك تلقائيا. ثم لدينا مدخلات المختلفة للاستمارة، لا شيء مجنون للغاية هنا، ولدينا أيضا `Form::submit` والتي نستخدمها كزر، بالإضافة إلى `Form::close()`. يمكنك أن ترى من مساعد الاستمارة أن الطريق route تم تعيينه إلى `marketingimage.store`، لذلك سوف نعرف من مورد الطريق في `routes.php` أن هذا سوف يأخذنا إلى تابع `store` في `MarketingImageController.php` والذي هو دليل المتحكِّمات. نُكمل في الجزء الثاني من الدرس. ترجمة -وبتصرّف- للمقال Basic Image Management Part 1 لصاحبه Bill Keck. حقوق الصورة البارزة: Designed by Freepik.
  2. ثبّتنا في الدرس السابق من هذه السلسلة إطار Laravel وأعددناه. سنستخدم تلك الإعدادات كقاعدة لبناء تطبيق صغير عليها؛ ونرى العناصر الأساسية لتطبيق يعمل على إطار العمل Laravel. هذا الدرس جزء من سلسلة تعلم 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 لتوليد بيانات وهمية قصدَ الاختبار. يشمل الدرس المواضيع التالية: مفهوم التوجيه Routing وآلية عمله.أداة Artisan التي تعمل على سطر الأوامر.استخدام أداة Artisan لتوليد شفرة مصدرية نمطية للمتحكّمات Controllers (وهي المسؤولة عن الإجابة على الطّلبات التي تردها Requests).إنشاء نداء لمتحكّم في مسار Route.تمرير المتغيّرات من متحكّم إلى عرض View.أساسيات التوجيه في Laravelعند وصول طلب إلى تطبيق Laravel تتلقى آلية التوجيه الطلب ثم تختار طريقة التعامل معه. سنرى في هذه الفقرة كيفية عمل هذه الآلية. أول ما سنفعله هو إنشاء مسار جديد؛ لذا افتح ملف routes.php الموجود على المسار app\Http بمحرّر النصوص المفضّل لديك. ملحوظة1: جميع المسارات المذكورة في الدرس هي بالنسبة لمجلد تطبيق Laravel. يعني هذا أن المقصود بالمسار (على افتراض أنك اتبعت خطوات الإعداد في الدرس السابق) app/Http هو المسار C:\laragon\www\larashop\app\Http على وندوز و /var/www/html/larashop/ على لينكس. ملحوظة2: انتبه لحالة الأحرف، كبيرة أو صغيرة. أضف المحتوى التالي إلى الملف routes.php : Route::get('/hello',function(){ return 'Hello World!'; });تعرّف الشفرة السابقة مسارًا لتلقي الطلبات من نوع GET (الدّالة get الموجودة في الصنف Route). المعطى الأول للدّالة هو الرابط المعني بالمسار (أي /hello) أما الثاني فهو دالة مجهولة الاسم Anonymous function تعرّف طريقة التعامل مع الطلب. يعني هذا أنه عند تلقي طلب على العنوان http://larashop.dev/hello فإن التطبيق ينفذ الدالة مجهولة الاسم والتي تُرجِع العبارة: Hello World!. احفظ الملف ثم اذهب إلى المتصفح وأدخل العنوان: http://larashop.dev/helloيجب أن تظهر صفحة بيضاء مطبوعة عليها عبارة: Hello World!. ربما تكون لاحظت وجود الشفرة التالية في الملف routes.php: Route::get('/', function () { return view('welcome'); });تتبع هذه الشفرة نفس المبدأ حيث تعرّف مسارا للطلبات الآتية على الرابط / أي رابط الصفحة الرئيسية (http://larashop.dev) وتحيلها إلى عرض باسمwelcome بدلا من طباعة عبارة مباشرةً (سنرى في ما بعد كيفية ذلك). أداة ArtisanArtisan عبارة عن أداة تُستدعى من سطر الأوامر لأتممة تنفيذ أنشطة اعتيادية على Laravel. يمكن استخدام أداة Artisan لتنفيذ الأنشطة التالية من بين أخرى: توليد شفرة نمطية: إنشاء المتحكّمات، النماذج Models، وغيرها بيُسر.تهجير قواعد البيانات Database migrations: وهو نظام لإدارة الإصدارات الخاصة بقواعد البيانات يجعل من التعامل مع الكائنات في قواعد البيانات (إنشاء جداول أو حذفها مثلا) أسهل عبر وصفها دون الحاجة للتعديل عليها مباشرةً.بذر قواعد البيانات Database seeding: وهو مصطلح يشير إلى إضافة بيانات وهمية للتسجيلات Records في جداول قاعدة البيانات لأغراض الاختبار.التوجيه: وهي الآليّة المسؤولة عن تلقي الطلبات ثم اختيار طريقة التعامل معها (عادةً بإرسالها إلى متحكّم).ضبط التطبيق.تشغيل الاختبارات الأحاديّة Unit tests.كيف تستخدم أداة Artisanافتح سطر الأوامر ثم انتقل إلى مجلد التطبيق. على افتراض أنك موجود في أصل المستند (C:\laragon\www على وندوز أو /var/www/html/ على لينكس): cd larashopثم نفّذ الأمر التالي: php artisan listملحوظة: تأكّد من وجودك في مجلّد التطبيق (أي المجلّد larashp) قبل تنفيذ الأمر artisan. تظهر أوامر artisan المتاحة للتنفيذ. مثال على النتيجة: Laravel Framework version 5.1.26 (LTS) Usage: command [options] [arguments] Options: -h, --help Display this help message -q, --quiet Do not output any message -V, --version Display this application version --ansi Force ANSI output --no-ansi Disable ANSI output -n, --no-interaction Do not ask any interactive question --env[=ENV] The environment the command should run under. -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug Available commands: clear-compiled Remove the compiled class file down Put the application into maintenance mode env Display the current framework environment help Displays help for a command inspire Display an inspiring quote list Lists commands migrate Run the database migrations optimize Optimize the framework for better performance serve Serve the application on the PHP development server tinker Interact with your application up Bring the application out of maintenance mode أمر Artisan لتوليد شفرة متحكمسنستخدم Artisan لتوليد متحكم بسيط يجيب على طلب Http ويحمّل عرضا باسم hello. افتح سطر الأوامر ونفذ الأمر التالي (تأكد من وجودك في مجلّد التطبيق قبل تنفيذ الأمر): php artisan make:controller Helloاستخدمنا أمر make:controller الذي توفره أداة Artisan لتوليد شفرةِ متحكّم ومررنا له اسم المتحكم الذي نريد توليده Hello. يُنشئ الأمر أعلاه ملفا باسم Hello.php على المسار app/Http/Controllers. يجب أن تظهر رسالة في سطر الأوامر تفيد بنجاح توليد المتحكم. نفتح ملف Hello.php لرؤية محتواه: <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Http\Requests; use App\Http\Controllers\Controller; class Hello2 extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { // } /** * Show the form for creating a new resource. * * @return \Illuminate\Http\Response */ public function create() { // } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { // } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { // } /** * Show the form for editing the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function edit($id) { // } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { // } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy($id) { // } }يعرف الملف فضاء اسم Namespace خاصًّا بالمتحكم: namespace App\Http\Controllers.تستورد التعليمات التالية (use Illuminate\Http\Request; use App\Http\Requests; use App\Http\Controllers\Controller;) الأصناف Classes المطلوبة لتشغيل المتحكم.الصنف Hello هو تمديد للصنف Controller الذي يعرّفه إطار العمل.بالنسبة للدوال التي يعرفها المتحكم فاستخدامها يكون كالآتي: الدالة index هي الدالة الافتراضية للمتحكم: تتعامل مع الطلبات الموجهة للرابط الجذر الذي يجيب عنه المتحكم.الدالة create: إنشاء موارد جديدة مثل تسجيلة في جدول قاعدة البيانات.الدالة store: تخزين مورد جديد مُنشَأ بالدالة السابقة.الدالة show: العثور على مورد اعتمادا على المعرِّف ID الممرَّر للدالة.الدالة edit: تتيح إمكانية التعديل على المورد الممرّر للدالة.الدالة update: تحديث مورد مخزّن.الدالة destroy: حذف مورد مخزَّن.سنأتي تباعا لتفصيل استخدام هذه الدوال في الوقت المناسب. توجيه طلب إلى متحكمفي المسار الذي عرفناه سابقا تُطبع العبارة مباشرة من داخل دالة التوجيه، وهذا خلط بين عناصر نموذج MVC، لذا سنضع المسار بين علامات تعليق لتجاهله: /* Route::get('/hello',function(){ return 'Hello World!'; }); */ثم نضيف شفرة مصدرية جديدة تنشئ مسارا لنفس الرابط hello/ ولكنها بدلا من طبع سلسلة محارف ترسل نداءً إلى المتحكم Hello وبالتحديد دالة index: Route::get('hello', 'Hello@index');نفتح ملف المتحكم لتحرير الدالة index لتأخذ المحتوى التالي: public function index() { return 'hello world from controller : )'; }احفظ الملف. افتح الآن الرابط http://larashop.dev/hello، وستجد أن الرسالة التالية تظهر في الصفحة: hello world from controller :)ما حدث هنا هو أن المسار الخاص بالرابط hello تلقى الطلب من المتصفح ثم أحاله إلى المتحكم Hello الذي طبع سلسلة محارف على الشاشة. تحميل عرض View انطلاقا من متحكماحترام مبادئ MVC يقضي بألا يتداخل عمل المتحكمات والعروض؛ فتنسيق ما يراه الزائر من مسؤولية العروض، ولذا فعلى المتحكم توكيل عرض بهذه المهمة مع إمداده بما يحتاجه من متغيرات. وهو ما سنفعله في الفقرات التالية. سيتلخص عملنا في ثلاث نقاط: إنشاء مسار لتلقي الطلب على الرابط hello/ وإرساله إلى المتحكم المناسب (تم هذا الأمر).إنشاء متحكم للإجابة عن الطلب (تم).إنشاء عرض لتنسيق ما سيظهر على شاشة الزائر.تغيير المتحكم لإرسال نداء إلى العرض وتمرير المتغيرات المناسبة إليه.أنشئ ملفا باسم hello.blade.php في المسار resources/views/ وأضف إليه المحتوى التالي: <!DOCTYPE html> <html> <head> <title>Laravel</title> <link href="//fonts.googleapis.com/css?family=Lato:100" rel="stylesheet" type="text/css"> <style> html, body { height: 100%; } body { margin: 0; padding: 0; width: 100%; display: table; font-weight: 100; font-family: 'Lato'; } .container { text-align: center; display: table-cell; vertical-align: middle; } .content { text-align: center; display: inline-block; } .title { font-size: 96px; } </style> </head> <body> <div class="container"> <div class="content"> <div class="title">Hello {{$name}}, welcome to Laraland! : )</div> </div> </div> </body> </html>يحوي الملف كما يظهر شيفرة HTML عادية مع تغييرين أساسيين، هما لاحقة اسم الملف (blade.php) واستخدام المتغير name في الملف. تشير اللاحقة إلى أن العرض يستخدم نظام Blade للقوالب الذي يأتي مضمّنا في Laravel (سنخصص درسا للعروض والقوالب). نكتفي الآن بالقول إن {{$name}} تطبع قيمة المتغير name. افتح الملف app/Http/routes.php وأضف الشفرة التالية: Route::get('/hello/{name}', 'Hello@show');يعمل هذا السطر على إنشاء مسار للروابط ذات الصيغة /hello/value حيث value قيمة ما، تخزن هذه القيمة في المتغير name ثم تمرّر إلى الدالة show الموجودة في المتحكم Hello. نفتح ملف المتحكم Hello ونعدّل الدالة show($id) لتصبح على النحو التالي: public function show($name) { return view('hello',array('name' => $name)); }نعرف الدالة show التي تقبل المعطى name.تحمِّل الدالة عرضا باسم hello.blade.php (يُكتفى بذكر اسم العرض دون اللاحقة blade.php) ثم تمرر له مصفوفة تحوي متغيراتٍ وقيمَها. في حالتنا يوجد متغير واحد باسم name وقيمته هي المعطى الممرَّر للدالة show.احفظ التعديلات التي أجريناها في الفقرات السابقة ثم افتح الرابط http://larashop.dev/hello/HsoubAcademy في المتصفح. يمكن أن نلاحظ هنا أن HsoubAcademy هي قيمة المتغير name الموجود في تعريف المسار التالي: Route::get('/hello/{name}', 'Hello@show');إذن: طلب الزائر العنوان http://larashop.dev/hello/HsoubAcademy في المتصفح.وجد التطبيق أن المسار الموافق لهذا الرابط هو المسار /hello/{name{ وأعطى القيمة HsoubAcademy للمتغير name ثم وجّه الطلب إلى الدالة show في المتحكم Hello.تلقت الدالة show الطلب ثم أرسلته إلى العرض hello مع إنشاء متغير جديد بنفس الاسم المستخدم في العرض وحددت قيمته بالمعطى الذي تلقته من المسار. كان بإمكان الدالة show إجراء عمليات على المعطى قبل تمريره.بدأ نظام القوالب العمل ووجد أن العرض hello يحوي متغيرا باسم name وأن قيمة هذا المتغير كما مررها له المتحكم هي HsoubAcademy، فوضعها مكان المتغير وأرسل النتيجة إلى المتصفح.خاتمةتعرفنا في هذا الدرس على الآلية الأساسية التي تعمل بها تطبيقات Laravel. من المهم جدّا فهم محتويات هذا الدرس قبل الانتقال إلى الدروس الموالية. ترجمة -وبتصرّف- لمقال Laravel 5 Hello World لصاحبه Rodrick Kazembe.
  3. كثُر الحديث في السنوات الأخيرة عن إطار العمل 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.
  4. يأتي Laravel، وهذه إحدى ميزاته الكثيرة، مضمنّا بآليات استيثاق Authentication جاهزة للاستخدام. سنطبق في هذا الدرس آلية الاستيثاق على صفحة الدفع checkout بحيث يُسمح بالدخول للمستخدمين المسجلين فقط. هذا الدرس جزء من سلسلة تعلم 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 5. أساسيات الاستيثاق في Laravel 5. تغيير رابط تسجيل الدخول المبدئي. إعدادات الاستيثاق في Laravel 5 يوجد ملف إعداد الاستيثاق على المسار config/auth.php. في ما يلي جزء من الملف: 'model' => App\User::class, 'table' => 'users', 'password' => [ 'email' => 'emails.password', 'table' => 'password_resets', 'expire' => 60, ], يحدّد الملف: اسم نموذج الاستيثاق. اسم جدول المستخدمين. خيارات إعادة تعيين كلمة السر. سنستخدم النموذج User لاستيثاق المستخدمين. افتح الملف User.php وعدّله على النحو التالي: <?php namespace App; use Illuminate\Auth\Authenticatable; use Illuminate\Database\Eloquent\Model; use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; class User extends Model implements AuthenticatableContract { use Authenticatable; /** * The database table used by the model. * * @var string */ protected $table = 'users'; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = ['name', 'email', 'password']; /** * The attributes excluded from the model's JSON form. * * @var array */ protected $hidden = ['password', 'remember_token']; } فلنعرّج قليلا على الأصناف الجديدة علينا: use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; توجد في Laravel أصناف يطلق عليها اسم العقود Contracts. العقود هي مجموعة واجهات Interfaces تعرّف خدمات يوفّرها إطار العمل. تعرّف العقود دوال يحتاجها إطار العمل لتأدية الخدمة. يستورد السطر أعلاه العقد Authenticatable وهي واجهة تعرّف الدوال الضرورية لاستيثاق المستخدمين. عند استيراد الواجهة أعطيناها الاسم AuthenticatableContract حتى لا تختلط مع السمة Trait الذي يحمل نفس الاسم (نستعمله في نموذج المستخدم كما سنرى لاحقا). يجب على الكائن الذي يستوثق من المستخدمين (نموذج المستخدم في حالتنا) أن ينجز Implement هذه الواجهة: class User extends Model implements AuthenticatableContract لإنجاز دوال الواجهة (تعرّف واجهة Authenticatable الدوال دون أن تنجزها) نستخدم السمة Illuminate\Auth\Authenticatable. نستورده أولا: use Illuminate\Auth\Authenticatable; ثم نستخدمه: use Authenticatable; يحدّد النموذج جدول البيانات المستخدم لتخزين بيانات المسجَّلين، ويفعّل الإسناد الشامل لبعض الحقول. تعيّن مصفوفة hidden$ بيانات المستخدم التي لا نودّ عرضها عند الإجابة على طلب عبر واجهة تطبيقات برمجية API (يجب إخفاء كلمة سر المستخدم password ورمز الأمان remember_token عن الخارج). يأتي مع Laravel مبدئيا ملف تهجير لإنشاء جدول المستخدمين. افتح ملف التهجير 2014_10_12_000000_create_users_table.php (قد يختلف الختم الزمني في اسم الملف حسب إصدار Laravel): <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('users', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->string('email')->unique(); $table->string('password', 60); $table->rememberToken(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('users'); } } يعرّف ملف التهجير حقول جدول المستخدمين. تعيّن الدالة rememberToken رمز حماية لتأمين المستخدمين ضدّ هجمات تزوير الطلب عبر الموقع CSRF. استمارات التسجيل والولوج Login يوجد في عرض الدخول login.blade.php استمارتان، واحدة لتسجيل المستخدمين Registration والأخرى لدخولهم Login. افتح ملف العرض login وحدّثه على النحو التالي: @extends('layouts.layout') @section('content') <section id="form"><!--form--> <div class="container"> <div class="row"> <div class="col-sm-4 col-sm-offset-1"> <div class="login-form"><!--login form--> <h2>Login to your account</h2> <form method="POST" action="{{url('auth/login')}}"> {!! csrf_field() !!} <input type="email" name="email" id="email" placeholder="Email Address" /> <input type="password" name="password" id="password" placeholder="Password" /> <span> <input name="remember" id="remember" type="checkbox" class="checkbox"> Keep me signed in </span> <button type="submit" class="btn btn-default">Login</button> </form> </div><!--/login form--> </div> <div class="col-sm-1"> <h2 class="or">OR</h2> </div> <div class="col-sm-4"> <div class="signup-form"><!--sign up form--> <h2>New User Signup!</h2> <form method="POST" action="{{url('register')}}"> {!! csrf_field() !!} <input type="text" name="name" id="name" placeholder="Name"> <input type="email" name="email" placeholder="Email Address"/> <input type="password" name="password" placeholder="Password"> <button type="submit" class="btn btn-default">Signup</button> </form> </div><!--/sign up form--> </div> </div> </div> </section><!--/form--> @endsection التغييرات الأساسية هنا هي: تعريف رابط مناسب لاستمارتي التسجيل والدخول مع تحديد أن البيانات تُرسَل بإجراء POST: // دخول المستخدمين <form method="POST" action="{{url('auth/login')}}"> // تسجيل المستخدمين <form method="POST" action="{{url('register')}}"> تُرسل بيانات الدخول إلى الرابط larashop.dev/auth/login وبيانات التسجيل إلى الرابط larashop.dev/register. تضيف التعليمة ()csrf_field حقلا أمنيا في الاستمارتين للحيلولة دون هجمات CSRF. مسارات الدخول، الخروج والتسجيل نضيف الآن المسارات الخاصة بالاستيثاق. افتح ملف المسارات routes.php وأضف المسارات التالية: // مسارات الدخول والخروج Route::get('auth/login', 'Front@login'); Route::post('auth/login', 'Front@authenticate'); Route::get('auth/logout', 'Front@logout'); // مسار التسجيل Route::post('/register', 'Front@register'); نعرّف المسار الذي يعرض استمارتي التسجيل والدخول: Route::get('auth/login', 'Front@login'); نعرّف إجراء HTTP POST الذي يوثّق المستخدمين: Route::post('auth/login', 'Front@authenticate'); نعرّف مسار خروج المستخدم: Route::get('auth/logout', 'Front@logout'); نعرف مسار تسجيل المستخدمين الجدد (إجراء HTTP POST): Route::post('/register', 'Front@register'); المسارات المَحمِيّة مسار محمي هو مسار يطلُب من الزائر الدخول قبل الوصول إليه. سنحمي في هذه الفقرة الرابط http://larashop.dev/checkout. يعني هذا أن المستخدمين المسجّلين فقط يمكنهم رؤية صفحة الدفع. عدّل مسار checkout/ في ملف المسارات ليصبح على النحو التالي: Route::get('/checkout', [ 'middleware' => 'auth', 'uses' => 'Front@checkout' ]); تُنفّذ التعليمة 'middleware' => 'auth', قبل دالة Front@checkout؛ وتتحقق من دخول الزائر. فإن لم يكن سجّل دخوله توجّهه إلى الرابط auth/login/، وتعرض له صفحة الدفع بعد الدخول. دوال التسجيل والاستيثاق نعدّل ملف المتحكّم لإضافة دوال تجيب على الطلبات القادمة من المسارات السابقة. افتح ملف المتحكم Front.php لتعديله. نبدأ باستيراد فضاءات الأسماء التي نحتاجها: use App\User; use Illuminate\Support\Facades\Auth; استوردنا نموذج المستخدم User وفضاء الأسماء الخاص بالاستيثاق Auth. توجد في فضاء الأسماء Auth الدوال والكائنات التي نحتاجها للاستيثاق من المستخدمين. تسجيل مستخدم جديد public function register() { if (Request::isMethod('post')) { User::create([ 'name' => Request::get('name'), 'email' => Request::get('email'), 'password' => bcrypt(Request::get('password')), ]); } return Redirect::away('login'); } تستخدم دالة التسجيل المعلومات المذكورة في استمارة التسجيل New User Signup! لإنشاء مستخدم جديد عبر طلب الدالة User::create (تعرّفنا على هذه الدالة خلال درس Eloquent ORM). ثم نوجّه الزائر بعد إلى صفحة الدخول. لاحظ استخدام الدالة bcrypt أثناء تسجيل المستخدم. تعمّي هذه الدالة كلمة السر قبل تخزينها في جدول البيانات. الاستيثاق من المستخدمين تستوثق الدالة التالية من المستخدمين: public function authenticate() { if (Auth::attempt(['email' => Request::get('email'), 'password' => Request::get('password')])) { return redirect()->intended('checkout'); } else { return view('login', array('title' => 'Welcome', 'description' => '', 'page' => 'home')); } } ستوثق الدالة Auth::attempt من المستخدم بناء على عنوان البريد email وكلمة السر password الذين أرسلتهما استمارة الدخول. في حال نجاح دخول المستخدم يُعاد توجيهه إلى صفحة الدفع checkout عبر الدالة ()redirect. تسجيل خروج المستخدمين يؤدي طلب الدالة Auth::logout إلى تسجيل خروج المستخدمين بعد دخولهم عبر الدالة السابقة. عدّل دالة logout الموجودة في ملف المتحكم لتصبح كالتالي: public function logout() { Auth::logout(); return Redirect::away('auth/login'); } تخرج الدالة المستخدم وتوجهه إلى صفحة الدخول. إظهار بيانات الدخول في العرض نحتاج، قبل اختبار التسجيل والدخول، إجراء تغيير أخير. تُظهر الصورة التالية الشريط العلوي الأيمن من الموقع: نريد أن يظهر الشريط على النحو التالي بعد دخول المستخدم: نريد أن يظهر اسم المستخدم بعد الدخول، وإبدال رابط Login بـLogout. افتح ملف العرض layout.blade.php للتعديل عليه. تذكر أن هذا هو العرض الرئيس الذي تمدّده بقية العروض. نغيّر جزئية الترويسة (header) من ملف العرض لتصبح كالتالي: <header id="header"><!--header--> <div class="header_top"><!--header_top--> <div class="container"> <div class="row"> <div class="col-sm-6"> <div class="contactinfo"> <ul class="nav nav-pills"> <li><a href="#"><i class="fa fa-phone"></i> +2 95 01 88 821</a></li> <li><a href="#"><i class="fa fa-envelope"></i> info@domain.com</a></li> </ul> </div> </div> <div class="col-sm-6"> <div class="social-icons pull-right"> <ul class="nav navbar-nav"> <li><a href="#"><i class="fa fa-facebook"></i></a></li> <li><a href="#"><i class="fa fa-twitter"></i></a></li> <li><a href="#"><i class="fa fa-linkedin"></i></a></li> <li><a href="#"><i class="fa fa-dribbble"></i></a></li> <li><a href="#"><i class="fa fa-google-plus"></i></a></li> </ul> </div> </div> </div> </div> </div><!--/header_top--> <div class="header-middle"><!--header-middle--> <div class="container"> <div class="row"> <div class="col-sm-4"> <div class="logo pull-left"> <a href="{{url('')}}"><img src="{{asset('images/home/logo.png')}}" alt="" /></a> </div> </div> <div class="col-sm-8"> <div class="shop-menu pull-right"> <ul class="nav navbar-nav"> <li><a href="#"><i class="fa fa-user"></i> {{Auth::check() ? Auth::user()->name : 'Account'}}</a></li> <li><a href="{{url('checkout')}}"><i class="fa fa-crosshairs"></i> Checkout</a></li> <li><a href="{{url('cart')}}"><i class="fa fa-shopping-cart"></i> Cart</a></li> <li><a href="{{Auth::check() ? url('auth/logout') : url('auth/login')}}"><i class="fa fa-lock"></i> {{Auth::check() ? 'Logout' : 'Login'}}</a></li> </ul> </div> </div> </div> </div> </div><!--/header-middle--> <div class="header-bottom"><!--header-bottom--> <div class="container"> <div class="row"> <div class="col-sm-9"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> </div> <div class="mainmenu pull-left"> <ul class="nav navbar-nav collapse navbar-collapse"> <li><a href="{{url('')}}" {{$page == 'home' ? 'class=active' : ''}}>Home</a></li> <li><a href="{{url('products')}}" {{$page == 'products' ? 'class=active' : ''}}>Products</a></li> <li><a href="{{url('blog')}}" {{$page == 'blog' ? 'class=active' : ''}}>Blog</a></li> <li><a href="{{url('contact-us')}}" {{$page == 'contact_us' ? 'class=active' : ''}}>Contact Us</a></li> </ul> </div> </div> <div class="col-sm-3"> <div class="search_box pull-right"> <input type="text" placeholder="Search"/> </div> </div> </div> </div> </div><!--/header-bottom--> </header><!--/header--> أضفنا التغييرين التاليين على ترويسة العرض: إبدال Account بالتعليمة: {{Auth::check() ? Auth::user()->name : ‘Account’}} نستعمل الدالة Auth::check للتحقق من دخول المستخدم؛ في حال الإيجاب نظهر اسمه بالدالة Auth::user وإلا نبقي على عبارة Account. نفس المبدأ مع عبارة Login التي تصبح بعد الدخول Logout، وتغيير الرابط بما يُناسب (larashop.dev/auth/login للدخول وlarashop.dev/logout للخروج). افتح الرابط http://larashop.dev/auth/login وسجل مستخدما جديد عبر الاستمارة New User Signup. بالضغط على زر Signup تستدعي المسار http://laravel.dev/register مع الإجراء POST. تتولى دالة register في المتحكم تلقي الطلب واستدعاء النموذج الذي ينشئ تسجيلة جديدة في جدول البيانات ثم تعيد الدالة توجيه المستخدم إلى صفحة الدخول. يمكنك التأكد من إنشاء المستخدم في الجدول users ضمن قاعدة البيانات. نجرّب الدخول بالمستخدم الجديد بإدخال عنوانه البريدي وكلمة السر في استمارة التسجيل. إن أدخل بيانات مستخدم صالحة فستُنقل إلى صفحة الدفع. لاحظ أن اسم المستخدم وعبارة Logout يظهران في الشريط العلوي. ترجمة -وبتصرّف- للمقال Laravel 5 Authentication لصاحبه Rodrick Kazembe.
  5. أنشأنا في الدرس السابق بنية قاعدة البيانات الخاصة بمشروع Larashop. نكمل في هذا الدرس حديثنا عن قواعد البيانات في Laravel بشرح كيفية إدراج تسجيلات في قواعد البيانات وكيفية استخراجها منها باستخدام إطار العمل Eloquent. هذا الدرس جزء من سلسلة تعلم 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 لتوليد بيانات وهمية قصدَ الاختبار. سنغطي في هذا الدرس المواضيع التالية: نماذج Eloquentأعراف التسمية.أسماء الجداول والمفاتيح الخارجية.الأختام الزمنية.إطار العمل Eloquentقراءة البيانات READ.تحديث البيانات UPDATE.حذف البيانات DELETE.إدراج البيانات INSERT.تنفيذ استعلامات SQL في Laravel.نماذج Eloquent لمشروع Larashop.استخدام النماذج في المتحكمات.إظهار بيانات النماذج في العروض.إطار عمل Eloquentيأتي Laravel مضمنًّا بإطار عمل Eloquent الذي يُستخدَم للتخاطب مع قاعدة البيانات وتنفيذ عمليات مثل الإدراج Insert، التحديث Update أو الحذف Delete على الجداول. Eloquent هو إطار عمل لربط كائنات التطبيق بعلاقات (جداول) قاعدة البيانات Object Relational Mapper, ORM. يقوم مبدأ ربط العلاقات بالكائنات على تنفيذ نمط ActiveRecord (التسجيلة النشطة)؛ الذي هو وسيلة للوصول إلى البيانات في قاعدة البيانات، حيث يضمن جدول بيانات (أو علاقة في قاعدة البيانات بصفة عامة) في صنف Class وتُربط كل تسجيلة من جدول البيانات بكائن Object من الصنف. بهذه الطريقة يُصبح التعامل مع الصنف مماثلا للتعامل مع الجدول في قاعدة البيانات. مثلا، لإدراج تسجيلة جديدة في جدول قاعدة البيانات ننشئ - في التطبيق - كائنا جديدا من الصنف المربوط بالجدول. وإذا أردنا أن نحدّث بيانات تسجيلة من الجدول نحدّث خاصيّات الكائن المربوط بها. نماذج Eloquentتُستخدَم النماذج في بنية MVC للتفاعل مع مصادر البيانات (قواعد البيانات، ملفات نصية، … إلخ). تُعرَّف النماذج في Laravel بتمديد الصنف Illuminate\Database\Eloquent\Model الذي يوفّر دوال جاهزة للاستخدام من أجل التفاعل مع مصدر البيانات. أعراف التسمية في Eloquentتوجد بعض الأعراف التي يفترض إطار العمل Eloquent مبدئيا اتّباعها، مع وجود إمكانية لتغييرها حسب الرغبة. في العرف أن اسم النموذج يكون كلمة مفردة تبدأ بحرف كبير Upper case، بينما اسم الجدول في قاعدة البيانات كلمة للجمع بأحرف صغيرة Lower case. يعتمد Laravel هذا العرف فيربط تلقائيا بين النموذج ذي الاسم المفرد والجدول الذي يكون اسمه جمعا لاسم النموذج. نستخدم أداة Artisan لإنشاء نموذج لجدول التصنيفات categories باسم Category (مفرد categories): php artisan make:model Categoryينشئ الأمر ملفا للنموذج على المسار app/Category.php. نفتح الملف لرؤية محتواه: <?php namespace App; use Illuminate\Database\Eloquent\Model; class Category extends Model { // }نعرف فضاء الأسماء الذي يتبع له النموذج: ;namespace App.نستورد فضاء الأسماء الخاص بـ Eloquent بالتعليمة: use Illuminate\Database\Eloquent\Model;.يمدّد الصنفُ Category صنفَ نماذج Eloquent الذي تحدثنا عنه أعلاه: class Category extends Model.من المتعارف عليه أيضا أن حقل المفتاح الرئيس للجدول يُسمّى id، ومن الممكن مثل ما هو الحال مع اسم الجدول، تحديدُ اسم مغاير لحقل المفتح الرئيس. يمكن تحديد اسم الجدول في النموذج بغض النظر عن المتعارف عليه بإعطاء قيمة للمتغير table$، نفس الشيء بالنسبة للمفتاح الرئيس مع المتغير primaryKey$: protected $primaryKey = 'id'; protected $table = 'categories';تسجيلات الأختام الزمنيةيفترض Laravel إضافةَ الحقلين created_at وupdated_at إلى جداول قاعدة البيانات. تُدرج قيمتا الحقلين عند إنشاء تسجيلة جديدة في الجدول، وتحدّث قيمة updated_at عند تحديث قيمة التسجيلة. إن لم تضف هذين الحقلين في جداول قاعدة البيانات فيمكن تعطيل الإعداد المبدئي على النحو التالي: public $timestamps = false;استخدام Eloquentنكمل كتابة الشفرة المصدرية للنموذج Category ليصبح كما يلي: <?php namespace App; class Category extends Model { protected $primaryKey = 'id'; protected $table = 'categories'; }عرّفنا حقل المفتاح الرئيس للجدول: ;'$primaryKey = 'id. ليس هذا ضروريا هنا ما دام اسم الحقل يوافق العُرْف (id). نفس الملحوظة تنطبق على تعريف اسم الجدول في التعليمة الموالية.قراءة محتوى جدول في قاعدة البياناتسنرى، في هذه الفقرة، كيفية العثور على جميع التصنيفات التي نحتفظ بها في جدول التصنيفات. ملحوظة: نطبع النتائج في الأمثلة أدناه مباشرة من الشيفرة المصدرية للمسار دون الاستعانة بالمتحكم رغم أن ذلك مخالف لمبدأ MVC، إلا أن الغرض هنا هو رؤية عمل Eloquent. سنعود لترتيب الأمور في ما بعد. افتح ملف المسارات routes.php وأضف المسار التالي: Route::get('/read', function() { $category = new App\Category(); $data = $category->all(array('name','id')); foreach ($data as $list) { echo $list->id . ' ' . $list->name . '</br>'; } }); ننشئ كائنا جديدا من صنف النموذج: $category = new App\Category();التعليمة التالية تستدعي الدالة all في الكائن الذي أنشأناه للتو، وتمرر له مصفوفة تحدد الحقول التي نود الحصول عليها؛ في حالتنا حدّدنا الحقلين id (المعرِّف) وname (اسم التصنيف). إن لم تُحدَّد معطيات للمصفوفة فستُرجع الدالة جميع الحقول. نستخدم حلقة تكرارية foreach لإظهار النتائج التي تحصلنا عليها.احفظ التعديلات ثم افتح الرابط http://larashop.dev/read في المتصفح. ستحصُل على لائحة شبيهة بالتالي (قد تختلف النتيجة لديك قليلا): 5 CLOTHING 4 FASHION 3 KIDS 1 MEN 2 WOMENتحديث تسجيلاتسنحدّث في هذه الفقرة تسجيلة في جدول التصنيفات باستخدام المعرِّف id. نختار معرّف إحدى التصنيفات الظاهرة في نتيجة المثال السابق، مثلا التصنيفKIDS ذو المعرِّف 3. نعيد فتح ملف المسارات routes.php ونضيف مسارا جديدا كما يلي: Route::get('/update', function() { $category = App\Category::find(4); $category->name = 'KIDS 2'; $category->save(); $data = $category->all(array('name','id')); foreach ($data as $list) { echo $list->id . ' ' . $list->name . '</br>'; } });نستدعي الدالة find الموجودة في النموذج مع تمرير معرّف التصنيف إليها. ترجع الدالة كائنا من صنف Category يحوي بيانات التصنيف المستقاة من تسجيلة في الجدول categories.نعيّن الاسم الجديد للتصنيف بالتعديل على الخاصية name في الكائن category$.لتُعتمَد التعديلات وتخزَّن في السجل نستدعي الدالة save من الكائن category$.نستخدم حلقة تكرارية foreach لإظهار النتائج التي تحصلنا عليها.احفظ الملف ثم افتح الرابط http://larashop.dev/update في المتصفح. لاحظ تغيّر اسم التصنيف من KIDS إلى KIDS 2. حذف تسجيلة من جدول في قاعدة البياناتنختار أحد التصنيفات لحذفه (مثلا، التصنيف CLOTHING ذو المعرف 5). افتح ملف المسارات routes.php وأضف المسار التالي: Route::get('/delete', function() { $category = App\Category::find(5); $category->delete(); $data = $category->all(array('name','id')); foreach ($data as $list) { echo $list->id . ' ' . $list->name . '</br>'; } }); يوجد شبه كبير بين تحديث تسجيلة وحذفها. الفرق هو أنه بعد إيجاد التصنيف (الدالة find) نستدعي الدالة delete في الكائن category$ لحذف التسجيلة المربوطة به. افتح الرابط http://larashop.dev/delete ولاحظ أن التصنيف لم يعد موجودا. إدراج تسجيلةلإدراج تسجيلة جديدة في جدول قاعدة البيانات ننشئ كائنا جديدا من صنف Category ونعيّن خواصّه ثم نخزنه في الجدول، كما يلي: Route::get('/insert', function() { $category= new App\Category; $category->name='Music'; $category->save(); return 'category added'; }); بالذهاب إلى الرابط http://larashop.dev/insert تظهر رسالة category added دلالةً على إضافة التصنيف. يمكن أيضا التحقق من إضافة التصنيف من سطر أوامر MySQL أو بالذهاب إلى الرابط http://larashop.dev/read. توجد طريقة أخرى لاستخدام سطر برمجي واحد لإدراج تصنيف في تسجيلة. نستخدم لهذا الغرض الدالة create من نموذج التصنيف Category؛ ولكن يجب قبل ذلك التعديل على النموذج Category لتمكين الإسناد الشامل Mass assignment (تحديد قيم معطيات عدّة مرة واحدة). نفتح ملف النموذج لتحريره ثم نضيف السطر التالي: protected $fillable = array('name', 'created_at_ip', 'updated_at_ip'); يعرف المتغير fillable$ مصفوفة بالحقول التي يمكن تعيين قيمها دفعة واحدة. احفظ ملف النموذج ثم افتح ملف المسارات routes.php وعدل المسار insert/ ليصبح التالي: Route::get('/insert', function() { App\Category::create(array('name' => 'New Music')); return 'category added'; }); نستدعي الدالة create من الصنف Category ونمرر لها مصفوفة بحقول التسجيلة الجديدة مع قيمها. ينبغي أن تكون الحقول الممررة قابلة للإسناد الشامل، أي مذكورة في المتغير fillable$. لاحظ أن إنشاء الكائن وتعيين قيم خاصياته ثم تخزين محتوياته في قاعدة البيانات كل هذا تم من خلال استدعاء الدالة create. ملحوظة 1: عند طلب الرابط http://larashop.dev/insert في المرة الأولى تظهر الرسالة category added ولكن عند طلب نفس الرابط مرة أخرى دون تعديل المسار تظهر صفحة بيضاء دلالة على عدم إدراج التسجيلة. يعود السبب في ذلك إلى أننا أثناء تعريف الجدول categories في الدرس السابق علّمنا الحقل name بالدالة unique أي أنه لا يمكن لتسجيلتين من هذا الجدول أن يكون لهما نفس الاسم. ملحوظة 2: الإسناد الشامل غير ممكّن مبدئيا لأسباب أمنية ويجب عند تمكينه اختيار حقول fillable$ بعناية حتى لا تمثل خطرا أمنيا. يجب دائما تطهير Sanitize البيانات التي يستقيها التطبيق من المستخدم. تنفيذ استعلامات SQL مباشرةقد ترغب، لسبب أو آخر، في التعامل المباشر مع قاعدة البيانات باستخدام استعلامات SQL؛ يوفر Laravel صنف DB لهذا الغرض. استعلامات SELECTتُستخدَم دالة select لتنفيذ استعلامات القراءة من قاعدة البيانات على النحو التالي: $category = DB::select('SELECT name FROM categories WHERE id = ?', [1]);تأخذ الدالة DB::select معطيين: الأول هو استعلام القراءة المراد تنفيذه، والثاني معطيات نود استخدامها في الاستعلام. بالنسبة للمعطيات المراد استخدامها في الاستعلام فتُحدّد أماكنها بعلامة ? وتكون قيمتها في مصفوفة تمرّر في المعطى الثاني للدالة DB::select. ينفذ السطر أعلاه استعلام SQL التالي: SELECT name FROM categories WHERE id = 1;نفرض أننا نريد تنفيذ استعلام SQL التالي: SELECT name FROM categories WHERE id BETWEEN 1 AND 4;يطلب الاستعلام قيمتين (1 و4). يُترجم الاستعلام في النموذج على النحو التالي: $category = DB::select('SELECT name FROM categories WHERE id BETWEEN ? AND ?', [1,4]);تُبدل أول علامة ? في الاستعلام بأول عنصر من المصفوفة في معطى الدالة الثاني، وعلامة ? الثانية بالمعطى الموالي وهكذا. يمكن أيضا استخدامُ متغيرات بدلا من ? على النحو التالي: $category = DB::select('SELECT name FROM categories WHERE id BETWEEN :id1 AND :id2', ['id1' => 1, 'id2' => 4]);لاحظ استخدام : قبل أسماء المتغيرات في استعلام SQL. استعلامات INSERTتُستخدم دالة DB::insert لإدراج تسجيلات في الجدول بنفس طريقة استخدام DB::select للقراءة منه: $inserted=DB::insert('INSERT INTO categories (name) VALUES (?)', ['TEST']);ترجع الدالة DB::insert عدد التسجيلات التي أدرجها الاستعلام. استعلامات UPDATEلتحديث تسجيلة في جدول بقاعدة البيانات نستخدم الدالة DB::update: $affected = DB::update('UPDATE categories SET name = 'TEST UPDATE' WHERE name = ?', ['TEST']);ترجع الدالة DB::update عدد التسجيلات التي حدثها الاستعلام. استعلامات DELETEتوفر الدالة DB::delete إمكانية تنفيذ استعلامات DELETE على النحو التالي: $deleted = DB::delete('DELETE FROM categories WHERE id = ?', [13]);ترجع الدالة DB::delete عدد التسجيلات التي حذفها الاستعلام. استعلامات عامةبالنسبة للاستعلامات التي لا ترجع أية قيمة فيمكن استخدام الدالة DB::statement: DB::statement('drop tables drinks');نماذج Eloquent لمشروع Larashopنشرع الآن بعد أن رأينا آلية عمل Eloquent ببناء بقية نماذج مشروع Larashop. نفذ الأوامر التالية لإنشاء نماذج للعلامات التجارية، المنتجات ومنشورات المدونة على التوالي: php artisan make:model Brand php artisan make:model Product php artisan make:model Postنعرّف في كل ملف نموذج حقل المفتاح الرئيس، اسم الجدول وأسماء الحقول المسموح بإسنادها fillable. ملف Brand.php: <?php namespace App; class Brand extends Model { protected $primaryKey = 'id'; protected $table = 'brands'; protected $fillable = array('name', 'created_at_ip', 'updated_at_ip'); } ملف Product.php: <?php namespace App; class Product extends Model { protected $primaryKey = 'id'; protected $table = 'products'; protected $fillable = array('name', 'title', 'description','price','category_id','brand_id','created_at_ip', 'updated_at_ip'); } ملف Post.php: <?php namespace App; class Post extends Model { protected $primaryKey = 'id'; protected $table = 'posts'; protected $fillable = array('url', 'title', 'description','content','blog','created_at_ip', 'updated_at_ip'); } استخدام النماذج في المتحكماتتقضي بنية MVC وعادات البرمجة الصحيحة أن تكون المتحكمات هي من يتعامل مع النماذج. سنعدّ متحكم المشروع Front.php للعثور على البيانات من النماذج وتمريرها إلى العروض لتظهر لدى المتصفح. عدّل ملف Front.php كالتالي: <?php namespace App\Http\Controllers; use App\Brand; use App\Category; use App\Product; use App\Http\Controllers\Controller; class Front extends Controller { var $brands; var $categories; var $products; var $title; var $description; public function __construct() { $this->brands = Brand::all(array('name')); $this->categories = Category::all(array('name')); $this->products = Product::all(array('id','name','price')); } public function index() { return view('home', array('title' => 'Welcome','description' => '','page' => 'home', 'brands' => $this->brands, 'categories' => $this->categories, 'products' => $this->products)); } public function products() { return view('products', array('title' => 'Products Listing','description' => '','page' => 'products', 'brands' => $this->brands, 'categories' => $this->categories, 'products' => $this->products)); } public function product_details($id) { $product = Product::find($id); return view('product_details', array('product' => $product, 'title' => $product->name,'description' => '','page' => 'products', 'brands' => $this->brands, 'categories' => $this->categories, 'products' => $this->products)); } public function product_categories($name) { return view('products', array('title' => 'Welcome','description' => '','page' => 'products', 'brands' => $this->brands, 'categories' => $this->categories, 'products' => $this->products)); } public function product_brands($name, $category = null) { return view('products', array('title' => 'Welcome','description' => '','page' => 'products', 'brands' => $this->brands, 'categories' => $this->categories, 'products' => $this->products)); } public function blog() { return view('blog', array('title' => 'Welcome','description' => '','page' => 'blog', 'brands' => $this->brands, 'categories' => $this->categories, 'products' => $this->products)); } public function blog_post($id) { return view('blog_post', array('title' => 'Welcome','description' => '','page' => 'blog', 'brands' => $this->brands, 'categories' => $this->categories, 'products' => $this->products)); } public function contact_us() { return view('contact_us', array('title' => 'Welcome','description' => '','page' => 'contact_us')); } public function login() { return view('login', array('title' => 'Welcome','description' => '','page' => 'home')); } public function logout() { return view('login', array('title' => 'Welcome','description' => '','page' => 'home')); } public function cart() { return view('cart', array('title' => 'Welcome','description' => '','page' => 'home')); } public function checkout() { return view('checkout', array('title' => 'Welcome','description' => '','page' => 'home')); } public function search($query) { return view('products', array('title' => 'Welcome','description' => '','page' => 'products')); } } في المتحكم: نستورد النماذج: use App\Brand; use App\Category; use App\Product; نعرف متغيرات لتحميل بيانات النماذج: var $brands; var $categories; var $products; يعرف المتغيران title$ وdescription$ على التوالي عنوانا ووصفا لأغراض التحسين لمحركات البحث. نُعرّف باني Constructor صنف المتحكم: public function __construct(){…}تحمّل هذه الدالة البيانات من النماذج إلى المتغيرات المعرّفة سابقا. نحمّل في الدالة index العرض home مع تمرير مصفوفة معطيات تمثل بيانات النماذج مع بيانات أخرى لغرض التحسين لمحركات البحث.عرض بيانات النماذج في العروضنستخدم الحلقات التكرارية في قوالب Blade من أجل عرض بيانات النماذج التي مررها المتحكم إلى العروض. على سبيل المثال: @foreach ($brands as $brand) <li><a href='{{url("products/brands/$brand->name")}}'> <span class="pull-right">(50)</span>{{$brand->name}}</a></li> @endforeachتوجد عروض المشروع في الملف المرفق. خاتمةمن السهل إنشاء نماذج Eloquent واستخدامها؛ كل ما عليك فعله هو تمديد صنف Model والبدء باستخدام النموذج. يوفر Laravel أيضا إمكانية تخصيص استعلامات SQL دون المرور بـEloquent لمن يرغب في ذلك. ملف مرفق: عروض المشروع. ترجمة -وبتصرف- لمقال Laravel 5 Eloquent ORM لصاحبه Rodrick Kazembe.
  6. تلعب روابط URL دورا هامًّا في العثور على مواقع الويب؛ لذا من المهم تحسينها لمحركات البحث Search Engine Optimization. سنرى في هذا الدرس طريقةً لجعل روابط مشروع larashop محسّنة للمحركات. رأينا في الدرس السابق كيف تعمل المسارات والمتحكمات، سنبني على هذه المعرفة التي اكتسبناها من أجل الوصول إلى الهدف المحدّد. هذا الدرس جزء من سلسلة تعلم 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.العوامل المؤثرة في التحسين لمحركات البحثلا نهدف إلى تقديم دليل شامل عن التحسين لمحركات البحث؛ ما نريده هنا هو ذكر بضعة عوامل يجب على المطور أن يكون على اطّلاع عليها. في ما يلي عوامل تؤثر على تقويم محركات البحث مثل Google لصفحات الويب: سرعة الموقع: يحب الجميع أن تظهر صفحة الويب التي يزورها بسرعة، فلا أحد يحب الانتظار إلى ما لا نهاية حتى تظهر الصفحة التي يطلبها. من الأحسن ألا يتعدى زمن تنزيل الصفحة ثانيتين وكل ما قلّ كلّ ما كان الأمر أفضل. يجب عليك بوصفك مطوّرا اختبارُ سرعة تطبيقك وإجراء التحسينات اللازمة إن اقتضت الضرورة.إحصاءات الشبكات الاجتماعية: من الطبيعي، عند قراءتك شيئا مهمّا، مشاركتُه مع متابعيك وأصدقائك على الشبكات الاجتماعية؛ وهذا دليل على الأهمية بالنسبة لمحركات البحث. دورك كمطور هو توفير الأدوات التي تسهل على الزوار مشاركة محتوى الموقع.تصميم تجاوبي Responsive: يمثل مستخدمو الأجهزة المتنقلة جزءًا كبيرًا من مستخدمي خدمات الويب. من هذا المنطلق يجب التأكد من أن موقع الويب يظهر بشكل صحيح على أجهزة الجوّال، الأجهزة اللوحية وأجهزة سطح المكتب؛ إذ أن تجربة المستخدم من العوامل المؤثرة في تقويم محركات البحث.الكلمات المفتاحية Keywords: تصنف محركات البحث مليارات صفحات الويب حسب الكلمات الأساسية الواردة فيها. يتمثل دور المطور في التأكد من توفير آليات مثل الوسوم Tags، أوصاف meta، وعناوين HTML يمكن لكاتب المحتوى استخدامها لتمييز المحتوى المفتاحي.روابط URL الخاصة بالموقع: يجب أن تظهر الكلمات المفتاحية في روابط الموقع.كيفية إنشاء روابط محسنة لمحركات البحث في Laravelعرضنا لأساسيات تحسين محركات البحث مع ذكر دور المطور في تنفيذها. سنبدأ الآن في وضع هذه المبادئ موضع التنفيذ. سننشئ مسارات ونربطها بمت حكم. يُظهر الجدول التالي الروابط التي سيتكون منها متجرنا الإلكتروني. التسلسل الرابط الدالة الوصف1/indexالصفحة الرئيسية2/productsproductsصفحة المنتجات3/products/details/{id}product_details(id)صفحة المنتج ذي المعرّف id4/products/categoryproduct_categoriesعرض تصنيفات المنتجات5/products/brandsproduct_brandsعرض العلامات التجارية للمنتجات6/blogblogعرض فهرس بمنشورات المدونة7/blog/post/{id}blog_post($id)عرض محتوى التدوينة ذات المعرّف id8/contact-uscontact_usعرض صفحة الاتصال9/loginloginصفحة تسجيل الدخول10/logoutlogoutتسجيل خروج المستخدم11/cartcartعرض محتوى سلة المشتريات12/checkoutcheckoutصفحة الدفع13/search/{query}search($query)عرض نتائج البحث في الموقعتعريف مسارات الروابطسنعرّف مسارا لكل من الروابط الموجودة في الجدول أعلاه، لذا نفتح الملف app/Http/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('/','Front@index'); Route::get('/products','Front@products'); Route::get('/products/details/{id}','Front@product_details'); Route::get('/products/category','Front@product_categories'); Route::get('/products/brands','Front@product_brands'); Route::get('/blog','Front@blog'); Route::get('/blog/post/{id}','Front@blog_post'); Route::get('/contact-us','Front@contact_us'); Route::get('/login','Front@login'); Route::get('/logout','Front@logout'); Route::get('/cart','Front@cart'); Route::get('/checkout','Front@checkout'); Route::get('/search/{query}','Front@search');احفظ الملف. يستدعي كلٌّ مسار دالة المتحكم Front الموافقة له، حسب الجدول أعلاه. بقي الآن إنشاء المتحكم وكتابة الدوال. نستخدم أداة Artisan لإنشاء شفرة نمطية لمتحكم Laravel. تأكد من وجودك في مجلد المشروع larashop ثم نفذ الأمر التالي: php artisan make:controller Front يعني ظهور الرسالة التالية أن الأمر نُفذ كما يجب: Controller created successfully.افتح ملف المتحكم Font الذي أنشأناه للتو (app/Http/Controllers/Front.php) وعدّل عليه بحيث يصبح محتواه التالي: <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Http\Controllers\Controller; class Front extends Controller { public function index() { return 'index page'; } public function products() { return 'products page'; } public function product_details($id) { return 'product details page'; } public function product_categories() { return 'product categories page'; } public function product_brands() { return 'product brands page'; } public function blog() { return 'blog page'; } public function blog_post($id) { return 'blog post page'; } public function contact_us() { return 'contact us page'; } public function login() { return 'login page'; } public function logout() { return 'logout page'; } public function cart() { return 'cart page'; } public function checkout() { return 'checkout page'; } public function search($query) { return "$query search page"; } }تعرّف الشفرة أعلاه الدوال التي تجيب على كل طلب يأتي من المسارات التي عرّفناها في ملف routes.php. اكتفينا -لحد الساعة- بجعل كل دالة ترجع اسم المسار الذي تجيب على طلباته. انتقل الآن للمتصفح وأدخل الرابط التالي في شريط العناوين: http://larashop.dev/search/bootsستحصل على صفحة بالمحتوى التالي: boots search pageجرب الروابط الأخرى أيضا: http://larashop.dev/ http://larashop.dev/products http://larashop.dev/products/details/7 http://larashop.dev/products/category http://larashop.dev/products/brands http://larashop.dev/blog http://larashop.dev/blog/post/3 http://larashop.dev/contact-us http://larashop.dev/login http://larashop.dev/logout http://larashop.dev/cart http://larashop.dev/checkout http://larashop.dev/search/Keywordترجمة -وبتصرّف- لمقال Laravel 5 SEO Friendly URLs لصاحبه Rodrick Kazembe.
  7. أنشأنا في الدرس السابق مسارات تكتفي بكتابة عبارات في صفحة الويب. سننشئ في هذا الدرس عروضا لتقديمها إلى الزوار حسب الرابط الذي يختارونه؛ نستخدم لهذا الغرض قوالب Blade. هذا الدرس جزء من سلسلة تعلم Laravel والتي تنتهج مبدأ "أفضل وسيلة للتعلم هي الممارسة"، حيث ستكون ممارستنا عبارة عن إنشاء تطبيق ويب للتسوق مع ميزة سلة المشتريات. يتكون فهرس السلسلة من التالي: مدخل إلى Laravel 5.تثبيت Laravel وإعداده على كلّ من Windows وUbuntu.أساسيات بناء تطبيق باستخدام Laravel.إنشاء روابط محسنة لمحركات البحث (SEO) في إطار عمل Laravel.نظام Blade للقوالب. (هذا الدرس)تهجير قواعد البيانات في Laravel.استخدام Eloquent ORM لإدخال البيانات في قاعدة البيانات، تحديثها أو حذفها.إنشاء سلة مشتريات في Laravel.الاستيثاق في Laravel.إنشاء واجهة لبرمجة التطبيقات API في Laravel.إنشاء مدوّنة باستخدام Laravel.استخدام AngularJS واجهةً أمامية Front end لتطبيق Laravel.الدوّال المساعدة المخصّصة في Laravel.استخدام مكتبة Faker في تطبيق Laravel لتوليد بيانات وهمية قصدَ الاختبار. تعرِّف القوالب Templates إطارا عامًّا للعرض، يحدّد أجزاءه والعناصر التي تكوّنه. Blade هو نظام إدارة القوالب والتعامل معها المضمَّن في Laravel. نحصُل بنهاية هذا الدرس على الواجهة التالية. يشمل الدرس المواضيع التالية: توريث القالب.المخطّط الرئيس Master layout.تمديد المخطّط الرئيس.عرض المتغيرات.التعبيرات الشرطية Conditional statements في Blade.الحلقات التكراراية Loops في Blade.تنفيذ تعليمات PHP في Blade,تنتهي جميع ملفات العروض في Blade بالامتداد blade.php. توريث القوالبيمكن تعريف توريث القوالب بأنه تلك الخاصيّة التي تسمح بجمع عناصر مشتركة بين عدة عروض ضمن عرض تعيد استخدامه عند الحاجة مع إضافة العناصر الخاصة بالصفحة؛ مما يجنب تكرار العناصر المشتركة في كلّ مرة. المخطط الرئيستُجمع العناصر المشتركة في عرض يُطلَق عليه المخطّط الرئيس تعيد العروض الأخرى استخدامه وتضيف إليه العناصر الخاصة بها. سننشئ في ما يلي مخطّطا رئيسا نضمنه عناصر مشتركة بين العروض.ننشئ مجلدا جديدا باسم layouts على المسار resources/views/. ثم ننشئ ملفا باسم master.blade.php ضمن المجلد layouts.نضيف الشفرة التالية إلى الملف master.blade.php:<html> <head> <title>@yield('title')</title> </head> <body dir="rtl"> @section('sidebar') هنا يوجد محتوى المقطع sidebar في المخطط الرئيس. @show <div class="container"> @yield('content') </div> </body> </html>قالب Blade عبارة عن وسوم HTML مع تعليمات خاصة بنظام القوالب. يستخدم القالب أعلاه ثلاث تعليمات هي section ،@yield@ و show@. تُستخدم التعليمة section@ لتعريف مقطع (عنصر) من القالب.بينما تستخدم التعليمة yield@ لعرض محتوى مقطع معطى (مقطع باسم title في أول استخدام للتعليمة yield@ في المخطّط السابق).أما التعليمة show@ فتستخدم لعرض محتوى مقطع.تمديد المخطط الرئيسننشئ الآن قالبا يمدّد القالب الرئيس السابق. أنشئ ملفا باسم page.blade.php في المسار resources/views وأضف إليه الشفرة التالية: @extends('layouts.master') @section('title', 'عنوان الصفحة') @section('sidebar') @parent <p>هذا المحتوى ملحق بمحتوى المقطع sidebar الموجود في المخطط الرئيس</p> @endsection @section('content') <p>جسم الصفحة.</p> @endsectionتشير التعليمة ('extends('layouts.master إلى أننا في صدد تمديد المخطّط الرئيس master.blade.php الموجود ضمن المجلد layouts.تعيّن التعليمة ('section('title', 'Page Title قيمة المقطع title المعرّف في المخطّط الرئيس. ثم نعرّف مقطع جديدا باسم sidebar ضمن العرض page. داخل المقطع sidebar نطبع محتوى المقطع الذي يحمل نفس الاسم في المخطّط الرئيس باستخدام التعليمة parent@، نضيف فقرة HTML باستخدام الوسم <p>...</p> ثم ننهي المقطع sidebar بالتعليمة endsection@.تعرّف التعليمة ('section('content محتوى المقطع content وهو في هذا المثال الفقرة <p>جسم الصفحة.</p>.في المخطط الرئيس توجد ثلاثة مقاطع وهي، حسب ترتيب الاستخدام، sidebar ،title و content. بالنسبة للمقطعين title و content فقد اكتفينا بتحديد أماكنهما (التعليمة yield@)؛ أما المقطع sidebar فقد عرفنا محتواه وعرضناه (التعليمتان section@ و show@). في القالب page أعدنا استخدام المخطّط الرئيس ثم أعطينا قيمتي المقطعين title و content المعرّفين سابقا. بالنسبة للمقطع sidebar فقد أعدنا تعريفه مع إعادة استخدام محتوى المقطع المماثل له في الاسم ضمن القالب الرئيس (تعليمة parent@) وإضافة فقرة نصية أخرى. سنضيف مسارا خاصًّا لتجربة عمل نظام القوالب. افتح ملف المسارات routes.php وأضف المسار التالي: Route::get('blade', function () { return view('page'); });احفظ التعديلات. الآن أدخل الرابط في المتصفح: http://larashop.dev/bladeستحصل على الصفحة التالية: استخدام متغيرات في قوالب bladeنعرّف متغيرا باسم name ونمرره إلى قالب blade. افتح ملف المسارات وغيره بحيث يصبح على النحو التالي: Route::get('blade', function () { return view('page',array('name' => 'حسوب')); });احفظ التعديلات. نحدّث القالب page.blade.php لإظهار المتغير الذي يمرره المسار: @extends('layouts.master') @section('title', 'عنوان الصفحة') @section('sidebar') @parent <p>هذا المحتوى ملحق بمحتوى المقطع sidebar الموجود في المخطط الرئيس</p> @endsection @section('content') <h2>{{$name}}</h2> <p>جسم الصفحة</p> @endsectionتستخدم التعليمة {{name$}} لطباعة قيمة المتغير name$. احفظ التعديلات ثم أعد تحميل الصفحة http://larashop.dev/blade. ستلاحظ وجود عنوان h2 جديد هو حسوب التي هي قيمة المتغير الممرًّر لقالب page.blade.php. التعبيرات الشرطية في Bladeيدعم نظام Blade التعبيرات الشرطية التي تحدّد ما يُعرض حسب شرط معرَّف مسبقا. سنمرر متغيرا إلى القالب ثم نختبر قيمته (الشرط) وحسب نتيجة الاختبار يكون العرض. افتح ملف routes.php وعدل المسار بحيث يصبح ما يلي: Route::get('blade', function () { return view('page',array('name' => 'حسوب','day' => 'Friday')); });أضفنا هنا متغيرا جديد باسم day وأعطيناه القيمة Friday. احفظ التعديلات. افتح ملف القالب وعدله على النحو التالي: @extends('layouts.master') @section('title', 'عنوان الصفحة') @section('sidebar') @parent <p>هذا المحتوى ملحق بمحتوى المقطع sidebar الموجود في المخطط الرئيس</p> @endsection @section('content') <h2>{{$name}}</h2> <p>جسم الصفحة</p> <h2>تعبير if الشرطي</h2> @if ($day == 'Friday') <p>إنه يوم الجمعة</p> @else <p>اليوم ليس يوم الجمعة</p> @endif @endsectionإذا كانت قيمة المتغير day هي Friday نعرض الجملة <p>إنه يوم الجمعة</p> وإلا فإن الفقرة المعروضة تصبح <p>اليوم ليس يوم الجمعة</p>. احفظ التعديلات ثم أعد تنزيل الصفحة ولاحظ الفرق. الحلقات التكرارية في Bladeيدعم Blade كل الحلقات التكرارية التي يدعمها PHP. سنرى مثالا لاستخدام الحلقة التكرارية foreach لعرض محتويات مصفوفة Array في قالب Blade. عدل ملف المسارات routes.php على النحو التالي: Route::get('blade', function () { $foods = array('Barbecue','Couscous','Fish'); return view('page',array('name' => 'حسوب', 'day' => 'Friday', 'foods' => $foods)); });عرّفنا مصفوفة تحوي ثلاثة عناصر ومررناها إلى قالب Blade. احفظ التعديلات ثم افتح ملف القالب وعدّله على النحو التالي: @extends('layouts.master') @section('title', 'عنوان الصفحة') @section('sidebar') @parent <p>هذا المحتوى ملحق بمحتوى المقطع sidebar الموجود في المخطط الرئيس</p> @endsection @section('content') <h2>{{$name}}</h2> <p>جسم الصفحة</p> <h2>تعبير if الشرطي</h2> @if ($day == 'Friday') <p>إنه يوم الجمعة</p> @else <p>اليوم ليس يوم الجمعة</p> @endif <h2>حلقة foreach التكرارية</h2> @foreach ($foods as $food) {{$food}} <br> @endforeach @endsectionاحفظ التعديلات ثم أعد تحميل الصفحة ولاحظ طباعة محتوى المصفوفة. تضمين شفرة PHP في قالب Bladeافتح ملف القالب وعدّله بإضافة سطر يستخدم إحدى دوالّ PHP (اخترنا الدالة date). يصبح ملف القالب كما يلي: @extends('layouts.master') @section('title', 'عنوان الصفحة') @section('sidebar') @parent <p>هذا المحتوى ملحق بمحتوى المقطع sidebar الموجود في المخطط الرئيس</p> @endsection @section('content') <h2>{{$name}}</h2> <p>جسم الصفحة</p> <h2>تعبير if الشرطي</h2> @if ($day == 'Friday') <p>إنه يوم الجمعة</p> @else <p>اليوم ليس يوم الجمعة</p> @endif <h2>حلقة Loop التكرارية</h2> @foreach ($foods as $food) {{$food}} <br> @endforeach <h2>شفرة PHP</h2> <p>تاريخ اليوم {{date(' D M, Y')}}</p> @endsectionوضعنا دالة PHP داخل معكوفين مزدوجين لتنفيذها. أعد تنزيل الصفحة http://laravel.dev/blade بعد حفظ التعديلات. العروض المكونة لمشروع Larashopذكرنا في بداية السلسلة أننا نهدف إلى إنشاء موقع للتسوق الإلكتروني. سنستخدم ما تعلمناه في هذا الدرس والدروس السابقة لبناء اللبنة الأولى من هذا المشروع وهي الجانب المرئي. لإعطاء وجه لائق لمشروعنا بحثنا عن تصميم HTML جاهز ووجدنا أن قالب Eshopper من موقع shapebootstrap.net مناسب لما نريد. الخطوة التالية للحصول على تصميم HTML هي تحويله إلى قالب Blade يعمل مع Laravel. سنبدأ أولا بمحتوى الملف المرفق وكيفية استخدامه للحصول على واجهة الموقع المعروضة في أول الدرس، ثم نشرح بعد ذلك تعليمات Blade التي لم نتطرق إليها حتى الآن. محتوى الملف المرفقيحوي الملف المرفق: عروض المشروع larashop.ملف المتحكم Front الذي حدثناه ليحمّل عروض المشروع.ملف المسارات.الموارد المستخدمة في القالب: ملفات CSS، الصور، ملفات Js والخطوط.العروضيحوي المشروع العروض التالية: layout: وهو المخطط الرئيس ويوجد في المجلد الفرعي layouts.sidebar: وهو عرض مشترك بين صفحاتٍ عدة، يوجد في مجلد فرعي باسم shared.blog: صفحة المدونة.blog_post: صفحة منشور على المدونة.cart: صفحة سلة المشتريات.checkout: صفحة الدفع.contact_us: صفحة الاتصال.home: الصفحة الرئيسية.login: صفحة تسجيل الدخول.products: صفحة المنتجات.product_details: تفاصيل منتج.يجب أن توضع العروض في المجلد resources/views. تبدو بنية هذا المجلد كالتالي بعد إضافة العروض إليها. المتحكم Front وملف المساراتأنشأنا في الدرس السابق متحكم Front لكنه يكتفي بعرض نص في المتصفح. سنحتاج لتعديله ليحمِّل العروض. عدّلنا قليلا على ملف المسارات routes.php لتعريف مسار لكل تصنيف أو علامة تجارية. مجلد publicيحوي الموارد (صور، css، js) التي تحتاجها واجهة الموقع للعمل. يجب وضع هذه الموارد في مجلد public في المشروع. ملحوظة: تأكد بعد نقل الملفات من المرفق إلى أماكنها في المشروع من أن الأذون ما زالت على الحال التي ضبطناها بها في درس الإعداد (لينكس). الآن وبعد التأكد من نقل الملفات من المرفق إلى أماكنها الصحيحة، اذهب إلى الصفحة الرئيسية http://larashop.dev وستظهر واجهة الموقع. نأخذ وقتا لشرح المشروع. تحويل صفحات HTML إلى قالب Bladeقوالب Blade هي، كما رأينا، وسوم HTML مع تعليمات خاصّة بنظام القوالب؛ لذا نحافظ على البنية العاملة لملفات HTML المكوِّنة للموقع مع إجراء تغييرين أساسيين: جمع العناصر المشتركة بين مختلف الصفحات ضمن صفحة خاصة.إبدال الروابط في صفحة HTML بتعليمات Blade.يُترجَم تحويل صفحات HTML إلى قوالب Blade بالخطوات التالية: إنشاء مخطّط رئيس تُمدده جميع الصفحات. يحوي المخطط الرئيس العناصر المشتركة بين الصفحات.إنشاء صفحة (عرض) لكل مسار من المسارات المعرَّفة في الدرس السابق.تحديث المتحكم Front.php لتحميل العروض.إضافة الموارد (الصور، ملفات css وjs) إلى مجلد public في تطبيق Laravel.يحوي الملف المرفق بهذا المقال عروض Blade الناتجة عن تحويل صفحات HTML إلى قوالب Blade، إضافة إلى ملف المسارات الخاص بمشروع Larahop، المتحكم Front.php والموارد مثل الصور وملفات css (مجلد public). المخطط الرئيسأنشأنا ملفا لمخطط رئيس باسم layout.blade.php على المسار resources/views/layouts. في هذا الملف توجد وسوم HTML مع تعليمات Blade؛ بعضها لم نتطرق له بعد: تعليمة {{url}}:{{url('products')}}تنشئ التعليمة {{url}} رابط URL بالنسبة للمجلدpublic. في المثال أعلاه فإن الرابط الذي ترجعه التعليمة هو http://larashop.dev/products؛ وهو الرابط الذي تتعامل معه دالة المسار products/. لإنشاء رابط إلى الصفحة الرئيسية فالتعليمة تكون: {{url('')}}نأخذ أيضا المثال التالي الموجود في المخطط الرئيس: <li><a href="{{url('products')}}" {{$page == 'products' ? 'class=active' : ''}}>Products</a></li>نلاحظ استخدام التعليمة url لإعطاء قيمة الرابط ضمن وسم <a>. في نفس السطر توجد تعليمة تشبه تعليمةً مألوفة في PHP وهي {{$page == 'products' ? 'class=active' : ''}}هنا نتحقق من قيمة المتغير page فإذا كانت تساوي products نضيف صنف CSS يسمّى active إلى الوسم. تعليمة {{asset}}:{{asset('css/bootstrap.min.css')}}تُرجع الدالة asset مسار مجلد public (أي عنوان الموقع) وتلحق به المعطى الممرَّر إليها. في السطر أعلاه ترجِع الدالةُ القيمةَ http://larashop.dev/css/bootstrap.min.css. تُستخدم هذه الدالة كثيرا لإضافة ملفات CSS، الصور وملفات JavaScript كما في الأمثلة التالية المأخدوذة من المخطط الرئيس. <!-- CSS --> <link href="{{asset('css/bootstrap.min.css')}}" rel="stylesheet"> <!-- صورة --> <img src="{{asset('images/home/iframe1.png')}}" alt="" /> <!-- JavaScript --> <script src="{{asset('js/jquery.js')}}"></script>يمكن من خلال المعطيات الممرَّرة إلى الدالة asset في الأمثلة أعلاه اسنتاجُ أننا نستخدم مجلدًّا فرعيا في public لكل نوع من الموارد (CSS، الصور، JS إضافة للخطوط fonts). إن نظرت جيدا في ملف المخطط الرئيس فستميز ثلاثة أجزاء فارقة: الجزء الأول ويحوي الوسوم المؤسِّسة للجزء الأعلى المشترك بين مختلف صفحات الموقع، ويحوي ترويسة الموقع وقائمته الرئيسية.الجزء الثاني تمثله التعليمة ('yield('content@ وتلعب دور ماسك مكان Place holder. ستحدّد العروض الأخرى الممدّدة للمخطط الرئيس محتوى ماسك المكان.الجزء الثالث وبه التذييل المشترك بين صفحات الموقع.إن فهمت جيدا آلية عمل نظام القواعد فستعرف أن الجزأين الأول والثالث لا يتغيران بتغير الصفحة التي يطلبها الزائر. ما يتغير هو فقط الجزء الثاني الذي يعبئه نظام القوالب بمحتوى مختلف حسب الصفحة. الصفحات المشتقةننتقل الآن للعروض الخاصة بكل صفحة. يمدّد كل عرض المخطّط الرئيس. في ما يلي المنحى العام للعروض: @extends('layouts.layout') @section('content') <!--وسوم HTML --> @include('shared.sidebar') <!--وسوم HTML --> @endsectionيمدد العرض المخطط الرئيس بتنفيذ التعليمة التالية:@extends('layouts.layout')يعرّف مقطعا باسم content:@section('content')يُحمَّل محتوى المقطع content في المكان المعرّف بنفس الاسم في المخطّط الرئيس. ينتهي المقطع عند التعليمة endsection@. نضمِّن محتوى العرض sidebar الموجود في المجلد resources/views/shared:@include('shared.sidebar')تستخدم التعليمة include لتحميل محتوى عرض ضمن آخر. عرض sidebar الذي يمثل شريطا جانبيا للموقع موجود في أغلب الصفحات. نضيف وسوم HTML المأخوذة من قالب E-Shopper لتكوين الصفحة.تحديث المتحكم Frontنحدّث المتحكم Front.php ليحمل العروض بدلا من الاكتفاء بطباعة نص في الصفحة. يصبح محتوى المتحكم بعد التحديث على النحو التالي. تحمل كل دالّة العرض الموافق لها حسب جدول الدرس السابق. <?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; class Front extends Controller { public function index() { return view('home', array('page' => 'home')); } public function products() { return view('products', array('page' => 'products')); } public function product_details($id) { return view('product_details', array('page' => 'products')); } public function product_categories($name) { return view('products', array('page' => 'products')); } public function product_brands($name, $category = null) { return view('products', array('page' => 'products')); } public function blog() { return view('blog', array('page' => 'blog')); } public function blog_post($id) { return view('blog_post', array('page' => 'blog')); } public function contact_us() { return view('contact_us', array('page' => 'contact_us')); } public function login() { return view('login', array('page' => 'home')); } public function logout() { return view('login', array('page' => 'home')); } public function cart() { return view('cart', array('page' => 'home')); } public function checkout() { return view('checkout', array('page' => 'home')); } public function search($query) { return view('products', array('page' => 'products')); } } جرب تصفح الموقع والتنقل بين صفحاته. إذا اتبعت خطوات الدرس على النحو المشروع فستكون قادرا على التنقل بين صفحات الموقع دون مشاكل. يمكنك أيضا فتح الشفرة المصدرية لصفحات موقع الويب ومقارنتها بما كتبناه في قوالب Blade. خاتمةنحصل بنهاية الدرس على تصميم أنيق لصفحات الموقع، استخدمنا لإنشائه Blade الذي يوفر نظاما فعّالا لكتابة قوالب العروض في Laravel مما يتيح تجنب تكرار العناصر المشتركة. بانتهاء هذا الدرس نكون قد أنهينا أساس جزء العرض من بنية MVC. الدروس التالية من السلسلة تتناول بقية الأجزاء. ترجمة -وبتصرّف- لمقال Laravel 5 Blade Template لصاحبه Rodrick Kazembe.
  8. يوفر تهجير قواعد البيانات Database migration في Laravel آليات لإنشاء الجداول Tablesوالتعديل عليها بغض النظر نظام إدارة قواعد البيانات المستخدم. يعني هذا أنك لن تضطر للاهتمام بالاختلافات بين نظم إدارة قواعد البيانات في صياغة أوامر SQL. يمكّن التهجير أيضا من التراجع والعودة إلى ما كانت عليه قاعدة البيانات قبل آخر التعديلات. هذا الدرس جزء من سلسلة تعلم 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 لتوليد بيانات وهمية قصدَ الاختبار. يمكن النظر إلى تهجير قواعد البيانات كما لو كان نظام إدارة نسخ خاص بقواعد البيانات، إذ يتيح لفريق العمل سهولة تغيير مخطّط Schema البيانات وتشاركه. نكمل في هذا الدرس اعتمادا على ما أنشأناه في الدروس السابقة من السلسلة. يغطي الدرس المواضيع التالية: متطلبات التهجير.أمر Artisan لتهجير قواعد البيانات.بنية التهجير.إنشاء جدول بآلية التهجير.استخدام آلية التهجير للتراجع Rollback عن التعديلات.بذر قواعد البيانات Database seeding.بنية قاعدة البيانات الخاصة بمشروع Larashop.ملفات التهجير لقاعدة بيانات Larashop.متطلبات التهجيريجب أولا إنشاء قاعدة بيانات في نظام إدارة قواعد البيانات المستخدم (MySQL في حالتنا) وإعداد معطيات الاتصال بها في Laravel ولدى أداة سطر الأوامر Artisan. إنشاء قاعدة بياناتنفذ الأمر التالي في سطر أوامر MySQL أو استخدم التطبيق المفضّل لديك (PHPMyAdmin مثلا) لإنشاء قاعدة بيانات larashop: CREATE DATABASE `larashop`;إعداد Laravel للاتصال بقاعدة البياناتأعددنا Laravel في الدرس الأول من هذه السلسلة للاتصال بقاعدة بيانات باسم larashop. في ما يلي تذكير بخطوات الإعداد. افتح الملف config/database.php واعثر على الأسطُر التالية: 'mysql' => [ 'driver' => 'mysql', 'host' => env('DB_HOST', 'localhost'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', 'strict' => false, ],حدّث القيم التالية لتوافق إعدادات MySQL لديك: 'database' => env('DB_DATABASE', 'larashop'), 'username' => env('DB_USERNAME', 'root'), 'password' => env('DB_PASSWORD', 'melody'), إعداد معطيات اتصال Artisan بقاعدة البياناتيواجه الكثير من المطورين رسالة الخطأ التالية عند العمل على تهجير قواعد البيانات باستخدام أداة Artisan: Access denied for user 'homestead'@' localhost' (using password: YES)ستظهر الرسالة أعلاه حتى ولو كانت معطيات الاتصال في الملف configuration/database.php صحيحة. يعود السبب في ذلك إلى أن Artisan يستخدم المعطيات الموجودة في الملف env.. الحل هو إذن تحرير الملف env. الواقع في مجلد التطبيق، ستجد ما يلي: APP_ENV=local APP_DEBUG=true APP_KEY=aqk5XHULL8TZ8t6pXE43o7MBSFchfgy2 DB_HOST=localhost DB_DATABASE=homestead DB_USERNAME=homestead DB_PASSWORD=secret CACHE_DRIVER=file SESSION_DRIVER=file QUEUE_DRIVER=sync MAIL_DRIVER=smtp MAIL_HOST=mailtrap.io MAIL_PORT=2525 MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_ENCRYPTION=null حدث المتغيرات التالية: DB_HOST=localhost DB_DATABASE=homestead DB_USERNAME=homestead DB_PASSWORD=secretلتصبح: DB_HOST=localhost DB_DATABASE=larashop DB_USERNAME=root DB_PASSWORD=melody احرص على موافقة اسم قاعدة البيانات، اسم المستخدم وكلمة مروره للمعطيات لديك. احفظ التعديلات. تهجير قواعد البيانات بأداة Artisanينشئ أمر artisan ملفا على المسار database/migrations لكل عملية تهجير. يمكن تغيير المسار الخاص بحفظ ملفات التهجير إن أردت ولكننا هنا سنكتفي بالمسار المبدئي. ننفذ الأمر التالي لإنشاء أول ملف تهجير: php artisan make:migration create_drinks_tableتظهر رسالة باسم ملف التهجير الجديد. اخترنا اسم create_drinks_table للدلالة على أن التهجير ينشئ جدولا باسم drinks في قاعدة البيانات. نتيجة الأمر هي إنشاء ملف للتهجير بنفس الاسم الذي أعطيناه مع إضافة ختم زمني قبله، مثلا: 2015_12_21_215845_create_drinks_table.phpبنية ملف التهجيرندرس الآن محتوى ملف التهجير الذي أنشأناه للتو. افتح الملف التالي لرؤية محتواه (انتبه إلى أن اسم الملف يبدأ بختم زمني للحظة إنشائه): database/migrations/2015_12_21_215845_create_drinks_table.phpنجد ما يلي: <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateDrinksTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { // } /** * Reverse the migrations. * * @return void */ public function down() { // } }يعرف ملف التهجير صنفا جديدا باسم CreateDrinksTable يمدد الصنف Migration: CreateDrinksTable extends Migrationداخل الصنف CreateDrinksTable توجد دالة باسم up. تنفّذ تعليمات الدالة up عند تشغيل التهجير. توجد أيضا دالة باسم down في الصنف CreateDrinksTable. تنفذ تعليمات الدالة down عند التراجع عن تغييراتِ تهجير.ملف تهجير لإنشاء جدول بقاعدة البياناتليمكن إنشاء جدول في قاعدة البيانات فجيب تعريف حقوله في ملف التهجير. نعيد فتح ملف التهجير السابق ونعدله ليصبح محتواه التالي : <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateDrinksTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('drinks', function (Blueprint $table) { $table->increments('id'); $table->string('name',75)->unique(); $table->text('comments')->nullable(); $table->integer('rating'); $table->date('juice_date'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('drinks'); } }في الدالة up: نستدعي الدالة create المعرَّفة في الصنف Schema ونمرر لها معطيين، الأول اسم الجدول الذي نريد إنشاءه drinks، والمعطى الثاني دالة غير محدّدة الاسم تعرّف حقول الجدول. نستخدم كائنا من صنف Blueprint لتعريف الجدول.نعرف أول حقل من الجدول وهو الحقل id. تعرف الدالة increments التابعة للصنف Blueprint عددا طبيعيا (عدد صحيح إشارته موجبة) يزداد تلقائيّا مع كل إدخال للبيانات في الجدول.الحقل الثاني هو حقل الاسم name، الذي نعرفه بالدالة string. تنشئ الدالة stringحقلا من سلسلة محارف مع تحديد طول السلسلة (75 في المثال). نعلّم الحقل name بالدالة unique \لجعله وحيدا وهو ما يعني أنه لا يمكن لتسجيلتين في الجدول أن تحويا نفس القيمة بالنسبة لهذا الحقل.الحقل الثالث comments نصي، وتستخدم الدالة text لتعريفه. نتيح إمكانية ألا يحوي الحقل بيانات باستخدام الدالة nullable.الحقل الرابع rating للتقيمات. نستخدم الدالة integer للإشارة إلى أنه عدد صحيح.ثم نضيف حقلا لتخزين تاريخ المشروب juice_date ونستخدم الدالة date لهذا الغرض.تُستخدم الدالة timestamps لإضافة حقلين هما created_at وupdated_at في الجدول تلقائيا. الحقلان عبارة عن ختم زمني ل، على التوالي، تاريخ إضافة التسجيلة إلى قاعدة البيانات وتاريخ آخر تحديث عليها.في الدالة down نحذف الجدول drinks من قاعدة البيانات في حالة وجوده.ننفذ بعد حفظ ملف التهجير الأمر التالي: 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: 2015_12_21_215845_create_drinks_tableإن نظرت في جداول قاعدة البيانات الآن فستجد التالي: ستلاحظ وجود أربعة جداول من بينها جدول drinks. الجداول الأخرى أنشأها Laravel لأن ملفات تهجيرها تأتي مبدئيا مع Laravel. التراجع عن التعديلاتيوفر التهجير إمكانية التراجع عن تعديلاته والعودة إلى حالة قاعدة البيانات قبل تنفيذه. أنشأنا في الفقرة السابقة جداول في قاعدة البيانات، ننفذ الأمر التالي للتراجع عن ذلك: php artisan migrate:rollbackتظهر الرسائل التالية: Rolled back: 2015_12_21_215845_create_drinks_table Rolled back: 2014_10_12_100000_create_password_resets_table Rolled back: 2014_10_12_000000_create_users_tableإن أعدت التحقق في MySQL سترى أن الجدول drinks لم يعد موجودا. نعيد إنشاء الجدول بتنفيذ التهجير مرة أخرى: php artisan migrateتمكن ملاحظة أن تنفيذ التهجير يكون بالتسلسل الزمني التصاعدي لتاريخ إنشاء ملفات التهجير (من الأقدم إلى الأحدث)، في ما يكون التراجع بتنفيذ ملفات التهجير حسب التسلسل الزمني التنازلي (من الأحدث إلى الأقدم). إدارة جداول البيانات في Laravel باستخدام التهجيرسنرى في هذه الفقرة كيفية استخدام التهجير للقيام بأشغال شائعة على جداول قواعد البيانات. إدراج بياناتسنرى الآن كيفية استخدام التهجير لإدراج بيانات في جدول أثناء إنشائه. ننشئ جدولا بالموظفين employees وندرج فيه 33 تسجيلة بالاعتماد على مكتبة Faker (سنخصص درسا لتفصيل استخدام Faker). نفذ الأمر التالي لإنشاء ملف تهجير لجدول employees: php artisan make:migration employeesنفتح الملف المنشأ للتو ونضيف الشفرة التالية: <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class Employees extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('employees', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->string('email')->unique(); $table->string('contact_number'); $table->timestamps(); }); $faker = Faker\Factory::create(); $limit = 33; for ($i = 0; $i < $limit; $i++) { DB::table('employees')->insert([ //, 'name' => $faker->name, 'email' => $faker->unique()->email, 'contact_number' => $faker->phoneNumber, ]); } } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('employees'); } } ننشئ كائنا من صنف Faker بالتعليمة $faker = Faker\Factory::create();نحدد عدد التسجيلات التي نود إدراجها: limit$. نستخدم حلقة for التكرارية لإضافة التسجيلات إلى الجدول. تولد التعليمة faker->name$ اسما وهميّا، faker->unique()->email$ اسم بريد وحيد وfaker->phoneNumber$ رقم هاتف وهميا.الأمر التالي ينفذ التهجير: php artisan migrateتظهر الرسالة التالية دلالة على تهجير الجدول employees: Migrated: 2015_12_21_225233_employees إن بحثت الآن عن محتوى الجدول employees، مثلا بتنفيذ الاستعلام التالي في سطر أوامر MySQL: SELECT * FROM employees;ستحصُل على أسماء الموظفين، عناوينهم البريدية وأرقام هواتفهم. نتراجع عن إنشاء الجدول employees بتنفيذ الأمر: php artisan migrate:rollbackتظهر رسالة دلالة على التراجع عن إنشاء الجدول. نفتح ملف التهجير للتعديل عليه ثم نضع الشفرة الخاصة بإدراج بيانات وهمية بين علامتي تعليق، هكذا: /* $faker = Faker\Factory::create(); $limit = 33; for ($i = 0; $i < $limit; $i++) { DB::table('employees')->insert([ //, 'name' => $faker->name, 'email' => $faker->unique()->email, 'contact_number' => $faker->phoneNumber, ]); } */احفظ ملف التهجير ثم نفذ الأمر: php artisan migrateسيُنشأ جدول employees من جديد ولكن هذه المرة دون إدراج تسجيلات في الجدول. إضافة عمود إلى جدول أو حذفه منهنفرض أننا نود إضافة عمود جديد gender لتخزين جنس الموظّف، مباشرة بعد العمود contact_number. ننفذ الأمر التالي لإنشاء ملف تهجير باسم add_gender_to_employees مع تحديد الجدول الذي نريد العمل عليه وهو employees: php artisan make:migration add_gender_to_employees --table=employeesتشير التعليمة table=employees-- إلى أننا نريد العمل على الجدول employees الموجود في قاعدة البيانات. افتح ملف التهجير المنشأ بعد الأمر السابق، وعدله ليصبح على النحو التالي: <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class AddGenderToEmployees extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('employees', function (Blueprint $table) { $table->string('gender')->after('contact_number'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('employees', function (Blueprint $table) { $table->dropColumn('gender'); }); } } في الدالة up أضفنا حقلا جديدا من نوع string (سلسلة محارف) وحددنا مكانه بأنه بعد العمود contact_number.في الدالة down نحذف الحقل gender.الآن عند تنفيذ أمر التهجير php artisan migrate ستلاحظ إضافة عمود جديد باسم gender بعد عمود contact_number. تغيير نوع عموديحتاج تغيير نوع العمود لتثبيت حزمة Doctrine Database Abstract Layer, DBAL. تُستخدم هذه الحزمة لتهجيرات التعديل على الجداول Alter table. سنستخدم أداة إدارة الاعتماديات Composer لتثبيت الحزمة. افتح ملف composer.json الذي يوجد في مجلد التطبيق. ابحث عن مقطع require: "require": { "php": ">=5.5.9", "laravel/framework": "5.2.*" },توجد في هذا المقطع حزم المكتبات التي يحتاجها تطبيقنا. حتى الآن توجد حزمتان فقط هما php وlaravel. يشير الجزء الأول (قبل النقطتين) إلى اسم الحزمة، في ما يشير الثاني لإصدارها. نضيف حزمة dbal` إلى هذه الاعتماديات، وذلك على النجو التالي: "require": { "php": ">=5.5.9", "laravel/framework": "5.2.*", "doctrine/dbal": "v2.4.2" }, لاحظ الفاصلة اللاتينية التي أضفناها بعد حزمة Laravel. نفذ الأمر التالي لتحديث المشروع: composer updateعند إنشاء العمود gender لم نحدد طول الحقل، أي أنه سيأخذ الطول المبدئي للحقول من نوع string وهو255 محرفا. ننشئ ملف تهجير جديدا لتعديل طول الحقل ليصبح 5 كحد أقصى. نعدل الملف على النحو التالي: php artisan make:migration modify_gender_in_employees --table=employeesقبول فراغ الحقول في الجدوليفترض Laravel عند إنشاء الحقول أنها لا تقبل فراغ القيمة، أي أنه يجب ذكر قيمة للحقل عند إدراج تسجيلات في الجدول. يمكننا تغيير هذا الإعداد المبدئي وجعل قيمة حقل ما اختيارية. سنأخذ الحقل gender للتمثيل به. ننشئ ملفا للتهجير: php artisan make:migration make_gender_null_in_employees --table=employeesثم نعدله على النحو التالي: <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class MakeGenderNullInEmployees extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('employees', function (Blueprint $table) { $table->string('gender', 5)->nullable()->change(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('employees', function (Blueprint $table) { $table->string('gender', 5)->change(); }); } } تجعل الدالة nullable الحقل gender يقبل قيما فارغة.php artisan migrate إضافة مفتاح خارجي Foreign keyنصنف موظفينا حسب القسم الذي يعملون فيه. ننشئ جدولا للأقسام depts ثم نضيف مفتاحا خاريجا في جدول الموظفين employees. الأمر أدناه ينشئ ملف تهجير لجدول الأقسام: php artisan make:migration deptsعدل ملف التهجير: <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class Depts extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('depts', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('depts'); } }ثم ننفذ أمر التهجير لإنشاء الجدول: php artisan migrateيُشترط لتصح علاقة عبر مفتاح خارجي بين جدولين أن يكون المفتاح الخارجي والمفتاح الرئيس Primary key متطابقين في النوع. استخدمنا في تعريف المفتاح الرئيس idضمن الجدول depts دالة increments التي تعطي النوع عددا طبيعيا من عشرة أرقام ;(unsigned integer INT(10 وهو ما يعني أننا سنعطي نفس النوع للمفتاح الخارجي الذي سننشئه في الجدول employees. الفرق أن المفتاح الخارجي لا يزداد تلقائيا لذا سنستخدم الدالة unsignedInteger التي لها نفس مفعول increments من حيث نوع الحقل وطوله، مع فرق أنها لا تضيف الازدياد التلقائي. ملحوظة: حتى تمكن إضافة مفتاح خارجي في الجدول employees يجب أن يكون الجدول فارغا (بدون تسجيلات). لهذا السبب علقنا في فقرة ماضية الشفرة الخاصة بـFaker. نفذ الأمر التالي لإنشاء ملف تهجير لإضافة حقل المفتاح الخارجي dept_id إلى الجدول employees: php artisan make:migration add_dept_id_in_employees --table=employeesثم نعدل ملف التهجير: <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class AddDeptIdInEmployees extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('employees', function (Blueprint $table) { $table-> unsignedInteger ('dept_id')->after('gender'); $table->foreign('dept_id') ->references('id')->on('depts') ->onDelete('cascade'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('employees', function (Blueprint $table) { $table->dropColumn('dept_id'); }); } }ثم ننفذ التهجير: php artisan migrate بذر قواعد البياناتيشير مصطلح البذر Seeding إلى عملية إضافة بيانات وهمية لأغراض الاختبار في قواعد البيانات. نطبق هذا الإجراء على جدول drinks الذي أنشأناه في أول الدرس. نفذ الأمر التالي لإنشاء ملف للبذر: php artisan make:seeder DrinksTableSeederينشئ الأمر ملفا باسم DrinksTableSeeder.php على المسار database/seeds. افتح الملف: <?php use Illuminate\Database\Seeder; class DrinksTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { // } } يمدد الصنف DrinksTableSeeder الصنف Seeder ويعرّف الدالة run التي تُنفّذ عند تشغيل أمر البذر في Artisan. عدل الملف ليصبح محتواه التالي: <?php use Illuminate\Database\Seeder; class DrinksTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { DB::table('drinks')->insert([ 'name' => 'Orange Juice', 'comments' => 'Rich in C vitamin', 'rating' => 9, 'juice_date' => '2015-12-20', ]); } أضفنا في الدالة run أمر إدراج في جدول البيانات drinks ومررنا مصفوفة توافق عناصرها حقول الجدول مع تحديد قيم عناصر المصفوفة. ننفذ الأمر أمر البذر لإضافة التسجيلة أعلاه إلى الجدول: php artisan db:seed --class=DrinksTableSeederنمرر لأمر البذر php artisan db::seed اسم الملف المراد تنفيذه. الآن عند التحقق نجد في جدول قاعدة البيانات التسجيلة التالية: قاعدة البيانات الخاصة بمشروع Larashopتعرفنا في الفقرات الماضية على أساسيات التهجير في Laravel. سنجعل هذه المعرفة موضع التطبيق لإنشاء قاعدة بيانات لمشروع Larashop. ستشنرك جميع الجداول في الحقول التالية التي أنشأناها لأغراض الفحص والتدقيق. التسلسلالحقلنوع البياناتالوصف1created_at Timestamp ختم زمني لتاريخ إدراج التسجيلة2updated_at Timestamp ختم زمني لتاريخ تحديث التسجيلة3created_at_ip (Varchar(45 عنوان IP المستخدم لإدراج التسجيلة4updated_at_ip (Varchar(45 عنوان IP المستخدم لتحديث التسجيلةجدول منشورات المدونةالتسلسلالحقلنوع البياناتالوصف1id INT مفتاح رئيس (AUTOINCREMENT) عدد طبيعي يزداد تلقائيا2url (Varchar(255 رابط الصفحة3title (Varchar(140 عنوان الصفحة4description (Varchar(170 وصف يظهر في محركات البحث5content Text محتوى الصفحة أو المنشور 6conblogtent (Tinyint(1 يحدد ما إذا كان المنشور صفحةجدول التصنيفاتالتسلسلالحقلنوع البياناتالوصف1id INT مفتاح رئيس (AUTOINCREMENT) عدد طبيعي يزداد تلقائيا2name (Varchar(255 اسم التصنيفجدول العلامات التجاريةالتسلسلالحقلنوع البياناتالوصف1id INT مفتاح رئيس (AUTOINCREMENT) عدد طبيعي يزداد تلقائيا2name (Varchar(255 اسم العلامة التجاريةجدول المنتجاتلكل منتج تصنيف وعلامة تجارية وحيدين. التسلسلالحقلنوع البياناتالوصف1id INT مفتاح رئيس (AUTOINCREMENT) عدد طبيعي يزداد تلقائيا2name (Varchar(255 اسم المنتج3title (Varchar(140 عنوان المنتج4description (Varchar(500 عنوان المنتج5price int ثمن المنتج6category_id int معرف تصنيف المنتج7brand_id int معرف العلامة التجارية للمنتجملفات التهجير لجداول قاعدة بيانات المشروعسننشئ في هذه الفقرة ملفات تهجير لجداول البيانات المذكورة أعلاه؛ سنضيف أيضا بعض البيانات الوهمية إلى الجداول باستخدام آلية البذر التي تعرفنا عليها سابقا. توليد ملفات التهجيرافتح سطر الأوامر ونفذ الأوامر التالية لتوليد ملفات الجداول: جدول منشورات المدونة: php artisan make:migration create_posts_table جدول تصنيفات المنتجات php artisan make:migration create_categories_tableجدول العلامات التجارية للمنتجات php artisan make:migration create_brands_tableجدول المنتجات php artisan make:migration create_products_tableتحرير ملفات التهجيرننتقل لتحرير كل ملف من ملفات التهجير. جدول منشورات المدونة <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreatePostsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('posts', function (Blueprint $table) { $table->increments('id'); $table->string('url', 255)->unique(); $table->string('title', 140); $table->string('description', 170); $table->text('content'); $table->boolean('blog'); $table->timestamps(); $table->string('created_at_ip'); $table->string('updated_at_ip'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('posts'); } } جدول التصنيفات <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateCategoriesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('categories', function (Blueprint $table) { $table->increments('id'); $table->string('name', 255)->unique(); $table->timestamps(); $table->string('created_at_ip'); $table->string('updated_at_ip'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('categories'); } } جدول العلامات التجارية <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateBrandsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('brands', function (Blueprint $table) { $table->increments('id'); $table->string('name', 255)->unique(); $table->timestamps(); $table->string('created_at_ip'); $table->string('updated_at_ip'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('brands'); } } جدول المنتجات <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateProductsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('products', function (Blueprint $table) { $table->increments('id'); $table->string('name', 255)->unique(); $table->string('title', 140); $table->string('description', 500); $table->integer('price'); $table->unsignedInteger('category_id'); $table->unsignedInteger('brand_id'); $table->timestamps(); $table->string('created_at_ip'); $table->string('updated_at_ip'); // مفتاح خارجي على جدول التصنيفات $table->foreign('category_id') ->references('id')->on('categories') ->onDelete('cascade'); // مفتاح خارجي على جدول العلامات التجارية $table->foreign('brand_id') ->references('id')->on('brands') ->onDelete('cascade'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('products'); } }بذر قاعدة بيانات المشروعندرج بيانات وهمية في جداول قاعدة البيانات قصدَ الاختبار. أنشئ ملفات البذر بتنفيذ الأوامر أدناه على التوالي: php artisan make:seeder CategoriesTableSeeder php artisan make:seeder BrandsTableSeeder php artisan make:seeder ProductsTableSeederيحوي جدول المنتجات مفتاحين خارجيين لجدولي التصنيف والعلامة التجارية. لذا يجب البدء بهما (لا يصح إدراج مفتاح خارجي لتسجيلة غير موجودة في الجدول الذي مثل المفتاح الخارجي مرجعا إليه). بذر جدول التصنيفات <?php use Illuminate\Database\Seeder; class CategoriesTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { DB::table('categories')->insert(['name' => 'MENS']); DB::table('categories')->insert(['name' => 'WOMENS']); DB::table('categories')->insert(['name' => 'KIDS']); DB::table('categories')->insert(['name' => 'FASHION']); DB::table('categories')->insert(['name' => 'CLOTHING']); } } بذر جدول العلامات التجارية<?php use Illuminate\Database\Seeder; class BrandsTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { DB::table('brands')->insert(['name' => 'ACNE']); DB::table('brands')->insert(['name' => 'RONHILL']); DB::table('brands')->insert(['name' => 'ALBIRO']); DB::table('brands')->insert(['name' => 'ODDMOLLY']); } } بذر جدول المنتجات<?php use Illuminate\Database\Seeder; class ProductsTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { DB::table('products')->insert(['name' => 'Mini skirt black edition', 'title' => 'Mini skirt black edition','description' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna','price' => 35,'category_id' => 1,'brand_id' => 1,]); DB::table('products')->insert(['name' => 'T-shirt blue edition', 'title' => 'T-shirt blue edition','description' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna','price' => 64,'category_id' => 2,'brand_id' => 3,]); DB::table('products')->insert(['name' => 'Sleeveless Colorblock Scuba', 'title' => 'Sleeveless Colorblock Scuba','description' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna','price' => 13,'category_id' => 3,'brand_id' => 2,]); } } ثم ننفذ أوامر البذر لكل جدول. خاتمةتعرفنا في هذا الدرس على تهجير قواعد البيانات وبذرها في Laravel. كما أننا حددنا هيكلة قاعدة بيانات المشروع الذي نعمل عليه. في الدروس القادمة سنتعرف على إطار عمل Eloquent الذي سنعتمد عليه للتخاطب مع قاعدة البيانات وعرض محتوياتها عند الاقتضاء. ترجمة -وبتصرّف- لمقال Laravel 5 Migrations لصاحبه Rodrick Kazembe.
  9. في الحالة العادية، سوف تقوم بكتابة تابع (store method) أولا، ومن ثم تترك عملية التحقق في النهاية حتى يعمل store بشكل جيد، لكن في حالتنا هذه سيكون الأمر معقدا قليلا بما أننا نتعامل مع ملفات منفصلة يجب حفظها، ففي حالة الصور، سوف نحتاج إلى التحقق أولا. صنف Requestسوف نبدأ بإنشاء صنف (request class) والذي سيقوم بالتعامل مع عملية التحقق من استمارة الإنشاء. سوف نبدأ بكتابة هذا الأمر على سطر الأوامر: php artisan make:request CreateImageRequestهذا الأمر سيقوم بإنشاء الملف ووضعه داخل مجلد app/Http/Requests. بعد ذلك، عدل الملف كالتالي: <?php namespace App\Http\Requests; use App\Http\Requests\Request; use App\Marketingimage; class CreateImageRequest extends Request { /** * 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 [ 'image_name' => 'alpha_num | required | unique:marketing_images', 'mobile_image_name' => 'alpha_num | required | unique:marketing_images', 'is_active' => 'boolean', 'is_featured' => 'boolean', 'image' => 'required | mimes:jpeg,jpg,bmp,png | max:1000', 'mobile_image' => 'required | mimes:jpeg,jpg,bmp,png | max:1000' ]; } }واحد من الأشياء التي أحبها في إطار Laravel هو كيفية تعامله مع عملية التحقق، فإذا كانت هذه المرة الأولى التي ستتعامل فيها مع عملية التحقق، سوف تجد أن هذه العملية بسيطة للغاية. لاحظ أننا قمنا بكتابة السطر التالي في تابع authorize: return true;هذا السطر سوف يسمح للطلب أن يمر، فإذا وضعنا شرطا عليه فسنستطيع التحكم فيه، فعلى سبيل المثال، يمكننا استخدامه في تسجيل الدخول للأعضاء فقط. بعد ذلك لدينا قواعد التابع، الذي سوف يتم فرضها على عملية التحقق في حقول الاستمارة، لن نتعمق أكثر هنا، فإذا أردت المزيد يمكنك الإطلاع على توثيق Laravel. للتذكير فإننا نفصل ما بين قواعد التّحقق بمحرف "|" ولما نضيف قاعدة "unique" فإننا نُرفقها باسم الجدول الذي يجب أن نبحث فيه (يعني الجدول الذي نرغب في أن يكون السّجل record الذي نقوم بحفظه وحيدًا "unique"). ومن الطبيعي أننا أننا قمنا بإضافة قيد على حجم الملفات. يمكنك إيجاد قائمة كاملة من قواعد التحقق في الوثائق. تابع Storeعلى أي حال، سوف ننتقل الآن لتابع store في MarketingImageController، عدل التابع كما يلي: public function store(CreateImageRequest $request) { //create new instance of model to save from form $marketingImage = new Marketingimage([ 'image_name' => $request->get('image_name'), 'image_extension' => $request->file('image')->getClientOriginalExtension(), 'mobile_image_name' => $request->get('mobile_image_name'), 'mobile_extension' => $request->file('mobile_image')->getClientOriginalExtension(), 'is_active' => $request->get('is_active'), 'is_featured' => $request->get('is_featured'), ]); //define the image paths $destinationFolder = '/imgs/marketing/'; $destinationThumbnail = '/imgs/marketing/thumbnails/'; $destinationMobile = '/imgs/marketing/mobile/'; //assign the image paths to new model, so we can save them to DB $marketingImage->image_path = $destinationFolder; $marketingImage->mobile_image_path = $destinationMobile; // format checkbox values and save model $this->formatCheckboxValue($marketingImage); $marketingImage->save(); //parts of the image we will need $file = Input::file('image'); $imageName = $marketingImage->image_name; $extension = $request->file('image')->getClientOriginalExtension(); //create instance of image from temp upload $image = Image::make($file->getRealPath()); //save image with thumbnail $image->save(public_path() . $destinationFolder . $imageName . '.' . $extension) ->resize(60, 60) // ->greyscale() ->save(public_path() . $destinationThumbnail . 'thumb-' . $imageName . '.' . $extension); // now for mobile $mobileFile = Input::file('mobile_image'); $mobileImageName = $marketingImage->mobile_image_name; $mobileExtension = $request->file('mobile_image')->getClientOriginalExtension(); //create instance of image from temp upload $mobileImage = Image::make($mobileFile->getRealPath()); $mobileImage->save(public_path() . $destinationMobile . $mobileImageName . '.' . $mobileExtension); // Process the uploaded image, add $model->attribute and folder name flash()->success('Marketing Image Created!'); return redirect()->route('marketingimage.show', [$marketingImage]); }حسنا، دعونا نبدأ بفهم هذه الشفرة الطويلة، سنبدأ مع توقيع الدالة: public function store(CreateImageRequest $request)هذا الجزء واضح، فلقد قمنا فقط بسحب نسخة (instance) من كائن request يحمل الاسم request$ وهذا سوف يساعدنا على إنشاء نسخة جديدة للنموذج: //create new instance of model to save from form $marketingImage = new Marketingimage([ 'image_name' => $request->get('image_name'), 'image_extension' => $request->file('image')->getClientOriginalExtension(), 'mobile_image_name' => $request->get('mobile_image_name'), 'mobile_extension' => $request->file('mobile_image')->getClientOriginalExtension(), 'is_active' => $request->get('is_active'), 'is_featured' => $request->get('is_featured'), ]);لاحظ أنني أقوم بالتعليق كثيرا على هذا التابع (method)، لأنه من السهل أن يربكك. على أي حال، قمنا بإنشاء مثيل جديد لـ Marketingimage ووضعنا خصائص النموذج باستخدام مثيل request$. أما البقية الشيفرة، فلقد قُمنا بسحب البيانات من الاستمارة إذا نجحت في عملية التحقق. ثم سوف نحتاج إلى تعريف مسارات الصور: //define the image paths $destinationFolder = '/imgs/marketing/'; $destinationThumbnail = '/imgs/marketing/thumbnails/'; $destinationMobile = '/imgs/marketing/mobile/';ملاحظة: حاولت أن أجعل هذه الأسماء بديهية قدر الإمكان. بعد ذلك، سوف نقوم بتعيينها إلى النموذج حتى نتمكن من حفظهم في قاعدة البيانات. //assign the image paths to new model, so we can save them to DB $marketingImage->image_path = $destinationFolder; $marketingImage->mobile_image_path = $destinationMobile;نستطيع فعل هذا بطريقة أخرى، فيمكننا أن نقوم بتقديم معلومات المسار في الاستمارة أو يمكننا تخطي هذا كليا، لكن وجدت أن إبقاء المسار في قاعدة البيانات يجعل العمل مع الصور أسهل عندما نحتاج إلى استخدامها في العروض (views)، وهذا هو سبب استخدامنا هذه الطريقة. ثم سنقوم بتهيئة (format) قيم خانة اختيار ومن ثم نقوم بحفظها: // format checkbox values and save model $this->formatCheckboxValue($marketingImage); $marketingImage->save(); يمكنك أن ترى أنني أقوم بتسليم مثيل النموذج marketingImage$ إلى تابع formatCheckboxValue، وهو تابع قمت بعمله للتأكد من أن خانة الاختيار يتم التعامل معها بشكل جيد: public function formatCheckboxValue($marketingImage) { $marketingImage->is_active = ($marketingImage->is_active == null) ? 0 : 1; $marketingImage->is_featured = ($marketingImage->is_featured == null) ? 0 : 1; }بسبب نوع البيانات في قاعدة البيانات، يمكننا توفير فقط رقمين 0 و 1، لذلك نحتاج إلى التأكد من أننا نقوم بالتحويل بشكل صحيح من خانة الاختيار (checkbox) في الاستمارة (form). لقد قمنا بتسليمها إلى مثيل النموذج ومن ثم سيقوم بوضع الخصائص وفقا لذلك. بعد ذلك نعود إلى تابع store، ونقوم ببساطة بالحفظ: $marketingImage->save();وهذا سوف يهتم بسجلات قاعدة البيانات، ومع ذلك، لانزال بحاجة إلى التعامل مع الملف. في البداية سوف نعمل على بعض أجزاء الصورة التي سنحتاجها: //parts of the image we will need $file = Input::file('image'); $imageName = $marketingImage->image_name; $extension = $request->file('image')->getClientOriginalExtension();بدلا من ذلك، يمكنك جعل بعض هذه الشفرات في سطر واحد (inline) لكنك ستحصل على سطور طويلة جدا بالإضافة إلى أن إبقائها هكذا أسهل للتتبع والفهم. الآن سوف نحتاج إلى استخدام مكتبة الصور (Image library) لمساعدتنا على الخروج من هنا، سنقوم بإنشاء مثيل لهذه الصورة من الصور المرفوعة: //create instance of image from temp upload $image = Image::make($file->getRealPath());بعد ذلك، سنقوم بحفظها وإنشاء صورة مصغرة والتي سنقوم بحفظها عن طريق سَلسَلة التوابع (chaining the methods): //save image with thumbnail $image->save(public_path() . $destinationFolder . $imageName . '.' . $extension) ->resize(60, 60) // ->greyscale() ->save(public_path() . $destinationThumbnail . 'thumb-' . $imageName . '.' . $extension);سوف نقوم بتقسيم هذه الشيفرة إلى أجزاء حتى نفهمها بشكل أفضل، أول جزء يقوم بحفظ الصور الأولية: $image->save(public_path() . $destinationFolder . $imageName . '.' . $extension)استخدمنا ()public_path للوصول إلى المكان الذي يمكننا تعريف فيه مجلد الهدف (مجلد الصور) والذي هو imgs/marekting/. بعد ذلك قمنا بسَلسَلة أجزاء الصورة (مسار ملف الصورة) التي نحتاجها وهذا سوف يعطينا كل شيء نحتاجه وسيسهل علينا عملية متابعة الشيفرة البرمجية. بما أننا نحتاج أيضا إلى إنشاء صورة مصغرة، قمنا بسَلسَلة ذلك التابع: ->resize(60, 60)وهذا السطر سوف ينشئ لنا نسخة بحجم 60 × 60 من الصورة، وإذا أردت تغيير حجم النسخة يمكنك فعل هذا بسهولة بتغيير الأرقام، ويمكنك أيضا إنشاء حقل في الاستمارة للمستخدمين لتحديد ارتفاع و عرض الصور المصغر. (لن نقوم بهذا في هذا الدرس.) قمتُ بإرفاق (على شكل تعليق) تابع متسَلسَل لجعل الصورة المصغرة ذات تدرج رمادي، فإذا أردت صور مصغرة بيضاء وسوداء اجعل السطر شيفرة برمجية (عن طريق إزالة //). والآن سنقوم بحفظ الصورة المصغرة: ->save(public_path() . $destinationThumbnail . 'thumb-' . $imageName . '.' . $extension);وسنقوم بنفس الشيء لصور الهاتف: // create instance of image from temp upload $mobileImage = Image::make($mobileFile->getRealPath()); $mobileImage->save(public_path() . $destinationMobile . $mobileImageName . '.' . $mobileExtension);يما أنها مثل الصور الأولية لكن بدون صورة مصغرة، سوف نتركها هكذا. حسنا، بعد ذلك لدينا رسالة الفلاش (flash message): flash()->success('Marketing Image Created!');هذه الشيفرة لن تعمل إلا إذا قمت بتثبيت حزمة الفلاش لجفري ويِ (Jefferey Wey) وقمت باستدعائها في عرض (view) الصفحة الرئيسية، وإذا لم تقم بتثبيت هذه الحزمة فلا تكتب هذه الشيفرة. في النهاية، بعد حفظ كُل من النموذج وملفات الصور، سوف نقوم بإعادة التوجيه نحو صفحة العرض: return redirect()->route('marketingimage.show', [$marketingImage]);الآن يمكنك تجربة رفع وحفظ الصور وعمل صورة مصغرة وصورة للهاتف عن طريق زيارة الاستمارة في العنوان التالي: yourdomain.com/marketingimage/createيمكنك التأكد من إنشاء الصور من خلال النظر إلى المجلدات حيث يُفترض أن تكون الصور. سوف ترى أن تابع store يقوم بالكثير من الأشياء، لكن ينقصه آلية للتحقق من الأخطاء، يمكنك فعل هذا لجعل التطبيق أكثر قوة على الرغم من أنني أعتقد أن أمر ليس ضروري. بما أن Laravel يقوم بوظيفة جيدة عن طريق فصل استمارة التحقق من تابع store، لن يتوقف التابع إذا فشلت عملية التحقق. حسنا ماذا يمكن أن يفشل أيضا ؟ حسنا ربما تفشل عملية حفظ الملف وهذا يمكن أن يكون بسبب امتلاء النظام، أو بسبب مشاكل في الصلاحيات أو خطأ في كتابة المسارات وأسماء المجلدات. هذه الأخطاء صعبة الاكتشاف والتصحيح بسبب أنه ربما قد لا تحصل على رسائل الخطأ المناسبة، وعلى أية حال، هذه هي أشهر الأخطاء إذا أردت اكتشافها وتصحيحها. يمكنك أن ترى أنه على الرغم من أنه لا شيء صعب في إدارة الصورة إلا أن الصعوبة موجودة بشكل ما. الخطوة المنطقية التالية هي إنشاء تابع show في المتحكم وإنشاء العرض الخاص به. تابع showحسنا، هذه هي شيفرة تابع العرض: public function show($id) { $marketingImage = Marketingimage::findOrFail($id); return view('marketingimage.show', compact('marketingImage')); }هذه الشيفرة واضحة للغاية، يقوم Laravel باسترجاع مثيل النموذج ثم يقوم بإرجاعه إلى العرض view، لاحظ استخدام findOrFail والتي تقوم بإرجاع ModelNotFoundException، والتي يمكنك التعامل معها من خلال ملف Handler.php في app/Exceptions. عرض showحسنا، بعدما انتهينا من التابع ننتقل إلى العرض view: @extends('layouts.master') @section('content') {!! Breadcrumb::withLinks(['Home' => '/', 'marketing images' => '/marketingimage', "show $marketingImage->image_name.$marketingImage->image_extension" ]) !!} <div> {{ $marketingImage->image_name }} : <br> <img src="/imgs/marketing/{{ $marketingImage->image_name . '.' . $marketingImage->image_extension . '?'. 'time='. time() }}"> </div> <div> {{ $marketingImage->image_name }} - thumbnail : <br> <img src="/imgs/marketing/thumbnails/{{ 'thumb-' . $marketingImage->image_name . '.' . $marketingImage->image_extension . '?'. 'time='. time() }}"> </div> <div> {{ $marketingImage->mobile_image_name }} - mobile : <br> <img src="/imgs/marketing/mobile/{{ $marketingImage->mobile_image_name . '.' . $marketingImage->mobile_extension . '?'. 'time='. time() }}"> </div> @endsectionملاحظة: يمكنك إزالة مساعدات Breadcrumb إذا لم تكن تستخدم تلك الحزمة. لم نجعل الواجهة الأمامية فاخرة هنا، قمنا فقط بعمل صفحة بسيطة لإظهار الصور. وبما أننا أرسلنا مثيل marketingImage$ إلى المتحكم، فإننا استخدمنا تركيبة blade لاستدعاء اسم الصورة: {{ $marketingImage->image_name }}ثم نقوم بإستدعاء الصور الأولية: <img src="/imgs/marketing/{{ $marketingImage->image_name . '.' . $marketingImage->image_extension . '?'. 'time='. time() }}">سترى أننا استخدمنا تركيبة blade طباعة اسم الصورة وامتدادها والتي هي مسجلة في قاعد البيانات، وبإبقاء الامتداد في قاعدة البيانات يمكننا استخدام امتدادات مختلفة بدلا من فرض استخدام jpg. على سبيل المثال. سوف تلاحظ أيضا أننا أضفنا: '?'. 'time='. time() للحصول على متغير، وهذا الأمر سيمنع عملية تخزين المؤقت للصور نظرا لأنه تم إلحاق الوقت في نهاية الرابط. إن التخزين المؤقت للصور يمكن أن يكون مشكلة بالنسبة لإدارة الصور عندما تقوم برفع الصور. وبالطبع هذا الأمر اختياري ويمكنك تجاوزه. بقية الشيفرة البرمجية تقريبا نفسها مع بعض التغييرات للصور المصغرة والصور الهواتف. لن تكون الصفحة جميلة جدا، لكنها تقوم بالمهمة. والآن إذا كان لديك صورة قمت برفعها لحفظها في قاعدة البيانات، يمكنك مشاهدتها عن طريق الذهاب إلى: yourproject.com/marketingimage/1يمكنك تغيير الرقم في النهاية لأن هذا الرقم هو رقم الصورة في سجل البيانات. حسنا، بعد ذلك، قبل أن نعمل على edit و update، لنقم ببناء تابع index في المتحكم ثم عرض (index view). تابع indexفي MarketingImageController، عدل تابع index كما يلي: public function index() { $images = Marketingimage::all(); return view('marketingimage.index', compact('images')); }يمكنك أن ترى أن الشيفرة سهلة للغاية، فلقد قمنا فقط باسترجاع جميع السجلات إلى كائن images$، والتي يتم تمريرها إلى العرض view عن طريق تابع compact. عرض Indexبعد ذلك، سنقوم بتعديل views/marketingimages/index.blade.php كما يلي: @extends('layouts.master') @section('content') {!! Breadcrumb::withLinks(['Home' => '/', 'marketing images' => '/marketingimage']) !!} <br> <div> <div class="panel panel-default"> <!-- Default panel contents --> <div class="panel-heading">List of Marketing Images </div> <div class="panel-body"> <a href="/marketingimage/create"> <button type="button" class="btn btn-lg btn-success">Create New </button> </a> </div> <!-- Table --> <table class="table"> <tr> <th>Id </th> <th>Name </th> <th>Thumbnail </th> <th>Edit </th> <th>Delete </th> </tr> @foreach($images as $image ) <tr> <td>{{ $image->id }} </td> <td>{{ $image->image_name }} </td> <td> <a href="/marketingimage/{{ $image->id }}"> <img src="/imgs/marketing/thumbnails/{{ 'thumb-'. $image->image_name . '.' . $image->image_extension . '?'. 'time='. time() }}"> </a> </td> <td><a href="/marketingimage/{{ $image->id }}/edit"> <span class="glyphicon glyphicon-edit" aria-hidden="true"> </span> </a> </td> <td>{!! Form::model($image, ['route' => ['marketingimage.destroy', $image->id], 'method' => 'DELETE']) !!} <div class="form-group"> {!! Form::submit('Delete', array('class'=>'btn btn-danger', 'Onclick' => 'return ConfirmDelete();')) !!} </div> {!! Form::close() !!} </td> </tr> @endforeach </table> </div> </div> @endsection @section('scripts') <script> function ConfirmDelete() { var x = confirm("Are you sure you want to delete?"); if (x) return true; else return false; } </script> @endsectionلقد بدأنا بتوسيع layouts.master ومن ثم قمنا بفتح content كما يلي: @section('content')ومن ثم استخدمنا Breadcrumb. (مرة أخرى، إذا كنت لا تستخدم الحزمة فاحذف هذا السطر.) بعد ذلك قمنا باستخدام شيفرات Bootstrap أساسية، والتي حصلنا عليها من الموقع الرسمي. وفي النهاية سنجد جدول داخل مُكوّن panel لـ bootstrap بالإضافة إلى زر لإنشاء صورة جديدة، وأزرار أخرى للتعديل والحذف لكل صورة، وستظهر الصور المصغرة لكل صورة في الجدول. سوف ترى في رأسية مُكوّن panel كيف قمنا بالتعامل مع زر create: <a href="/marketingimage/create"> <button type="button" class="btn btn-lg btn-success"> Create New </button> </a>كل شيء واضح، فالجدول ليس معقدا، لكنه تطلب حلقة foreach لطباعة جميع الصفوف (rows): <!-- Table --> <table class="table"> <tr> <th>Id </th> <th>Name </th> <th>Thumbnail </th> <th>Edit </th> <th>Delete </th> </tr> @foreach($images as $image ) <tr> <td>{{ $image->id }} </td> <td>{{ $image->image_name }} </td> <td> <a href="/marketingimage/{{ $image->id }}"> <img src="/imgs/marketing/thumbnails/{{ 'thumb-'. $image->image_name . '.' . $image->image_extension . '?'. 'time='. time() }}"> </a> </td> <td> <a href="/marketingimage/{{ $image->id }}/edit"> <span class="glyphicon glyphicon-edit" aria-hidden="true"> </span> </a> </td> <td>{!! Form::model($image, ['route' => ['marketingimage.destroy', $image->id], 'method' => 'DELETE' ]) !!} <div class="form-group"> {!! Form::submit('Delete', array('class'=>'btn btn-danger', 'Onclick' => 'return ConfirmDelete();')) !!} </div> {!! Form::close() !!} </td> </tr> @endforeach </table>لا توجد أية صعوبة في الشيفرة، يمكنك أن ترى أنني أضفت مساعدات النموذج form helper حول رابط الحذف delete، وهذا لأسباب أمنية، يجب علينا الحذف باستخدام POST بدل السماح بأن تكون مفتوحة بشكل واسع من خلال استعمال GET. سوف تلاحظ أيضا أننا قمنا باستخدام التالي: 'Onclick' => 'return ConfirmDelete();'والتي استخدمناها مع الجافاسكربت لفتح صندوق التأكيد confirm box، حتى لا يقوم المستخدمون بحذف شيء عن طريق الخطأ. ثم في ('section('scripts@ أضفنا شيفرات جافاسكربت التالية، وكملاحظة سريعة، افترضنا أنه لديك ('yeld('scripts@ في صفحتك الرئيسية (master page)، وإذا لم يكن لديك هذا السطر، يمكنك ببساطة إرفاق الجافاسكربت قبل endsection@ التابعة لـ ('section('content@. هذه هي شيفرة الجافاسكربت: <script> function ConfirmDelete() { var x = confirm("Are you sure you want to delete?"); if (x) return true; else return false; } </script>شيفرة بسيطة للغاية. والآن، يجب أن تحصل على صفحة index تعمل بدون مشاكل، قم بتجربة ذلك عن طريق الذهاب بمتصفحك إلى: yourproject.com/marketingimageنُكمل في الجزء الثالث من الدرس إن شاء الله. ترجمة -وبتصرّف- للمقال Basic Image Management Part 2 لصاحبه Bill Keck. حقوق الصورة البارزة: Designed by Freepik.
×
×
  • أضف...