الأمر Artisan console) Artisan) في Laravel

من موسوعة حسوب

مقدمة

Artisan هي واجهة الأوامر المُرفقة ب Laravel. وهي تُوفّر عددًا من الأوامر المفيدة والتي ستساعدك في بناء التطبيق. لإظهار جميع الأوامر التي يوفّرها Artisan، يمكنك استعمال الأمر list

php artisan list

يحتوي كل أمر على صفحة مساعدة "help" تعرّف وتوضّح الأمر كما تُقدّم قائمة المعاملات والخيارات لكل أمر. يُستعمل الأمر مسبوقًا بالكلمة help لإظهار صفحة المساعدة:

php artisan help migrate

Laravel REPL

تأتي كل تطبيقات Laravel مُرفَقَةً ب Tinker، وهي REPL مشغّلة بواسطة حُزمة PsySH. يسمح Tinker بالتفاعل مع كافّة مكوّنات التطبيق من سطر الأوامر بما في ذلك رابط الكائنات بالعلاقات Eloquent، والمهام، و الأحداث و غيرها الكثير. للدخول لبيئة Tinker، استعمل الأمر tinker:

php artisan tinker

كتابة الأوامر

بالإضافة للأوامر التي يُوفّرها artisan، يمكنك إنشاء أوامرك الخاصّة. هذه الأوامر تحفظ عادةً في الدليل app/console/Commands. لكن يمكنك اختيار مكان حفظ خاص بك طالما بإمكان composer تحميل الأوامر.

توليد الأوامر

لتوليد أمر جديد، استعمل الأمر make:command. سينشئ هذا الأمر صنف أوامر جديدًا في الدليل app/Console/Commands. إن لم يكن الدليل موجودا في التطبيق فإن الأمر سينشئه أول مرّة يُنفّذ فيها. سيحتوي الأمر المنشأ على الخصائص والتوابع المبدئية الحاضرة في كل الأوامر:

php artisan make:command SendEmails

هيكلة الأمر

بعد توليد الأمر، يجب ملأ الخاصّيتين signature وdescription في الصنف، والذين سيُستعملان حين إظهار الأمر الجديد في الصفحة list. سيُنادى التابع handle حين تنفيذ الأمر، يمكنك وضع منطق عمل الأمر في هذا التابع.

ملاحظة : لاستعمالٍ أمثل للأمر، يفضّل إبقاء الأمر خفيفا وتحويل المهام الثقيلة لبقية خدمات التطبيق. في المثال الموالي لاحظ أننا نحقن صنف خدمات ليرسل الرسائل.

لنلق نظرة على المثال الموالي، لاحظ أنّه بإمكاننا إضافة أي اعتماديات قد نحتاجها للدّالة البانية أو للتابع handle.ستضيف حاوي الخدمات في Laravel تلقائيا كل الاعتماديات المذكورة في الدالة البانية أو في التابع handle:

<?php

namespace App\Console\Commands;

use App\User; use App\DripEmailer;

use Illuminate\Console\Command;

class SendEmails extends Command

{

   /**
    *اسم و توقيع الأمر 
    *
    * @var string
    */
   protected $signature = 'email:send {user}';
   /**
    * وصف الأمر
    *
    * @var string
    */
   protected $description = 'Send drip e-mails to a user';
   /**
    * خدمة الرسائل
    *
    * @var DripEmailer
    */
   protected $drip;
   /**
    *إنشاء نسخة أمر جديدة
    *
    * @param  DripEmailer  $drip
    * @return void
    */
   public function __construct(DripEmailer $drip)
   {
       parent::__construct();
       $this->drip = $drip;
   }
   /**
    * تنفيذ الأمر
    *
    * @return mixed
    */
   public function handle()
   {
       $this->drip->send(User::find($this->argument('user')));
   }

}

أوامر النطاق المغلق Closure

تُقدّم الأوامر المبنية على النطاق المغلق Closure بديلًا عن الأوامر المُعرَّفة كأصناف. كما تعوِّض مسارات النطاق المغلق Closure وحدات الأوامر. يمكن اعتبار أوامر النطاق المغلق Closure معوِّضاً لأصناف الأوامر. في تابع command من الملف app/Console/Kernel.php ، يحمّل Laravel الملف routes/console.php:

/**
* تثبيت أصول  الأوامر Closure 
*
* @return void
*/

protected function commands() {

   require base_path('routes/console.php');
}

رغم أنّ هذا الملف لا يعرّف مسارات HTTP، إلّا أنّه يعرّف نقاط دخول (مسارات) تابعة لسطر الأوامر console. في هذا الملف يمكنك تعريف مسارات النطاق المغلق Closure باستعمال التابع Artisan::command. يقبل التابع command معاملَيْن : توقيع الأمر و كائن Closure لاستقبال معاملات و خيارات الأمر:

Artisan::command('build {project}', function ($project) {

   $this->info("Building {$project}!");
});

النطاق المغلق Closure مرتبط بنسخة الأمر، لذا بإمكانك استعمال جميع التوابع المساعدة التي تأتي مع صنف الأوامر.

التلميح إلى نوع الاعتماديات

بالإضافة إلى استقبال معامِلات وخيارات الأوامر، يمكن لأوامر النطاق المغلق Closure التلميح إلى نوع بعض الاعتماديات التي قد تريد حلّها خارج حاوية الخدمات.

use App\User;
use App\DripEmailer;

Artisan::command('email:send {user}', function (DripEmailer $drip, $user) {
    $drip->send(User::find($user));
});

توصيف أوامر النطاق المغلق Closure

عند تعريف أمر Closure، يمكنك استعمال التابع describe لإضافة تعريف للأمر. سيظهر هذا التعريف عند تنفيذ الأمر php artisan list أو php artisan help:

Artisan::command('build {project}', function ($project) {
   $this->info("Building {$project}!");

})->describe('Build the project');

تعريف استثناءات الإدخال

عند كتابة أوامر التحكم، من الطبيعي جمع البيانات المدخلة من المستخدم عن طريق الخيارات أو المعاملات. يجعل Laravel توقع البيانات المدخلة أمرًا سهلًا عبر تحديد خاصية الأمر signature. تسمح هذه الخاصية بتحديد إسم، ومعاملات، وخيارات الأمر في صياغة واحدة معبّرة، وشبيهة بصياغة المسارات.

المعاملات

تُحاط كل المعاملات والخيارات المزوَّدة بأقواس معقّفة. في المثال التالي، يعرِّف الأمر خيارًا واحدًا إجباريًّا هو user

/**
* إسم و إمضاء الأمر
*
* @var string
*/

protected $signature = 'email:send {user}';

يمكن أيضًا تعريف معاملات غير إجبارية و إعطاؤها قيما مبدئية:

// معاملات غير إجبارية

email:send {user?}

// معاملات غير إجبارية بقيم مبدئية

email:send {user=foo}

الخيارات

الخيارات، مثل المعاملات، هي شكل من أشكال البيانات التي يدخلها المستخدم. تُسبَق الخيارات في سطر الأمر بمطَّتين قصيرتين (--). يوجد نوعان من الخيارات :تلك التي تقبل قيمة ما وتلك التي لا تقبل. الخيارات التي لا تقبل قيمة تعمل كمبدّل بقيمة منطقية "switch". لنلاحظ المثال التالي:

/**
*
* @var string
*/

protected $signature = 'email:send {user} {--queue}';

في هذا المثال، يمكن ذكر المبدّل queue-- عند استعمال الأمر. إذا مُرّر المبدّل، فإنّ قيمة الخيار ستكون "true"وإلّا فإنّ قيمته ستكون "false".

php artisan email:send 1 --queue

الخيارات القابلة لقيمة

لنلق نظرة على الخيارات التي تتوقّع أن يُدخِل المستخدم قيمة. إذا كان تمرير القيمة إجباريًّا للخيار، أتبع الخيار بالرمز =:

/**
*
* @var string
*/

protected $signature = 'email:send {user} {--queue=}';

في هذا المثال يمكن للمستخدم أن يُدخِل قيمة للخيار كما يلي:

php artisan email:send 1 --queue=default

يمكن تخصيص قيمة مبدئية بعد اسم الخيار، إذا لم يمرّر المستخدم أي قيمة للخيار، تُعتمد القيمة المبدئية

email:send {user} {--queue=default}

اختصار الخيارات

لتخصيص اختصار لخيار ما، يمكنك تعريفه قبل اسم الخيار واستعمال الرمز | للتفريق بين الاختصار و الإسم الكامل:

email:send {user} {--Q|queue}

إدخال مصفوفات البيانات

إن أردت تعريف خيارات تتوقع مصفوفات كبيانات مُمرّرة، يمكنك استعمال الرمز * . لنلق نظرة على المثال الأول:

email:send {user*}

عند استعمال هذا الأمر، ستُمرَّر القيم للخيار user بالترتيب. مثلا، الأمر الموالي سيغيّر قيمة user إلى ['foo', 'bar']:

php artisan email:send foo bar

عند تمرير مصفوفة بيانات للخيارات التي تقبل مصفوفات، يجب أن تُسبَق كل قيمة ممرّرة باسم الخيار:

email:send {user} {--id=*}
php artisan email:send --id=1 --id=2

وصف البيانات المدخلة

يمكن تخصيص وصف أو تعريف للخيارات والمعاملات المدخلة عبر تفريق المعامل عن التعريف باستخدام نقطتين ":". إن احتجت مزيدا من المساحة لتعريف الأمر يمكنك توزيع التعريف على أكثر من سطر:

/**
* اسم و توقيع الأمر 
*
* @var string
*/

protected $signature = 'email:send
                       {user : The ID of the user}
                       {--queue= : Whether the job should be queued}';

أوامر الإدخال والإخراج I/O

استرداد البيانات المدخَلة

عندما يعمل الأمر، ستحتاج طبعا للإطلاع على قيم المعاملات والخيارات التي تلقاها الأمر. للقيام بهذا، يمكنك استعمال أحد التابعين argument و option:

/**
*  تنفيذ الأمر *
* @return mixed
*/

public function handle() {
   $userId = $this->argument('user');
  //

}

إذا أردت استرداد كل المعاملات على شكل مصفوفة، يمكنك استعمال التابع arguments:

$arguments = $this->arguments();

تُسترجَع الخيارات بسهولة مثل المعاملات باستعمال التابع option. وتُسترجع كل الخيارات كمصفوفة باستعمال التابع options:

//استرجاع خيار معيّن
$queueName = $this->option('queue');

// استرجاع كل الخيارات
$options = $this->options();

إن كان المعامل أو الخيار غير موجود، تُرجَع القيمة null.

الحث على إدخال البيانات

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

/**
*
*
* @return mixed
*/

public function handle() {

   $name = $this->ask('What is your name?');
}

التابع secret شبيه بالتابع ask لكن القيمة التي يُدخلها المستخدم لن تكون ظاهرة له عند كتابتها. هذا التابع مفيد عند إدخال بيانات حساسة مثل كلمات المرور:

$password = $this->secret('What is the password?');

طلب التأكيد

إذا أردت أن تطلب من المستخدم تأكيدًا بسيطًا، يمكنك استخدام التابع confirm. يعيد هذا التابع تلقائيًّا القيمة false إلّا إذا أدخل المستخدم "y" أو "yes" فإنّ القيمة المعادة تصبح true:

if ($this->confirm('Do you wish to continue?')) {

  //

}

الإكمال الآلي

يُستخدم التابع anticipate لتوفير خيارات إكمال آلي. مازال بإمكان المستخدم إدخال أي قيمة يريد رغم تلميحات الإكمال الآلي:

$name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']);

الأسئلة ذات الخيارات المتعدّدة

إذا أردت أن تُقدّم للمستخدم مجموعة من الخيارات المٌعدّة مسبقا، يمكنك ذلك باستعمال التابع choice. يمكنك أيضًا تحديد مكان القيمة المبدئية من مصفوفة الخيارات في حال لم يُرجع المستخدم أي قيمة:

$name = $this->choice('What is your name?', ['Taylor', 'Dayle'], $defaultIndex);

كتابة البيانات المخرجَة

لإرسال بيانات لوحدة الأوامر، استعمل التوابع line ،info ،comment ،question، و error. ستستخدم كل هذه التوابع ألوان ANSII الملائمة. مثلًا، لإظهار بعض المعلومات العامة للمستخدم، تستخدم التابع info الذي يظهر البيانات عادة بالأخضر:

/**
* تنفيذ الأمر
*
* @return mixed
*/

public function handle() {

   $this->info('Display this on the screen');

}

لإظهار رسالة خطأ، استعمل التابع error الذي يظهر البيانات عادة باللون الأحمر:

$this->error('Something went wrong!');

إذا أردت إظهار البيانات دون لون، استخدم التابع line:

$this->line('Display this on the screen');

أنساق الجداول

يجعل التابع table تصميم و تنسيق سطور وأعمدة متعددة من البيانات أمرًا سهلًا. فقط مرّر ترويسة الجدول وسطور البيانات للتابع و سيحسب تلقائيًّا طول وعرض الجدول حسب البيانات المتوفّرة:

$headers = ['Name', 'Email'];
$users = App\User::all(['name', 'email'])->toArray();
$this->table($headers, $users);

شريط التقدم

بالنسبة للمهام التي تأخذ وقتا طويلًا، قد يكون من المفيد إظهار مؤشر تقدّم لها. باستخدام كائن الإخراج، بالإمكان بدء وتقديم وإيقاف شريط التقدّم. في البداية، حدّد عدد الخطوات التي سيمرّ بها العمل، ثم قدّم الشريط بعد نهاية كل خطوة:

$users = App\User::all();
$bar = $this->output->createProgressBar(count($users));

foreach ($users as $user) {

   $this->performTask($user);
   $bar->advance();

}
$bar->finish();

للمزيد من الخيارات، راجع شريط التقدم في توثيق symfony.

تسجيل الأوامر

بسبب نداء التابع load في التابع commands من نواة وحدة الأوامر،تٌسجّل كل الأوامر في الدليل app/console/Commands تلقائيا في artisan. بإمكانك أيضا نداء التابع load للبحث عن أوامر artisan في أماكن أخرى:

/**
* تسجيل الأوامر للتطبيق
*
* @return void
*/

protected function commands() {

   $this->load(__DIR__.'/Commands');
   $this->load(__DIR__.'/MoreCommands');
  // ...

}

يمكنك أيضا تسجيل الأوامر يدويًّا عبر إضافة إسم الصنف للخاصية commands$ في الملف app/console/kernel.php. كل الأوامر الموجودة في هذه الخاصية ستحمل في حاوي الخدمات وتضاف لأوامر artisan:

protected $commands = [

   Commands\SendEmails::class

];

تنفيذ الأوامر بطريقة برمجية

في بعض الأحيان، قد تريد تنفيذ أمر artisan خارج واجهة خطوط الأوامر(CLI). مثلا، قد تريد تنفيذ الأمر من مسار أو من وحدة تحكم. يمكنك استعمال التابع call في الواجهة الساكنة ل artisan. يقبل التابع call إسم أمر أو صنفا كمعامل أول، و مصفوفة من معامِلات الأمر كمعامل ثاني. يُعيد المعامل شيفرة خروج الأمر:

Route::get('/foo', function () {

   $exitCode = Artisan::call('email:send', [
       'user' => 1, '--queue' => 'default'
   ]);

});

باستعمال التابع queue في الواجهة الساكنة artisan، يمكنك صفّ الأوامر ليُنفّذها عمّال قائمة الانتظار في الخلفيّة. تثبت من الضبط الجيد لقوائم الانتظار والمستمعين على قوائم الإنتظار:

Route::get('/foo', function () {

   Artisan::queue('email:send', [
       'user' => 1, '--queue' => 'default'
   ]);
  //

});

يمكنك أيضًا تحديد الصلة أو قائمة الانتظار التي تُرسل إليها أوامر artisan:

Artisan::queue('email:send', [

   'user' => 1, '--queue' => 'default'

])->onConnection('redis')->onQueue('commands');

تمرير مصفوفة قيم

لو كان للأمر خيارات تقبل مصفوفة بيانات، يمكن تمرير هذه المصفوفة كما يلي:

Route::get('/foo', function () {

   $exitCode = Artisan::call('email:send', [
       'user' => 1, '--id' => [5, 13]
   ]);

});

تمرير قيم منطقية

إن احتجت أن تمرّر قيمة لخيار لا يقبل قيمة نصيّة، مثل الخيار force-- من الأمر migrate:refresh، يجب أن تُمرِّر القيمة true أو false:

$exitCode = Artisan::call('migrate:refresh', [

   '--force' => true,

]);

نداء الأوامر من أوامر أخرى

في بعض الأحيان، قد تحتاج لنداء أمرٍ من أمر artisan آخر. يمكن القيام بذلك باستخدام التابع call. يقبل هذا التابع كمعاملات إسم الأمر و مصفوفة معاملاته:

/**
* تنفيذ الأمر
*
* @return mixed
*/

public function handle() {

   $this->call('email:send', [
       'user' => 1, '--queue' => 'default'
   ]);
  //

}

إن أردت نداء أمر مع كبح كل مُخرجاته، يمكنك ذلك باستعمال التابع callsilent. يعمل هذا التابع تماما مثل التابع call:

$this->callSilent('email:send', [

   'user' => 1, '--queue' => 'default'

]);

مصادر