Skip to content

Commit 591ca0a

Browse files
feat: add exception for models with conflicting url/urls columns
- Add validation in HasUniqueUrls trait initialization - Check if model has 'url' or 'urls' database columns - Throw descriptive exception with guidance on fixing conflicts - Add tests (test #12 and #13) to verify exception behavior Fixes #67 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Vladislav Stoitsov <[email protected]>
1 parent 1f53afa commit 591ca0a

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

src/HasUniqueUrls.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,55 @@ trait HasUniqueUrls
1818

1919
abstract public function urlHandler(): array;
2020

21+
/**
22+
* Initialize the HasUniqueUrls trait for an instance.
23+
*
24+
* @throws Exception
25+
*/
26+
public function initializeHasUniqueUrls(): void
27+
{
28+
$this->checkForConflictingAttributes();
29+
}
30+
31+
/**
32+
* Check if the model has conflicting 'url' or 'urls' attributes.
33+
*
34+
* @throws Exception
35+
*/
36+
private function checkForConflictingAttributes(): void
37+
{
38+
$conflictingAttributes = ['url', 'urls'];
39+
$modelClass = get_class($this);
40+
41+
foreach ($conflictingAttributes as $attribute) {
42+
// Check if attribute exists in fillable, guarded, or as a database column
43+
if ($this->hasColumn($attribute)) {
44+
throw new Exception(
45+
"Model [{$modelClass}] has a conflicting column '{$attribute}'. " .
46+
"The HasUniqueUrls trait uses 'urls' as a relationship name and provides 'relative_url' and 'absolute_url' attributes. " .
47+
"Please rename the '{$attribute}' column in your model to avoid conflicts."
48+
);
49+
}
50+
}
51+
}
52+
53+
/**
54+
* Check if the model has a specific column.
55+
*/
56+
private function hasColumn(string $column): bool
57+
{
58+
try {
59+
// Check if the table exists and has the column
60+
if ($this->getConnection()->getSchemaBuilder()->hasColumn($this->getTable(), $column)) {
61+
return true;
62+
}
63+
} catch (\Exception $e) {
64+
// If we can't check the schema (e.g., during testing without migrations), skip the check
65+
}
66+
67+
return false;
68+
}
69+
2170
/**
2271
* Generate a unique URL for the model.
2372
*

tests/HasUniqueUrlsTest.php

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<?php
22

3+
use Illuminate\Database\Schema\Blueprint;
34
use Illuminate\Foundation\Testing\RefreshDatabase;
5+
use Illuminate\Support\Facades\Schema;
46
use Vlados\LaravelUniqueUrls\LaravelUniqueUrlsController;
57
use Vlados\LaravelUniqueUrls\Models\Url;
68
use Vlados\LaravelUniqueUrls\Tests\Models\ChildModel;
@@ -169,3 +171,77 @@
169171
expect($model->relative_url)->toEqual(app()->getLocale()."/parent/test".($i > 0 ? "_".$i : ""));
170172
}
171173
});
174+
175+
test('12. Check if exception is thrown when model has conflicting url column', function () {
176+
// Create a table with 'url' column
177+
Schema::create('models_with_url_column', function (Blueprint $table) {
178+
$table->increments('id');
179+
$table->string('name');
180+
$table->string('url');
181+
});
182+
183+
// Create a model class that uses HasUniqueUrls trait
184+
$modelClass = new class extends \Illuminate\Database\Eloquent\Model {
185+
use \Vlados\LaravelUniqueUrls\HasUniqueUrls;
186+
187+
protected $table = 'models_with_url_column';
188+
protected $guarded = [];
189+
public $timestamps = false;
190+
191+
public function urlHandler(): array
192+
{
193+
return [
194+
'controller' => \Vlados\LaravelUniqueUrls\Tests\TestUrlHandler::class,
195+
'method' => 'view',
196+
'arguments' => [],
197+
];
198+
}
199+
200+
public function urlStrategy($language, $locale): string
201+
{
202+
return \Illuminate\Support\Str::slug($this->name);
203+
}
204+
};
205+
206+
expect(fn() => $modelClass::create(['name' => 'test', 'url' => 'test-url']))
207+
->toThrow(Exception::class, "has a conflicting column 'url'");
208+
209+
Schema::dropIfExists('models_with_url_column');
210+
});
211+
212+
test('13. Check if exception is thrown when model has conflicting urls column', function () {
213+
// Create a table with 'urls' column
214+
Schema::create('models_with_urls_column', function (Blueprint $table) {
215+
$table->increments('id');
216+
$table->string('name');
217+
$table->string('urls');
218+
});
219+
220+
// Create a model class that uses HasUniqueUrls trait
221+
$modelClass = new class extends \Illuminate\Database\Eloquent\Model {
222+
use \Vlados\LaravelUniqueUrls\HasUniqueUrls;
223+
224+
protected $table = 'models_with_urls_column';
225+
protected $guarded = [];
226+
public $timestamps = false;
227+
228+
public function urlHandler(): array
229+
{
230+
return [
231+
'controller' => \Vlados\LaravelUniqueUrls\Tests\TestUrlHandler::class,
232+
'method' => 'view',
233+
'arguments' => [],
234+
];
235+
}
236+
237+
public function urlStrategy($language, $locale): string
238+
{
239+
return \Illuminate\Support\Str::slug($this->name);
240+
}
241+
};
242+
243+
expect(fn() => $modelClass::create(['name' => 'test', 'urls' => 'test-urls']))
244+
->toThrow(Exception::class, "has a conflicting column 'urls'");
245+
246+
Schema::dropIfExists('models_with_urls_column');
247+
});

0 commit comments

Comments
 (0)