跳转到内容

从 v1.15 升级到 v1.16

令人兴奋的新功能 🎉

功能增强 🚀

破坏性变化 🛠

升级指南

随着 Golang v1.22 不再被维护,Goravel v1.16 默认支持 Golang 版本由 1.22 升级为 1.23。

goravel/example 项目由 v1.15 升级到 v1.16 PR 可以作为升级参考:goravel/example#68

1. 更新依赖

shell
go get github.com/goravel/framework@latest

// 如果使用 gin
go get github.com/goravel/gin@latest

// 如果使用 fiber
go get github.com/goravel/fiber@latest

// 如果使用 redis
go get github.com/goravel/redis@latest

// 如果使用 S3
go get github.com/goravel/s3@latest

// 如果使用 Oss
go get github.com/goravel/oss@latest

// 如果使用 Cos
go get github.com/goravel/cos@latest

// 如果使用 Minio
go get github.com/goravel/minio@latest

go mod tidy

2. 修改数据库配置

删除数据库配置文件 config/database.go 中自己用不到的 connections,安装自己需要的数据库驱动。

以 Postgres 为例:

  1. 安装驱动包
shell
go get github.com/goravel/postgres
  1. 添加 postgres.ServiceProviderconfig/app.go 文件
go
// config/app.go
import "github.com/goravel/postgres"

"providers": []foundation.ServiceProvider{
  ...
  &postgres.ServiceProvider{},
},
  1. 修改 config/database.go 文件中的配置
diff
// config/database.go
import (
	"github.com/goravel/framework/contracts/database/driver"
	postgresfacades "github.com/goravel/postgres/facades"
)

"connections": map[string]any{
  "postgres": map[string]any{
    ...
++    "via": func() (driver.Driver, error) {
++      return postgresfacades.Postgres("postgres")
++    },
  },
},

3. 修改 auth.go 配置文件

diff
// config/auth.go

// Supported: "jwt"
"guards": map[string]any{
  "user": map[string]any{
    "driver":   "jwt",
++    "provider": "user",
  },
},

++ // Supported: "orm"
++ "providers": map[string]any{
++   "user": map[string]any{
++     "driver": "orm",
++   },
++ },

4. 修改 session.go 配置文件

diff
// config/session.go

-- "driver": config.Env("SESSION_DRIVER", "file"),
++ "default": config.Env("SESSION_DRIVER", "file"),
++ "drivers": map[string]any{
++   "file": map[string]any{
++     "driver": "file",
++   },
++ },

5. 修改 queue.go 配置文件

  • 如果正在使用 Queue 模块的 Redis 驱动,需相应修改:优化 Queue 配置

  • 如果没有使用或想要以后使用 database 驱动,需要修改 config/queue.go 文件中的配置:

diff
// config/queue.go

-- // Drivers: "sync", "redis"
++ // Drivers: "sync", "database", "custom"
"connections": map[string]any{
  "sync": map[string]any{
    "driver": "sync",
  },
--  "redis": map[string]any{
--    "driver":     "redis",
--    "connection": "default",
--    "queue":      config.Env("REDIS_QUEUE", "default"),
--  },
++  "database": map[string]any{
++    "driver":     "database",
++    "connection": "postgres",
++    "queue":      "default",
++    "concurrent": 1,
++  },
},

++ "failed": map[string]any{
++  "database": config.Env("DB_CONNECTION", "postgres"),
++  "table":    "failed_jobs",
++ },

添加 database 驱动需要的迁移文件: database/migrations/20210101000002_create_jobs_table.go,并在 database/kernel.go 文件中注册该迁移文件。

6. 如果需要使用 HTTP Client

config/http.go 文件中新增 HTTP Client 配置项:

diff
// config/http.go
++ "client": map[string]any{
++   "base_url":                config.GetString("HTTP_CLIENT_BASE_URL"),
++   "timeout":                 config.GetDuration("HTTP_CLIENT_TIMEOUT"),
++   "max_idle_conns":          config.GetInt("HTTP_CLIENT_MAX_IDLE_CONNS"),
++   "max_idle_conns_per_host": config.GetInt("HTTP_CLIENT_MAX_IDLE_CONNS_PER_HOST"),
++   "max_conns_per_host":      config.GetInt("HTTP_CLIENT_MAX_CONN_PER_HOST"),
++   "idle_conn_timeout":       config.GetDuration("HTTP_CLIENT_IDLE_CONN_TIMEOUT"),
++ },

7. 如果正在使用 goravel/redis 驱动

需修改 config/cache.go 文件中的配置:

diff
// config/cache.go
"redis": map[string]any{
  "driver":     "custom",
  "connection": "default",
  "via": func() (cache.Driver, error) {
--  return redisfacades.Redis("redis"), nil
++  return redisfacades.Cache("redis")
  },
},

8. 如果正在使用 carbon.DateTime 等方法

需相应修改:优化 Carbon 方法

9. 如果正在使用 session 自定义驱动

需相应修改:优化 Session 自定义驱动方式

10. 如果正在使用 facades.Config() 中的方法

需相应修改:优化 Config 模块方法默认值类型

11. 如果正在使用 SQL 数据迁移

需相应修改:移除 SQL 迁移

12. 如果正在使用 Orm

需相应修改:优化 Orm 方法

13. 如果正在使用 Path 方法

Path 方法由原来返回相对路径改为返回绝对路径,如果正在使用需检查是否需要修改:优化 Path 方法

14. 如果 正在使用 ctx.Request().InputMap 方法

需相应修改:优化 Request 方法

15. 如果正在使用 console.Confirm 方法

需相应修改:优化 console Confirm 方法

16. 如果正在使用 Testing.Request 方法

需相应修改:优化 Testing.Request 方法

功能介绍

新增 facades.DB()

新增 facades.DB() 模块,方便进行数据库的原生操作,比 ORM 速度更快。

查看文档

新增 facades.Http()

新增一个内置的 HTTP 客户端 facades.Http(),让 API 调用变得轻而易举。

查看文档

重构 facades.Queue()

  • v1.15 之前 Queue 仅支持同步驱动与 Redis 驱动,从 v1.16 开始支持数据库驱动及自定义驱动。

  • 新增 jobsfailed_jobs 表,用于存储任务及失败任务。

  • 新增 queue:retry 命令,用于重试失败的任务。

  • 新增 queue:failed 命令,用于查看失败任务。

  • 支持在启动队列任务时设置重试次数。

详情请 查看文档

facades.Auth() 支持自定义驱动

v1.15 之前 Auth 仅支持 JWT 驱动,从 v1.16 开始支持 Session 及自定义驱动,详情请 查看文档

make:* 命令生成的文件支持自动注册

make:migrationmake:seeder 等命令生成的文件,在生成后会自动注册到框架中,无需像之前一样需要手动注册。

Goravel Installer 支持选择驱动

使用 Goravel Installer 安装新项目的过程中可以选择安装不同的驱动,例如:可以选择安装 goravel/gin 或 goravel/fiber 等。

拆分数据库驱动

之前多个数据库驱动同时集成在框架中,使得软件打包体积变大,从 v1.16 开始,数据库驱动将作为独立包存在,只需安装自己需要的数据库驱动即可。

数据库类型驱动包
Postgresgithub.com/goravel/postgres
MySQLgithub.com/goravel/mysql
Sqlservergithub.com/goravel/sqlserver
SQLitegithub.com/goravel/sqlite

Orm 新增特性

  • 支持查找 JSON 字段,查看文档

  • 支持更新 JSON 字段,查看文档

  • Model 中支持设置 GlobalScope 方法,在查找、更新和删除操作时限制作用域:

go
import (
  contractsorm"github.com/goravel/framework/contracts/database/orm"
  "github.com/goravel/framework/database/orm"
)

type User struct {
  orm.Model
  Name string
}

func (r *User) GlobalScopes() []func(contractsorm.Query) contractsorm.Query {
  return []func(contractsorm.Query) contractsorm.Query{
    func(query contractsorm.Query) contractsorm.Query {
      return query.Where("name", "goravel")
    },
  }
}

支持根据数据表创建 Model

make:model 命令新增 --table 选项,用于根据数据表创建 Model:

shell
./artisan make:model --table=users User

// 如果 Model 已存在可以使用 -f 选项强制覆盖
./artisan make:model --table=users -f User

支持运行时动态获取 SQL 语句

新增 EnableQueryLog 等方法,用于在运行时动态获取 SQL 语句:

go
ctx := db.EnableQueryLog(ctx)

facades.Orm().WithContext(ctx).Query().Find()

queryLogs := db.GetQueryLog(ctx)
ctx := db.DisableQueryLog(ctx)

Migration 新增特性

  • 新增 Change 方法(适用于 Postgres, MySQL, Sqlserver),用于修改表结构:
go
table.String("name").Change()
  • 新增 RenameColumn 方法,用于重命名表列:
go
table.RenameColumn("old_name", "new_name")
  • 新增 Comment 方法,用于为表添加注释(适用于 Postgres, MySQL):
go
table.Comment("user table")
  • 新增 First 方法,用于将字段设置为表的第一个字段(适用于 MySQL):
go
table.String("name").First()
  • 新增 After 方法,用于将字段设置为表的最后一个字段(适用于 MySQL):
go
table.String("name").After("id")
  • 新增 Morphs, NullableMorphs, NumericMorphs, UuidMorphs, UlidMorphs 方法,用于创建多态关联字段:
go
table.Morphs("morphable")
// morphable_type, morphable_id
  • 新增 Uuid, Ulid 方法,用于创建 UUID 和 ULID 字段:
go
table.Uuid("uuid")
table.Ulid("ulid")
  • 新增 GeneratedAsAlways 方法,用于创建生成列(仅 PostgreSQL):
go
table.String("name").GeneratedAs().Always()

Grpc 新增 Shutdown 方法

新增 Shutdown 方法以便优雅的关闭 Grpc,查看文档

Artisan 新增禁用打印颜色选项

有些命令默认会打印颜色,例如 list 命令,但在某些终端或日志中颜色值会是乱码,这时你可以使用 --no-ansi 选项禁用打印颜色:

shell
go run . artisan list --no-ansi

加解密 env 文件

你也许想将生产环境的 env 文件添加到版本控制中,但又不想将敏感信息暴露出来,这时你可以加解密 env 文件。

查看文档

发送邮件支持设置 Header

新增 Headers 方法,用于设置邮件的 Header。

go
facades.Mail().Headers(map[string]string{"X-Mailer": "Goravel"})

Installer 支持自升级

goravel/installer 新增 upgrade 命令,用于 installer 的自身升级:

shell
goravel upgrade
goravel upgrade v1.1.1

多语言文件支持 embed 加载

使用 embed 加载时,多语言文件将会被编译到二进制文件中,部署时不再需要多语言文件。

查看文档

Schedule 新增特性

  • 新增 EverySecond 等方法,详细请 查看文档

  • 新增 schedule:run 命令,用于手动运行任务。

  • 新增 schedule:list 方法,用于查看所有任务。

Request 新增特性

  • v1.15 之前下面 Request 绑定将报错,从 v1.16 开始支持绑定多个文件:
go
type StoreMediaRequest struct {
	Files []*multipart.FileHeader `form:"files" json:"files"`
}
  • 新增 OriginalPath 方法,用于获取原始路由路径:
go
ctx.Request().OriginPath()
  • Request 新增 Info 方法,用于获取当前请求路由信息:
go
info := ctx.Request().Info()
  • Request 新增 Name 方法,用于获取当前请求路由名称:
go
name := ctx.Request().Name()
  • 当设置 http.request_timeout 配置项 为 0 时,请求将不会超时。

Route 新增特性

  • 新增 GetRoutes 方法,用于获取所有路由:
go
routes := facades.Route().GetRoutes()
  • 新增 Name 方法,用于设置路由名称:
go
facades.Route().Get("users", usersController.Index).Name("users.index")

然后可以使用 Info 方法获取路由信息:

go
route := facades.Route().Info("users.index")
  • 新增 route:list 命令,用于查看所有路由:
shell
./artisan route:list

Testing 支持创建 Cache 镜像

新增 Cache 方法,用于创建 Cache 镜像:

go
cache, err := facades.Testing().Docker().Cache()

详细请 查看文档

不同 JWT Guard 支持设置不同的 ttl 与 secert

之前 JWT Guard 的 ttlsecret 配置项是全局配置,从 v1.16 开始,你可以为不同的 JWT Guard 设置不同的 ttlsecret查看文档

注册 ServiceProvider 不再依赖顺序

ServiceProvider 新增可选方法 Relationship() binding.Relationship,用来声明当前 ServicerProvider 的依赖关系,设置了该方法的 ServiceProvider 将不依赖注册顺序,未设置的 ServiceProvider 将被最后注册,例如:

go
type ServiceProvider struct {
}

func (r *ServiceProvider) Relationship() binding.Relationship {
	return binding.Relationship{
		Bindings: []string{
			BindingSession,
		},
		Dependencies: []string{
			binding.Config,
		},
		ProvideFor: []string{
			binding.Cache,
		},
	}
}

func (r *ServiceProvider) Register(app foundation.Application) {}

func (r *ServiceProvider) Boot(app foundation.Application) {}

移除 SQL 迁移

SQL 迁移被完全移除,请使用 Go 语言迁移。迁移步骤:

  1. 移除 config/database.go 中的 migrations.driver 键;
go
// config/database.go
"migrations": map[string]any{
--   "driver": "sql",
  "table":  "migrations",
},
  1. database/migrations 目录下的 SQL 迁移文件转换为 Go 语言迁移文件:
go
// Up Run the migrations.
func (r *M20241207095921CreateUsersTable) Up() error {
  return facades.Schema().Sql({Original SQL})
}

// Down Reverse the migrations.
func (r *M20241207095921CreateUsersTable) Down() error {
  return facades.Schema().Sql({Original SQL})
}
  1. database/kernel.go 文件中注册迁移文件;

优化 Config 模块方法默认值类型

之前 GetStringGetIntGetBool 方法的默认值类型为 any,从 v1.16 开始,默认值类型为 stringintbool,以保证类型安全。

diff
-- GetString(path string, defaultValue ...any) string
++ GetString(path string, defaultValue ...string) string

-- GetInt(path string, defaultValue ...any) int
++ GetInt(path string, defaultValue ...int) int

-- GetBool(path string, defaultValue ...any) bool
++ GetBool(path string, defaultValue ...bool) bool

优化 Orm 方法

  • 优化 Count, Distinct, Select, Exists, Sum 方法:
diff
-- Count(count *int64) error
++ Count() (int64, error)

-- Distinct(args ...any) Query
++ Distinct(columns ...string) Query

-- Exists(exists *bool) error
++ Exists() (bool, error)

-- Select(query any, args ...any) Query
++ Select(columns ...string) Query

-- Sum(column string, dest any) error
++ Sum(column string) (int64, error)
  • Where 方法支持闭包:
go
facades.Orm().Query().Where(func(query orm.Query) orm.Query {
  return query.Where("height", 180).Where("age", 18)
}).FindOrFail(&user, 100)
// SELECT * FROM users WHERE id = 100 AND (height = 180 AND age = 18);

优化 Path 方法

  • path 方法返回绝对路径

之前 path 方法返回的是相对于根目录的路径,例如 path.Config("app.go") == config/app.go,从 v1.16 开始,path 方法返回的是绝对路径,例如 path.Config("app.go") == /Users/goravel/workspace/goravel/config/app.go

  • 新增 Resource 方法
go
path.Resource("views/welcome.tmpl")

优化 Request 方法

  • 修改 InputMap 方法默认值类型:
diff
-- ctx.Request().InputMap(key string, defaultValue ...map[string]string) map[string]string
++ ctx.Request().InputMap(key string, defaultValue ...map[string]any) map[string]any
  • 新增 InputMapArray 方法,用于获取数组类型的 Map:
go
ctx.Request().InputMapArray(key string, defaultValue ...[]map[string]any) []map[string]any
  • 新增 Files 方法,用于获取多个文件:
go
ctx.Request().Files(name string) ([]filesystem.File, error)

优化 console Confirm 方法

修改 Confirm 方法的返回值,简化判断逻辑:

diff
-- Confirm(question string, option ...ConfirmOption) (bool, error)
++ Confirm(question string, option ...ConfirmOption) bool

优化 Session 自定义驱动方式

之前,你需要通过 facades.Session().Extend 方法注册驱动,从 v1.16 开始,你只需要将其添加到 config/session.go 配置文件中即可:

diff
// app/providers/app_service_provider.go
-- facades.Session().Extend("custom", func() session.Driver {
--   return &CustomDriver{}
-- })

// config/session.go
"drivers": map[string]any{
  "custom": map[string]any{
    "driver": "custom",
    "via": func() (session.Driver, error) {
      return &CustomDriver{}, nil
    },
  }
},

查看文档

优化 Testing.Request 方法

优化 WithCookiesWithCookie 方法的入参:

diff
-- WithCookies(cookies map[string]string) Request
++ WithCookies(cookies []*http.Cookie) Request

-- WithCookie(key, value string) Request
++ WithCookie(cookie *http.Cookie) Request

优化 Carbon 方法

carbon.NewDateTime 等方法原来返回的是 struct 实例,v1.16 开始返回指针,如果你定义了 carbon.DateTime 等类型,需要修改为 *carbon.DateTime 等指针类型。

优化 str.Snake 方法

str.Snake 方法之前会将 userID 转换为 user_i_d,从 v1.16 开始,会转换为 user_id

goravel/cloudinary 停止维护

goravel/cloudinary 停止维护,请使用 goravel/s3 等其他驱动替代。

优化 Queue 配置

v1.15 之前,Queue 模块的 Redis 驱动使用 RichardKnop/machinery 实现。从 v1.16 开始,Redis 驱动在 goravel/redis 中提供官方支持。

你依然可以在 v1.16 中使用 Machinery 驱动,但其将在 v1.17 中被移除,建议使用 Redis 驱动。下面提供两种升级方式:

继续使用 Machinery 驱动

修改 config/queue.go 文件中的配置:

diff
// config/queue.go
"connections": map[string]any{
...
  "redis": map[string]any{
--    "driver":     "redis",
++    "driver":     "machinery",
    "connection": "default",
    "queue":      config.Env("REDIS_QUEUE", "default"),
  },
},

使用 Redis 队列驱动

修改 config/queue.go 文件中的配置:

diff
// config/queue.go
import (
  "github.com/goravel/framework/contracts/queue"
  redisfacades "github.com/goravel/redis/facades"
)

"connections": map[string]any{
...
  "redis": map[string]any{
--  "driver":     "redis",
++  "driver":     "custom",
    "connection": "default",
    "queue":      config.Env("REDIS_QUEUE", "default"),
++  "via": func() (queue.Driver, error) {
++    return redisfacades.Queue("redis") // The ` + "`redis`" + ` value is the key of ` + "`connections`" + `
++  },
  },
},

新的 Redis 队列驱动与原 machinery 队列驱动的任务都保存在同一个 Redis 中,但使用不同的队列名称。即使你切换为新的 Redis 队列驱动,框架会继续读取原 Machinery 队列驱动的任务,直到 Machinery 中所有任务执行完毕。与此同时,新的队列任务不再写入 Machinery 队列中,而是写入新的 Redis 队列,并被新的 Redis 队列驱动消费。以实现两个驱动间的无缝切换。

你可以到 Redis 中查看两个驱动的数据是否被正确写入与消费:

shell
redis-cli

# 获取 Redis 中所有的键
keys

# 查看 Machinery 队列驱动数据(替换 {} 中的值)
LRANGE {app_name}_queues:{queue_name} 0 -1

# 查看 Redis 队列驱动数据(替换 {} 中的值)
LRANGE {app_name}_queues:{connection}_{queue} 0 -1

基于 MIT 许可发布