Ad

Scheduled Command To Update Records

- 1 answer

Morning all,

I am trying to create a command that I can schedule to check if a certification date has expired and if it has, update the boolean from 0 to 1. I have never used commands before and I have read the OctoberCMS documentation but I found it confusing.

If anyone could help me, that would be perfect.

Here is what I have so far.

<?php

namespace Bitpixlimited\Concert\Console;

use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use BitpixLimited\ConCert\Models\Certification;
use Carbon\Carbon;

/**
 * CheckExpiredCertifications Command
 */
class CheckExpiredCertifications extends Command
{
    /**
     * @var string name is the console command name
     */
    protected $name = 'concert:checkexpiredcertifications';

    /**
     * @var string description is the console command description
     */
    protected $description = 'No description provided yet...';

    /**
     * handle executes the console command
     */
    public function handle()
    {
        $certifications = Certification::all();
        $date = now();
        $expiredValue = '1';

        foreach ($certifications as $certification) {

            if ($certification->expiry_date < $date) {

                $certification->status = $expiredValue;
            
            }

            $certification->save();
        }
    }

    /**
     * getArguments get the console command arguments
     */
    protected function getArguments()
    {
        return [];
    }

    /**
     * getOptions get the console command options
     */
    protected function getOptions()
    {
        return [];
    }
}

Ad

Answer

Take a look at this code:

public function handle()
{
    $certifications = Certification::query()
        ->where('expiry_date', '<', now())
        ->update(['status' => '1'])
}

It does what you are trying to achieve, it's a simplified version of your code and it is more performant.

  1. We don't actually get the records, we update them directly
  2. We update all records that have a expiry_date before now()
  3. All these records now have the status equals to 1

Since we don't store the records in memory and we don't need to "build" the Collection, it's far better performance wise.

The drawback is that you lose model events (if you declared any) and mutators, but I assume that's not the case here.

If you need to access all models mutators, methods, events (now or in the future), then use the following code:

public function handle()
{
    $certifications = Certification::query()
        ->where('expiry_date', '<', now())
        ->each(function(Certification $certification){
            $certification->status = '1';
            $certification->save();
        });
}

The main difference is that we actually retrieve the records and build all the Certification instances. It gives you more capabilities but the performances will take a hit.

There are more optimized ways to do this, especially if you have a large number of rows, but this is another topic.


You should run this command in your scheduler at the frequency you wish, for instance every minute:

protected function schedule(Schedule $schedule)
{
    $schedule->command('concert:checkexpiredcertifications')->everyMinute();
}

Every minute, we will update all records that have expiry_date in the past and set their status to '1'.

Of course, you must have a working scheduler to do this, but that's a little bit off topic here (docs here: https://laravel.com/docs/8.x/scheduling#running-the-scheduler).

Ad
source: stackoverflow.com
Ad