diff --git a/CHANGELOG.md b/CHANGELOG.md index bbb1b70..1e3e8ea 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-sluggable` will be documented in this file +## 2.1.8 - 2019-04-21 + +- ensure slugs are still unique when soft deletes are in use on model + ## 2.1.7 - 2019-02-26 ❤️ - Add support for Laravel 5.8 diff --git a/src/HasSlug.php b/src/HasSlug.php index 26e1954..fa8a0ca 100644 --- a/src/HasSlug.php +++ b/src/HasSlug.php @@ -122,10 +122,24 @@ protected function otherRecordExistsWithSlug(string $slug): bool $key = $key ?? '0'; } - return static::where($this->slugOptions->slugField, $slug) + $query = static::where($this->slugOptions->slugField, $slug) ->where($this->getKeyName(), '!=', $key) - ->withoutGlobalScopes() - ->exists(); + ->withoutGlobalScopes(); + + if ($this->usesSoftDeletes()) { + $query->withTrashed(); + } + + return $query->exists(); + } + + protected function usesSoftDeletes() + { + if (in_array('Illuminate\Database\Eloquent\SoftDeletes', class_uses($this))) { + return true; + } + + return false; } protected function ensureValidSlugOptions() diff --git a/tests/Integration/HasSlugTest.php b/tests/Integration/HasSlugTest.php index 4e31a87..3b0c8b0 100644 --- a/tests/Integration/HasSlugTest.php +++ b/tests/Integration/HasSlugTest.php @@ -280,4 +280,15 @@ public function getSlugOptions(): SlugOptions $model->save(); $this->assertEquals('guete-nacht', $model->url); } + + /** @test */ + public function it_will_save_a_unique_slug_by_default_even_when_soft_deletes_are_on() + { + TestModelSoftDeletes::create(['name' => 'this is a test', 'deleted_at' => date('Y-m-d h:i:s')]); + + foreach (range(1, 10) as $i) { + $model = TestModelSoftDeletes::create(['name' => 'this is a test']); + $this->assertEquals("this-is-a-test-{$i}", $model->url); + } + } } diff --git a/tests/Integration/TestCase.php b/tests/Integration/TestCase.php index 9b57cf9..eb42fa7 100644 --- a/tests/Integration/TestCase.php +++ b/tests/Integration/TestCase.php @@ -47,6 +47,14 @@ protected function setUpDatabase(Application $app) $table->string('other_field')->nullable(); $table->string('url')->nullable(); }); + + $app['db']->connection()->getSchemaBuilder()->create('test_model_soft_deletes', function (Blueprint $table) { + $table->increments('id'); + $table->string('name')->nullable(); + $table->string('other_field')->nullable(); + $table->string('url')->nullable(); + $table->softDeletes(); + }); } protected function initializeDirectory(string $directory) diff --git a/tests/Integration/TestModelSoftDeletes.php b/tests/Integration/TestModelSoftDeletes.php new file mode 100644 index 0000000..9073845 --- /dev/null +++ b/tests/Integration/TestModelSoftDeletes.php @@ -0,0 +1,48 @@ +slugOptions ?? $this->getDefaultSlugOptions(); + } + + /** + * Set the options for generating the slug. + */ + public function setSlugOptions(SlugOptions $slugOptions) : self + { + $this->slugOptions = $slugOptions; + + return $this; + } + + /** + * Get the default slug options used in the tests. + */ + public function getDefaultSlugOptions() : SlugOptions + { + return SlugOptions::create() + ->generateSlugsFrom('name') + ->saveSlugsTo('url'); + } +}