PHPackages                             devsrv/laravel-scheduled-action - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. devsrv/laravel-scheduled-action

ActiveLibrary[Database &amp; ORM](/categories/database)

devsrv/laravel-scheduled-action
===============================

Handle Scheduled Model Action For Laravel

v3.1.0(3y ago)18195MITPHPPHP ^8.1|^8.2

Since Jul 1Pushed 3y ago2 watchersCompare

[ Source](https://github.com/devsrv/laravel-scheduled-model-action)[ Packagist](https://packagist.org/packages/devsrv/laravel-scheduled-action)[ RSS](/packages/devsrv-laravel-scheduled-action/feed)WikiDiscussions master Synced 3w ago

READMEChangelog (7)Dependencies (5)Versions (9)Used By (0)

Laravel Scheduled Action
========================

[](#laravel-scheduled-action)

[![Latest Version on Packagist](https://camo.githubusercontent.com/59f88f5be65b14dfabb2a037b24f6751bc954ded267c4d972e740dc92e7f3155/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6465767372762f6c61726176656c2d7363686564756c65642d616374696f6e2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/devsrv/laravel-scheduled-action)[![Total Downloads](https://camo.githubusercontent.com/67a3c234d7c42578cf57842716d82e69beac09fee7dc96e75558aaf754387e1a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6465767372762f6c61726176656c2d7363686564756c65642d616374696f6e2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/devsrv/laravel-scheduled-action)[![GitHub Tests Action Status](https://github.com/devsrv/laravel-scheduled-model-action/actions/workflows/test.yaml/badge.svg)](https://github.com/devsrv/laravel-scheduled-model-action/actions/workflows/test.yaml)

Handle scheduled tasks associated with Eloquent models.

 [![create schedule](https://camo.githubusercontent.com/18257c6e74d4a1f65ac9c47abbbef68becb4ca9ba1eebf87069ddaef759b4972/68747470733a2f2f62696e6172796d6573682e6465762f6173736574732f7061636b6167652f616374696f6e732d6372656174652d7461736b31312e737667)](https://camo.githubusercontent.com/18257c6e74d4a1f65ac9c47abbbef68becb4ca9ba1eebf87069ddaef759b4972/68747470733a2f2f62696e6172796d6573682e6465762f6173736574732f7061636b6167652f616374696f6e732d6372656174652d7461736b31312e737667) [![poll schedules](https://camo.githubusercontent.com/d6444dbe7f6d27ca38eb48716945f2342027d217d7ec60c79b68813349766196/68747470733a2f2f62696e6172796d6573682e6465762f6173736574732f7061636b6167652f616374696f6e732d706f6c6c2d3031312e737667)](https://camo.githubusercontent.com/d6444dbe7f6d27ca38eb48716945f2342027d217d7ec60c79b68813349766196/68747470733a2f2f62696e6172796d6573682e6465762f6173736574732f7061636b6167652f616374696f6e732d706f6c6c2d3031312e737667)

For any scheduled task we can directly use Laravel's [queue](https://laravel.com/docs/8.x/queues) but what if that task needs to be modified in some way before it gets executed?

This package stores all the tasks that needs to run on a future date &amp; time and executes each only on the day when it is scheduled to run so that we get the chance to modify the task before it gets executed.

It uses Laravel's task [scheduling](https://laravel.com/docs/8.x/scheduling) to figure out &amp; handle the tasks that needs to be run for the current day at the specified time for that task, and sends the task payload to a [receiver class](https://github.com/devsrv/laravel-scheduled-model-action#step---3-) of your app ([configurable](#%EF%B8%8F-publish-config)). So how to perform the task is totally up to you.

💡 How it works:
---------------

[](#-how-it-works)

- This package creates one table `model_actions`
- Every task has 4 satatus `PENDING` `FINISHED` `CANCELLED` `DISPATCHED`
- The `scheduledaction:poll` artisan command polls `PENDING` tasks for the present day and passes the tasks payload to your receiver class.
- Set how often you want the poll to happen and how many tasks needs to be passed to your receiver (the above [example](#%EF%B8%8F-add-scheduled-task-to-appconsolekernelphp) shows 10 per hour)
- `PENDING` tasks gets run at specified date &amp; time, remember to mark the task as `FINISHED` or `CANCELLED` based on how it was handled [check example](#step---4-).
- Most likely you'll use queue to run a task at a specified time so after dispatching to a queued job you might want to set the status as `DISPATCHED`

Installation
------------

[](#installation)

```
composer require devsrv/laravel-scheduled-action
```

Setup
-----

[](#setup)

#### ✔️ publish migrations

[](#️-publish-migrations)

```
php artisan vendor:publish --provider="Devsrv\ScheduledAction\ScheduledActionServiceProvider" --tag="migrations"
```

#### ✔️ run migrations

[](#️-run-migrations)

```
php artisan migrate
```

#### ✔️ publish config

[](#️-publish-config)

```
php artisan vendor:publish --provider="Devsrv\ScheduledAction\ScheduledActionServiceProvider" --tag="config"
```

```
// the class that takes care of how to perform the task, the payload will be passed to this invokable class
return [
    'receiver' => \App\Http\AutoAction\ScheduledActionReceiver::class, 👈 needs to be invokable
];
```

#### ✔️ Add Scheduled Task to `app/Console/Kernel.php`

[](#️-add-scheduled-task-to-appconsolekernelphp)

```
$schedule->command('scheduledaction:poll --tasks=10')->hourly();  // poll pending tasks (10 tasks every hour & sends payload to your receiver, customize as per your app)
```

#### ✔️ Use the `HasScheduledAction` trait in your models

[](#️-use-the-hasscheduledaction-trait-in-your-models)

```
use Devsrv\ScheduledAction\Traits\HasScheduledAction;

class Candidate extends Model
{
    use HasFactory, HasScheduledAction;

    ...
}
```

There are many fluent methods to interact with the scheduled action
-------------------------------------------------------------------

[](#there-are-many-fluent-methods-to-interact-with-the-scheduled-action)

### Get

[](#get)

```
use Devsrv\ScheduledAction\Models\ModelAction;
use Devsrv\ScheduledAction\Facades\Action;

$model = \App\Models\Candidate::find(10);

$model->scheduledActions()->get();
$model->scheduledActions()->finished()->get();
$model->scheduledActions()->cancelled()->first();
$model->scheduledActions()->pending()->get();
$model->scheduledActions()->dispatched()->paginate();
$model->scheduledActions()->pending()->toActBetweenTime(Carbon::createFromTimeString('14:00:00'), Carbon::createFromTimeString('16:30:00'))->get();
$model->scheduledActions()->pending()->whereExtraProperty('prefers', 'mail')->get();
$model->scheduledActions()->whereExtraProperty('channel', 'slack')->get();
$model->scheduledActions()->whereExtraProperties(['prefers' => 'mail', 'applicant' => 27])->get();
$model->scheduledActions()->wherePropertyContains('languages', ['en', 'de'])->get();
$model->scheduledActions()->first()->isPending();
$model->scheduledActions()->first()->getExtraProperty('customProperty');

$task = ModelAction::find(1);

$task->getExtraProperty('customProperty');
$task->act_time;
$task->action;
$task->actionable; 	// associated model

$task->isPending;	    // bool
$task->isFinished; 	    // bool
$task->isDispatched; 	    // bool
$task->isCancelled; 	    // bool
$task->isRecurring; 	    // bool

ModelAction::finished()->get();
ModelAction::forModel($modlel)->pending()->get();
ModelAction::forClass(Candidate::class)->get();
ModelAction::whereAction('EMAIL')->get();
ModelAction::forClass(Candidate::class)->modelId(10)->get();
ModelAction::modelIdIn([10, 11, 12])->get();
ModelAction::forModel($modlel)->whereProperty('mailable', \App\Mail\RejectMail::class)->get();
ModelAction::forModel($modlel)->whereProperties(['type' => 'info', 'applicant' => 27])->get();
ModelAction::wherePropertyContains('languages', ['en', 'de'])->get();
ModelAction::where('properties->type', 'success')->get();

\Devsrv\ScheduledAction\Facades\Action::needsToRunOn(now()->tomorrow(), 10, 'asc');
\Devsrv\ScheduledAction\Facades\Action::needsToRunToday(3);
```

### Create

[](#create)

```
$action = $model->scheduledActions()->create([
    'action' => 'EMAIL',
    'properties' => ['color' => 'silver'],
    'status' => \Devsrv\ScheduledAction\Enums\Status::PENDING,
    'act_date' => now(),
    'act_time' => now()->setHour(11),
]);

$model->scheduledActions()->createMany([]);

ModelAction::for(Candidate::find(10))
    ->actWith('EMAIL')
    ->actAt(Carbon::tomorrow()->setHour(11))    // date + time will be set together
    ->setExtraProperties(['foo' => 'bar'])
    ->createSchedule();

ModelAction::for($model)
    ->actWith('EMAIL')
    ->actDate($actDate)
    ->actTime(Carbon::createFromTimeString('20:00:00'))
    ->setExtraProperties(['foo' => 'bar'])
    ->createSchedule();

ModelAction::for($model)->actWith('EMAIL')->actTime($carbon)->asDispatched()->createSchedule();
```

### Update

[](#update)

```
$action->setPending()->save();
$action->setCancelled()->save();
$action->setDispatched()->save();
$action->setFinished()->save();							// default sets finished_at as now()
$action->setFinished($carbon)->save();						// set a finished_at time
$action->mergeExtraProperties(['key' => 'val'])->save();  			// merges extra properties
$action->withExtraProperties([])->save();                   			// overwrites existing
$action->setPending()->setActAt($actAt)->save();
$action->setActAt($carbon)->save();						// date and time will be extracted
$action->setActDate($carbon)->save();						// only date will be used
$action->setActTime($carbon)->save();						// only time will be used
```

Example
-------

[](#example)

> imagine a job portal where an application is auto approved after 3 days of apply unless it was auto rejected by some qualifier checks by bot, during that period the admin may override the application status or prevent the auto mail sending or modify the mail content

#### Step - 1 :

[](#step---1-)

Some event happend and a task is created to execute on future day &amp; time```
ModelAction::for($application)
->actWith('MAIL')
->actAt($inThreeDays)
->setExtraProperties([
  'mailable' => ApproveApplication::class,
  'template' => $template
])
->createSchedule();
```

#### Step - 2 :

[](#step---2-)

admin decides to alter the task```
public function modifyScheduledTask() {
    $this->validate();

    $this->task
        ->setActDate(Carbon::createFromFormat('m/d/Y', $this->act_date))
        ->setActTime(Carbon::createFromTimeString($this->act_time))
        ->mergeExtraProperties([
            'template' => $this->templateid,
            'extra_data' => $this->role
        ])
        ->save();

    $this->info('schedule updated');
}

public function cancelSchedule() {
    $this->task->setCancelled()->save();
    $this->info('schedule cancelled');
}
```

#### Step - 3 :

[](#step---3-)

receiver class gets task payload &amp; passes the task to classes based on task action (for this example sending email)```
