I have the following routes in routes/api.php
:
Route::get('items/{item}', function(Guid $item) {...});
Route::get('users/{user}', function(Guid $user) {...});
Since Guid
is a custom type, how can I resolve that via dependency injection? As shown, the route parameter {item}
differs from the callback parameter type-hint:Guid
so it can not be automatically resolved.
That's what I've tried in app/Providers/AppServiceProvider.php
:
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->bind(Guid::class, function(Application $app, array $params) {
return Guid::fromString($params[0]);
});
}
}
I'd expect $params
to be something like this: [ 'item' => 'guid' ]
-- but it is: []
.
You can make use of explicit binding Laravel Routing:
in RouteServiceProvider::boot()
:
public function boot()
{
Route::model('item', Guid $item);
Route::model('user', Guid $user);
}
If Guid
is not a model use a Closure to map onto the string:
Route::bind('user', function ($value) {
return Guid::fromString($value);
});
UPDATED
And I found another way, much better - implement UrlRoutable contract Lavaravel API:
<?php
namespace App\Models;
use Illuminate\Contracts\Routing\UrlRoutable;
class Guid implements UrlRoutable
{
private string $guid;
public function setGuid(string $guid)
{
$this->guid = $guid;
return $this;
}
public function getGuid(): string
{
return $this->guid;
}
public static function fromString(string $guid): self
{
//you cannot set props from constructor in this case
//because binder make new object of this class
//or you can resolve constructor depts with "give" construction in ServiceProvider
return (new self)->setGuid($guid);
}
public function getRouteKey()
{
return $this->guid;
}
public function getRouteKeyName()
{
return 'guid';
}
public function resolveRouteBinding($value, $field = null)
{
//for using another "fields" check documentation
//and maybe another resolving logic
return self::fromString($value);
}
public function resolveChildRouteBinding($childType, $value, $field)
{
//or maybe you have relations
return null;
}
}
And, with this, you can use routes like you want as Guid
now implements UrlRoutable
and can turn {item}
(or whatever) URL-path sub-string markers into Guids per dependency injection (by the type-hint as you asked for it):
Route::get('items/{item}', function(Guid $item) {
return $item->getGuid();
});
BTW: NEVER EVER use closures in routes as you cannot cache closure routes - and routes are good to be optimized, and caching helps with that in Laravel routing.