Route model binding with a column that is not the key

Exposing an auto-increment id in a URL tells anyone counting how many orders exist, and switching to a slug or a uuid normally means resolving it by hand in every controller.

// routes
Route::get('/products/{product:slug}', 'ProductController@show');   // 5.7 syntax

// or on the model, for every route
public function getRouteKeyName()
{
    return 'slug';
}

// and the binding that needs a scope
Route::bind('product', function ($value) {
    return Product::published()->where('slug', $value)->firstOrFail();
});

The explicit binding is the one worth knowing, because the automatic version resolves without any scope — so an unpublished product is reachable by anyone who guesses the slug, and the controller never sees the request. Adding the scope in the binding rather than in the controller means it cannot be forgotten in a new route. The column needs an index; it is now in the hot path of every request to that route.