Laravel - Console Commands

Makale İçerik Listesi

Command Oluşturmak

  1. Terminalde php artisan make:command TempGenerateSearchableForStudent komutunu yazarak yeni bir command oluştur.
  2. Yeni oluşturulan komut dosyası app > Console > Commands içine TempGenerateSearchableForStudent.php olarak eklenir.
  3. Bu dosyada bu komutu çalıştırdığımızda ne yapacağı handle() fonksiyonu içinde tanımlanır.
  4. Komutun $signature değişkeni onun nasıl çağırılacağını belirler. Ör.
    protected $signature = 'temp:generate-searchable-for-student'; dersek, bu komutu çalıştırmak için terminalde php artisan temp:generate-searchable-for-student dememiz yeterli.

Command'i Uygularken kullanılabilecek komutlar

  1. ->info() Terminale bilgi satırı eklememizi sağlar.
  2. ->warn() Terminalde uyarı satırı eklememizi sağlar. 
  3. ->error() Terminalde hata satırı göstermemizi sağlar. 
  4. ->confirm() İşleme başlamadan önce teyit almamızı sağlar.

Command'i Uygularken ProgressBar ile Süreç takibi

  1. ProgressBar'ın max limitini belirle
    $queryCount = Student::query()->whereNull('searchable')->count();
  2. Max limiti bu değer üzerinden belirleyerek yeni bir progressbar oluştur ve başlat
    $progressBar = $this->output->createProgressBar($totalRecords);
    $progressBar->setFormat('debug');
    $progressBar->start();

     

  3. Komutun ana fonksiyonunu veritabanındaki nesneler üzerinde dönerek uygula... bu sırada progressbar'ın ilerlemesi için ->advance() fonksiyonunu kullan.
  4. İşlem bitince ->finish() fonksiyonunu kullan.
  5. Örnek kod:
    $queryCount = Student::query()->whereNull('searchable')->count();
    
    $progressBar = $this->output->createProgressBar($totalRecords);
    $progressBar->setFormat('debug');
    $progressBar->start();
    
    foreach($students as $student) {
       // ... do some database operation
       $progressBar->advance();
    }
    
    $progressBar->finish();

Püf Noktalar

  1. chunkById ile veritabanı değerlerini bloklar halinde işle
  2. Veritabanı yazma işlemini try & catch içine al

Cookbook

<?php

namespace App\Console\Commands;

use App\Student;
use Exception;
use Illuminate\Console\Command;
use Illuminate\Support\Str;

class TempGenerateSearchableForStudent extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'temp:generate-searchable-for-student';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Generate searchable for Student';

    protected int $chunkSize = 250;
    protected int $processed = 0;
    protected int $failed = 0;
    /**
     * Execute the console command.
     */
    public function handle()
    {
        $this->warn('Please make sure you have a backup of the related database table before proceeding!');
        $this->warn('Table: students');
        
        if ($this->confirm('Do you wish to continue?')) {
            $query = Student::query()->whereNull('searchable');

            $totalRecords = $query->count();

            $progressBar = $this->output->createProgressBar($totalRecords);
            $progressBar->setFormat('debug');
            $progressBar->start();

            $query->chunkById($this->chunkSize, function($queryTexts) use ($progressBar) {
                foreach($queryTexts as $queryText) {
                    $queryText->searchable = sprintf('%s %s', $queryText->name, Str::slug($queryText->name, ' '));

                    try {
                        $queryText->save();
                        $this->processed++;
                    } catch (Exception $e) {
                        $this->error(sprintf('Error on ID: %d Error: %s',
                            $queryText->id,
                            $e->getMessage()
                        ));
                        $this->failed++;
                    }

                    $progressBar->advance();
                }
            });

            $progressBar->finish();

            $this->info(PHP_EOL);
            $this->info('Operation completed');
            $this->info(sprintf('Total Student %d', $totalRecords));
            $this->info(sprintf('Processed Student %d', $this->processed));

            if($this->failed) {
                $this->warn(sprintf('Failed Student %d', $this->failed));
            }
        }
    }
}

Cookbook2

<?php declare(strict_types=1);

namespace App\Console\Commands\Temp;

use Exception;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Symfony\Component\Console\Command\Command as CommandResponse;

class CustomerContractsWithNewField extends Command
{
    // Number of records to process at a time
    protected int $chunkSize = 50;

    // Number of records successfully processed
    protected int $countLogFound = 0;

    // Number of records failed
    protected int $countCustomerSet = 0;

    // Number of errors occurred
    protected int $countErrors = 0;

    /**
     * Populate data into newly created field for table from existing fields
     *
     * @var string
     */
    protected $signature = 'temp:customer-contracts-cohb';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Add new charge out handled by field to customer contracts';

    /**
     * Execute the console command.
     */
    public function handle(): int
    {
        $this->warn('Please make sure you have a backup of the related database table before proceeding!');
        $this->warn('Table: crm_customer_contracts');

        if ($this->confirm('Do you wish to continue?')) {
            $this->info('Operation started...');

            $this->info('Counting total records...');

            $totalContracts = Model::count();

            $this->info(sprintf('Total records: %d', $totalContracts));

            $sellers_list = $this->sellersList();

            $progressBar = $this->output->createProgressBar($totalContracts);
            $progressBar->setFormat('debug');
            $progressBar->start();

            $totalContracts = Model::query()
                ->whereNotNull('charge_out_date')
                ->orderBy('id')
                ->chunk($this->chunkSize, function ($contracts) use (&$progressBar, $sellers_list) {
                    foreach ($contracts as $contract) {
                        if(!in_array($contract->seller_id, $sellers_list)) {

                            try {
                                $adviserId = $contract->seller_id;

                                $this->countLogFound++;

                                $contract->charge_out_handled_by = (in_array($adviserId, [0, 25559])) ? 22603 : $adviserId;
                                $contract->charge_out_handled_by_team_id = 0;
                                $contract->save();
                            } catch (Exception $e) {
                                $this->countErrors++;
                            }

                            $progressBar->advance();
                            continue;
                        }

                        $log = DB::table('test');


                        if($log) {
                            try {
                                $contract->charge_out_handled_by = $adviserId;
                                $contract->save();

                                $this->countLogFound++;

                            } catch (Exception $e) {
                                $this->countErrors++;

                                $this->error(
                                    sprintf(
                                        'Error occurred in log when updating contract %d, customer %s: %d',
                                        $contract->id,
                                        $contract->customer_id,
                                        $e->getMessage()
                                    )
                                );
                            }
                        } else {
                            $customer = CrmCustomer::first();

                                if($customer) {
                                    try {
                                        $contract->charge_out_handled_by = $customer->adviser_id;
                                        $contract->save();

                                        $this->countCustomerSet++;

                                    } catch (Exception $e) {
                                        $this->countErrors++;

                                        /* */
                                        $this->error(
                                            sprintf(
                                                'Error occurred when updating contract %d, customer %s: %d',
                                                $contract->id,
                                                $contract->customer_id,
                                                $e->getMessage()
                                            )
                                        );
                                    }
                                }

                        }

                        $progressBar->advance();
                    }
                });

            $progressBar->finish();

            $this->info('Operation completed!');
            $this->info(
                sprintf(
                    'Total records processed: %d. Logs found: %d. Default customer set: %d, Errors: %d',
                    $totalContracts,
                    $this->countLogFound,
                    $this->countCustomerSet,
                    $this->countErrors
                )
            );

            return CommandResponse::SUCCESS;
        }

        $this->warn('Operation cancelled!');

        return CommandResponse::FAILURE;
    }
}

Kaynaklar

  1. ChunkById - link