Laravel - Console Commands

Makale İçerik Listesi

  1. Command Oluşturmak
  2. Command'i Uygularken kullanılabilecek komutlar
  3. Command'i Uygularken ProgressBar ile Süreç takibi
  4. Püf Noktalar
  5. Cookbook
  6. Cookbook2
  7. Kaynaklar

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