Skip to content

Commit 83fd1f6

Browse files
committed
Unique functionality.
1 parent 98e268e commit 83fd1f6

File tree

5 files changed

+153
-30
lines changed

5 files changed

+153
-30
lines changed

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,32 @@ You can configure your scheduler to be marked as `completed_at` if in the you cu
303303

304304
To do so, you can use the `stopable()` method.
305305

306+
### Unique
307+
308+
You can configure your scheduler to store a unique relationship with the target class for mailable by specifying:
309+
310+
```php
311+
->unique()
312+
```
313+
314+
ie:
315+
316+
```php
317+
Scheduler::init()
318+
->mailable(new InvoiceReminderMailable())
319+
->target($user)
320+
->unique()
321+
->save();
322+
323+
Scheduler::init()
324+
->mailable(new InvoiceReminderMailable())
325+
->target($user)
326+
->unique()
327+
->save();
328+
```
329+
330+
This will store a single scheduler for the `$user`.
331+
306332
## Run
307333

308334
Now you have to run a scheduler command in your Kernel, and call:

database/migrations/create_mailator_tables.php.stub

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class CreateMailatorTables extends Migration
1515

1616
$table->string('name', 100)->nullable();
1717
$table->boolean('stopable')->default(false);
18+
$table->boolean('unique')->default(false);
1819
$table->string('tags', 100)->nullable();
1920
$table->text('mailable_class')->nullable();
2021
$table->nullableMorphs('targetable');

src/Models/Concerns/HasTarget.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@
55
use Binarcode\LaravelMailator\Models\MailatorSchedule;
66
use Illuminate\Database\Eloquent\Model;
77
use Illuminate\Database\Eloquent\Relations\MorphTo;
8+
use Illuminate\Database\Query\Builder;
89

910
/**
1011
* Trait HasTarget
1112
* @mixin MailatorSchedule
13+
* @method static Builder|MailatorSchedule targetableType($class)
14+
* @method static Builder|MailatorSchedule mailableClass($class)
15+
* @method static Builder|MailatorSchedule targetableId($id)
1216
* @package Binarcode\LaravelMailator\Models\Concerns
1317
*/
1418
trait HasTarget
@@ -25,4 +29,19 @@ public function target(Model $target): self
2529

2630
return $this;
2731
}
32+
33+
public function scopeTargetableType($query, $class)
34+
{
35+
$query->where('targetable_type', $class);
36+
}
37+
38+
public function scopeMailableClass($query, $class)
39+
{
40+
$query->where('mailable_class', 'LIKE', "%{$class}%");
41+
}
42+
43+
public function scopeTargetableId($query, $id)
44+
{
45+
$query->where('targetable_id', $id);
46+
}
2847
}

src/Models/MailatorSchedule.php

Lines changed: 65 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Binarcode\LaravelMailator\Models;
44

5+
use App\Domains\ResultDocuments\Models\ResultDocument;
56
use Binarcode\LaravelMailator\Actions\Action;
67
use Binarcode\LaravelMailator\Actions\ResolveGarbageAction;
78
use Binarcode\LaravelMailator\Actions\RunSchedulersAction;
@@ -32,23 +33,24 @@
3233
/**
3334
* Class MailatorSchedule.
3435
*
35-
* @property string tags
36-
* @property string name
37-
* @property string stopable
38-
* @property string targetable_type
39-
* @property string targetable_id
40-
* @property string mailable_class
41-
* @property string delay_minutes
42-
* @property string time_frame_origin
43-
* @property array constraints
44-
* @property Carbon timestamp_target
45-
* @property array recipients
46-
* @property string action
47-
* @property Closure when
48-
* @property Carbon last_failed_at
49-
* @property Carbon last_sent_at
50-
* @property Carbon completed_at
51-
* @property string frequency_option
36+
* @property string $tags
37+
* @property string $name
38+
* @property string $stopable
39+
* @property string $unique
40+
* @property string $targetable_type
41+
* @property string $targetable_id
42+
* @property string $mailable_class
43+
* @property string $delay_minutes
44+
* @property string $time_frame_origin
45+
* @property array $constraints
46+
* @property Carbon $timestamp_target
47+
* @property array $recipients
48+
* @property string $action
49+
* @property Closure $when
50+
* @property Carbon $last_failed_at
51+
* @property Carbon $last_sent_at
52+
* @property Carbon $completed_at
53+
* @property string $frequency_option
5254
* @method static MailatorSchedulerBuilder query()
5355
*/
5456
class MailatorSchedule extends Model
@@ -88,6 +90,7 @@ public function getTable()
8890
'end_at' => 'datetime',
8991
'completed_at' => 'datetime',
9092
'stopable' => 'boolean',
93+
'unique' => 'boolean',
9194
];
9295

9396
protected $attributes = [
@@ -103,8 +106,8 @@ public function mailable(Mailable $mailable): self
103106
{
104107
if ($mailable instanceof Constraintable) {
105108
collect($mailable->constraints())
106-
->filter(fn ($constraint) => $constraint instanceof SendScheduleConstraint)
107-
->each(fn (SendScheduleConstraint $constraint) => $this->constraint($constraint));
109+
->filter(fn($constraint) => $constraint instanceof SendScheduleConstraint)
110+
->each(fn(SendScheduleConstraint $constraint) => $this->constraint($constraint));
108111
}
109112

110113
$this->mailable_class = serialize($mailable);
@@ -183,6 +186,18 @@ public function isStopable(): bool
183186
return (bool) $this->stopable;
184187
}
185188

189+
public function unique(): self
190+
{
191+
$this->unique = true;
192+
193+
return $this;
194+
}
195+
196+
public function isUnique(): bool
197+
{
198+
return (bool) $this->unique;
199+
}
200+
186201
public function after(CarbonInterface $date = null): self
187202
{
188203
$this->time_frame_origin = static::TIME_FRAME_ORIGIN_AFTER;
@@ -303,7 +318,7 @@ public function recipients(...$recipients): self
303318
{
304319
$this->recipients = array_merge(collect($recipients)
305320
->flatten()
306-
->filter(fn ($email) => $this->ensureValidEmail($email))
321+
->filter(fn($email) => $this->ensureValidEmail($email))
307322
->unique()
308323
->toArray(), $this->recipients ?? []);
309324

@@ -329,15 +344,15 @@ public function shouldSend(): bool
329344
try {
330345
$this->load('logs');
331346

332-
if (! $this->configurationsPasses()) {
347+
if (!$this->configurationsPasses()) {
333348
return false;
334349
}
335350

336-
if (! $this->whenPasses()) {
351+
if (!$this->whenPasses()) {
337352
return false;
338353
}
339354

340-
if (! $this->eventsPasses()) {
355+
if (!$this->eventsPasses()) {
341356
if ($this->isStopable()) {
342357
$this->markComplete();
343358
}
@@ -394,7 +409,7 @@ public static function run(): void
394409

395410
public function hasCustomAction(): bool
396411
{
397-
return ! is_null($this->action);
412+
return !is_null($this->action);
398413
}
399414

400415
public function getMailable(): ?Mailable
@@ -449,13 +464,13 @@ public function markAsFailed(string $failureReason): self
449464
public function getRecipients(): array
450465
{
451466
return collect($this->recipients)
452-
->filter(fn ($email) => $this->ensureValidEmail($email))
467+
->filter(fn($email) => $this->ensureValidEmail($email))
453468
->toArray();
454469
}
455470

456471
protected function ensureValidEmail(string $email): bool
457472
{
458-
return ! Validator::make(
473+
return !Validator::make(
459474
compact('email'),
460475
['email' => 'required|email']
461476
)->fails();
@@ -468,7 +483,7 @@ public function actionClass(Action $action): self
468483
return $this;
469484
}
470485

471-
public function tag(string | array $tag): self
486+
public function tag(string|array $tag): self
472487
{
473488
if (is_array($tag)) {
474489
$tag = implode(',', $tag);
@@ -519,7 +534,7 @@ public function markComplete(): self
519534

520535
public function isCompleted(): bool
521536
{
522-
return ! is_null($this->completed_at);
537+
return !is_null($this->completed_at);
523538
}
524539

525540
public function failedLastTimes(int $times): bool
@@ -541,16 +556,36 @@ public function timestampTarget(): ?CarbonInterface
541556

542557
public function isRepetitive(): bool
543558
{
544-
return ! $this->isOnce();
559+
return !$this->isOnce();
545560
}
546561

547562
public function wasSentOnce(): bool
548563
{
549-
return ! is_null($this->last_sent_at);
564+
return !is_null($this->last_sent_at);
550565
}
551566

552567
public function getConstraints(): ConstraintsCollection
553568
{
554569
return ConstraintsCollection::make($this->constraints);
555570
}
571+
572+
public function save(array $options = [])
573+
{
574+
if (!$this->isUnique()) {
575+
return parent::save($options);
576+
}
577+
578+
$mailable = get_class(unserialize($this->mailable_class));
579+
580+
$exists = static:: targetableType($this->targetable_type)
581+
->targetableId($this->targetable_id)
582+
->mailableClass($mailable)
583+
->exists();
584+
585+
if ($exists) {
586+
return false;
587+
}
588+
589+
return parent::save($options);
590+
}
556591
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace Binarcode\LaravelMailator\Tests\Feature;
4+
5+
use Binarcode\LaravelMailator\Scheduler;
6+
use Binarcode\LaravelMailator\Tests\database\Factories\UserFactory;
7+
use Binarcode\LaravelMailator\Tests\Fixtures\Constraints\DynamicContraint;
8+
use Binarcode\LaravelMailator\Tests\Fixtures\InvoiceReminderMailable;
9+
use Binarcode\LaravelMailator\Tests\TestCase;
10+
use Illuminate\Support\Facades\Mail;
11+
12+
class UniqueSchedulerTest extends TestCase
13+
{
14+
public function test_unique_per_target_will_prevent_duplications(): void
15+
{
16+
Mail::fake();
17+
$user = UserFactory::one();
18+
19+
Mail::assertNothingSent();
20+
21+
Scheduler::init()
22+
->mailable(new InvoiceReminderMailable())
23+
->target($user)
24+
->unique()
25+
->save();
26+
27+
Scheduler::init()
28+
->mailable(new InvoiceReminderMailable())
29+
->target($user)
30+
->unique()
31+
->save();
32+
33+
self::assertCount(1, $user->schedulers()->get());
34+
35+
Scheduler::init()
36+
->mailable(new InvoiceReminderMailable())
37+
->target($user)
38+
->save();
39+
40+
self::assertCount(2, $user->schedulers()->get());
41+
}
42+
}

0 commit comments

Comments
 (0)