Laravel 路由解析自定义数据类型

Posted

技术标签:

【中文标题】Laravel 路由解析自定义数据类型【英文标题】:Laravel route resolve custom data type 【发布时间】:2021-10-05 02:10:51 【问题描述】:

我在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' ]——但它是:[]

【问题讨论】:

itemGuid $item 的差异有多大?第一个是字符串(URL-.Path 的子字符串),而第二个根本不是字符串?根据您的理解,Laravel 通常如何将 URL-Path 子字符串映射到 any PHP 对象类型?还是您在其他地方看到了不同之处? item 路由参数是一个 guid 字符串,而 Guid 是一个包装器对象,它具有一些实用方法,如验证。 Laravel 通常映射到模型。但是由于我必须自己实现模型(它不是像 Laravel 的模型那样的数据库模型),我想,这样解决它比实现整个 URLRoutable 合约更容易。 【参考方案1】:

您可以使用explicit bindingLaravel Routing:

RouteServiceProvider::boot()

public function boot()

    Route::model('item', Guid $item);
    Route::model('user', Guid $user);

如果 Guid 不是 模型,则使用 闭包 映射到字符串:

Route::bind('user', function ($value) 
   return Guid::fromString($value);
);

更新

我找到了另一种更好的方法——实现UrlRoutable contractLavaravel 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 路径子字符串标记转换为 Guid s per 依赖注入(根据你要求的类型提示):

Route::get('items/item', function(Guid $item) 
   return $item->getGuid();
);

顺便说一句:永远不要在路由中使用闭包,因为你不能缓存闭包路由 - 路由很适合优化,缓存有助于 Laravel 路由。

【讨论】:

但是Guid 不是模型。它只是一个自定义复合类型。关闭仅用于演示目的 - 感谢您的提示! 非模型更新 谢谢,但在这种情况下,每次我想使用 guid,路由参数都必须命名为 user 或者我必须手动为每个参数创建一个绑定,对吗? @shaedrich 我正在更新答案,请检查:) @hakre 可以通过使用控制器元组 ([ YourController::class, 'yourMethod' ]) 或字符串 (YourController::yourMethod') 来防止关闭【参考方案2】:

利用路由绑定回调的简单助手。

if (!function_exists('resolve_bind')) 
    function resolve_bind(string $key, mixed $value) 
        return call_user_func(Route::getBindingCallback($key), $value);
    

用法

resolve_bind('key', 'value');

【讨论】:

以上是关于Laravel 路由解析自定义数据类型的主要内容,如果未能解决你的问题,请参考以下文章

自定义路由在 Laravel 中无法解析

具有自定义 id 类型的 Laravel 多对多工厂

Swift之Codable自定义解析将任意数据类型解析为想要的类型

Swift之Codable自定义解析将任意数据类型解析为想要的类型

解决DataX自定义kuduWriter无法解析Blob类型字段的问题

[Doctrine Migrations] 数据库迁移组件的深入解析三:自定义数据字段类型