diff --git a/README.md b/README.md index 3b02979..2dd4ea1 100644 --- a/README.md +++ b/README.md @@ -419,6 +419,18 @@ $model = Article::findBySlug('my-article'); `findBySlug` also accepts a second parameter `$columns` just like the default Eloquent `find` method. +### Find models by slug or +For convenience, you can use the alias `findBySlugOr` to retrieve a model. The query will compare against the field passed to `saveSlugsTo` when defining the `SlugOptions`. If the model does not exist, the callable will be executed and the result will be returned. + +```php +$model = Article::findBySlugOr('my-article', ['*'], function () { + return Article::create(['name' => 'my-article']); +}); + +// or +$model = Article::findBySlugOr('my-article', ['*'],fn () => throw new \Exception('Article not found')); +``` + ## Changelog diff --git a/src/Exceptions/InvalidOption.php b/src/Exceptions/InvalidOption.php index 8f008a0..f394f49 100644 --- a/src/Exceptions/InvalidOption.php +++ b/src/Exceptions/InvalidOption.php @@ -20,4 +20,9 @@ public static function invalidMaximumLength(): static { return new static('Maximum length should be greater than zero'); } + + public static function missingCallback(): static + { + return new static('Could not determine which callback should be used'); + } } diff --git a/src/HasSlug.php b/src/HasSlug.php index 137525b..4b4bd08 100644 --- a/src/HasSlug.php +++ b/src/HasSlug.php @@ -201,4 +201,19 @@ public static function findBySlug(string $slug, array $columns = ['*']) return static::where($field, $slug)->first($columns); } + + public static function findBySlugOr(string $slug, array $columns = ['*'], ?callable $callback = null) + { + if (!is_callable($callback) && $callback !== null) { + throw InvalidOption::missingCallback(); + } + + $result = static::findBySlug($slug, $columns); + + if (!$result && is_callable($callback)) { + return $callback($slug); + } + + return $result; + } } diff --git a/tests/HasSlugTest.php b/tests/HasSlugTest.php index 593dd85..ffd8308 100644 --- a/tests/HasSlugTest.php +++ b/tests/HasSlugTest.php @@ -349,3 +349,22 @@ public function getSlugOptions(): SlugOptions expect($savedModel->id)->toEqual($model->id); }); + +it('can use a callable using findBySlugOr alias', function () { + $model = new class () extends TestModel { + public function getSlugOptions(): SlugOptions + { + return parent::getSlugOptions() + ->saveSlugsTo('url'); + } + }; + + $model->name = 'my custom url'; + $model->save(); + + $savedModel = $model::findBySlugOr('my-custom-url1', ['*'], function () { + return 'not found'; + }); + + expect($savedModel)->toEqual('not found'); +}); \ No newline at end of file