Upgrading To v1.16 From v1.15
Exciting New Features 🎉
- Add facades.DB()
- Add facades.Http()
- Reconstruct facades.Queue()
- facades.Auth() supports custom driver
- make:* commands support automatic registration
- Goravel Installer supports selecting driver
Enhancements 🚀
- Split Database Driver
- Orm adds features
- Support creating Model based on data table
- Support runtime dynamic SQL statement
- Migration adds features
- Grpc adds Shutdown method
- Artisan adds disable print colors option
- Encrypt and decrypt env file
- Send email supports setting Header
- Installer supports self upgrade
- Localization supports embed loading
- Schedule adds features
- Request adds features
- Route adds features
- Testing supports creating Cache image
- Different JWT Guard supports different configurations
- ServiceProvider no longer depends on order
Breaking Changes 🛠
- Remove SQL Migration
- Optimize Config module methods default value type
- Optimize Orm methods
- Optimize Path methods
- Optimize Request methods
- Optimize console Confirm methods
- Optimize Session custom driver
- Optimize Testing.Request methods
- Optimize Carbon methods
- Optimize str.Snake methods
- goravel/cloudinary is no longer maintained
Upgrade Guide
As Golang v1.22 is no longer maintained, the Golang version of Goravel supports has been upgraded from 1.22 to 1.23.
goravel/example project from v1.15 to v1.16 PR can be used as an upgrade reference: goravel/example#68.
1. Update Dependencies
go get github.com/goravel/framework@latest
// If using gin
go get github.com/goravel/gin@latest
// If using fiber
go get github.com/goravel/fiber@latest
// If using redis
go get github.com/goravel/redis@latest
// If using S3
go get github.com/goravel/s3@latest
// If using Oss
go get github.com/goravel/oss@latest
// If using Cos
go get github.com/goravel/cos@latest
// If using Minio
go get github.com/goravel/minio@latest
go mod tidy
2. Modify Database Configuration
Delete the connections
in the database configuration file config/database.go
that you don't need, and install the database driver you need.
For example, Postgres:
- Install the driver package
go get github.com/goravel/postgres
- Add
postgres.ServiceProvider
to theconfig/app.go
file
// config/app.go
import "github.com/goravel/postgres"
"providers": []foundation.ServiceProvider{
...
&postgres.ServiceProvider{},
},
- Modify the configuration in the
config/database.go
file
// 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. Modify auth.go configuration file
// 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. Modify session.go configuration file
// 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. Modify queue.go configuration file
If you are using the Redis driver of the Queue module, you need to modify accordingly: Optimize Queue module configuration.
If you are not using it or want to use the database driver in the future, you need to modify the configuration in the
config/queue.go
file:
// 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",
++ },
Add the migration file required for the database driver: database/migrations/20210101000002_create_jobs_table.go, and register the migration file in the database/kernel.go
file.
6. If you need to use HTTP Client
Add the HTTP Client configuration item in the config/http.go
file:
// 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. If using goravel/redis driver
Need to modify the configuration in the config/cache.go
file:
// 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. If using carbon.DateTime etc. methods
Need to modify accordingly: Optimize Carbon methods
9. If using session custom driver
Need to modify accordingly: Optimize Session custom driver
10. If using methods of facades.Config()
Need to modify accordingly: Modify Config module methods default value type
11. If Using SQL Migrations
Need to modify accordingly: Remove SQL Migration
12. If Using Orm
Need to modify accordingly: Optimize Orm methods
13. If Using Path Method
The path
method returns the absolute path, if you are using it, you need to check if you need to modify: Optimize Path method
14. If Using ctx.Request().InputMap
Method
Need to modify accordingly: Optimize Request method
15. If Using console.Confirm
Method
Need to modify accordingly: Optimize console Confirm method
16. If Using Testing.Request method
Need to modify accordingly: Optimize Testing.Request method
Feature Introduction
Add facades.DB()
Add the facades.DB()
module, which is convenient for performing native database operations, faster than ORM.
Add facades.Http()
Add the facades.Http()
module, which is convenient for performing HTTP operations.
Reconstruct facades.Queue()
Before v1.15, Queue only supported sync and Redis drivers, starting from v1.16, it supports database and custom driver.
Add
jobs
andfailed_jobs
table, used to store tasks and failed tasks.Add
queue:retry
command, used to retry failed tasks.Add
queue:failed
command, used to view failed tasks.Support setting the number of retries when starting the queue task.
facades.Auth() supports custom driver
Before v1.15, Auth only supported JWT driver, starting from v1.16, it supports Session and custom driver, please view document.
make:* commands support automatic registration
The filesmake:migration
and make:seeder
, etc. commands generated files will be automatically registered to the framework after generation, no longer need to manually register like before.
Goravel Installer supports selecting driver
When installing a new project using Goravel Installer, you can select different drivers, such as: you can choose to install goravel/gin or goravel/fiber, etc.
Split Database Driver
Before multiple database drivers were integrated in the framework, which increased the software package size. Starting from v1.16, the database driver will be a separate package, so you only need to install the database driver you need.
Database Type | Driver Package |
---|---|
Postgres | github.com/goravel/postgres |
MySQL | github.com/goravel/mysql |
Sqlserver | github.com/goravel/sqlserver |
SQLite | github.com/goravel/sqlite |
Orm adds features
Support querying JSON fields, view document.
Support updating JSON fields, view document.
Model supports setting the
GlobalScope
method, which restricts the scope of the query, update, and delete operations:
import "github.com/goravel/framework/contracts/orm"
type User struct {
orm.Model
Name string
}
func (r *User) GlobalScopes() []func(orm.Query) orm.Query {
return []func(orm.Query) orm.Query{
func(query orm.Query) orm.Query {
return query.Where("name", "goravel")
},
}
}
Support creating Model based on data table
make:model
command adds --table
option, used to create Model based on data table:
./artisan make:model --table=users User
// If the Model already exists, you can use the -f option to force overwrite
./artisan make:model --table=users -f User
Support runtime dynamic SQL statement
Add the EnableQueryLog
method, which is used to enable query log:
ctx := db.EnableQueryLog(ctx)
facades.Orm().WithContext(ctx).Query()
facades.DB().WithContext(ctx).Table()
queryLogs := db.GetQueryLog(ctx)
ctx := db.DisableQueryLog(ctx)
Migration adds features
- Add the
Change
method to modify the table structure(Apply to Postgres, MySQL, Sqlserver):
table.String("name").Change()
- Add the
RenameColumn
method, for renaming the table column:
table.RenameColumn("old_name", "new_name")
- Add the
Comment
method, for adding a comment to the table (Apply to Postgres, MySQL):
table.Comment("user table")
- Add the
First
method, for setting the field as the first field of the table (Apply to MySQL):
table.String("name").First()
- Add the
After
method, for setting the field as the last field of the table (Apply to MySQL):
table.String("name").After("id")
- Add the
Morphs
,NullableMorphs
,NumericMorphs
,UuidMorphs
,UlidMorphs
methods, used to create polymorphic association fields:
table.Morphs("morphable")
// morphable_type, morphable_id
- Add the
Uuid
,Ulid
methods, used to create UUID and ULID fields:
table.Uuid("uuid")
table.Ulid("ulid")
- Add the
GeneratedAs
andAlways
methods, used to create generated columns (only PostgreSQL):
table.String("name").GeneratedAs().Always()
Grpc adds Shutdown method
Add the Shutdown
method to gracefully shut down Grpc, View Document.
Artisan adds disable print colors option
Some commands print colors by default, such as the list
command. However, in some terminals or logs, the color values may be garbled. You can use the --no-ansi
option to disable the print colors:
go run . artisan list --no-ansi
Encrypt and decrypt env file
You may want to add the production environment env file to version control, but you don't want to expose sensitive information, you can encrypt and decrypt the env file:
Send email supports setting Header
Add the Headers
method, which is used to set the Header of the email.
facades.Mail().Headers(map[string]string{"X-Mailer": "Goravel"})
Installer supports self upgrade
goravel/installer adds upgrade
command, which is used to upgrade the installer itself:
goravel upgrade
goravel upgrade v1.1.1
Localization supports embed loading
When using embed loading, the language files will be compiled into the binary file and no longer need to be deployed.
Schedule adds features
Add the
EverySecond
method, etc., please view document.Add the
schedule:run
command, which is used to manually run tasks.Add the
schedule:list
method, which is used to view all tasks.
Request adds features
- Before v1.15, the following
Request
binding will report an error, starting from v1.16, it supports binding multiple files:
type StoreMediaRequest struct {
Files []*multipart.FileHeader `form:"files" json:"files"`
}
- Add the
OriginPath
method, which is used to get the original route path:
ctx.Request().OriginPath()
- Add the
Info
method, which is used to get the route information:
info := ctx.Request().Info()
- Add the
Name
method, which is used to get the route name:
name := ctx.Request().Name()
- When the
http.request_timeout
configuration item is set to0
, the request will not timeout.
Route adds features
- Add the
GetRoutes
method, which is used to get all routes:
routes := facades.Route().GetRoutes()
- Add the
Name
method, which is used to set the route name:
facades.Route().Get("users", usersController.Index).Name("users.index")
Then you can use the Info
method to get the route information:
route := facades.Route().Info("users.index")
- Add the
route:list
command, which is used to view all routes:
./artisan route:list
Testing supports creating Cache image
Add the Cache
method, which is used to create Cache image:
cache, err := facades.Testing().Docker().Cache()
Different JWT Guard supports different configurations
Before v1.15, the ttl
and secret
configuration items of the JWT Guard were global configurations, starting from v1.16, you can set different ttl
and secret
for different JWT Guards, View Document.
ServiceProvider no longer depends on order
ServiceProvider adds an optional method Relationship() binding.Relationship
, used to declare the dependency relationship of the current ServicerProvider, the ServiceProvider that sets this method will not depend on the registration order, and the ServiceProvider that does not set it will be registered last, for example:
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) {}
Remove SQL Migration
SQL migrations have been completely removed, please use Go language migrations. Migration steps:
- Remove the
migrations.driver
key inconfig/database.go
;
// config/database.go
"migrations": map[string]any{
-- "driver": "sql",
"table": "migrations",
},
- Convert the SQL migration files in the
database/migrations
directory to Go language migration files:
// 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})
}
- Register the migration files in the
database/kernel.go
file;
Optimize Config module methods default value type
Before the GetString
、GetInt
、GetBool
method of the Config
module had a default value type of any
, starting from v1.16, the default value type is string
、int
、bool
, to ensure type safety.
-- 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
Optimize Orm methods
- Optimize the return value of the
Count
,Exists
method:
-- 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)
- The
Where
method supports closures:
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);
Optimize Path methods
- Add the
Resource
method
path.Resource("views/welcome.tmpl")
- The
path
method returns the absolute path
Before the path
method returned the relative path of the root directory, for example, path.Config("app.go") == config/app.go
. Starting from v1.16, the path
method returns the absolute path, for example, path.Config("app.go") == /Users/goravel/workspace/goravel/config/app.go
.
Optimize Request methods
- Modify the default value type of the
InputMap
method:
-- ctx.Request().InputMap(key string, defaultValue ...map[string]string) map[string]string
++ ctx.Request().InputMap(key string, defaultValue ...map[string]any) map[string]any
- Add the
InputMapArray
method, which is used to get the array type of Map:
ctx.Request().InputMapArray(key string, defaultValue ...[]map[string]any) []map[string]any
- Add the
Files
method, which is used to get multiple files:
ctx.Request().Files(name string) ([]filesystem.File, error)
Optimize console Confirm methods
Modify the return value of the Confirm
method, simplifying the judgment logic:
-- Confirm(question string, option ...ConfirmOption) (bool, error)
++ Confirm(question string, option ...ConfirmOption) bool
Optimize Session custom driver
Before, you needed to register the driver through the facades.Session().Extend
method. Starting from v1.16, you only need to add it to the config/session.go
configuration file:
// 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
},
}
},
Optimize Testing.Request methods
Optimize the parameters of the WithCookies
and WithCookie
methods:
-- WithCookies(cookies map[string]string) Request
++ WithCookies(cookies []*http.Cookie) Request
-- WithCookie(key, value string) Request
++ WithCookie(cookie *http.Cookie) Request
Optimize Carbon methods
Previously, the carbon.NewDateTime
, etc. methods return a struct instance, starting from v1.16, it returns a pointer, if you define the carbon.DateTime
type, etc., you need to modify it to *carbon.DateTime
etc. pointer type.
Optimize str.Snake methods
The str.Snake
method previously converted userID
to user_i_d
, starting from v1.16, it will be converted to user_id
.
goravel/cloudinary is no longer maintained
goravel/cloudinary is no longer maintained, please use goravel/s3 or other drivers instead.
Optimize Queue module configuration
Before v1.15, the Redis driver of the Queue module was implemented using RichardKnop/machinery. Starting from v1.16, the Redis driver is officially supported in goravel/redis.
You can still use the Machinery driver in v1.16, but it will be removed in v1.17, it is recommended to use the Redis driver. The following provides two upgrade methods:
Continue using Machinery driver
Modify the configuration in the config/queue.go
file:
// config/queue.go
"connections": map[string]any{
...
"redis": map[string]any{
-- "driver": "redis",
++ "driver": "machinery",
"connection": "default",
"queue": config.Env("REDIS_QUEUE", "default"),
},
},
Use Redis queue driver
Modify the configuration in the config/queue.go
file:
// 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`" + `
++ },
},
},
The new Redis queue driver and the original machinery queue driver tasks are stored in the same Redis, but use different queue names. Even if you switch to the new Redis queue driver, the framework will continue to read the original Machinery queue driver tasks until all tasks in Machinery are completed. At the same time, the new queue tasks are no longer written to the Machinery queue, but written to the new Redis queue, and consumed by the new Redis queue driver. To achieve seamless switching between two drivers.
You can check the data of the two drivers in Redis to see if they are correctly written and consumed:
redis-cli
# Get all keys in Redis
keys
# View Machinery queue driver data (replace {} with the value)
LRANGE {app_name}_queues:{queue_name} 0 -1
# View Redis queue driver data (replace {} with the value)
LRANGE {app_name}_queues:{connection}_{queue} 0 -1