【问题标题】:Laravel route resolve custom data typeLaravel 路由解析自定义数据类型
【发布时间】: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' ]——但它是:[]

【问题讨论】:

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

标签: php laravel laravel-8 laravel-routing laravel-service-container


【解决方案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');

【讨论】:

    猜你喜欢
    • 2016-06-14
    • 2019-08-25
    • 1970-01-01
    • 2018-10-04
    • 2015-04-26
    • 2013-09-22
    • 2023-03-25
    • 2020-10-04
    相关资源
    最近更新 更多