Hey! I'm using Laravel to craft an API and most of my routes are resource routes, and I'm following API best practices where the resource name is in plural form. The wildcard name will automatically be the same as the resource name, meaning a resource called "cars" will end up with an update route of
PUT /cars/{cars}
This is all fine, but the implicit route model binding only works when the argument name is the same as the wildcard name, meaning you have to do this:
public function update(Car $cars){
...
}
Having a variable named in plural form that represents one single car does not seem very intuitive.
Alright, been testing a bit, and looks like I've gotten a working solution. Will work some more on it before I send a pull request. Adding what I have so far below - any feedback is appreciated. Ended up creating a new function to not make the substituteImplicitBindings function too big.
/**
* Substitute the implicit Eloquent model bindings for the route.
*
* @param \Illuminate\Routing\Route $route
* @return void
*/
protected function substituteImplicitBindings($route)
{
$parameters = $route->parameters();
foreach ($route->signatureParameters(Model::class) as $parameter) {
$class = $parameter->getClass();
$parameterName = $this->findMatchingBindingParameter( $parameter->name, $parameters );
if ( $parameterName && ! $route->getParameter($parameter->name) instanceof Model) {
$method = $parameter->isDefaultValueAvailable() ? 'first' : 'firstOrFail';
$model = $class->newInstance();
$route->setParameter(
$parameterName, $model->where(
$model->getRouteKeyName(), $parameters[$parameterName]
)->{$method}()
);
}
}
}
/**
* Return a matching parameter name for an implicit binding substitute.
*
* @param string $parameter
* @param array $parameters
* @return mixed
*/
protected function findMatchingBindingParameter($parameter, $parameters)
{
if (array_key_exists($parameter, $parameters)) {
return $parameter;
}
if (array_key_exists($parameter = Str::plural($parameter), $parameters)) {
return $parameter;
}
return null;
}
There just came an update in laravel which fixes this problem:
class RouteServiceProvider extends ServiceProvider
{
/**
* Define your route model bindings, pattern filters, etc.
*
* @param \Illuminate\Routing\Router $router
* @return void
*/
public function boot(Router $router)
{
\Route::singularResourceParameters();
}
}
With the function "singularResourceParameters()" laravel will rewrite all the plural strings to singular strings. This was fixed in this github issue: https://github.com/laravel/framework/issues/11644