المحتوى عن 'واجهة برمجية'.



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

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

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

نوع المُحتوى


التصنيفات

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

التصنيفات

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

التصنيفات

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

التصنيفات

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

التصنيفات

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

التصنيفات

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

التصنيفات

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

التصنيفات

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

أسئلة وأجوبة

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

التصنيفات

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

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

  1. إن كنت مطور ويب أو أحد المهتمين بتطوير الأنظمة المعلوماتية المختلفة في بيئة الويب، فإنك تعلم حجم التنوع الكبير للغات البرمجة المستخدمة في تطوير مواقع الويب وخدماته، ولربما كنت أحد مطوري هذه الخدمات وترغب بأن تكون خدماتك سريعة الانتشار وسهلة الاستخدام من قبل التطبيقات المختلفة ، وكما تعلم فإن كثرة لغات البرمجة المستخدمة في تطوير خدمات الويب تجعل من الصعب التواصل والتكامل بين هذه التطبيقات. إن المصطلح REST وهو اختصار لـ Representational state transfer يعبر عن المعمارية المستخدمة في تطوير خدمات الويب، التي تهدف إلى وضع معايير تضبط إدارة موارد الأنظمة resources وتحدد كيفية عنونتها ونقلها عبر بروتوكل HTTP إلى طيف واسع من التطبيقات المختلفة بغض النظر عن لغات البرمجة التي طورت بها تلك التطبيقات، وتعد معمارية REST أكثر معماريات تصميم الويب هيمنة خلال السنوات الماضية وذلك لسهولة استخدامها والتعامل معها. بعد التعرف على RESTful ستكون قادر على الانطلاق لتصميم الخدمة الخاصة بك دون القلق بشأن من سيستخدم الخدمة الخاصة بك.
  2. Lumen هو إطار عمل مصغّر Micro-framework مبني باستخدام إطار العمل Laravel، وهما من صنع Taylor Otwell. صُمّم Lumen لتطوير الخدمات المصغّرة مثل التطبيقات الصغيرة أو خدمات الويب، والهدف من تطويره هو الحصول على أقصى قدر من السرعة، فقد تم استبدال مكوّن التوجيه Symfony في Laravel بـ FastRoute في Lument لتحسين الأداء وزيادة السرعة. في هذا الدرس سننشئ واجهة برمجية بنمط RESTful، وستعمل هذه الواجهة البرمجية على تخزين وعرض المعلومات الخاصّة بالكتب. تثبيت Lumen سنستخدم Composer لتثبيت lumen، لذا سنتحقّق من وجود هذه المكتبة في النظام، وذلك بكتابة الأمر التالي في الطرفية أو في سطر الأوامر: composer إن ظهرت أوامر Composer فهذا يعني أنّه مثبت في الجهاز، أمّا في حالة عدم تثبيت Composer يمكنك الاطلاع على طريقة التثبيت في هذا المقال. بعد تثبيت composer توجّه إلى المجلّد الجذر في الخادوم: cd /var/www/html لمستخدمي نظام ويندوز سنفترض أن المستخدم يمتلك نسخة من خادوم Wamp في الجهاز، لذا يمكن التوجّه إلى المجلّد الجذر في الخادوم بواسطة الأمر التالي: cd wamp\www والآن سنخبر composer بأنّ ينشئ مشروع Lumen باسم “lumen_rest_ce” باستخدام حزمة “laravel/lumen”: composer create-project laravel/lumen lumen_rest_ce سينشئ هذا الأمر مجلّدًا باسم “lumen_rest_ce” ويثبت جميع ملفّات إطار العمل Lumen إضافة إلى جميع الاعتماديات المتعلّقة به. أداة Artisan موجودة في Lumen كما هو الحال في Laravel، ولكنّها تدعم عددًا أقلّ من الأوامر، ويمكنك الاطلاع على قائمة الأوامر بكتابة الأمر التالي في سطر الأوامر: php artisan لاحظ أنّ الأمر serve والمسؤول عن تشغيل التطبيق على الخادوم غير متوفّر في Lumen لذا سنستعين بخادوم التطوير الخاصّ بلغة PHP لتشغيل Lumen وكما يلي: php -S localhost:8000 -t public افتح المتصفّح الآن وتوجّه إلى العنوان localhost:8000. إن ظهر لك رقم الإصدار الخاص بـ Lumen فهذا يعني أنّ عملية التثبيت قد تمّت بنجاح. الإعدادات أنشئ قاعدة بيانات mysql باستخدام phpmyadmin أو أي عميل Mysql آخر، ثمّ عدّل ملف إعدادات Lumen في مجلد المشروع والذي يحمل الاسم “lumen_rest_ce/.env” بالصورة التالية: DB_CONNECTION=mysql DB_HOST=localhost DB_DATABASE=lumen_rest_ce DB_USERNAME=root DB_PASSWORD=your_password افتح الملف lumen_rest_ce/bootstrap/app.php وأزل علامات التعليق من السطرين التاليين: $app->withFacades(); $app->withEloquent(); إزالة التعليق عن هذين السطرين يسمح لنا باستخدام فئة Facade و Eloquent ORM في مشروعنا. التهجير Migration سنكتب الآن مخطّط قاعدة البيانات ونهيّئه لعملية التهجير، حيث سننشئ جدولًا باسم book يتضمّن ستة أعمدة. المعرّف id (قيمته رقمية int وتتزايد تلقائيًا)، العنوان title (من نوع varchar) الكاتب author (من نوع varchar)، الرقم المعياري الدولي للكتاب isbn (من نوع varchar) وحقلي تاريخ الإنشاء وتاريخ التعديل. سنستخدم عملية التهجير والتي هي بمثابة نظام إدارة نسخ خاصّ بقواعد البيانات. اكتب الأمر التالي في سطر الأوامر: php artisan make:migration create_books_table --create=books سينشئ هذا الأمر ملف تهجير في المجلد dbaatase/migration. يتضمّن هذا الملف صنفًا يحمل الاسم CreateBooksTable والذي يضمّ بدوره تابعين الأول هو up حيث سنكتب مخطّط البيانات، أما الآخر فهو down وهو التابع المسؤول عن حذف الجدول. عدّل الملف ليصبح بالصورة التالية: use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateBooksTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('books', function(Blueprint $table) { $table->increments('id'); $table->string('title'); $table->string('author'); $table->string('isbn'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('books'); } } لإنشاء الجدول في قاعدة البيانات سنحتاج إلى تهجير أو تنفيذ ملف التهجير الذي أنشأناه قبل قليل وذلك بواسطة الأمر التالي: php artisan migrate النموذج Model أنشئ الآن نموذج Book ضمن الملف app/Book.php وأضف إليه الشيفرة التالية: <?php namespace App; use Illuminate\Database\Eloquent\Model; class Book extends Model { protected $fillable = ['title', 'author', 'isbn']; } ?> أنشئ كذلك ملفّ المتحكّم BookController.php في المجلد app/Http/Controllers وأضف إليه الشيفرة التالية: <?php namespace App\Http\Controllers; use App\Book; use App\Http\Controllers\Controller; use Illuminate\Http\Request; class BookController extends Controller{ ..... ..... } ?> التوجيه Routing افتح الملف web.php في المجلد routes وستجد أنّه يتضمن مسارًا معرّفًا مسبقًا: $app->get('/', function() use ($app) { لغرض كتابة واجهة برمجية بنمط RESTful سنحتاج إلى كتابة المزيد من المسارات وتوابع المتحكّمات المرتبطة بها، وحسب الجدول التالي: التابع عنوان Url Controller@method GET /api/v1/book BookController@index جميع الكتب GET {api/v1/book/{id BookController@getbook إحضار الكتاب حسب المعرّف id POST /api/v1/book BookController@createBook إنشاء سجل جديد في الجدول PUT {api/v1/book/{id BookController@updateBook تحديث الكتاب حسب المعرّف id DELETE {api/v1/book/{id BookController@deleteBook حذف الكتاب حسب المعرّف id لاحظ أنّنا أضفنا v1 إلى جميع المسارات ونقصد به الإصدار الأول، وهذا من الممارسات التي ينصح باتباعها عند إنشاء خدمات الويب. حسب الجدول السابق فإن ملف web.php سيبدو كالتالي: $app->get('/', function() use ($app) { return 'Lumen RESTful API By Hsoub Academy (<a class="vglnk" href="https://academy.hsoub.com" rel="nofollow"><span>https</span><span>://</span><span>academy.hsoub</span><span>.</span><span>com</span></a>)'; }); $app->get('api/v1/book','App\Http\Controllers\BookController@index'); $app->get('api/v1/book/{id}','App\Http\Controllers\BookController@getbook'); $app->post('api/v1/book','App\Http\Controllers\BookController@createBook'); $app->put('api/v1/book/{id}','App\Http\Controllers\BookController@updateBook'); $app->delete('api/v1/book/{id}','App\Http\Controllers\BookController@deleteBook'); يمكننا كذلك تجميع المسارات حسب لاحقة معيّنة أو حسب نطاقات الأسماء، وبهذا لن نكون بحاجة إلى إضافة api/vi ولا إلى كتابة App\Http\Controllers في جميع المسارات. عدّل الشيفرة السابقة لتصبح بالصورة التالية: $app->get('/', function() use ($app) { return 'Lumen RESTful API By Hsoub Academy (<a class="vglnk" href="https://academy.hsoub.com" rel="nofollow"><span>https</span><span>://</span><span>academy.hsoub</span><span>.</span><span>com</span></a>)'; }); $app->group(['prefix' => 'api/v1','namespace' => 'App\Http\Controllers'], function($app) { $app->get('book','BookController@index'); $app->get('book/{id}','BookController@getbook'); $app->post('book','BookController@createBook'); $app->put('book/{id}','BookController@updateBook'); $app->delete('book/{id}','BookController@deleteBook'); }); المتحكّم والآن عدّل الملف BookController.php وأضف إليه التوابع التي عرّفناها في ملف web.php السابق: <?php namespace App\Http\Controllers; use App\Book; use App\Http\Controllers\Controller; use Illuminate\Http\Request; class BookController extends Controller{ public function index(){ $Books = Book::all(); return response()->json($Books); } public function getBook($id){ $Book = Book::find($id); return response()->json($Book); } public function createBook(Request $request){ $Book = Book::create($request->all()); return response()->json($Book); } public function deleteBook($id){ $Book = Book::find($id); $Book->delete(); return response()->json('deleted'); } public function updateBook(Request $request,$id){ $Book = Book::find($id); $Book->title = $request->input('title'); $Book->author = $request->input('author'); $Book->isbn = $request->input('isbn'); $Book->save(); return response()->json($Book); } } اختبار الواجهة البرمجية أصبحت الواجهة البرمجية جاهزة الآن للاختبار، وسنستخدم الأداة CURL لإجراء الاختبار: curl -I <a class="vglnk" href="http://localhost:8000/api/v1/book" rel="nofollow"><span>http</span><span>://</span><span>localhost</span><span>:</span><span>8000</span><span>/</span><span>api</span><span>/</span><span>v1</span><span>/</span><span>book</span></a> curl -v -H "Accept:application/json" <a class="vglnk" href="http://localhost:8000/api/v1/book/2" rel="nofollow"><span>http</span><span>://</span><span>localhost</span><span>:</span><span>8000</span><span>/</span><span>api</span><span>/</span><span>v1</span><span>/</span><span>book</span><span>/</span><span>2</span></a> curl -i -X POST -H "Content-Type:application/json" <a class="vglnk" href="http://localhost:8000/api/v1/book" rel="nofollow"><span>http</span><span>://</span><span>localhost</span><span>:</span><span>8000</span><span>/</span><span>api</span><span>/</span><span>v1</span><span>/</span><span>book</span></a> -d '{"title":"Test Title","author":"test author","isbn":"12345"}' curl -v -H "Content-Type:application/json" -X PUT <a class="vglnk" href="http://localhost:8000/api/v1/book" rel="nofollow"><span>http</span><span>://</span><span>localhost</span><span>:</span><span>8000</span><span>/</span><span>api</span><span>/</span><span>v1</span><span>/</span><span>book</span></a> -d '{"title":"Test updated title","author":"test upadted author","isbn":"1234567"}' curl -i -X DELETE <a class="vglnk" href="http://localhost:8000/api/v1/book/2" rel="nofollow"><span>http</span><span>://</span><span>localhost</span><span>:</span><span>8000</span><span>/</span><span>api</span><span>/</span><span>v1</span><span>/</span><span>book</span><span>/</span><span>2</span></a> تتيح الإضافة Postman إجراء الاختبارات على الواجهات البرمجية بنمط RESTful وبسهولة. بعد تثبيت هذه الإضافة توجّه في متصفح Chrome إلى العنوان chrome://apps/ لعرض الإضافات المثبّتة وتشغيل POSTMAN. ختامًا ها قد أصبحت الواجهة البرمجية البسيطة التي أنشأناها جاهزة، ولكن لا زال ينقصها الكثير من الخصائص كالاستثياق والتحقّق من البيانات ومعالجة الأخطاء وغير ذلك الكثير. ترجمة - وبتصرّف - للمقال RESTful API in Lumen, A Laravel Micro Framework لصاحبه Arkaprava Majumder.
  3. اكتشفت مؤخرًا المتعة الكبيرة في استخدام مكتبة [Fractal المقدّمة من PHP League] لإنشاء استجابات للواجهات البرمجية التي تعطي مخرجات من نوع JSON وذلك عند العمل على نماذج Eloquent في إطاري العمل Laravel و Lumen للحصول على المخرجات التي أرغب بها. هذه الحزمة مشابهة إلى حدٍّ كبير لمكتبة ActiveModel Serializer في إطار العمل Rails، إذ إنّها تتيح لك التحكّم الدقيق بالمخرجات التي ترغب في وصولها إلى المستخدم، إضافة إلى أنّها تفصل الشيفرة المسؤولة عن إنشاء كائن JSON عن نموذج Eloquent وهذا أمر في غاية الأهمية. والآن بعد أن أتيح لي تطوير عدد من الواجهات البرمجية لفترة زمنية لا بأس بها، خطر لي أن أتحدّث عن الطرق التي اتبعتها في ربط Fractal مع تطبيقات Laravel و Lumen (تختلف طريقة الربط في إطار Lumen لأنّه لا يدعم ماكروات Response). المُسَلسِلات المخصّصة Costum Serializers بادئ ذي بدء، تدعم Fractal عددًا من المُسَلسِلات Serializers لتكوين بنية خاصة بالاستجابة، وتستخدم بصورة افتراضية المسَلسِل الذي يدعى بـ DataArraySerializer والذي يضيف مفتاح جذر root key يحمل الاسم data إلى الاستجابة، لذا إن كنت لا تمانع من استخدام هذا المُسَلسِل فيمكنك تجاوز هذه الخطوة. أما لو كنت ترغب في استخدام مُسَلسِل آخر فعليك تسجيل الصنف Manager مع حاوية IoC في مزوّد الخدمة AppServiceProvider أو في مزوّد خدمة آخر إن كنت ترى أنّه يناسبك أكثر، ولكن عليك الانتباه إلى أنّ دعم JSON-API غير مكتمل حتى الآن (المقالة الأصلية نشرت سنة 2015. (المترجم)). public function register() { $this->app->bind('League\Fractal\Manager', function($app) { $manager = new \League\Fractal\Manager; // Use the serializer of your choice. $manager->setSerializer(new \App\Http\Serializers\RootSerializer); return $manager; }); } إنشاء المحوّلات Transformers بعد ذلك سنحتاج إلى إنشاء بعض المحوّلات - محوّل لكل نوع من أنواع نماذج Eloquent التي ترغب في تخريجها بواسطة الواجهة البرمجية - وفي مثالنا هذا سأستخدم مدوّنة حيث يضمّ النموذج AppUser عددًا من نماذج AppPost وسنعرض المستخدم مع المقالات الخاصّة به. أنشأت مجلّدً للتحويلات داخل مجلّد Http: app/Http/Transoformers، والآن يمكنني إنشاء محوّلين، الأول لنموذج User والثاني لنموذج Post. محوّل المستخدمين User سيكون سهلًا، إذ أنّه سيُرجع الحقول المطلوبة من قبل واجهتي البرمجية. في هذا المثال، يمتلك النموذج User خاصّية is_admin وهي عبارة عن قيمة منطقية boolean. ويمكنني التعبير عن ذلك في المحوّل بواسطة العبارة (bool) $user->is_admin ولكن اعتبارًا من الإصدار 5.0 وما بعده من Laravel أصبح بالإمكان استخدام خاصّية $casts في النموذج وسيكون Eloquent قادرًا بعدها على معالجة عملية الوصف بالنيابة عنك. يستحسن معالجة مثل هذه الأمور ضمن النموذج لأنّها ستكون متاحة في التطبيق برمّته. <?php namespace App\Http\Transformers; use App\User; use League\Fractal\TransformerAbstract; class UserTransformer extends TransformerAbstract { /** * Turn this item object into a generic array. * * @param \App\User $user * @return array */ public function transform(User $user) { return [ 'id' => $user->id, 'first_name' => $user->first_name, 'last_name' => $user->last_name, 'email' => $user->email, 'is_admin' => $user->is_admin, 'created_at' => $post->created_at->toDateTimeString(), 'updated_at' => $post->updated_at->toDateTimeString() ]; } } بما أنّ خصائص التاريخ في نماذج Eloquent هي نسخ من مكتبة Carbon يمكن إذًا استخدام الدوال المساعدة التي تقدّمها هذه المكتبة لإرجاع التاريخ بالصيغة التي نرغب بها. وفي مثالنا سنستخدم الدالة toDateTimeString() وسيكون التاريخ بالصيغة التالية: Y-m-d H:i:s (السنة - الشهر - اليوم الساعة:الدقائق:الثواني). والآن سنحتاج إلى محوّل لأجل نموذج Post، وسيكون هذا المحوّل مختلفًا عن السابق لأنّنا نرغب في تضمين النموذج User المرتبط بنموذج Post مع هذه الاستجابة. <?php namespace App\Http\Transforers; use App\Post; use League\Fractal\TransformerAbstract; class PostTransformer extends TransformerAbstract { /** * List of resources possible to include * * @var array */ protected $availableIncludes = ['user']; /** * List of resources to automatically include. * * @var array */ protected $defaultIncludes = ['user']; /** * Turn this item object into a generic array. * * @param \App\Post $post * @return array */ public function transform(Post $post) { return [ 'id' => $post->id, 'title' => $post->title, 'content' => $post->content, 'created_at' => $post->created_at->toDateTimeString(), 'updated_at' => $post->updated_at->toDateTimeString(), 'published_at' => $post->published_at->toDateTimeString() ]; } /** * Include user. * * @param \App\Post $post * @return League\Fractal\ItemResource */ public function includeLevels(Post $post) { return $this->item($post->user, new UserTransformer); } } لاحظ أنّه بالإمكان إرجاع $this->collection داخل المحوّل إن كنت ترغب في ربط مجموعة بدل من عنصر واحد. إنشاء الاستجابات في Laravel عادة ما أنشئ مزوّد خدمة Fractal FractalServiceProvider والذي يضمّ التابع register() الذي قمت بوصفه سابقًا، ثم أسجّل بعض الماكروات في التابع boot() كما تلاحظ هنا. سيؤدي ذلك إلى إضافة تابعين إضافيين إلى معمل (factory) Response في Laravel وسيسهّل إرجاع الاستجابات على هيئة عناصر أو مجموعات. لاحظ أنّي حدّدت نوع (type hint) المحوّل ليكون نسخة من الصنف TransformerAbstract وذلك لأنّي أنشئ دائمًا المحوّلات من الاستجابات بدلًا من صيغة الدالة المغلقة closure لأنّي أرى بأنّ هذه الطريقة ستحافظ على ترتيب الشيفرات التي أكتبها. لكن إن كنت تفضل استخدام الدوال المغلقة بدلًا من المحوّلات فيمكنك بكل ساطة أن لا تحدد نوع المحوّل ضمن المعاملات. public function boot() { $fractal = $this->app->make('League\Fractal\Manager'); response()->macro('item', function ($item, \League\Fractal\TransformerAbstract $transformer, $status = 200, array $headers = []) use ($fractal) { $resource = new \League\Fractal\Resource\Item($item, $transformer); return response()->json( $fractal->createData($resource)->toArray(), $status, $headers ); }); response()->macro('collection', function ($collection, \League\Fractal\TransformerAbstract $transformer, $status = 200, array $headers = []) use ($fractal) { $resource = new \League\Fractal\Resource\Collection($collection, $transformer); return response()->json( $fractal->createData($resource)->toArray(), $status, $headers ); }); } والآن أصبح من السهل إنشاء استجابة واحدة (لمستخدم واحد مثلًا) ومجموعة من الاستجابات (لجميع مقالات المدوّنة مثلًا). /** * GET /users/1 * * @param int $userId * @return \Illuminate\Http\Response */ public function showUser($userId) { $user = \App\User::findOrFail($userId); return response()->item($user, new \App\Http\Transformers\UserTransformer); } /** * GET /posts * * @return \Illuminate\Http\Response */ public function showPosts() { $posts = \App\Post::with('user')->get(); return response()->collection($posts, new \App\Http\Transformers\PostTransformer); } إن كنت ترغب في استخدام حالة استجابة HTTP أخرى مثل 201 (تم الإنشاء) أو 204 (لا يوجد محتوى) يمكنك وبكل سهولة تمرير رمز الحالة كمعامل ثالث إلى الماكرو. إنشاء الاستجابات في Lumen يتطلّب إنشاء الاستجابات في Lumen اتباع أسلوب مختلف قليلًا؛ ذلك لأنّ Lumen لا يدعم الماكروات في معمل Response؛ لذا سأضيف هذه التوابع إلى المتحكّم الرئيسي في الواجهة البرمجية. /** * Create the response for an item. * * @param mixed $item * @param \League\Fractal\TransformerAbstract $transformer * @param int $status * @param array $headers * @return Response */ protected function buildItemResponse($item, \League\Fractal\TransformerAbstract $transformer, $status = 200, array $headers = []) { $resource = new \League\Fractal\Resource\Item($item, $transformer); return $this->buildResourceResponse($resource, $status, $headers); } /** * Create the response for a collection. * * @param mixed $collection * @param \League\Fractal\TransformerAbstract $transformer * @param int $status * @param array $headers * @return Response */ protected function buildCollectionResponse($collection, \League\Fractal\TransformerAbstract $transformer, $status = 200, array $headers = []) { $resource = new \League\Fractal\Resource\Collection($collection, $transformer); return $this->buildResourceResponse($resource, $status, $headers); } /** * Create the response for a resource. * * @param \League\Fractal\Resource\ResourceAbstract $resource * @param int $status * @param array $headers * @return Response */ protected function buildResourceResponse(\League\Fractal\Resource\ResourceAbstract $resource, $status = 200, array $headers = []) { $fractal = app('League\Fractal\Manager'); return response()->json( $fractal->createData($resource)->toArray(), $status, $headers ); } يمكنك الآن استدعاء أي تابع من هذه التوابع في أي متحكّم موروث من هذا المتحكّم لإنشاء نفس الاستجابات التي أنشأناها مع Laravel. return $this->buildItemResponse($user, new \App\Http\Transformers\UserTransformer); return $this->buildCollectionResponse($posts, new \App\Http\Transformers\PostTransformer); ترجمة - وبتصرّف - للمقال Using Fractal with Laravel and Lumen لصاحبه Dwight Conrad Watson.
  4. هنالك الكثير من الواجهات البرمجية المبنية على JSON التي توفر وصولًا عبر دوال من جهة الخادوم فقط، فلو أردنا استخدام عميل JavaScript مع تلك الواجهات البرمجية الخارجية، فسنحتاج إلى ضبط خادومنا للوصول إلى تلك الواجهات البرمجية الخارجية ثم تخديم تلك البيانات عبر Ajax أو عبر نقطة نهاية (endpoint) خاصة بك. ولحسن الحظ، فعل ذلك سهلٌ جدًا في ووردبريس. سأريك في هذا الدرس كيفية الحصول على أجور الشحن عبر Easy Post API باستخدام نقطة نهاية في ووردبريس. لتبسيط هذا الدرس (وجعله قصيرًا) فسنرسل ستة معاملات (وهو عدد كاف لواجهة Easy Post البرمجية لإعادة أجور الشحن): عرض الطرد ارتفاع الطرد طول الطرد وزن الطرد كود Zip للمرسل كود Zip للمستقبل ضبط نقطة نهاية JSON أوّل خطوة هي ضبط المسار الذي ستُخدَّم منه بيانات JSON، وفي هذه الحالة هو: /wp-json/easy-post/v1/rates/ الشيفرة: /** * Sets up a JSON endpoint at /wp-json/easy-post/v1/rates/ */ function easy_post_api_init() { $namespace = 'easy-post/v1'; register_rest_route( $namespace, '/rates/', array( 'methods' => 'GET', 'callback' => 'easy_post_return_rates', ) ); } add_action( 'rest_api_init', 'easy_post_api_init' ); عرض البيانات تتوقع نقطة النهاية إرسال ست قيم من البيانات كطلبية، وستستخدمها للحصول على البيانات من الواجهة البرمجية الخارجية، فلو لم تكن تلك القيم موجودةً فستستعمل القيم الافتراضية، وسنحرص أن تكون تلك القيم رقميةً فقط. مثال عن رابط URL مع قيم لكل المعاملات: /wp-json/easy-post/v1/rates/?zip=78701&width=10&length=10&height=10&weight=10&shipping_zip=78751 الشيفرة: /** * عرض مخرجات Easy Post عبر النهاية الطرفية * * نستخدم القيم المبدئية في حال عدم ذكر بيانات في الطلب، إلا أن إعادة خطأ ربما تكون فكرة أفضل. * Valid URL: /wp-json/easy-post/v1/rates/?zip=78701&width=10&length=10&height=10&weight=10&shipping_zip=78751 */ function easy_post_return_rates( WP_REST_Request $request ) { // الإعدادات المبدئية للشحن $defaults = array( 'zip' => 78701, 'width' => 10, 'length' => 10, 'height' => 10, 'weight' => 16, 'shipping_zip' => 94105 ); // الحصول على المعطيات من الطلب $params = $request->get_query_params(); // التأكد من توفر جميع المعطيات $params = array_replace( $defaults, $params ); // تنظيف المفاتيح $params = array_map( "absint", $params ); // إنشاء قيم مفاتيح فريدة لتحديد قيم البيانات المؤقتة transient أو العثور عليها $key = 'easy_post_' . implode( "_", $params ); /** * نحتفظ بالإجابة في قيمة مؤقتة transient ضمن قاعدة بيانات ووردبريس * لتجنب إرسال الكثير من الطلبات في وقت قصير * * تنتهي صلاحية هذه البيانات بعد عشر دقائق */ if ( false === ( $data = get_transient( $key ) ) ) { $data = easy_post_make_request( $params ); $response = new WP_REST_Response( $data ); // التخبئة لمدة عشر دقائق set_transient( $key, $response, 60 * 10 ); } else { // إرجاع القيمة المخبّأة return get_transient( $key ); } return $response; } الحصول على البيانات الدالة easy_post_make_request()‎ هي الدالة التي تطلب البيانات من الواجهة البرمجية الخارجية، والغرض من أغلبية الشيفرات التي هنا هي تجهيز الطلبية ضمن مصفوفة يمكن لواجهة Easy Post البرمجية أن تعالجها: /** *العثور على البيانات من الواجهة البرمجية لـ Easy Post باستخدام الدالة wp_remote_post */ function easy_post_make_request( $params ) { $to_address = array( 'zip' => $params['shipping_zip'], 'country' => 'US' ); $from_address = array( 'zip' => $params['zip'], 'country' => 'US' ); $parcel = array( 'length' => $params['length'], 'width' => $params['width'], 'height' => $params['height'], 'weight' => $params['weight'] ); $request = array( 'shipment' => array( 'to_address' => $to_address, 'from_address' => $from_address, 'parcel' => $parcel ) ); $args = array( 'method' => 'POST', 'blocking' => true, 'headers' => array( 'Content-Type' => 'application/json' ), 'timeout' => 15, 'sslverify' => false, 'body' => json_encode( $request ) ); // ضع مفتاح API الخاص بك مكان EASYPOST_TEST_API_KEY $api_url = 'https://' . EASYPOST_TEST_API_KEY . ':@api.easypost.com/v2/shipments'; $response = wp_remote_post( $api_url, $args ); if ( ! is_wp_error( $response ) ) { $response = json_decode( $response['body'] ); } return $response; } استخدام البيانات عندما نحاول الوصول إلى نقطة النهاية التي أنشأناها، فإن بيانات JSON التي جلبناها من Easy Post ستظهر لنا: يمكنك الآن الحصول على أجور الشحن ديناميكيًا في موقعك باستخدام نقطة النهاية التي أنشأناها في هذا الدرس. يمكنك الاطلاع على كامل الشيفرة هنا. ترجمة –وبتصرّف– للمقال How to Set JSON Endpoints in WordPress to Access an External API لصاحبه Devin Price حقوق الصورة البارزة محفوظة لـ Freepik
  5. بدأنا في دروس سابقة بـإنشاء متجر إلكتروني على WooCommerce وقمنا بضبط إعدادات المتجر العامة General، إعدادات المنتجات Products، الضريبة Tax، الدفع Checkout، والشحن Shipping. سنغطي في هذا الدرس ما تبقّى من إعدادات المتجر والتي تتضمن إعدادات الحسابات Accounts، البريد الإلكتروني Email، والواجهة البرمجية API. إعدادات الحسابات من هذا التبويب تستطيع ضبط كيفيّة عمل حسابات عملائك. للوصول إلى هذه الإعدادات قم بتسجيل الدخول إلى موقعك ثم اذهب إلى: Dashboard > WooCommerce > Settings > Accounts يحتوي هذا التبويب على ثلاثة أقسام: Account Pages ومنه تقوم بإعداد صفحات الحسابات للعملاء: عندما تقوم بتثبيت WooCommerce سيقوم بإنشاء هذه الصفحة تلقائيًا، تأكّد من إبقاء الصفحة الافتراضية التي تم إنشاؤها، أو قم بإنشاء واحدة لكي يستطيع العميل استعراض الوظائف الخاصة بحسابه، كالطلبات، بالإضافة إلى تغيير تفاصيل الحساب عند الحاجة. My Account Endpoints Endpoints هي أجزاء من عنوان الصفحة URL، كصفحة My Account، تُلحق بذلك العنوان لمعالجة إجراءات معيّنة على الصفحة: إذا كنت تريد إنشاء Endpoints مخصّصة لعرض الطلب View Order، تعديل الحساب Edit Account، أو الإجراءات الأخرى، تأكّد من كون هذه الأجزاء فريدة ولا تظهر في عناوين الصفحات الأخرى على المتجر. وإلا ستعطل الروابط وستسبب مشاكل أخرى في صفحات حسابات العملاء. Registration Options من هذا القسم تتحكّم في خيارات التسجيل: بإمكانك تمكين التسجيل من على صفحة الدفع بتأشير الخيار Enable registration on the Checkout page، و/أو التسجيل من على صفحة "حسابي" Enable registration on the My Account page. هذه الخيارات مفيدة في حال كنت لا تسمح بإجراء الدفع من قبل زوار المتجر (غير المسجّلين)، ويتيح للعملاء الجدد سهولة التسجيل وإنشاء الحساب. من الخيارات الأخرى المفيدة هو Display returning customer login reminder on the Checkout page الذي يقوم بعرض تذكير بتسجيل الدخول للعملاء المتكررين على صفحة الدفع مما يتيح لهم سهولة الدخول إلى حساباتهم من على صفحة الدفع: وأخيرا من خيارات إنشاء الحساب Account Creation بإمكانك القيام بتوليد اسم مستخدم للعميل تلقائيًا من عنوان بريده الإلكتروني بتأشير الخيار Automatically generate username from customer email، وكذلك توليد كلمة سريّة لحساب العميل تلقائيًا بتأشير الخيار Automatically generate customer password، وسيتم إرسال تلك الكلمة السرية إلى عنوان البريد الإلكتروني الخاص بالعميل. انقر على Save Changes لحفظ التغييرات والانتقال إلى التبويب التالي. إعدادات البريد الإلكتروني توجد في هذا التبويب خيارات تعديل إعدادات البريد الإلكتروني والقوالب. للبدء بضبط الإعدادات اذهب إلى: Dashboard > WooCommerce > Settings > Emails يحتوي هذا التبويب أيضًا على ثلاثة أقسام: Email Notifications يحتوي هذا القسم على قائمة الإشعارات التي ستصلك (أو تُرسل للعميل) على البريد الإلكتروني والتي يمكنك تفعيلها أو إلغاء تفعيلها. ولكل رسالة إشعار، تستطيع تعديل بعض الخيارات مثل عنوان البريد الإلكتروني الذي سيُرسل إليه، عنوان الرسالة، إلخ: يمكن أن يقوم WooCommerce بإرسال إشعارات في الحالات التالية: الطلبات الجديدة New Order الطلبات الملغية Cancelled Order الطلبات الفاشلة Failed Order الطلبات الجارية Processing Order الطلبات المكتملة Completed Order الطلبات المستردّة Refunded Order فواتير العملاء Customer Invoice ملاحظات العملاء Customer Note استعادة الكلمة السرية Reset Password إنشاء حسابات جديدة New Account ملاحظة: الإشعارات الثلاثة الأولى تُرسل إلى عنوان البريد الإلكتروني الذي تحدده، أما الإشعارات المتبقية فتُرسل إلى العميل. يملك كل إشعار نفس الإعدادات تقريبًا، مع بعض الاختلافات التي سنأتي إلى ذكرها. بإمكانك الوصول إلى الإعدادات أما بالنقر على عنوان الإشعار في القائمة، أو النقر على أيقونة الترس المقابلة للعنوان في أقصى اليمين. لنبدأ بإعدادات إشعار New Order أولًا: الخيار الأول هو تفعيل/ إلغاء تفعيل هذا الإشعار بتأشير/إلغاء تأشير الخيار Enable this email notification. يفضّل معظم أصحاب المتاجر الإلكترونية استلام إشعار عن الحصول على طلب جديد، مع ذلك، الخيار راجع لك. في حقل (Recipient(s قم بإدخال عنوان/عناوين البريد الإلكتروني الذي تريد استلام الإشعار عليه. إذا قمت بإدخال أكثر من عنوان، تأكّد من فصلها بواسطة الفاصلة (,). في حقل Subject قم بإدخال عنوان الإشعار الذي سيصلك، بإمكانك استخدام العنوان الافتراضي الذي يحتوي على عنوان الموقع+ "New Customer Order"+ رقم الطلب+ تاريخ الطلب في نهايته: {site_title}] New customer order ({order_number}) - {order_date} أو بإمكانك إنشاء واحد مخصص بإدخال نص العنوان والتفاصيل الإضافية المرغوبة. من حقل Email Header يمكنك التحكم في العنوان الرئيسي لإشعار البريد الإلكتروني، ووظيفته تشبه وظيفة العنوان Subject. بإمكانك تركه فارغًا لاستخدام العنوان الرئيسي الافتراضي. لهذا الحقل المزيد من المعلومات التقنية التي سنتجاوزها لأنّها غير مهمة في هذا الدرس. من حقل Email Type يمكنك التحكّم في الصيغة التي سيرسل بها البريد الإلكتروني. الخيارات المتاحة هي Plain Text (نص عادي)، HTML، أو Multipart (أجزاء متعددة). أخيرًا، هناك خياران تحت حقل Email Type، وهما يعتمدان على صيغة البريد الإلكتروني التي اخترتها. الأول Copy file to theme والذي من خلاله تقوم بنسخ قالب البريد الإلكتروني الحالي إلى مجلد القوالب للقيام بتخصيصه أكثر ممّا توفّره هذه الإعدادات. إذا قمت بالفعل بنسخ مجلّد woocommerce/templates/emails بالكامل إلى مجلد القوالب، فلا حاجة إلى نسخ القوالب بشكل منفصل مجددا. وفي تلك الحالة ستجد زر Delete template file بدلًا من Copy file to theme. الخيار الثاني هو View template ويمكنك من خلاله عرض شيفرة قالب البريد الإلكتروني الحالي وستتمكّن من تعديل القالب إذا قمت بالفعل بنسخه إلى مجلد القوالب. وبالرغم من أننا لا ننصحك بتغيير شفرة القوالب مباشرة من هذه النافذة، لكن تأكّد من امتلاك نسخ احتياطية لهذه القوالب والنقر على Save Changes بعد الانتهاء من تخصيص الشفرة إذا قمت بتعديل القالب من ووردبريس. كما ذكرنا سابقًا، تحتوي بقية إعدادات إشعارات البريد الإلكتروني على نفس الحقول التي قم بشرحها في إعدادات New Order. هناك بعض الاستثناءات في إعدادات إشعار الطلبات المكتملة، الطلبات المستردّة، وفواتير العملاء. هناك حقلان إضافيان في إعدادات Completed Order: هذه الحقول خاصّة بعنوان الإشعار (Subject (downloadable والعنوان الرئيسي (Email Heading (downloadable للمنتجات الرقمية القابلة للتنزيل. وفي إعدادات Refunded Order، هناك حقلان للعنوان وحقلان للعنوان الرئيسي: الحقلان الأولان هما للطلبات المستردّة بشكل جزئي Partial Refund والآخران للطلبات المستردّة بشكل كلي Full Refund، مما يتيح لك مستوى تحكّم جيّد في النص المرسل إلى العميل في الحالتين، الاسترداد الجزئي، والاسترداد الكلي. أما إعدادات Customer Invoice فتحتوي على حقلين إضافيين، الأول لعنوان إشعار الفاتورة المدفوعة (Email Subject (paid والثاني للعنوان الرئيسي لإشعار الفاتورة المدفوعة (Email Heading (paid: بعد الانتهاء من ضبط إعدادات كل إشعار، انقر على Save Changes لحفظ التغييرات. Email Sender Options من خيارات مرسل البريد الإلكتروني يمكنك التحكّم في اسم المرسل من حقل "From" Name بالإضافة إلى عنوان البريد الإلكتروني للمرسل "From" Address. من المهم ضبط هذه الإعدادات لأنّها ستُعرض على العملاء في صندوق الوارد لبريدهم الإلكتروني: على سبيل المثال، من خلال الإعدادات أعلاه، سيستلم العميل بريد إلكتروني من المرسل "My Store" صاحب عنوان البريد الإلكتروني " example@gmail.com". Email Template من هذه الخيارات يمكنك تخصيص قالب البريد الإلكتروني الافتراضي الذي يستخدمه WooCommerce: بإمكانك إدخال رابط لصورة الترويسة في حقل Header Image، أو رفع صورة من خلال المسار: Dashboard > Media > Add New وكذلك بإمكانك تخصيص نص هامش القالب بإدخال النص المرغوب في حقل Footer Text وسيظهر هذا النص في الجزء السفلي من جميع رسائل البريد الإلكتروني التي ترسلها. بعد ذلك يمكنك اختيار لون الأساس Base Color، لون الخلفية Background Color، لون خلفية متن البريد الإلكتروني Body Background Color، وكذلك لون نص المتن Body Text Color. بإمكانك معاينة القالب أثناء تخصيصه بالنقر على رابط Click here to preview your email template. بإمكانك عمل المزيد من التخصيصات المعقّدة بنسخ قالب البريد الإلكتروني إلى مجلد القوالب. قم بنسخ مجلد emails من على الامتداد woocommerce/templates/emails ولصقه في مجلد قالبك على الامتداد "theme name"/woocommerce/emails. اعلم فقط أنّ ذلك سيؤدي إلى إلغاء أي تخصيص قمت به من إعدادات قالب البريد الإلكتروني Email Template المذكورة. بعد الانتهاء من ضبط جميع الاعدادات انقر على Save Changes لحفظ التغييرات. إعدادات API من هذا التبويب تستطيع تفعيل REST API، بالإضافة إلى إنشاء Keys و Webhooks لتطبيقاتك. للوصول إلى تبويب إعدادات API اذهب إلى Dashboard > WooCommerce > Settings > API يحتوي هذا التبويب على ثلاثة تبويبات فرعية: Settings من هذا التبويب تستطيع تفعيل/إلغاء تفعيل REST API بتأشير/إلغاء تأشير الخيار Enable the REST API: إنّ هذا الخيار ضروري لكي تعمل تطبيقات للهاتف المحمول في متجرك. فهو يتيح للتطبيقات الخارجية معرفة أشياء مثل حالة المخزون، الطلبات، معلومات المنتجات، وغيرها الكثير. يُعتبر RESU API من الأجزاء الفعّالة في WooCommerce ويمكن أن يحقق الكثير من الأشياء الرائعة. Keys/Apps يتيح لك هذا التبويب إدارة التحكّم في الوصول إلى REST API: ترتبط المفاتيح keys بالمستخدمين على موقعك. ولإنشاء مفتاح انقر على Add Key: في حقل User، قم بتحديد المستخدم الذي تريد توليد مفتاح له، ثم قم بإضافة وصف في حقل Description. من قائمة Permissions قم بتحديد مستوى الوصول لهذا المفتاح. الخيارات المتاحة هي Read (قراءة)، Write (كتابة)، أو Read/Write (قراءة/كتابة). بعد ذلك انقر على زر Generate API Key، وسيقوم WooCommerce بتوليد مفتاح API لذلك المستخدم. بعد توليد المفتاح ستلاحظ وجود مفتاح المستهلك Consumer Key، الرمز السري للمستهلك Consumer Secret، رمز QR، بالإضافة إلى زر إبطال المفتاح Revoke API Key: قم بوضع مفتاح المستهلك والرمز السري للمستهلك في التطبيق الذي يستخدم WooCommerce API. وكذلك يجب أن يطلب ذلك التطبيق عنوان URL لمتجرك. Webhooks Webhooks هي عبارة عن أداة يمكنك استخدامها لإرسال إشعار حول حدث ما إلى عنوان URL من اختيارك. على سبيل المثال عند إنشاء منتج جديد، أو إنشاء قسيمة جديدة. وهي توفّر طريقة سهلة للتكامل مع الخدمات الخارجية وAPI الخارجية الأخرى التي تدعم Webhooks: سنقوم بإنشاء Webhook وهمي لاستخدامه لنشر منشور على منصة تواصل اجتماعي من اختيارنا عندما نقوم بإنشاء منتج جديد. وهذه من الطرق البسيطة للترويج لمنتجاتنا الجديدة عبر الإنترنت بصورة تلقائية. انقر على زر Add Webhook: قم بإدخال عنوان مناسب في حقل Title ثم حدّد الحالة من قائمة Status حسب حاجتك. خيارات الحالة المتوفّرة هي Active (مفعّل)، Paused (متوقف مؤقتًا)، أو Disabled (غير مفعّل). إذا رغبت في تشغيل Webhook تأكّد من اختيار الحالة Active. الخطوة التالية هي تحديد الموضوع من قائمة Topic، ويقصد به الحدث الذي سيشغّل Webhook. تتضمن القائمة العديد من الخيارات، مثل إنشاء طلب Order Created، حذف منتج Product Deleted، أو تحديث عميل Customer Updated. وكذلك يوجد خيار تحديد موضوع مخصص Custom لغرض إنشاء Webhook أكثر تقدّمًا. سنحدد Product Created مثلا. الحقل التالي هو Delivery URL ويُستخدم لتحديد العنوان الذي سيتم توصيل حمل Webhook إليه. في مثالنا هذا سنبحث في توثيق المطوّرين لمنصة التواصل الاجتماعي التي اخترناها للعثور على Webhook يمكننا استخدامه للتوصيل. في حقل Secret قم بإعداد مفتاح سرّي يدويًا، أو اترك الحقل فارغًا وسيتم استخدام مفتاح Consumer Secret للمستخدم الحالي والذي يوجد في قسم API لحساب المستخدم على WooCommerce. بعد الانتهاء من ضبط الإعدادات أعلاه، انقر على Save Webhook لبدء تشغيله ورصد المنتجات الجديدة. عندما يُشغّل Webhook بإمكانك العودة إلى هذه النافذة لمشاهدة التسجيلات في قسم Webhook Logs. إذ ستكون هناك مدخلات تبيّن وقت تشغيله وما هي استجابات الخدمات الأخرى التي تتكامل معها. وهذه التسجيلات توفّر لك طريقة سهلة لاختبار Webhook وإصلاحه. لن نكون قادرين على تغطية جميع التفاصيل التقنية المتعلّقة بالتكامل مع الخدمات الأخرى، لأنها ستكون معقّدة جدًا بالنسبة لغرض هذا الدرس. بهذا تكون قد تمكّنت من ضبط جميع إعدادات متجرك الإلكتروني على WooCommerce. سنغطّي في الدرس القادم -إن شاء الله- كيفية إنشاء المنتجات وسنلقي نظرة عامة على أنواعها.
  6. توفر الكثير من المواقع واجهات برمجية Application Programming Interface ،API بهدف إتاحة موارد الموقع لتطبيقات خارجية؛ قد تكون تطبيقات ٍللجوال، أجهزةً لوحية، أو أجهزةً مكتبية. قد نود مثلا إنشاء تطبيق للجوال نعرض فيه منتجات الموقع. نستخدم لغة البرمجة المناسبة للتطبيق (جافا مثلا لتطبيقات أندرويد) الذي يرسل طلبات لواجهتنا البرمجية يحصُل بموجبها على بيانات يتولى هو طريقة عرضها. نقول إن تطبيق الجوال في هذه الحالة يستهلك Consume الواجهة البرمجية. هذا الدرس جزء من سلسلة تعلم 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 لتوليد بيانات وهمية قصدَ الاختبار. نغطي في هذا الدرس المواضيع التالية: ماهي واجهات REST البرمجية؟الممارسات المنصوح بها في واجهات REST البرمجية.إنشاء واجهة برمجية لمشروع Larashop.ماهي واجهات REST البرمجية؟توصف الكثير من الواجهات البرمجية بأنها RESTful، فما المقصود بهذا الوصف؟ تختصر REST العبارة Representational State Transition (النقل التمثيلي للحالة) وهي طريقة لتصميم البرمجيات تعرِّف معاييرَ يجب على خدمات الويب اتباعها من أجل أداء أعلى وصيانة أسهل. تعتمد بنية التطبيقات REST على بروتوكول HTTP لإرسال الطلبات والحصول على إجابات؛ ومن أهم القيود التي يجب الالتزام بها في تطبيقات REST: العمل حسب مبدأ خادوم-عميل Server-Client، انعدام الحالة Stateless وتوحيد الواجهات (إضافة لقيود أخرى). مبدأ خادوم-عميل: يجب التفريق بين واجهة المستخدم والخادوم الذي يخزن البيانات ويطبق العمليات عليها.انعدام الحالة: يجب أن يحوي الطلب الموجّه من العميل إلى الخادوم كل المعلومات الضرورية ليستطيع الخادوم فهمه والإجابة عليه؛ دون الحاجة لسياق محفوظ على الخادوم (لفهم الطلب).توحيد الواجهات بمعنى أن كل مورد على الخادوم يمكن تعريفه فرديا واستغلاله عبر بيانات تمثله يحتفظ بها العميل. يجب أن تكون الطلبات واضحة يمكن فهمها والإجابة عنها دون الحاجة لمعلومات خارجة عنها. يدخل ضمن توحيد الواجهات أيضا افتراضُ العميل أن أي إجراء Action غيرُ متوفر على الخادوم، ما لم يصّرح هذا الأخير بتوفره.تساهم هذه القيود (والقيود الأخرى التي تعرفها بنية REST) في تسهيل عمل الواجهات، الرفع من أدائها، تيسير الصيانة وقابلية التمدد Scalability. سنرى في الفقرة التالية توصيات لبناء واجهات برمجية تساعد في احترام مبادئ REST. ملحوظة: يكثُر وصف الواجهات البرمجية بأنها RESTful (تلتزم بقيود REST) دون أن تلتزم بكامل القيود التي تعرِّفها بنية REST، وهو ما يجعلها أقرب لواجهات شبيهة لـREST منها لواجهات RESTful. الممارسات المنصوح بها في واجهات REST البرمجيةيُساعد الالتزام بالممارسات التالية في بناء واجهة تطبيقات برمجية ذات أداء عال وقابلية كبيرة للتمدد والصيانة. استخدام إجراءات HTTP لتحديد العمل الذي سيؤديه الخادوم: GET للحصول على مورد، POST لإنشاء مورد جديد، PUT لتحديث مورد وDELETE لحذفه.أَصْدَرَة Versioning الواجهة: يساعد استخدام إصدارات في عدم كسر التطبيقات التي تستهلك الواجهة البرمجية. يحدّد العميل إصدار واجهة التطبيق الذي يود العمل عليه مما يسمح بإحداث تغييرات على الخادوم تضمَّن في إصدار جديد دون أن يتوقف عملاء الواجهة البرمجية.من المتعارف عليه استخدام أسماء جموع لوصف الموارد، api.mysite/v1/products مثلا للمنتجات. ليس واجبا اتباع هذا العرف لكن الأهم هو تناسق تسمية الموارد: لا تخلط بين أسماء مفردة للموارد وجموع.استخدام الإجابات الجزئية: طلب العميل اسم المنتج؟ أرسل اسم المنتج فقط، وليس كامل بيانات المنتج، في الإجابة.استخدام رموز الحالة: تسهّل رموز الحالة في HTTP التخاطب مع العميل. عولج الطلب على النحو الأمثل؟ أرسِل الرمز 200 في الإجابة. طلب العميل إنشاء مورد وتم الأمر؟ أرسل الرمز 201 في الإجابة؛ وهكذا. راجع هذا الرابط للمزيد من رموز الحالة في HTTP.ضع حدًّا أقصى لعدد الطلبات القادمة من نفس عنوان IP في الواجهات المفتوحة للجميع. يساعد هذا الأمر في التصدي للعملاء الذي يفرطون في استخدام واجهة تطبيقاتك البرمجية. ينصح أيضا بحظر عناوين IP ذات السلوك المشبوه حتى لا يؤثر على بقية المستخدمين.قد يُختلف حول هذه التوصية، إلا أنه يُنصح باستخدام صيغة JSON لإرسال البيانات في الإجابة عن الطلب، ما لم يحدّد العميل عكس ذلك.خبِّئ Cache نتائج طلبات GET التي لا تتغير كثيرا. ربما تكون قائمة العلامات التجارية في مواقع التسوق مثالا جيدا للبيانات التي يجب تخبئتها (قد تمضي أشهر دون الحاجة لإضافة علامة تجارية جديدة).واجهة Larashop البرمجيةسننشئ في هذه الفقرة واجهة تطبيقات برمجية لمشروع Larashop. تشتمل الواجهة على المسارات أدناه. تستخدم جميع المسارات إجراء GET للحصول على المورد. التسلسل المورد الرابط الوصف رمز الحالة1Product/api/v1/productsسرد لائحة بالمنتجات وخاصياتها2002Product/api/v1/products/1سرد خاصيات المنتج رقم 12003Category/api/v1/categoriesسرد لائحة بتصنيفات المنتجات2004Category/api/v1/categories/1التصنيف ذو المعرّف 1200لاحظ أننا لم نتح إمكانية التعديل على الموارد عبر الواجهة. تشير v1 في المسارات إلى رقم الإصدار 1. نفتح ملف المسارات routes.php ونعدّله بإضافة المسارات التالية: // API routes... Route::get('/api/v1/products/{id?}', ['middleware' => 'auth.basic', function($id = null) { if ($id == null) { $products = App\Product::all(array('id', 'name', 'price')); } else { $products = App\Product::find($id, array('id', 'name', 'price')); } return Response::json(array( 'error' => false, 'products' => $products, 'status_code' => 200 )); }]); Route::get('/api/v1/categories/{id?}', ['middleware' => 'auth.basic', function($id = null) { if ($id == null) { $categories = App\Category::all(array('id', 'name')); } else { $categories = App\Category::find($id, array('id', 'name')); } return Response::json(array( 'error' => false, 'user' => $categories, 'status_code' => 200 )); }]);يعرف المسار Route::get('/api/v1/products/{id?}', ['middleware' => 'auth.basic', function($id = null)رابطًا يطلب المنتجات مع معرّف اختياري id. يُستخدم المعرف لطلب منتج واحد وفي حال عدم ذكره ترجِع واجهة التطبيقات جميع المنتجات. نحمي المورد بالتعليمة 'middleware' => 'auth.basic' التي تستوثق من العميل. حددنا نمط الاستيثاق بـauth.basic لاستخدام بريد المستخدِم (حقل email في جدول users) مع كلمة السر. يستدعي كل مسار النموذج المناسب للعثور على البيانات في القاعدة ثم نرسل الإجابة بصيغة JSON بالتعليمة Response::json. عند طلب الرابط http://larashop.dev/api/v1/products ستظهر نافذة تطلب إدخال بريد المستخدم وكلمة سره. استخدم الحساب الذي أنشأته في درس الاستيثاق وستظهر النتيجة التالية في المتصفح (بعد التنسيق) { "error":false, "products": [ { "id":"1", "name":"Mini skirt black edition", "price":"35" }, { "id":"2", "name":"T-shirt blue edition", "price":"64" }, { "id":"3", "name":"Sleeveless Colorblock Scuba", "price":"13" } ], "status_code":200 }حصلنا على إجابة بصيغة JSON للطلب الذي أرسلناه من أجل الحصول على منتجات الموقع. يشير الرمز 200 إلى أن معالجة الطلب تمّت دون مشاكل. يمكن للعميل الآن تنسيق الإجابة لعرضها بطريقة مناسبة. خاتمةوضعنا في هذا الدرس أساسا يمكن البناء عليه لإنشاء واجهات برمجية أكثر تطورا. يتلخص إنشاء واجهات برمجية في Laravel في تعريف المسارات، استخدام النماذج للحصول على البيانات المطلوبة ثم تهيئة الإجابة بصيغة JSON ثم إرسالها. ترجمة -وبتصرّف- للمقال Laravel 5 REST API لصاحبه Rodrick Kazembe.
  7. يهدف هذا الدرس إلى بناء تطبيق CRUD (إدراج بيانات في قاعدة بيانات، القراءة منها، تحديثها وحذفها؛ اختصار لـUpdate، Read، Create وDelete). التطبيق عبارة عن واجهة لإدارة لائحة من الموظفين: إضافة موظّف، تحرير بياناته أو حذفها. سنستخدم Laravel 5 للنهاية الخلفية Backend و AngularJS للنهاية الأمامية Frontend. سنستخدم أيضا Bootstrap لإضافة لمسة جمالية إلى التطبيق. هذا الدرس جزء من سلسلة تعلم Laravel والتي تنتهج مبدأ "أفضل وسيلة للتعلم هي الممارسة"، حيث ستكون ممارستنا عبارة عن إنشاء تطبيق ويب للتسوق مع ميزة سلة المشتريات. يتكون فهرس السلسلة من التالي: مدخل إلى Laravel 5.تثبيت Laravel وإعداده على كلّ من Windows وUbuntu.أساسيات بناء تطبيق باستخدام Laravel.إنشاء روابط محسنة لمحركات البحث (SEO) في إطار عمل Laravel.نظام Blade للقوالب.تهجير قواعد البيانات في Laravel.استخدام Eloquent ORM لإدخال البيانات في قاعدة البيانات، تحديثها أو حذفها.إنشاء سلة مشتريات في Laravel.الاستيثاق في Laravel.إنشاء واجهة لبرمجة التطبيقات API في Laravel.إنشاء مدوّنة باستخدام Laravel.استخدام AngularJS واجهةً أمامية Front end لتطبيق Laravel. (هذا الدرس)الدوّال المساعدة المخصّصة في Laravel.استخدام مكتبة Faker في تطبيق Laravel لتوليد بيانات وهمية قصدَ الاختبار. AngularJS هو إطار عمل جافاسكريبت قويّ وفعّال، يتبنى مبدأ النموذج-العرض-المتحكم MVC ويعمل لدى العميل (المتصفّح). للاطلاع على المزيد عن AngularJS تابع سلسلة دروس مدخل إلى تعلم AngularJS . يفترض هذا الدرس معرفة أساسيات Laravel 5، تثبيت كلّ من PHP، MySQL، ِApache وComposer. يغطي الدرس المواضيع التالية: إنشاء نهاية خلفية في Laravel 5، ستكون عبارة عن واجهة برمجية API.بنية تطبيق AngularJS.واجهة برمجية باستخدام Laravel 5ننشئ في هذه الفقرة النهاية الخلفية للتطبيق الذي نعمل عليه. سيتولى Laravel هذه المهمة. نبدأ بإنشاء تطبيق Laravel ثم نعدّه لتوفير الواجهة البرمجية. الخطوة الأولى: إنشاء تطبيق Laravelننفذ الأمر التالي في أصل المستند Document root لإنشاء مشروع Laravel باسم angulara: composer create-project laravel/laravel angularaراجع درس تثبيت Laravel 5 وإعداده على Windows وUbuntu للمزيد حول تثبيت Laravel وإعداده. سنفترض في بقية هذا الدرس تثبيت Laravel على المنصة المفضلة لديك وإنشاء مضيف افتراضي باسم angulara.dev. الخطوة التالية هي إعداد تهجير قاعدة البيانات. الخطوة الثانية: إعداد قاعدة البياناتستحتاج لقاعدة بيانات للعمل مع التطبيق. استخدم برنامج إدارة قاعدة البيانات المفضل لديك أو نفذ الأمر التالي في سطر أوامر MySQL لإنشاء قاعدة بيانات للمشروع: CREATE DATABASE `angulara`;ننتقل الآن لإعداد Laravel لكي يعمل مع قاعدة البيانات. افتح ملف env. في مجلد تطبيق Laravel وعدل القيم التالية بما يناسب: DB_HOST=localhost // اسم قاعدة البيانات DB_DATABASE=angulara // اسم مستخدم في MySQL لديه صلاحيات الكتابة والقراءة في القاعدة أعلاه DB_USERNAME=root // كلمة سر المستخدم DB_PASSWORD=melodyاحفظ التعديلات. نستغل أداة Artisan لإنشاء ملف تهجير خاص بجدول يحوي بيانات الموظفين employees. نفذ الأمر التالي لإنشاء ملف التهجير: php artisan make:migration create_employees_tableستحصُل على الرسالة التالية التي تعرض اسم الملف المنشأ: Created Migration: 2016_01_05_203637_create_employees_tableينشئ الأمر ملفا في المجلد database/migrations، نفتحه للتعديل عليه. عدّل المحتوى كالتالي: <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateEmployeesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('employees', function (Blueprint $table) { $table->increments('id'); $table->string('name')->unique(); $table->string('email')->unique(); $table->string('contact_number'); $table->string('position'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('employees'); } }احفظ التعديلات ثم نفذ أمر ِArtisan التالي: php artisan migrateينفذ الأمر التهجيرات وينشئ جدول بيانات الموظفين. تظهر الرسائل التالية بعد تنفيذ الأمر: Migration table created successfully. Migrated: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_100000_create_password_resets_table Migrated: 2016_01_05_203637_create_employees_tableتحقق من قاعدة بيانات MySQL، ستجد أن جدولا جديدا أُدرِج في القاعدة. الخطوة الثالثة: إنشاء واجهة برمجيةننشئ متحكما Controller للتطبيق، سنسميه Employees: php artisan make:controller Employeesثم يأتي دور النموذج Model: php artisan make:model Employeeسنضيف مصفوفة في النموذج لتفعيل الإسناد الشامل؛ افتح ملف النموذج وعدّله على النحو التالي: <?php namespace App; use Illuminate\Database\Eloquent\Model; class Employee extends Model { protected $fillable = array('id', 'name', 'email','contact_number','position'); }احفظ التعديلات. ننتقل للتعديل على المتحكم. افتح ملف المتحكم Employees وعدله ليصبح كالتالي <?php namespace App\Http\Controllers; use App\Employee; use Illuminate\Http\Request; use App\Http\Requests; use App\Http\Controllers\Controller; class Employees extends Controller { /** * Display a listing of the resource. * * @return Response */ public function index($id = null) { if ($id == null) { return Employee::orderBy('id', 'asc')->get(); } else { return $this->show($id); } } /** * Store a newly created resource in storage. * * @param Request $request * @return Response */ public function store(Request $request) { $employee = new Employee; $employee->name = $request->input('name'); $employee->email = $request->input('email'); $employee->contact_number = $request->input('contact_number'); $employee->position = $request->input('position'); $employee->save(); return 'Employee record successfully created with id ' . $employee->id; } /** * Display the specified resource. * * @param int $id * @return Response */ public function show($id) { return Employee::find($id); } /** * Update the specified resource in storage. * * @param Request $request * @param int $id * @return Response */ public function update(Request $request, $id) { $employee = Employee::find($id); $employee->name = $request->input('name'); $employee->email = $request->input('email'); $employee->contact_number = $request->input('contact_number'); $employee->position = $request->input('position'); $employee->save(); return "Sucess updating user #" . $employee->id; } /** * Remove the specified resource from storage. * * @param int $id * @return Response */ public function destroy($id = null) { if ($id == null) { } else { $employee = Employee::find($id); $employee->delete(); return "Employee record successfully deleted #" . $id; } } }يعرِّف المتحكم الدوالّ index لسرد قائمة بالموظفين، store لإضافة موظف جديد، show لعرض موظف بناء على معرّفه، update لتحديث بيانات موظّف وdestroy لحذف موظّف. تبقى لنا إعداد المسارات Routes في Laravel. افتح ملف المسارات routes.php وعدله كالتالي: <?php /* |-------------------------------------------------------------------------- | Application Routes |-------------------------------------------------------------------------- | | Here is where you can register all of the routes for an application. | It's a breeze. Simply tell Laravel the URIs it should respond to | and give it the controller to call when that URI is requested. | */ Route::get('/', function () { return view('index'); }); Route::get('/api/v1/employees/{id?}', 'Employees@index'); Route::post('/api/v1/employees', 'Employees@store'); Route::post('/api/v1/employees/{id}', 'Employees@update'); Route::delete('/api/v1/employees/{id}', 'Employees@destroy');لاحظ استخدام إجراءات HTTP وفقا للمبدأ المشروح في درس إنشاء واجهة برمجية API في Laravel 5. يختلف التعامل مع المسار api/v1/employees حسب إجراء HTTP المستخدم: get يُستخدم للحصول على معلومات موظف أو قائمة بالموظفين، post لإضافة موظف جديد، put لتحديث بيانات موظّف وdelete لحذف موظّف. أكملنا الآن جانب النهاية الخلفية بإنشاء واجهة برمجية. ننتقل للواجهة الأمامية التي ستستخدم الواجهة البرمجية للحصول على بيانات الموظفين وتنسيقها قبل عرضها في المتصفح. بنية تطبيق AngularJSسيأخذ مجلد public (الواجهة الأمامية لتطبيق Laravel) الشكل التالي: يحوي المجلّد الفرعي app ملفات جافاسكريبت التابعة لـAngularJS.توجد متحكمات AngularJS في المجلّد app/controllers.توجد ملفات نواة AngularJS في المجلّد app/lib. توجد أيضا إمكانية استخدام شبكة توصيل محتوى Content delivery network, CDN.توجد ملفات CSS في المجلد css.ملفات جافاسكريبت غير التابعة لـAngularJS توجد في المجلد js.توجد ملفات الواجهة الأمامية في الملف المرفق، سنشرح ما يحتاج لشرح منها. الملف app.jsسنستخدم الملف public/app/app.js لتعريف التطبيق الخاص بنا: var app = angular.module('employeeRecords', []) .constant('API_URL', 'http://angulara.dev/api/v1/');ننشئ وحدة Module في AngularJS ونسند الكائن إلى المتغير app. سيُستخدم هذا المتغير في جميع ملفات AngularJS؛ ثم نعرّف ثابتا Constant لرابط الواجهة البرمجية API_URL. ملحوظة: إن كنت اخترت اسما مختلفا للمضيف فضعه مكان angulara.dev. المتحكم Employees.jsسيكون هذا الملف مسؤولا عن التفاعل مع عروض تطبيق AngularJS: app.controller('employeesController', function($scope, $http, API_URL) { // الحصول على لائحة الموظفين $http.get(API_URL + "employees") .success(function(response) { $scope.employees = response; }); // عرض نافذة منبثقة $scope.toggle = function(modalstate, id) { $scope.modalstate = modalstate; switch (modalstate) { case 'add': $scope.form_title = "Add New Employee"; break; case 'edit': $scope.form_title = "Employee Detail"; $scope.id = id; $http.get(API_URL + 'employees/' + id) .success(function(response) { console.log(response); $scope.employee = response; }); break; default: break; } console.log(id); $('#myModal').modal('show'); } //save new record / update existing record $scope.save = function(modalstate, id) { var url = API_URL + "employees"; var request_method = 'POST'; //append employee id to the URL if the form is in edit mode if (modalstate === 'edit'){ url += "/" + id; request_method = 'PUT'; } $http({ method: request_method, url: url, data: $.param($scope.employee), headers: {'Content-Type': 'application/x-www-form-urlencoded'} }).success(function(response) { console.log(response); location.reload(); }).error(function(response) { console.log(response); alert('This is embarassing. An error has occured. Please check the log for details'); }); } //delete record $scope.confirmDelete = function(id) { var isConfirmDelete = confirm('Are you sure you want this record?'); if (isConfirmDelete) { $http({ method: 'DELETE', url: API_URL + 'employees/' + id }). success(function(data) { console.log(data); location.reload(); }). error(function(data) { console.log(data); alert('Unable to delete'); }); } else { return false; } } });نعرِّف متحكما باسم employeesController في المتغيّر app الذي أنشأناه في الملف app.js. حدّدنا الاعتماديات بـ $http، scope$ وAPI_URL. نستدعي خدمة http$ في AngularJS لإرسال طلب إلى الواجهة البرمجية، مع تمرير المعطى API_URL + "employees": $http.get(API_URL + "employees").success(function(response) {$scope.employees = response;});عند نجاح الطلب نُسنِد الإجابة إلى المتغير scope.employees$ الذي سيصبح متاحا في العرض View لإظهار محتواه. تعرض الدالة: $scope.toggle = function(modalstate, id) {…}نافذة منبثقة تحوي استمارة لإضافة موظّف جديد أو تعديل بيانات موظّف موجود حسب الحالة. نستخدم الدالة: $scope.save = function(modalstate, id){…}في حالتيْ الإضافة والتعديل. بالنسبة لإضافة موظّف نستخدم إجراء POST؛ وفي حالة التعديل نستخدم الإجراء PUT. تحذف الدالة: $scope.confirmDelete = function(id){…}بيانات موظّف من جدول الموظفين. عرض البيانات المتحصل عليها من الواجهة البرمجية بـAngularJSسننشئ عرضا لإظهار البيانات التي نتحصل عليها من الواجهة البرمجية؛ يستخدم كل من angularJS وBlade الحاضنات المزدوجة {{}} لعرض البيانات، لذا لن نحفظ عرض AngularJS بلاحقة blade.php حتى لا يعدّ نظام Blade العرض موجها له. محتوى العرض هو التالي، نحفظ الملف index.php في ملف العروض resources/views حتى يُحمّل عند طلبه من المسار / (الصفحة الرئيسية للموقع): <!DOCTYPE html> <html lang="en-US" ng-app="employeeRecords"> <head> <title>Laravel 5 AngularJS CRUD Example</title> <!-- Load Bootstrap CSS --> <link href="<?= asset('css/bootstrap.min.css') ?>" rel="stylesheet"> </head> <body> <h2>Employees Database</h2> <div ng-controller="employeesController"> <!-- Table-to-load-the-data Part --> <table class="table"> <thead> <tr> <th>ID</th> <th>Name</th> <th>Email</th> <th>Contact No</th> <th>Position</th> <th><button id="btn-add" class="btn btn-primary btn-xs" ng-click="toggle('add', 0)">Add New Employee</button></th> </tr> </thead> <tbody> <tr ng-repeat="employee in employees"> <td>{{ employee.id }}</td> <td>{{ employee.name }}</td> <td>{{ employee.email }}</td> <td>{{ employee.contact_number }}</td> <td>{{ employee.position }}</td> <td> <button class="btn btn-default btn-xs btn-detail" ng-click="toggle('edit', employee.id)">Edit</button> <button class="btn btn-danger btn-xs btn-delete" ng-click="confirmDelete(employee.id)">Delete</button> </td> </tr> </tbody> </table> <!-- End of Table-to-load-the-data Part --> <!-- Modal (Pop up when detail button clicked) --> <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel">{{form_title}}</h4> </div> <div class="modal-body"> <form name="frmEmployees" class="form-horizontal" novalidate=""> <div class="form-group error"> <label for="inputEmail3" class="col-sm-3 control-label">Name</label> <div class="col-sm-9"> <input type="text" class="form-control has-error" id="name" name="name" placeholder="Fullname" value="{{name}}" ng-model="employee.name" ng-required="true"> <span class="help-inline" ng-show="frmEmployees.name.$invalid && frmEmployees.name.$touched">Name field is required</span> </div> </div> <div class="form-group"> <label for="inputEmail3" class="col-sm-3 control-label">Email</label> <div class="col-sm-9"> <input type="email" class="form-control" id="email" name="email" placeholder="Email Address" value="{{email}}" ng-model="employee.email" ng-required="true"> <span class="help-inline" ng-show="frmEmployees.email.$invalid && frmEmployees.email.$touched">Valid Email field is required</span> </div> </div> <div class="form-group"> <label for="inputEmail3" class="col-sm-3 control-label">Contact Number</label> <div class="col-sm-9"> <input type="text" class="form-control" id="contact_number" name="contact_number" placeholder="Contact Number" value="{{contact_number}}" ng-model="employee.contact_number" ng-required="true"> <span class="help-inline" ng-show="frmEmployees.contact_number.$invalid && frmEmployees.contact_number.$touched">Contact number field is required</span> </div> </div> <div class="form-group"> <label for="inputEmail3" class="col-sm-3 control-label">Position</label> <div class="col-sm-9"> <input type="text" class="form-control" id="position" name="position" placeholder="Position" value="{{position}}" ng-model="employee.position" ng-required="true"> <span class="help-inline" ng-show="frmEmployees.position.$invalid && frmEmployees.position.$touched">Position field is required</span> </div> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-primary" id="btn-save" ng-click="save(modalstate, id)" ng-disabled="frmEmployees.$invalid">Save changes</button> </div> </div> </div> </div> </div> <!-- Load Javascript Libraries (AngularJS, JQuery, Bootstrap) --> <script src="<?= asset('app/lib/angular/angular.min.js') ?>"></script> <script src="<?= asset('js/jquery.min.js') ?>"></script> <script src="<?= asset('js/bootstrap.min.js') ?>"></script> <!-- AngularJS Application Scripts --> <script src="<?= asset('app/app.js') ?>"></script> <script src="<?= asset('app/controllers/employees.js') ?>"></script> </body> </html>نربط تطبيق AngularJS بوسم html حتى يكون له كامل التحكّم في العناصر الموجودة في الصفحة: <html lang="en-US" ng-app="employeeRecords"> نفس الشيء بالنسبة للمتحكم employeesController الذي نربطه بعنصر div حتى نجعل جميع دوال المتحكم متاحة في هذا العنصر: <div ng-controller="employeesController">نستخدم تعليمة ng-repeat للمرو على جميع عناصر المجموعة employees: <tr ng-repeat="employee in employees">تعمل ng-repeat بطريقة مشابهة لعمل الحلقة التكرارية foreach. التحقق من بيانات استمارات AngularJSاستخدمنا في استمارات الموظفين طرقا للتحقق من المُدخلات. اعثر على الشفرات التالية في ملف العرض index.php ولاحظ استخدامها: <form name="frmEmployees" class="form-horizontal" novalidate="">تعرّف هذه الشفرة استمارة باسم frmEmployees وتضيف إليها خاصيّة novalidate للطلب من HTML 5 الامتناع عن تدقيق الاستمارة، سنتولى الأمر. <input type… ng-model="employee.name" ng-required="true">تستخدم تعليمة ng-model لربط حقول الاستمارة ببيانات النموذج Employee. ربطنا الحقل أعلاه بخاصية name في النموذج. بهذه الطريقة يكون محتوى الحقل متاحا للنموذج، والعكس أيضا. تدل التعليمة ng-required أن الحقل مطلوب. إن لم تذكر قيمة لهذا الحقل فلن يمكن إرسال الاستمارة. <span class="help-inline" ng-show="frmEmployees.name.$invalid && frmEmployees.name.$touched">لا يظهر هذا العنصُر إلا إذا أخفق التحقق من حقل name قبله. تظهر رسالة تفيد أن قيمة الحقل مطلوبة. ng-disabled="frmEmployees.$invalid" تعطّل هذه التعليمة إمكانية إرسال الاستمارة عند إخفاق التحقق من أحد الحقول المطلوبة. حان الآن وقت تجربة ما عملناه في الخطوات السابقة، افتح الموقع (بالنسبة لي اخترتُ إنشاء مضيف افتراضي angulara.dev): http://angulara.dev/ستحصُل، إن اتبعت الخطوات السابقة، على الواجهة التالية: اضغط على زر Add New Employee لإضافة موظّف. ستظهر نافذة منبثقة لإضافة بيانات الموظّف. تصبح الواجهة بعد إضافة موظفين على النحو التالي: تمكّن الأزرار edit و delete الموجودة في كل سطر تحديثَ أو حذف بيانات موظّف. الملف المرفق: مجلد public. ترجمة -وبتصرّف- لمقال Laravel 5 AngularJS Tutorial لصاحبه Rodrick Kazembe.