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');