Laravel 路由解析自定义数据类型
Laravel route resolve custom data type
我在routes/api.php
中有以下路线:
Route::get('items/{item}', function(Guid $item) {...});
Route::get('users/{user}', function(Guid $user) {...});
由于 Guid
是自定义类型,我如何通过 依赖注入 解决这个问题?如图,路由参数{item}
与回调参数type-hint:Guid
不同,无法自动解析
这就是我在 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]);
});
}
}
我希望 $params
是这样的:[ 'item' => 'guid' ]
-- 但它是:[]
.
你可以利用explicit binding Laravel Routing:
在RouteServiceProvider::boot()
:
public function boot()
{
Route::model('item', Guid $item);
Route::model('user', Guid $user);
}
如果 Guid
是 不是 模型使用 Closure 映射到字符串:
Route::bind('user', function ($value) {
return Guid::fromString($value);
});
已更新
我找到了另一种更好的方法 - 实施 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;
}
}
而且,有了这个,你可以使用你想要的路由,因为 Guid
现在实现了 UrlRoutable
并且可以转换 {item}
(或其他)URL-path sub -string markers into Guids per dependency injection(根据您要求的类型提示):
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.
利用路由绑定回调的简单助手。
if (!function_exists('resolve_bind')) {
function resolve_bind(string $key, mixed $value) {
return call_user_func(Route::getBindingCallback($key), $value);
}
}
用法
resolve_bind('key', 'value');
我在routes/api.php
中有以下路线:
Route::get('items/{item}', function(Guid $item) {...});
Route::get('users/{user}', function(Guid $user) {...});
由于 Guid
是自定义类型,我如何通过 依赖注入 解决这个问题?如图,路由参数{item}
与回调参数type-hint:Guid
不同,无法自动解析
这就是我在 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]);
});
}
}
我希望 $params
是这样的:[ 'item' => 'guid' ]
-- 但它是:[]
.
你可以利用explicit binding Laravel Routing:
在RouteServiceProvider::boot()
:
public function boot()
{
Route::model('item', Guid $item);
Route::model('user', Guid $user);
}
如果 Guid
是 不是 模型使用 Closure 映射到字符串:
Route::bind('user', function ($value) {
return Guid::fromString($value);
});
已更新
我找到了另一种更好的方法 - 实施 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;
}
}
而且,有了这个,你可以使用你想要的路由,因为 Guid
现在实现了 UrlRoutable
并且可以转换 {item}
(或其他)URL-path sub -string markers into Guids per dependency injection(根据您要求的类型提示):
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.
利用路由绑定回调的简单助手。
if (!function_exists('resolve_bind')) {
function resolve_bind(string $key, mixed $value) {
return call_user_func(Route::getBindingCallback($key), $value);
}
}
用法
resolve_bind('key', 'value');