Skip to content

Commit

Permalink
[9.x] Validate uuid before route binding query (#44945)
Browse files Browse the repository at this point in the history
* validate uuid before route binding query

* Update HasUuids.php

* Update HasUuids.php

* validate uuid in resolveRouteBindingQuery

* validate uuid if field in uniqueIds

* styleci changes

* drop comments table

* formatting

Co-authored-by: Taylor Otwell <[email protected]>
  • Loading branch information
benbjurstrom and taylorotwell authored Nov 21, 2022
1 parent 171d0dc commit 1d18fae
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 0 deletions.
22 changes: 22 additions & 0 deletions src/Illuminate/Database/Eloquent/Concerns/HasUuids.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Illuminate\Database\Eloquent\Concerns;

use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Str;

trait HasUuids
Expand Down Expand Up @@ -42,6 +43,27 @@ public function uniqueIds()
return [$this->getKeyName()];
}

/**
* Retrieve the model for a bound value.
*
* @param \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Relations\Relation $query
* @param mixed $value
* @param string|null $field
* @return \Illuminate\Database\Eloquent\Relations\Relation
*/
public function resolveRouteBindingQuery($query, $value, $field = null)
{
if ($field && in_array($field, $this->uniqueIds()) && ! Str::isUuid($value)) {
throw (new ModelNotFoundException)->setModel(get_class($this), $value);
}

if (! $field && in_array($this->getRouteKeyName(), $this->uniqueIds()) && ! Str::isUuid($value)) {
throw (new ModelNotFoundException)->setModel(get_class($this), $value);
}

return parent::resolveRouteBindingQuery($query, $value, $field);
}

/**
* Get the auto-incrementing key type.
*
Expand Down
58 changes: 58 additions & 0 deletions tests/Integration/Routing/ImplicitModelRouteBindingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Illuminate\Tests\Integration\Routing;

use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Schema\Blueprint;
Expand Down Expand Up @@ -40,9 +41,17 @@ protected function defineDatabaseMigrations(): void
$table->timestamps();
});

Schema::create('comments', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('slug');
$table->integer('user_id');
$table->timestamps();
});

$this->beforeApplicationDestroyed(function () {
Schema::dropIfExists('users');
Schema::dropIfExists('posts');
Schema::dropIfExists('comments');
});
}

Expand Down Expand Up @@ -222,6 +231,36 @@ public function testWithoutEnforceScopingImplicitRouteBindings()
],
]);
}

public function testImplicitRouteBindingChildHasUuids()
{
$user = ImplicitBindingUser::create(['name' => 'Dries']);
$comment = ImplicitBindingComment::create([
'slug' => 'slug',
'user_id' => $user->id,
]);

config(['app.key' => str_repeat('a', 32)]);

$function = function (ImplicitBindingUser $user, ImplicitBindingComment $comment) {
return [$user, $comment];
};

Route::middleware(['web'])->group(function () use ($function) {
Route::get('/user/{user}/comment/{comment}', $function);
Route::get('/user/{user}/comment-id/{comment:id}', $function);
Route::get('/user/{user}/comment-slug/{comment:slug}', $function);
});

$response = $this->getJson("/user/{$user->id}/comment/{$comment->slug}");
$response->assertJsonFragment(['id' => $comment->id]);

$response = $this->getJson("/user/{$user->id}/comment-id/{$comment->id}");
$response->assertJsonFragment(['id' => $comment->id]);

$response = $this->getJson("/user/{$user->id}/comment-slug/{$comment->slug}");
$response->assertJsonFragment(['id' => $comment->id]);
}
}

class ImplicitBindingUser extends Model
Expand All @@ -236,6 +275,11 @@ public function posts()
{
return $this->hasMany(ImplicitBindingPost::class, 'user_id');
}

public function comments()
{
return $this->hasMany(ImplicitBindingComment::class, 'user_id');
}
}

class ImplicitBindingPost extends Model
Expand All @@ -244,3 +288,17 @@ class ImplicitBindingPost extends Model

protected $fillable = ['user_id'];
}

class ImplicitBindingComment extends Model
{
use HasUuids;

public $table = 'comments';

protected $fillable = ['slug', 'user_id'];

public function getRouteKeyName()
{
return 'slug';
}
}

0 comments on commit 1d18fae

Please sign in to comment.