Laravel route model binding for model with UUID does not instantiate the model

260 Views Asked by At

I've run out of ideas, so I thought I'll ask around. Here's my code:

# app/Map/MapServiceProvider.php

class MapServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any package services.
     */
    public function boot(): void
    {
        Route::model('map_marker', Marker::class);

        $this->loadMigrationsFrom(__DIR__.'/Migrations');
        $this->loadRoutesFrom(__DIR__.'/routes.php');
    }

    // ...
}

Provider added to the app.php

'providers' => ServiceProvider::defaultProviders()->merge([
    // ...
    App\Map\MapServiceProvider::class,
])->toArray(),
# app/Map/routes.php

use App\Map\Controllers\UpdateMarkerController;
use Illuminate\Support\Facades\Route;

Route::put('/marker/{map_marker}', UpdateMarkerController::class)
    ->whereUuid('map_marker');
// ...
# app/Map/Migrations/.._create_map_markers_table.php

Schema::create('map_markers', function (Blueprint $table) {
    $table->uuid('id')->primary();
    $table->double('lat');
    $table->double('lng');
    $table->timestamps();
});
# app/Map/Models/Marker.php

class Marker extends Model
{
    use HasUuids;

    protected $table = 'map_markers';

    protected $fillable = ['lat', 'lng'];
}

The model does not seem to resolve. I'm getting an empty model when injected to the controller's invoke method:

# app/Map/Controllers/UpdateMarkerController.php

class UpdateMarkerController extends Controller
{
    public function __invoke(Marker $marker): JsonResponse
    {
        dd($marker);
    }
}

Result:

App\Map\Models\Marker {#285 // app/Map/Controllers/UpdateMarkerController.php:21
  #connection: null
  #table: "map_markers"
  #primaryKey: "id"
  #keyType: "int"
  +incrementing: true
  #with: []
  #withCount: []
  +preventsLazyLoading: false
  #perPage: 15
  +exists: false
  +wasRecentlyCreated: false
  #escapeWhenCastingToString: false
  #attributes: []
  #original: []
  #changes: []
  #casts: []
  #classCastCache: []
  #attributeCastCache: []
  #dateFormat: null
  #appends: []
  #dispatchesEvents: []
  #observables: []
  #relations: []
  #touches: []
  +timestamps: true
  +usesUniqueIds: true
  #hidden: []
  #visible: []
  #fillable: array:2 [
    0 => "lat"
    1 => "lng"
  ]
  #guarded: array:1 [
    0 => "*"
  ]
}

When I try to pull it directly from the router:

# app/Map/Controllers/UpdateMarkerController.php

class UpdateMarkerController extends Controller
{
    public function __invoke(\Illuminate\Http\Request $request): JsonResponse
    {
        dd($request->route('map_marker'));
    }
}

I get just the value of the bound segment:

"9a783cd6-3e87-49b8-b392-e1bb8be45521"

I'm sure I must be missing something simple.

2

There are 2 best solutions below

2
On

It seems like there might be an issue with the model binding for your Marker model in the UpdateMarkerController. Let's take a look at your code and see if we can identify the problem.

Make sure that the route parameter in your route definition in routes.php is named correctly. In your code, you have specified the parameter as map_marker:

Route::put('/marker/{map_marker}', UpdateMarkerController::class)
    ->whereUuid('map_marker');

In your UpdateMarkerController, you should type-hint the parameter name to match the route parameter:

public function __invoke(Marker $map_marker): JsonResponse 
{
    dd($map_marker);
}

By doing this, Laravel should automatically resolve the Marker model using the map_marker route parameter.

Ensure that your Marker model uses the HasUuids trait correctly, and the UUID is stored as the primary key in the database. Based on your migration, it appears to be set up correctly. If you've checked all of the above and it's still not working, here are some additional troubleshooting steps:

Make sure that you have imported the Marker model at the top of your UpdateMarkerController file using use App\Map\Models\Marker;.

Verify that there are no typos or naming discrepancies in your model, controller, and route definitions.

Clear the route cache by running php artisan route:clear to make sure any changes to your routes are picked up.

Ensure that the UUID value you're passing in the route matches an existing record in your database.

3
On

The problem is in the route. It should have the same name as your model name.

Try to use:

Route::put('/marker/{marker}', UpdateMarkerController::class)

Your model will pick it up after this.

Also whereUuid is not needed for what you are trying to achieve.