From 3086cf2899738621a78a067ba8a2b6a3ebe18eb4 Mon Sep 17 00:00:00 2001 From: Sammyjo20 <29132017+Sammyjo20@users.noreply.github.com> Date: Tue, 2 Aug 2022 19:08:33 +0100 Subject: [PATCH 1/6] wip --- config/haystack.php | 13 ++++ database/factories/HaystackDataFactory.php | 21 +++++++ .../create_haystack_data_table.php.stub | 28 +++++++++ src/Models/Haystack.php | 10 +++ src/Models/HaystackData.php | 63 +++++++++++++++++++ .../Database/Migrations/create_jobs_table.php | 36 ----------- tests/TestCase.php | 2 +- tests/Unit/HaystackDataTest.php | 38 +++++++++++ 8 files changed, 174 insertions(+), 37 deletions(-) create mode 100644 database/factories/HaystackDataFactory.php create mode 100644 database/migrations/create_haystack_data_table.php.stub create mode 100644 src/Models/HaystackData.php delete mode 100644 tests/Database/Migrations/create_jobs_table.php create mode 100644 tests/Unit/HaystackDataTest.php diff --git a/config/haystack.php b/config/haystack.php index 02ce75d..c28e758 100644 --- a/config/haystack.php +++ b/config/haystack.php @@ -2,6 +2,19 @@ return [ + /* + |-------------------------------------------------------------------------- + | Return All Haystack Data When Finished + |-------------------------------------------------------------------------- + | + | This value if set to true, will instruct Haystack to query all the + | haystack data rows out of the database and return them to the + | then/finally/catch blocks as a collection. + | + */ + + 'return_all_haystack_data_when_finished' => true, + /* |-------------------------------------------------------------------------- | Queue Haystack Jobs Automatically diff --git a/database/factories/HaystackDataFactory.php b/database/factories/HaystackDataFactory.php new file mode 100644 index 0000000..4cdcd2b --- /dev/null +++ b/database/factories/HaystackDataFactory.php @@ -0,0 +1,21 @@ +id(); + $table->timestamps(); + $table->foreignIdFor(Haystack::class)->constrained()->cascadeOnDelete(); + $table->string('key'); + $table->binary('value'); + $table->string('cast')->nullable(); + + $table->unique(['haystack_id', 'key']); + }); + } + + public function down() + { + Schema::dropIfExists('haystack_data'); + } +}; diff --git a/src/Models/Haystack.php b/src/Models/Haystack.php index 383a696..f7eb003 100644 --- a/src/Models/Haystack.php +++ b/src/Models/Haystack.php @@ -78,6 +78,16 @@ public function bales(): HasMany return $this->hasMany(HaystackBale::class, 'haystack_id', 'id')->orderBy('id', 'asc'); } + /** + * The Haystack's data. + * + * @return HasMany + */ + public function data(): HasMany + { + return $this->hasMany(HaystackData::class); + } + /** * Start building a Haystack. * diff --git a/src/Models/HaystackData.php b/src/Models/HaystackData.php new file mode 100644 index 0000000..bb3113b --- /dev/null +++ b/src/Models/HaystackData.php @@ -0,0 +1,63 @@ +belongsTo(Haystack::class); + } + + /** + * Set the cast attribute and apply the casts. + * + * @param string|null $cast + * @return void + */ + public function setCastAttribute(?string $cast): void + { + if (! is_null($cast)) { + $this->casts = ['value' => $cast]; + } + + $this->attributes['cast'] = $cast; + } +} diff --git a/tests/Database/Migrations/create_jobs_table.php b/tests/Database/Migrations/create_jobs_table.php deleted file mode 100644 index e10f84f..0000000 --- a/tests/Database/Migrations/create_jobs_table.php +++ /dev/null @@ -1,36 +0,0 @@ -bigIncrements('id'); - $table->string('queue')->index(); - $table->longText('payload'); - $table->unsignedTinyInteger('attempts'); - $table->unsignedInteger('reserved_at')->nullable(); - $table->unsignedInteger('available_at'); - $table->unsignedInteger('created_at'); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('jobs'); - } -}; diff --git a/tests/TestCase.php b/tests/TestCase.php index f02f4ca..e1ada7a 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -41,7 +41,7 @@ public function getEnvironmentSetUp($app) $migration = include __DIR__.'/../database/migrations/create_haystack_bales_table.php.stub'; $migration->up(); - $migration = include __DIR__.'/Database/Migrations/create_jobs_table.php'; + $migration = include __DIR__.'/../database/migrations/create_haystack_data_table.php.stub'; $migration->up(); } } diff --git a/tests/Unit/HaystackDataTest.php b/tests/Unit/HaystackDataTest.php new file mode 100644 index 0000000..b3ef8fa --- /dev/null +++ b/tests/Unit/HaystackDataTest.php @@ -0,0 +1,38 @@ +create(); + + $haystackData = HaystackData::factory()->for($haystack)->create([ + 'key' => 'name', + 'cast' => null, + 'value' => 'Sam', + ]); + + expect($haystackData->haystack_id)->toEqual($haystack->getKey()); + expect($haystackData->haystack->getKey())->toEqual($haystack->getKey()); +}); + +test('a haystack data row can cast the data when retrieving', function () { + $haystackData = HaystackData::factory()->for(Haystack::factory())->create([ + 'key' => 'data', + 'cast' => 'collection', + 'value' => ['name' => 'Sam', 'age' => 22], + ]); + + expect($haystackData->value)->toBeInstanceOf(Collection::class); + expect($haystackData->value)->toEqual(new Collection(['name' => 'Sam', 'age' => 22])); +}); + +test('a haystack data row can cast the data to a custom cast when retrieving', function () { + // +}); + +test('a haystack data row can cast the data to a dto when retrieving', function () { + // +}); From a85c2464ae083beacbf40ac5b825a1ed1a98b83f Mon Sep 17 00:00:00 2001 From: Sammyjo20 <29132017+Sammyjo20@users.noreply.github.com> Date: Wed, 3 Aug 2022 00:14:06 +0100 Subject: [PATCH 2/6] Haystack data finished --- composer.json | 1 + .../create_haystacks_table.php.stub | 1 + src/Builders/HaystackBuilder.php | 20 +++ src/Concerns/ManagesBales.php | 88 ++++++++++--- src/Concerns/Stackable.php | 57 ++++++-- src/Contracts/StackableJob.php | 27 ++++ src/Models/Haystack.php | 1 + src/Models/HaystackData.php | 27 +++- tests/Feature/HaystackTest.php | 58 ++++++++ tests/Feature/StackableJobTest.php | 39 ++++++ tests/Fixtures/DataObjects/Repository.php | 12 ++ tests/Fixtures/Jobs/GetAllAndCacheDataJob.php | 42 ++++++ tests/Fixtures/Jobs/GetAndCacheDataJob.php | 42 ++++++ tests/Fixtures/Jobs/SetDataJob.php | 39 ++++++ tests/Unit/HaystackDataTest.php | 10 +- tests/Unit/HaystackTest.php | 124 ++++++++++++++++-- 16 files changed, 539 insertions(+), 49 deletions(-) create mode 100644 tests/Fixtures/DataObjects/Repository.php create mode 100644 tests/Fixtures/Jobs/GetAllAndCacheDataJob.php create mode 100644 tests/Fixtures/Jobs/GetAndCacheDataJob.php create mode 100644 tests/Fixtures/Jobs/SetDataJob.php diff --git a/composer.json b/composer.json index a6b5b1b..c491631 100644 --- a/composer.json +++ b/composer.json @@ -26,6 +26,7 @@ "spatie/laravel-package-tools": "^1.9.2" }, "require-dev": { + "jessarcher/laravel-castable-data-transfer-object": "^2.2", "laravel/pint": "^1.0", "orchestra/testbench": "^7.0", "pestphp/pest": "^1.21", diff --git a/database/migrations/create_haystacks_table.php.stub b/database/migrations/create_haystacks_table.php.stub index 653e7a2..57549ea 100644 --- a/database/migrations/create_haystacks_table.php.stub +++ b/database/migrations/create_haystacks_table.php.stub @@ -18,6 +18,7 @@ return new class extends Migration $table->dateTime('started_at')->nullable(); $table->dateTime('resume_at')->nullable(); $table->dateTime('finished_at')->nullable(); + $table->boolean('return_data')->default(true); }); } diff --git a/src/Builders/HaystackBuilder.php b/src/Builders/HaystackBuilder.php index b4edc0f..68920f7 100644 --- a/src/Builders/HaystackBuilder.php +++ b/src/Builders/HaystackBuilder.php @@ -69,6 +69,13 @@ class HaystackBuilder */ protected ?Closure $globalMiddleware = null; + /** + * Should we return the data when the haystack finishes? + * + * @var bool + */ + protected bool $returnDataOnFinish = true; + /** * Constructor */ @@ -263,6 +270,7 @@ protected function createHaystack(): Haystack $haystack->on_catch = $this->onCatch; $haystack->on_finally = $this->onFinally; $haystack->middleware = $this->globalMiddleware; + $haystack->return_data = $this->returnDataOnFinish; $haystack->save(); $haystack->bales()->insert($this->prepareJobsForInsert($haystack)); @@ -270,6 +278,18 @@ protected function createHaystack(): Haystack return $haystack; } + /** + * Specify if you do not want haystack to return the data. + * + * @return $this + */ + public function dontReturnData(): static + { + $this->returnDataOnFinish = false; + + return $this; + } + /** * Get all the jobs in the builder. * diff --git a/src/Concerns/ManagesBales.php b/src/Concerns/ManagesBales.php index e199057..611afe5 100644 --- a/src/Concerns/ManagesBales.php +++ b/src/Concerns/ManagesBales.php @@ -5,14 +5,17 @@ use Closure; use Carbon\CarbonImmutable; use Carbon\CarbonInterface; -use Illuminate\Queue\Jobs\Job; use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Support\LazyCollection; +use InvalidArgumentException; use Sammyjo20\LaravelHaystack\Data\NextJob; use Sammyjo20\LaravelHaystack\Models\HaystackBale; use Sammyjo20\LaravelHaystack\Helpers\CarbonHelper; use Sammyjo20\LaravelHaystack\Contracts\StackableJob; use Sammyjo20\LaravelHaystack\Data\PendingHaystackBale; use Sammyjo20\LaravelHaystack\Actions\CreatePendingHaystackBale; +use Sammyjo20\LaravelHaystack\Models\HaystackData; +use Illuminate\Support\Collection; trait ManagesBales { @@ -66,8 +69,8 @@ public function getNextJob(): ?NextJob /** * Dispatch the next job. * - * @param StackableJob|null $job - * @param int|CarbonInterface|null $delayInSecondsOrCarbon + * @param StackableJob|null $job + * @param int|CarbonInterface|null $delayInSecondsOrCarbon * @return void */ public function dispatchNextJob(StackableJob $job = null, int|CarbonInterface $delayInSecondsOrCarbon = null): void @@ -141,7 +144,7 @@ public function restart(): void /** * Finish the Haystack. * - * @param bool $fail + * @param bool $fail * @return void */ public function finish(bool $fail = false): void @@ -152,13 +155,17 @@ public function finish(bool $fail = false): void $this->update(['finished_at' => now()]); + $returnAllData = config('haystack.return_all_haystack_data_when_finished', false); + + $allData = $this->return_data === true && $returnAllData === true ? $this->allData() : null; + $fail === true - ? $this->executeClosure($this->on_catch) - : $this->executeClosure($this->on_then); + ? $this->executeClosure($this->on_catch, $allData) + : $this->executeClosure($this->on_then, $allData); // Always execute the finally closure. - $this->executeClosure($this->on_finally); + $this->executeClosure($this->on_finally, $allData); // Now finally delete itself. @@ -180,10 +187,10 @@ public function fail(): void /** * Append a new job to the job stack. * - * @param ShouldQueue $job - * @param int $delayInSeconds - * @param string|null $queue - * @param string|null $connection + * @param ShouldQueue $job + * @param int $delayInSeconds + * @param string|null $queue + * @param string|null $connection * @return void */ public function appendJob(ShouldQueue $job, int $delayInSeconds = 0, string $queue = null, string $connection = null): void @@ -196,7 +203,7 @@ public function appendJob(ShouldQueue $job, int $delayInSeconds = 0, string $que /** * Append the pending job to the Haystack. * - * @param PendingHaystackBale $pendingJob + * @param PendingHaystackBale $pendingJob * @return void */ public function appendPendingJob(PendingHaystackBale $pendingJob): void @@ -212,24 +219,73 @@ public function appendPendingJob(PendingHaystackBale $pendingJob): void /** * Execute the closure. * - * @param Closure|null $closure + * @param Closure|null $closure + * @param Collection|null $data * @return void */ - protected function executeClosure(?Closure $closure): void + protected function executeClosure(?Closure $closure, ?Collection $data = null): void { if ($closure instanceof Closure) { - $closure(); + $closure($data); } } /** * Pause the haystack. * - * @param CarbonImmutable $resumeAt + * @param CarbonImmutable $resumeAt * @return void */ public function pause(CarbonImmutable $resumeAt): void { $this->update(['resume_at' => $resumeAt]); } + + /** + * Store data on the Haystack. + * + * @param string $key + * @param mixed $value + * @param string|null $cast + * @return ManagesBales|\Sammyjo20\LaravelHaystack\Models\Haystack + */ + public function setData(string $key, mixed $value, string $cast = null): self + { + if (is_null($cast) && is_string($value) === false && is_int($value) === false) { + throw new InvalidArgumentException('You must specify a cast if the value is not a string or integer.'); + } + + $this->data()->updateOrCreate(['key' => $key], [ + 'cast' => $cast, + 'value' => $value, + ]); + + return $this; + } + + /** + * Retrieve data by a key from the Haystack. + * + * @param string $key + * @param mixed|null $default + * @return mixed + */ + public function getData(string $key, mixed $default = null): mixed + { + $data = $this->data()->where('key', $key)->first(); + + return $data instanceof HaystackData ? $data->value : $default; + } + + /** + * Retrieve all the data from the Haystack. + * + * @return Collection + */ + public function allData(): Collection + { + return $this->data()->orderBy('id')->get()->mapWithKeys(function ($value, $key) { + return [$value->key => $value->value]; + }); + } } diff --git a/src/Concerns/Stackable.php b/src/Concerns/Stackable.php index e43fab4..9516dc5 100644 --- a/src/Concerns/Stackable.php +++ b/src/Concerns/Stackable.php @@ -4,6 +4,8 @@ use Carbon\CarbonInterface; use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Support\Collection; +use Sammyjo20\LaravelHaystack\Contracts\StackableJob; use Sammyjo20\LaravelHaystack\Models\Haystack; use Sammyjo20\LaravelHaystack\Models\HaystackBale; use Sammyjo20\LaravelHaystack\Helpers\CarbonHelper; @@ -38,7 +40,7 @@ public function getHaystack(): Haystack /** * Set the Haystack onto the job. * - * @param Haystack $haystack + * @param Haystack $haystack * @return $this */ public function setHaystack(Haystack $haystack): static @@ -69,7 +71,7 @@ public function nextJob(int|CarbonInterface $delayInSecondsOrCarbon = null): sta /** * Dispatch the next bale in the haystack. Yee-haw! * - * @param int|CarbonInterface|null $delayInSecondsOrCarbon + * @param int|CarbonInterface|null $delayInSecondsOrCarbon * @return $this * * @throws StackableException @@ -82,7 +84,7 @@ public function nextBale(int|CarbonInterface $delayInSecondsOrCarbon = null): st /** * Release the job for haystack to process later. * - * @param int|CarbonInterface $delayInSecondsOrCarbon + * @param int|CarbonInterface $delayInSecondsOrCarbon * @return $this */ public function longRelease(int|CarbonInterface $delayInSecondsOrCarbon): static @@ -121,10 +123,10 @@ public function failHaystack(): static /** * Append a job to the Haystack. * - * @param ShouldQueue $job - * @param int $delayInSeconds - * @param string|null $queue - * @param string|null $connection + * @param ShouldQueue $job + * @param int $delayInSeconds + * @param string|null $queue + * @param string|null $connection * @return $this */ public function appendToHaystack(ShouldQueue $job, int $delayInSeconds = 0, string $queue = null, string $connection = null): static @@ -147,7 +149,7 @@ public function getHaystackBaleId(): int /** * Set the Haystack bale ID. * - * @param int $haystackBaleId + * @param int $haystackBaleId * @return $this */ public function setHaystackBaleId(int $haystackBaleId): static @@ -160,7 +162,7 @@ public function setHaystackBaleId(int $haystackBaleId): static /** * Pause the haystack. We also need to delete the current row. * - * @param int|CarbonInterface $delayInSecondsOrCarbon + * @param int|CarbonInterface $delayInSecondsOrCarbon * @return $this * * @throws StackableException @@ -182,4 +184,41 @@ public function pauseHaystack(int|CarbonInterface $delayInSecondsOrCarbon): stat return $this; } + + /** + * Set data on the haystack. + * + * @param string $key + * @param mixed $value + * @param string|null $cast + * @return $this + */ + public function setHaystackData(string $key, mixed $value, string $cast = null): static + { + $this->haystack->setData($key, $value, $cast); + + return $this; + } + + /** + * Get data on the haystack. + * + * @param string $key + * @param mixed|null $default + * @return mixed + */ + public function getHaystackData(string $key, mixed $default = null): mixed + { + return $this->haystack->getData($key, $default); + } + + /** + * Get all data on the haystack. + * + * @return mixed + */ + public function allHaystackData(): Collection + { + return $this->haystack->allData(); + } } diff --git a/src/Contracts/StackableJob.php b/src/Contracts/StackableJob.php index cf6207d..8e87479 100644 --- a/src/Contracts/StackableJob.php +++ b/src/Contracts/StackableJob.php @@ -4,6 +4,7 @@ use Carbon\CarbonInterface; use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Support\Collection; use Sammyjo20\LaravelHaystack\Models\Haystack; use Sammyjo20\LaravelHaystack\Tests\Exceptions\StackableException; @@ -96,4 +97,30 @@ public function setHaystackBaleId(int $haystackBaleId): static; * @return $this */ public function pauseHaystack(int|CarbonInterface $delayInSecondsOrCarbon): static; + + /** + * Set data on the haystack. + * + * @param string $key + * @param mixed $value + * @param string|null $cast + * @return $this + */ + public function setHaystackData(string $key, mixed $value, string $cast = null): static; + + /** + * Get data on the haystack. + * + * @param string $key + * @param mixed|null $default + * @return mixed + */ + public function getHaystackData(string $key, mixed $default = null): mixed; + + /** + * Get all data on the haystack. + * + * @return mixed + */ + public function allHaystackData(): Collection; } diff --git a/src/Models/Haystack.php b/src/Models/Haystack.php index f7eb003..a502aac 100644 --- a/src/Models/Haystack.php +++ b/src/Models/Haystack.php @@ -37,6 +37,7 @@ class Haystack extends Model 'started_at' => 'immutable_datetime', 'resume_at' => 'immutable_datetime', 'finished_at' => 'immutable_datetime', + 'return_data' => 'boolean', ]; /** diff --git a/src/Models/HaystackData.php b/src/Models/HaystackData.php index bb3113b..730b3c2 100644 --- a/src/Models/HaystackData.php +++ b/src/Models/HaystackData.php @@ -19,13 +19,6 @@ class HaystackData extends Model */ protected $guarded = []; - /** - * @var array - */ - protected $casts = [ - // - ]; - /** * Create a new factory instance for the model. * @@ -59,5 +52,25 @@ public function setCastAttribute(?string $cast): void } $this->attributes['cast'] = $cast; + $this->attributes['value'] = null; + } + + /** + * Get the cast value. + * + * @param $value + * @return mixed + */ + public function getValueAttribute($value): mixed + { + if (blank($this->cast)) { + return $value; + } + + // We'll now manually add the cast and attempt to cast the attribute. + + $this->casts = ['value' => $this->cast]; + + return $this->castAttribute('value', $value); } } diff --git a/tests/Feature/HaystackTest.php b/tests/Feature/HaystackTest.php index 5871d86..26c574a 100644 --- a/tests/Feature/HaystackTest.php +++ b/tests/Feature/HaystackTest.php @@ -1,11 +1,13 @@ get('catch'))->toBeTrue(); expect(cache()->get('finally'))->toBeTrue(); }); + +test('the closures can receive the data if the option is enabled', function () { + Haystack::build() + ->addJob(new SetDataJob('name', 'Sam')) + ->addJob(new SetDataJob('friend', 'Steve')) + ->then(function ($data) { + cache()->set('then', $data); + }) + ->finally(function ($data) { + cache()->set('finally', $data); + }) + ->dispatch(); + + $data = new Collection([ + 'name' => 'Sam', + 'friend' => 'Steve', + ]); + + expect(cache()->get('then'))->toEqual($data); + expect(cache()->get('finally'))->toEqual($data); +}); + +test('the closures can receive the data if the option is enabled on a per builder instance', function () { + Haystack::build() + ->addJob(new SetDataJob('name', 'Sam')) + ->addJob(new SetDataJob('friend', 'Steve')) + ->then(function ($data) { + cache()->set('then', $data); + }) + ->finally(function ($data) { + cache()->set('finally', $data); + }) + ->dontReturnData() + ->dispatch(); + + expect(cache()->get('then'))->toBeNull(); + expect(cache()->get('finally'))->toBeNull(); +}); + +test('the closures will not receive the data if the option is enabled', function () { + config()->set('haystack.return_all_haystack_data_when_finished', false); + + Haystack::build() + ->addJob(new SetDataJob('name', 'Sam')) + ->addJob(new SetDataJob('friend', 'Steve')) + ->then(function ($data) { + cache()->set('then', $data); + }) + ->finally(function ($data) { + cache()->set('finally', $data); + }) + ->dispatch(); + + expect(cache()->get('then'))->toBeNull(); + expect(cache()->get('finally'))->toBeNull(); +}); diff --git a/tests/Feature/StackableJobTest.php b/tests/Feature/StackableJobTest.php index 1b07994..435c2fa 100644 --- a/tests/Feature/StackableJobTest.php +++ b/tests/Feature/StackableJobTest.php @@ -1,5 +1,6 @@ delay === 120 && $job->queue === 'cowboy' && $job->connection === 'redis'; }); }); + +test('a stackable job can set data and another job can retrieve it', function () { + expect(cache()->get('name'))->toBeNull(); + + Haystack::build() + ->addJob(new SetDataJob('name', 'Sam')) + ->addJob(new GetAndCacheDataJob('name')) + ->dispatch(); + + expect(cache()->get('name'))->toEqual('Sam'); +}); + +test('a stackable job can add haystack data', function () { + Haystack::build() + ->addJob(new SetDataJob('name', 'Sam')) + ->then(function ($data) { + cache()->set('data', $data); + }) + ->dispatch(); + + expect(cache()->get('data'))->toEqual(new Collection(['name' => 'Sam'])); +}); + +test('a stackable job can get all haystack data', function () { + Haystack::build() + ->addJob(new SetDataJob('name', 'Sam')) + ->addJob(new SetDataJob('boss', 'Gareth')) + ->addJob(new GetAllAndCacheDataJob) + ->dispatch(); + + expect(cache()->get('all'))->toEqual(new Collection([ + 'name' => 'Sam', + 'boss' => 'Gareth', + ])); +}); diff --git a/tests/Fixtures/DataObjects/Repository.php b/tests/Fixtures/DataObjects/Repository.php new file mode 100644 index 0000000..9b6a6b0 --- /dev/null +++ b/tests/Fixtures/DataObjects/Repository.php @@ -0,0 +1,12 @@ +allHaystackData(); + + cache()->set('all', $data); + + $this->nextBale(); // Alias of next job + } +} diff --git a/tests/Fixtures/Jobs/GetAndCacheDataJob.php b/tests/Fixtures/Jobs/GetAndCacheDataJob.php new file mode 100644 index 0000000..3b74393 --- /dev/null +++ b/tests/Fixtures/Jobs/GetAndCacheDataJob.php @@ -0,0 +1,42 @@ +getHaystackData($this->key); + + cache()->set($this->key, $data); + + $this->nextBale(); // Alias of next job + } +} diff --git a/tests/Fixtures/Jobs/SetDataJob.php b/tests/Fixtures/Jobs/SetDataJob.php new file mode 100644 index 0000000..c959fe3 --- /dev/null +++ b/tests/Fixtures/Jobs/SetDataJob.php @@ -0,0 +1,39 @@ +setHaystackData($this->key, $this->value); + + $this->nextBale(); // Alias of next job + } +} diff --git a/tests/Unit/HaystackDataTest.php b/tests/Unit/HaystackDataTest.php index b3ef8fa..ce0c20c 100644 --- a/tests/Unit/HaystackDataTest.php +++ b/tests/Unit/HaystackDataTest.php @@ -25,14 +25,8 @@ 'value' => ['name' => 'Sam', 'age' => 22], ]); + $haystackData->refresh(); + expect($haystackData->value)->toBeInstanceOf(Collection::class); expect($haystackData->value)->toEqual(new Collection(['name' => 'Sam', 'age' => 22])); }); - -test('a haystack data row can cast the data to a custom cast when retrieving', function () { - // -}); - -test('a haystack data row can cast the data to a dto when retrieving', function () { - // -}); diff --git a/tests/Unit/HaystackTest.php b/tests/Unit/HaystackTest.php index 613614f..753a9d7 100644 --- a/tests/Unit/HaystackTest.php +++ b/tests/Unit/HaystackTest.php @@ -1,13 +1,19 @@ 'Then'; - $catchClosure = fn () => 'Catch'; - $finallyClosure = fn () => 'Finally'; - $middlewareClosure = fn () => []; + $thenClosure = fn() => 'Then'; + $catchClosure = fn() => 'Catch'; + $finallyClosure = fn() => 'Finally'; + $middlewareClosure = fn() => []; $haystack = new Haystack; $haystack->on_then = $thenClosure; @@ -115,11 +121,11 @@ $haystack->on_then = $value; $haystack->save(); })->with([ - fn () => 'Hello', - fn () => 123, - fn () => true, - fn () => (object) [1], - fn () => [1], + fn() => 'Hello', + fn() => 123, + fn() => true, + fn() => (object)[1], + fn() => [1], ]); test('you must provide an invokable class if you do not provide a closure', function () { @@ -252,3 +258,103 @@ function myFunction() expect($haystack->started_at)->toEqual($startDate); expect($haystack->finished_at)->toEqual($endDate); }); + +test('you can add and get data from the haystack', function () { + $haystack = Haystack::factory()->create(); + + expect($haystack->data()->count())->toEqual(0); + + $haystack = $haystack->setData('name', 'Sam'); + + expect($haystack->data()->count())->toEqual(1); + + $name = $haystack->getData('name'); + + expect($name)->toEqual('Sam'); + + $otherName = $haystack->getData('otherName'); + + expect($otherName)->toBeNull(); + + $age = $haystack->getData('age', 22); + + expect($age)->toEqual(22); + + $allData = $haystack->allData(); + + expect($allData)->toBeInstanceOf(Collection::class); + expect($allData)->toHaveCount(1); + expect($allData['name'])->toEqual('Sam'); +}); + +test('setting the data with the same key twice will overwrite it', function () { + $haystack = Haystack::factory()->create(); + + expect($haystack->data()->count())->toEqual(0); + + $haystack = $haystack->setData('name', 'Sam'); + $name = $haystack->getData('name'); + + expect($name)->toEqual('Sam'); + + $haystack = $haystack->setData('name', 'Leon'); + $name = $haystack->getData('name'); + + expect($name)->toEqual('Leon'); +}); + +test('you can add data with a cast', function () { + $haystack = Haystack::factory()->create(); + + expect($haystack->data()->count())->toEqual(0); + + $repository = ['name' => 'Saloon', 'stars' => 700, 'isLaravel' => false]; + + $haystack->setData('repository', $repository, 'collection'); + + $data = $haystack->getData('repository'); + + expect($data)->toBeInstanceOf(BaseCollection::class); + expect($data['name'])->toEqual('Saloon'); + expect($data['stars'])->toEqual(700); + expect($data['isLaravel'])->toEqual(false); +}); + +test('it throws an exception if you try to enter a non string data without adding a cast', function () { + $haystack = Haystack::factory()->create(); + + expect($haystack->data()->count())->toEqual(0); + + $repository = ['name' => 'Saloon', 'stars' => 700, 'isLaravel' => false]; + + $haystack->setData('name', 'Sam'); + + $haystack->setData('age', 22); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('You must specify a cast if the value is not a string or integer.'); + + $haystack->setData('repository', $repository); +}); + +test('you can get all the data on a haystack at once', function () { + $haystack = Haystack::factory()->create(); + + $repository = new Repository(name: 'Saloon', stars: 700, isLaravel: false); + + $haystack->setData('name', 'Sam'); + $haystack->setData('data', ['name' => 'Sam', 'work' => 'Plannr Technologies'], 'array'); + $haystack->setData('age', 21, 'integer'); + $haystack->setData('repository', $repository, Repository::class); + + expect($haystack->data()->count())->toEqual(4); + + $all = $haystack->allData(); + + expect($all)->toEqual(new Collection([ + 'name' => 'Sam', + 'data' => ['name' => 'Sam', 'work' => 'Plannr Technologies'], + 'age' => 21, + 'repository' => $repository, + ])); +}); From cb1b060164b2dca6797d17ff49eabb17a1afc6c3 Mon Sep 17 00:00:00 2001 From: Sammyjo20 Date: Tue, 2 Aug 2022 23:15:06 +0000 Subject: [PATCH 3/6] PHP CS Fixer --- database/factories/HaystackDataFactory.php | 2 +- src/Concerns/ManagesBales.php | 39 +++++++++---------- src/Concerns/Stackable.php | 31 +++++++-------- src/Contracts/StackableJob.php | 12 +++--- src/Models/HaystackData.php | 5 +-- tests/Feature/HaystackTest.php | 2 +- tests/Feature/StackableJobTest.php | 4 +- tests/Fixtures/DataObjects/Repository.php | 2 + tests/Fixtures/Jobs/GetAllAndCacheDataJob.php | 2 +- tests/Fixtures/Jobs/GetAndCacheDataJob.php | 2 +- tests/Fixtures/Jobs/SetDataJob.php | 1 + tests/Unit/HaystackDataTest.php | 1 - tests/Unit/HaystackTest.php | 27 ++++++------- 13 files changed, 62 insertions(+), 68 deletions(-) diff --git a/database/factories/HaystackDataFactory.php b/database/factories/HaystackDataFactory.php index 4cdcd2b..5ae9bef 100644 --- a/database/factories/HaystackDataFactory.php +++ b/database/factories/HaystackDataFactory.php @@ -2,8 +2,8 @@ namespace Sammyjo20\LaravelHaystack\Database\Factories; -use Illuminate\Database\Eloquent\Factories\Factory; use Sammyjo20\LaravelHaystack\Models\HaystackData; +use Illuminate\Database\Eloquent\Factories\Factory; class HaystackDataFactory extends Factory { diff --git a/src/Concerns/ManagesBales.php b/src/Concerns/ManagesBales.php index 611afe5..c1d5098 100644 --- a/src/Concerns/ManagesBales.php +++ b/src/Concerns/ManagesBales.php @@ -5,17 +5,16 @@ use Closure; use Carbon\CarbonImmutable; use Carbon\CarbonInterface; -use Illuminate\Contracts\Queue\ShouldQueue; -use Illuminate\Support\LazyCollection; use InvalidArgumentException; +use Illuminate\Support\Collection; +use Illuminate\Contracts\Queue\ShouldQueue; use Sammyjo20\LaravelHaystack\Data\NextJob; use Sammyjo20\LaravelHaystack\Models\HaystackBale; +use Sammyjo20\LaravelHaystack\Models\HaystackData; use Sammyjo20\LaravelHaystack\Helpers\CarbonHelper; use Sammyjo20\LaravelHaystack\Contracts\StackableJob; use Sammyjo20\LaravelHaystack\Data\PendingHaystackBale; use Sammyjo20\LaravelHaystack\Actions\CreatePendingHaystackBale; -use Sammyjo20\LaravelHaystack\Models\HaystackData; -use Illuminate\Support\Collection; trait ManagesBales { @@ -69,8 +68,8 @@ public function getNextJob(): ?NextJob /** * Dispatch the next job. * - * @param StackableJob|null $job - * @param int|CarbonInterface|null $delayInSecondsOrCarbon + * @param StackableJob|null $job + * @param int|CarbonInterface|null $delayInSecondsOrCarbon * @return void */ public function dispatchNextJob(StackableJob $job = null, int|CarbonInterface $delayInSecondsOrCarbon = null): void @@ -144,7 +143,7 @@ public function restart(): void /** * Finish the Haystack. * - * @param bool $fail + * @param bool $fail * @return void */ public function finish(bool $fail = false): void @@ -187,10 +186,10 @@ public function fail(): void /** * Append a new job to the job stack. * - * @param ShouldQueue $job - * @param int $delayInSeconds - * @param string|null $queue - * @param string|null $connection + * @param ShouldQueue $job + * @param int $delayInSeconds + * @param string|null $queue + * @param string|null $connection * @return void */ public function appendJob(ShouldQueue $job, int $delayInSeconds = 0, string $queue = null, string $connection = null): void @@ -203,7 +202,7 @@ public function appendJob(ShouldQueue $job, int $delayInSeconds = 0, string $que /** * Append the pending job to the Haystack. * - * @param PendingHaystackBale $pendingJob + * @param PendingHaystackBale $pendingJob * @return void */ public function appendPendingJob(PendingHaystackBale $pendingJob): void @@ -219,8 +218,8 @@ public function appendPendingJob(PendingHaystackBale $pendingJob): void /** * Execute the closure. * - * @param Closure|null $closure - * @param Collection|null $data + * @param Closure|null $closure + * @param Collection|null $data * @return void */ protected function executeClosure(?Closure $closure, ?Collection $data = null): void @@ -233,7 +232,7 @@ protected function executeClosure(?Closure $closure, ?Collection $data = null): /** * Pause the haystack. * - * @param CarbonImmutable $resumeAt + * @param CarbonImmutable $resumeAt * @return void */ public function pause(CarbonImmutable $resumeAt): void @@ -244,9 +243,9 @@ public function pause(CarbonImmutable $resumeAt): void /** * Store data on the Haystack. * - * @param string $key - * @param mixed $value - * @param string|null $cast + * @param string $key + * @param mixed $value + * @param string|null $cast * @return ManagesBales|\Sammyjo20\LaravelHaystack\Models\Haystack */ public function setData(string $key, mixed $value, string $cast = null): self @@ -266,8 +265,8 @@ public function setData(string $key, mixed $value, string $cast = null): self /** * Retrieve data by a key from the Haystack. * - * @param string $key - * @param mixed|null $default + * @param string $key + * @param mixed|null $default * @return mixed */ public function getData(string $key, mixed $default = null): mixed diff --git a/src/Concerns/Stackable.php b/src/Concerns/Stackable.php index 9516dc5..0987197 100644 --- a/src/Concerns/Stackable.php +++ b/src/Concerns/Stackable.php @@ -3,9 +3,8 @@ namespace Sammyjo20\LaravelHaystack\Concerns; use Carbon\CarbonInterface; -use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Support\Collection; -use Sammyjo20\LaravelHaystack\Contracts\StackableJob; +use Illuminate\Contracts\Queue\ShouldQueue; use Sammyjo20\LaravelHaystack\Models\Haystack; use Sammyjo20\LaravelHaystack\Models\HaystackBale; use Sammyjo20\LaravelHaystack\Helpers\CarbonHelper; @@ -40,7 +39,7 @@ public function getHaystack(): Haystack /** * Set the Haystack onto the job. * - * @param Haystack $haystack + * @param Haystack $haystack * @return $this */ public function setHaystack(Haystack $haystack): static @@ -71,7 +70,7 @@ public function nextJob(int|CarbonInterface $delayInSecondsOrCarbon = null): sta /** * Dispatch the next bale in the haystack. Yee-haw! * - * @param int|CarbonInterface|null $delayInSecondsOrCarbon + * @param int|CarbonInterface|null $delayInSecondsOrCarbon * @return $this * * @throws StackableException @@ -84,7 +83,7 @@ public function nextBale(int|CarbonInterface $delayInSecondsOrCarbon = null): st /** * Release the job for haystack to process later. * - * @param int|CarbonInterface $delayInSecondsOrCarbon + * @param int|CarbonInterface $delayInSecondsOrCarbon * @return $this */ public function longRelease(int|CarbonInterface $delayInSecondsOrCarbon): static @@ -123,10 +122,10 @@ public function failHaystack(): static /** * Append a job to the Haystack. * - * @param ShouldQueue $job - * @param int $delayInSeconds - * @param string|null $queue - * @param string|null $connection + * @param ShouldQueue $job + * @param int $delayInSeconds + * @param string|null $queue + * @param string|null $connection * @return $this */ public function appendToHaystack(ShouldQueue $job, int $delayInSeconds = 0, string $queue = null, string $connection = null): static @@ -149,7 +148,7 @@ public function getHaystackBaleId(): int /** * Set the Haystack bale ID. * - * @param int $haystackBaleId + * @param int $haystackBaleId * @return $this */ public function setHaystackBaleId(int $haystackBaleId): static @@ -162,7 +161,7 @@ public function setHaystackBaleId(int $haystackBaleId): static /** * Pause the haystack. We also need to delete the current row. * - * @param int|CarbonInterface $delayInSecondsOrCarbon + * @param int|CarbonInterface $delayInSecondsOrCarbon * @return $this * * @throws StackableException @@ -188,9 +187,9 @@ public function pauseHaystack(int|CarbonInterface $delayInSecondsOrCarbon): stat /** * Set data on the haystack. * - * @param string $key - * @param mixed $value - * @param string|null $cast + * @param string $key + * @param mixed $value + * @param string|null $cast * @return $this */ public function setHaystackData(string $key, mixed $value, string $cast = null): static @@ -203,8 +202,8 @@ public function setHaystackData(string $key, mixed $value, string $cast = null): /** * Get data on the haystack. * - * @param string $key - * @param mixed|null $default + * @param string $key + * @param mixed|null $default * @return mixed */ public function getHaystackData(string $key, mixed $default = null): mixed diff --git a/src/Contracts/StackableJob.php b/src/Contracts/StackableJob.php index 8e87479..b18872f 100644 --- a/src/Contracts/StackableJob.php +++ b/src/Contracts/StackableJob.php @@ -3,8 +3,8 @@ namespace Sammyjo20\LaravelHaystack\Contracts; use Carbon\CarbonInterface; -use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Support\Collection; +use Illuminate\Contracts\Queue\ShouldQueue; use Sammyjo20\LaravelHaystack\Models\Haystack; use Sammyjo20\LaravelHaystack\Tests\Exceptions\StackableException; @@ -101,9 +101,9 @@ public function pauseHaystack(int|CarbonInterface $delayInSecondsOrCarbon): stat /** * Set data on the haystack. * - * @param string $key - * @param mixed $value - * @param string|null $cast + * @param string $key + * @param mixed $value + * @param string|null $cast * @return $this */ public function setHaystackData(string $key, mixed $value, string $cast = null): static; @@ -111,8 +111,8 @@ public function setHaystackData(string $key, mixed $value, string $cast = null): /** * Get data on the haystack. * - * @param string $key - * @param mixed|null $default + * @param string $key + * @param mixed|null $default * @return mixed */ public function getHaystackData(string $key, mixed $default = null): mixed; diff --git a/src/Models/HaystackData.php b/src/Models/HaystackData.php index 730b3c2..ac87ffd 100644 --- a/src/Models/HaystackData.php +++ b/src/Models/HaystackData.php @@ -3,11 +3,8 @@ namespace Sammyjo20\LaravelHaystack\Models; use Illuminate\Database\Eloquent\Model; -use Sammyjo20\LaravelHaystack\Casts\SerializeJob; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Sammyjo20\LaravelHaystack\Contracts\StackableJob; use Illuminate\Database\Eloquent\Factories\HasFactory; -use Sammyjo20\LaravelHaystack\Database\Factories\HaystackBaleFactory; use Sammyjo20\LaravelHaystack\Database\Factories\HaystackDataFactory; class HaystackData extends Model @@ -42,7 +39,7 @@ public function haystack(): BelongsTo /** * Set the cast attribute and apply the casts. * - * @param string|null $cast + * @param string|null $cast * @return void */ public function setCastAttribute(?string $cast): void diff --git a/tests/Feature/HaystackTest.php b/tests/Feature/HaystackTest.php index 26c574a..2e61f1b 100644 --- a/tests/Feature/HaystackTest.php +++ b/tests/Feature/HaystackTest.php @@ -5,9 +5,9 @@ use Sammyjo20\LaravelHaystack\Models\Haystack; use Sammyjo20\LaravelHaystack\Tests\Fixtures\Jobs\FailJob; use Sammyjo20\LaravelHaystack\Tests\Fixtures\Jobs\NameJob; +use Sammyjo20\LaravelHaystack\Tests\Fixtures\Jobs\SetDataJob; use Sammyjo20\LaravelHaystack\Tests\Fixtures\Jobs\OrderCheckCacheJob; use Sammyjo20\LaravelHaystack\Tests\Fixtures\Jobs\AppendingOrderCheckCacheJob; -use Sammyjo20\LaravelHaystack\Tests\Fixtures\Jobs\SetDataJob; test('you can start a haystack', function () { Queue::fake(); diff --git a/tests/Feature/StackableJobTest.php b/tests/Feature/StackableJobTest.php index 435c2fa..0f62863 100644 --- a/tests/Feature/StackableJobTest.php +++ b/tests/Feature/StackableJobTest.php @@ -7,10 +7,10 @@ use Sammyjo20\LaravelHaystack\Tests\Fixtures\Jobs\FailJob; use Sammyjo20\LaravelHaystack\Tests\Fixtures\Jobs\CacheJob; use Sammyjo20\LaravelHaystack\Tests\Fixtures\Jobs\ExcitedJob; +use Sammyjo20\LaravelHaystack\Tests\Fixtures\Jobs\SetDataJob; use Sammyjo20\LaravelHaystack\Tests\Fixtures\Jobs\AppendingDelayJob; -use Sammyjo20\LaravelHaystack\Tests\Fixtures\Jobs\GetAllAndCacheDataJob; use Sammyjo20\LaravelHaystack\Tests\Fixtures\Jobs\GetAndCacheDataJob; -use Sammyjo20\LaravelHaystack\Tests\Fixtures\Jobs\SetDataJob; +use Sammyjo20\LaravelHaystack\Tests\Fixtures\Jobs\GetAllAndCacheDataJob; test('a stackable job can call the next job', function () { $haystack = Haystack::build() diff --git a/tests/Fixtures/DataObjects/Repository.php b/tests/Fixtures/DataObjects/Repository.php index 9b6a6b0..de28088 100644 --- a/tests/Fixtures/DataObjects/Repository.php +++ b/tests/Fixtures/DataObjects/Repository.php @@ -7,6 +7,8 @@ class Repository extends CastableDataTransferObject { public readonly string $name; + public readonly string $stars; + public readonly string $isLaravel; } diff --git a/tests/Fixtures/Jobs/GetAllAndCacheDataJob.php b/tests/Fixtures/Jobs/GetAllAndCacheDataJob.php index 0b70d8a..56fb29f 100644 --- a/tests/Fixtures/Jobs/GetAllAndCacheDataJob.php +++ b/tests/Fixtures/Jobs/GetAllAndCacheDataJob.php @@ -2,7 +2,6 @@ namespace Sammyjo20\LaravelHaystack\Tests\Fixtures\Jobs; -use Dflydev\DotAccessData\Data; use Illuminate\Bus\Queueable; use Illuminate\Queue\SerializesModels; use Illuminate\Queue\InteractsWithQueue; @@ -29,6 +28,7 @@ public function __construct() * Execute the job. * * @return void + * * @throws \Sammyjo20\LaravelHaystack\Tests\Exceptions\StackableException */ public function handle() diff --git a/tests/Fixtures/Jobs/GetAndCacheDataJob.php b/tests/Fixtures/Jobs/GetAndCacheDataJob.php index 3b74393..083934a 100644 --- a/tests/Fixtures/Jobs/GetAndCacheDataJob.php +++ b/tests/Fixtures/Jobs/GetAndCacheDataJob.php @@ -2,7 +2,6 @@ namespace Sammyjo20\LaravelHaystack\Tests\Fixtures\Jobs; -use Dflydev\DotAccessData\Data; use Illuminate\Bus\Queueable; use Illuminate\Queue\SerializesModels; use Illuminate\Queue\InteractsWithQueue; @@ -29,6 +28,7 @@ public function __construct(public string $key) * Execute the job. * * @return void + * * @throws \Sammyjo20\LaravelHaystack\Tests\Exceptions\StackableException */ public function handle() diff --git a/tests/Fixtures/Jobs/SetDataJob.php b/tests/Fixtures/Jobs/SetDataJob.php index c959fe3..648e614 100644 --- a/tests/Fixtures/Jobs/SetDataJob.php +++ b/tests/Fixtures/Jobs/SetDataJob.php @@ -28,6 +28,7 @@ public function __construct(public string $key, public string $value) * Execute the job. * * @return void + * * @throws \Sammyjo20\LaravelHaystack\Tests\Exceptions\StackableException */ public function handle() diff --git a/tests/Unit/HaystackDataTest.php b/tests/Unit/HaystackDataTest.php index ce0c20c..a5e4f93 100644 --- a/tests/Unit/HaystackDataTest.php +++ b/tests/Unit/HaystackDataTest.php @@ -3,7 +3,6 @@ use Illuminate\Support\Collection; use Sammyjo20\LaravelHaystack\Models\Haystack; use Sammyjo20\LaravelHaystack\Models\HaystackData; -use Sammyjo20\LaravelHaystack\Tests\Fixtures\Jobs\NameJob; test('a haystack data row can belong to a haystack', function () { $haystack = Haystack::factory()->create(); diff --git a/tests/Unit/HaystackTest.php b/tests/Unit/HaystackTest.php index 753a9d7..1efb423 100644 --- a/tests/Unit/HaystackTest.php +++ b/tests/Unit/HaystackTest.php @@ -1,19 +1,16 @@ 'Then'; - $catchClosure = fn() => 'Catch'; - $finallyClosure = fn() => 'Finally'; - $middlewareClosure = fn() => []; + $thenClosure = fn () => 'Then'; + $catchClosure = fn () => 'Catch'; + $finallyClosure = fn () => 'Finally'; + $middlewareClosure = fn () => []; $haystack = new Haystack; $haystack->on_then = $thenClosure; @@ -121,11 +118,11 @@ $haystack->on_then = $value; $haystack->save(); })->with([ - fn() => 'Hello', - fn() => 123, - fn() => true, - fn() => (object)[1], - fn() => [1], + fn () => 'Hello', + fn () => 123, + fn () => true, + fn () => (object) [1], + fn () => [1], ]); test('you must provide an invokable class if you do not provide a closure', function () { From 3f40763e71c99177f7bbdb315aa0966a408f4c15 Mon Sep 17 00:00:00 2001 From: Sammyjo20 <29132017+Sammyjo20@users.noreply.github.com> Date: Wed, 3 Aug 2022 00:30:38 +0100 Subject: [PATCH 4/6] Docs --- README.md | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/README.md b/README.md index f13c89c..3473ac1 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ That's right! Let's just be clear that we're not talking about **Batched Jobs**. - They are volatile, meaning if you lose one job in the chain - you lose the whole chain. - They do not provide the `then`, `catch`, `finally` callable methods that batched jobs do. - Long delays with memory based or SQS queue is not possible as you could lose the jobs due to expiry or if the server shuts down. +- You can't share data between jobs as there is no "state" across the chain Laravel Haystack aims to solve this by storing the job chain in the database and queuing one job at a time. When the job is completed, Laravel Haystack listens out for the "job completed" event and queues the next job in the chain from the database. @@ -49,6 +50,7 @@ Laravel Haystack aims to solve this by storing the job chain in the database and - It provides callback methods like `then`, `catch` and `finally`. - Global middleware that can be applied to every single job in the chain - Delay that can be added to every job in the chain +- You can store and retrieve data in the chain to be accessed by jobs - You can store the model for later processing. ### Use Cases @@ -429,6 +431,102 @@ class ProcessPodcast implements ShouldQueue, StackableJo } ``` +## Shared Job Data + +Laravel Haystack has the ability for your jobs to store and retrieve state/data between jobs. This is really useful if you need to store data in the first job and then in the second job, process the data and in the final job, email the processed data. You are able to create a process pipeline since each job is processed in sequential order. This is really exciting because with traditional chained jobs, you cannot share data between jobs. + +```php +addJob(new RetrieveDataFromApi) + ->addJob(new ProcessDataFromApi) + ->addJob(new StoreDataFromApi) + ->dispatch(); +``` + +### Storing data inside of jobs + +Inside your job, you can use the `setHaystackData()` method to store some data. This method accepts a key, value and optional Eloquent cast. + +```php +setHaystackData('username', 'Sammyjo20'); + } +``` + +### Casting data + +The `setHaystackData` method supports any data type. It supports fully casting your data into any of Eloquent's existing casts, or even your custom casts. Just provide a third argument to specify the cast. + +```php +setHaystackData('data', ['username' => 'Sammyjo20'], 'array'); + + // Supports custom casts + + $this->setHaystackData('customData', $object, CustomCast::class); + } +``` + +### Retrieving data inside of jobs + +From one job you can set the data, but that data will be available to every job in the haystack there after. Just use the `getHaystackData` method to get data by key or use the `allHaystackData` to get a collection containing the haystack data. + +```php +getHaystackData('username'); // Sammyjo20 + + // Get all data + + $allData = $this->allHaystackData();// Collection: ['username' => 'Sammyjo20'] + } +``` + ## Manual Processing By default, Laravel Haystack will use events to automatically process the next job in the haystack. If you would like to disable this functionality, you will need to make sure to disable the `automatic_processing` in your config/haystack.php file. After that, you will need to make sure your jobs tell Haystack when to process the next job. From 828c2e28d4616d3a0214ba23ebad65b60bcaf21b Mon Sep 17 00:00:00 2001 From: Sammyjo20 <29132017+Sammyjo20@users.noreply.github.com> Date: Wed, 3 Aug 2022 00:32:45 +0100 Subject: [PATCH 5/6] Formatting --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3473ac1..e1a9e24 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Laravel Haystack aims to solve this by storing the job chain in the database and - It provides callback methods like `then`, `catch` and `finally`. - Global middleware that can be applied to every single job in the chain - Delay that can be added to every job in the chain -- You can store and retrieve data in the chain to be accessed by jobs +- You can store and retrieve data/state that is accessible to every job in the chain. - You can store the model for later processing. ### Use Cases @@ -523,7 +523,7 @@ class RetrieveDataFromApi implements ShouldQueue, StackableJob // Get all data - $allData = $this->allHaystackData();// Collection: ['username' => 'Sammyjo20'] + $allData = $this->allHaystackData(); // Collection: ['username' => 'Sammyjo20'] } ``` From 77c3f84dcb850eeeece62abfdf213da3a5504756 Mon Sep 17 00:00:00 2001 From: Sammyjo20 <29132017+Sammyjo20@users.noreply.github.com> Date: Wed, 3 Aug 2022 00:34:36 +0100 Subject: [PATCH 6/6] Published migration --- src/LaravelHaystackServiceProvider.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/LaravelHaystackServiceProvider.php b/src/LaravelHaystackServiceProvider.php index 7301f30..e5193f0 100644 --- a/src/LaravelHaystackServiceProvider.php +++ b/src/LaravelHaystackServiceProvider.php @@ -25,6 +25,7 @@ public function configurePackage(Package $package): void ->hasMigrations([ 'create_haystacks_table', 'create_haystack_bales_table', + 'create_haystack_data_table', ]) ->hasCommand(ResumeHaystacks::class); }