[[toc]]
Goravel makes it easy for developers to interact with databases using facades.Orm(). Currently, it provides official support for the following four databases:
- MySQL 5.7+
- PostgreSQL 9.6+
- SQLite 3.8.8+
- SQL Server 2017+
Before you start, configure the database in .env and confirm the default configuration in config/database.go.
To configure databases, navigate to config/database.go. This is where you can customize all database connections and choose a default connection. The configuration in this file relies on the project's environment variables and showcases various database configurations that Goravel supports.
You can also use DSN to connect to the database directly, just configure the dsn field in the configuration file:
"postgres": map[string]any{
"driver": "postgres",
++ "dsn": "postgres://user:password@localhost:5432/dbname?sslmode=disable",
...
}Sometimes you may wish to use one database connection for SELECT statements, and another for INSERT, UPDATE, and DELETE statements. Goravel makes this a breeze.
To see how read/write connections should be configured, let's look at this example:
import "github.com/goravel/framework/contracts/database"
// config/database.go
"connections": map[string]any{
"mysql": map[string]any{
"driver": "mysql",
"read": []database.Config{
{Host: "192.168.1.1", Port: 3306, Database: "forge", Username: "root", Password: "123123"},
},
"write": []database.Config{
{Host: "192.168.1.2", Port: 3306, Database: "forge", Username: "root", Password: "123123"},
},
"host": config.Env("DB_HOST", "127.0.0.1"),
"port": config.Env("DB_PORT", 3306),
"database": config.Env("DB_DATABASE", "forge"),
"username": config.Env("DB_USERNAME", ""),
"password": config.Env("DB_PASSWORD", ""),
"charset": "utf8mb4",
"loc": "Local",
},
}We have updated the configuration array with two new keys - read and write. The read connection will use 192.168.1.1 as the host, while the write connection will use 192.168.1.2. Both connections will share the same database prefix, character set, and other options specified in the main mysql array. In case of multiple values in the host configuration array, a database host will be selected randomly for each request.
You can configure a connection pool in the configuration file, reasonable configuration of connection pool parameters can greatly improve concurrency performance:
| Key | Action |
|---|---|
| pool.max_idle_conns | Max idle connections |
| pool.max_open_conns | Max open connections |
| pool.conn_max_idletime | Connections max idle time |
| pool.conn_max_lifetime | Connections max lifetime |
Postgres and Sqlserver support configuring Schema. Postgres can directly set the Schema in the configuration file, while Sqlserver needs to specify the Schema through the TableName method in the model.
"connections": map[string]any{
"postgres": map[string]any{
"driver": "postgres",
...
"schema": "goravel",
},
}func (r *User) TableName() string {
return "goravel.users"
}You can use the db:show command to view all tables in the database.
go run . artisan db:showYou can also use the db:table command to view the structure of a specific table.
go run . artisan db:table
go run . artisan db:table usersTo create a custom model, refer to the model file app/models/user.go that is included in the framework. The struct in app/models/user.go contains two embedded frameworks: orm.Model and orm.SoftDeletes. These frameworks define id, created_at, updated_at, and deleted_at properties respectively. With orm.SoftDeletes, you can enable soft deletion for the model.
- The model is named with a big hump;
- Use the plural form of the model "snake naming" as the table name;
For example, the model name is UserOrder, and the table name is user_orders.
Use the make:model command to create a model:
go run . artisan make:model User
go run . artisan make:model user/UserCreated model file is located in app/models/user.go file, the content is as follows:
package models
import (
"github.com/goravel/framework/database/orm"
)
type User struct {
orm.Model
Name string
Avatar string
orm.SoftDeletes
}If you want to set the model field to any, you need to add an additional Tag: gorm:"type:text":
type User struct {
orm.Model
Name string
Avatar string
Detail any `gorm:"type:text"`
orm.SoftDeletes
}More Tag usage details can be found at: https://gorm.io/docs/models.html.
package models
import (
"github.com/goravel/framework/database/orm"
)
type User struct {
orm.Model
Name string
Avatar string
orm.SoftDeletes
}
func (r *User) TableName() string {
return "goravel_user"
}By default, all models utilize the default database connection configured for your application. If you wish to specify a distinct connection to be used when interacting with a particular model, you need to define a Connection method on the model.
package models
import (
"github.com/goravel/framework/database/orm"
)
type User struct {
orm.Model
Name string
Avatar string
orm.SoftDeletes
}
func (r *User) Connection() string {
return "postgres"
}| Name | Action |
|---|---|
| Connection | Specify Database Connection |
| DB | Generic Database Interface sql.DB |
| Query | Get Database Instance |
| Transaction | Transaction |
| WithContext | Inject Context |
facades.Orm().WithContext(ctx)If multiple database connections are defined in config/database.go, you can use them through the Connection function of facades.Orm(). The connection name passed to Connection should be one of the connections configured in config/database.go:
facades.Orm().Connection("mysql")Generic database interface sql.DB, then use the functionality it provides:
db, err := facades.Orm().DB()
db, err := facades.Orm().Connection("mysql").DB()
// Ping
db.Ping()
// Close
db.Close()
// Returns database statistics
db.Stats()
// SetMaxIdleConns sets the maximum number of connections in the idle connection pool
db.SetMaxIdleConns(10)
// SetMaxOpenConns sets the maximum number of open connections to the database
db.SetMaxOpenConns(100)
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused
db.SetConnMaxLifetime(time.Hour)Before each specific database operation, it's necessary to obtain an instance of the database.
facades.Orm().Query()
facades.Orm().Connection("mysql").Query()
facades.Orm().WithContext(ctx).Query()var user models.User
facades.Orm().Query().First(&user)
// SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1;Sometimes you may wish to perform some other action if no results are found. The FirstOr method will return a single model instance or, if no results are found, execute the given closure. You can set values to model in closure:
facades.Orm().Query().Where("name", "first_user").FirstOr(&user, func() error {
user.Name = "goravel"
return nil
})var user models.User
facades.Orm().Query().Find(&user, 1)
// SELECT * FROM `users` WHERE `users`.`id` = 1;
var users []models.User
facades.Orm().Query().Find(&users, []int{1,2,3})
// SELECT * FROM `users` WHERE `users`.`id` IN (1,2,3);var user models.User
err := facades.Orm().Query().FindOrFail(&user, 1)When the primary key of the user table is string type, you need to specify the primary key when calling Find method
var user models.User
facades.Orm().Query().Find(&user, "uuid=?" ,"a")
// SELECT * FROM `users` WHERE `users`.`uuid` = "a";var users []models.User
facades.Orm().Query().Where("id in ?", []int{1,2,3}).Get(&users)
// SELECT * FROM `users` WHERE id in (1,2,3);The FirstOrCreate method searches for a database record using the specified column/value pairs. If the model cannot be found in the database, it creates a new record with the attributes from merging the first argument with the optional second argument.
Similarly, the FirstOrNew method also tries to locate a record in the database based on the attributes given. However, if it is not found, a new instance of the model is returned. It's important to note that this new model has not been saved to the database yet and you need to manually call the Save method to do so.
var user models.User
facades.Orm().Query().Where("gender", 1).FirstOrCreate(&user, models.User{Name: "tom"})
// SELECT * FROM `users` WHERE `gender` = 1 AND `users`.`name` = 'tom' ORDER BY `users`.`id` LIMIT 1;
// INSERT INTO `users` (`created_at`,`updated_at`,`name`) VALUES ('2023-09-18 12:51:32.556','2023-09-18 12:51:32.556','tom');
facades.Orm().Query().Where("gender", 1).FirstOrCreate(&user, models.User{Name: "tom"}, models.User{Avatar: "avatar"})
// SELECT * FROM `users` WHERE `gender` = 1 AND `users`.`name` = 'tom' ORDER BY `users`.`id` LIMIT 1;
// INSERT INTO `users` (`created_at`,`updated_at`,`name`,`avatar`) VALUES ('2023-09-18 12:52:59.913','2023-09-18 12:52:59.913','tom','avatar');
var user models.User
facades.Orm().Query().Where("gender", 1).FirstOrNew(&user, models.User{Name: "tom"})
// SELECT * FROM `users` WHERE `gender` = 1 AND `users`.`name` = 'tom' ORDER BY `users`.`id` LIMIT 1;
facades.Orm().Query().Where("gender", 1).FirstOrNew(&user, models.User{Name: "tom"}, models.User{Avatar: "avatar"})
// SELECT * FROM `users` WHERE `gender` = 1 AND `users`.`name` = 'tom' ORDER BY `users`.`id` LIMIT 1;When the requested item is not found, the First method does not generate an error. To generate an error, use the FirstOrFail method:
var user models.User
err := facades.Orm().Query().FirstOrFail(&user)
// import "github.com/goravel/framework/errors"
// if errors.Is(err, errors.OrmRecordNotFound) {}facades.Orm().Query().Where("name", "tom")
facades.Orm().Query().Where("name = 'tom'")
facades.Orm().Query().Where("name = ?", "tom")
facades.Orm().Query().WhereBetween("age", 1, 10)
facades.Orm().Query().WhereNotBetween("age", 1, 10)
facades.Orm().Query().WhereNotIn("name", []any{"a"})
facades.Orm().Query().WhereNull("name")
facades.Orm().Query().WhereIn("name", []any{"a"})
facades.Orm().Query().OrWhere("name = ?", "tom")
facades.Orm().Query().OrWhereNotIn("name", []any{"a"})
facades.Orm().Query().OrWhereNull("name")
facades.Orm().Query().OrWhereIn("name", []any{"a"})var users []models.User
facades.Orm().Query().Where("name = ?", "tom").Limit(3).Get(&users)
// SELECT * FROM `users` WHERE name = 'tom' LIMIT 3;var users []models.User
facades.Orm().Query().Where("name = ?", "tom").Offset(5).Limit(3).Get(&users)
// SELECT * FROM `users` WHERE name = 'tom' LIMIT 3 OFFSET 5;var users []models.User
facades.Orm().Query().Where("name = ?", "tom").Order("sort asc").Order("id desc").Get(&users)
// SELECT * FROM `users` WHERE name = 'tom' ORDER BY sort asc,id desc;
facades.Orm().Query().Where("name = ?", "tom").OrderBy("sort").Get(&users)
// SELECT * FROM `users` WHERE name = 'tom' ORDER BY sort asc;
facades.Orm().Query().Where("name = ?", "tom").OrderBy("sort", "desc").Get(&users)
// SELECT * FROM `users` WHERE name = 'tom' ORDER BY sort desc;
facades.Orm().Query().Where("name = ?", "tom").OrderByDesc("sort").Get(&users)
// SELECT * FROM `users` WHERE name = 'tom' ORDER BY sort desc;
facades.Orm().Query().Where("name = ?", "tom").InRandomOrder().Get(&users)
// SELECT * FROM `users` WHERE name = 'tom' ORDER BY RAND();var users []models.User
var total int64
facades.Orm().Query().Paginate(1, 10, &users, &total)
// SELECT count(*) FROM `users`;
// SELECT * FROM `users` LIMIT 10;var ages []int64
facades.Orm().Query().Model(&models.User{}).Pluck("age", &ages)
// SELECT `age` FROM `users`;If you want to query some aggregate data, you need to specify a specific table.
Specify a model
var count int64
facades.Orm().Query().Model(&models.User{}).Count(&count)
// SELECT count(*) FROM `users` WHERE deleted_at IS NULL;Specify a table
var count int
facades.Orm().Query().Table("users").Count(&count)
// SELECT count(*) FROM `users`; // get all records, whether deleted or notGet SQL with placeholder:
facades.Orm().Query().ToSql().Get(models.User{})
// SELECT * FROM "users" WHERE "id" = $1 AND "users"."deleted_at" IS NULLGet SQL with value:
facades.Orm().Query().ToRawSql().Get(models.User{})
// SELECT * FROM "users" WHERE "id" = 1 AND "users"."deleted_at" IS NULLThe methods can be called after ToSql and ToRawSql: Count, Create, Delete, Find, First, Get, Pluck, Save, Sum, Update.
var count int64
facades.Orm().Query().Table("users").Where("name = ?", "tom").Count(&count)
// SELECT count(*) FROM `users` WHERE name = 'tom';Select allows you to specify which fields to retrieve from the database, by default the ORM retrieves all fields.
facades.Orm().Query().Select("name", "age").Get(&users)
// SELECT `name`,`age` FROM `users`;
facades.Orm().Query().Select([]string{"name", "age"}).Get(&users)
// SELECT `name`,`age` FROM `users`;type Result struct {
Name string
Total int
}
var result Result
facades.Orm().Query().Model(&models.User{}).Select("name, sum(age) as total").Group("name").Having("name = ?", "tom").Get(&result)
// SELECT name, sum(age) as total FROM `users` GROUP BY `name` HAVING name = "tom";type Result struct {
Name string
Email string
}
var result Result
facades.Orm().Query().Model(&models.User{}).Select("users.name, emails.email").Join("left join emails on emails.user_id = users.id").Scan(&result)
// SELECT users.name, emails.email FROM `users` LEFT JOIN emails ON emails.user_id = users.id;user := models.User{Name: "tom", Age: 18}
err := facades.Orm().Query().Create(&user)
// INSERT INTO users (name, age, created_at, updated_at) VALUES ("tom", 18, "2022-09-27 22:00:00", "2022-09-27 22:00:00");
// Not trigger model events
err := facades.Orm().Query().Table("users").Create(map[string]any{
"name": "Goravel",
})
// Trigger model events
err := facades.Orm().Query().Model(&models.User{}).Create(map[string]any{
"name": "Goravel",
})users := []models.User{{Name: "tom", Age: 18}, {Name: "tim", Age: 19}}
err := facades.Orm().Query().Create(&users)
err := facades.Orm().Query().Table("users").Create(&[]map[string]any{
{"name": "Goravel"},
{"name": "Framework"},
})
err := facades.Orm().Query().Model(&models.User{}).Create(&[]map[string]any{
{"name": "Goravel"},
{"name": "Framework"},
})
created_atandupdated_atwill be filled automatically.
Can be used to significantly reduce your application's memory consumption when iterating through tens of thousands of Eloquent model records. Note, the Cursor method can be used with With at the same time, please use Lazy Eager Loading to load relationship in the for logic.
cursor, err := facades.Orm().Query().Model(models.User{}).Cursor()
if err != nil {
return err
}
for row := range cursor {
var user models.User
if err := row.Scan(&user); err != nil {
return err
}
fmt.Println(user)
}var user models.User
facades.Orm().Query().First(&user)
user.Name = "tom"
user.Age = 100
facades.Orm().Query().Save(&user)
// UPDATE `users` SET `created_at`='2023-09-14 16:03:29.454',`updated_at`='2023-09-18 21:05:59.896',`name`='tom',`age`=100,`avatar`='' WHERE `id` = 1;facades.Orm().Query().Model(&models.User{}).Where("name", "tom").Update("name", "hello")
// UPDATE `users` SET `name`='hello',`updated_at`='2023-09-18 21:06:30.373' WHERE `name` = 'tom';
facades.Orm().Query().Model(&models.User{}).Where("name", "tom").Update(models.User{Name: "hello", Age: 18})
facades.Orm().Query().Model(&models.User{}).Where("name", "tom").Update(map[string]any{"name": "hello", "age": 18})
// UPDATE `users` SET `updated_at`='2023-09-18 21:07:06.489',`name`='hello',`age`=18 WHERE `name` = 'tom';When updating with
struct, Orm will only update non-zero fields. You might want to usemapto update attributes or useSelectto specify fields to update. Note thatstructcan only beModel, if you want to update with nonModel, you need to use.Table("users"), however, theupdated_atfield cannot be updated automatically at this time.
Query by name, if not exist, create by name, avatar, if exists, update avatar based on name:
facades.Orm().Query().UpdateOrCreate(&user, models.User{Name: "name"}, models.User{Avatar: "avatar"})
// SELECT * FROM `users` WHERE `users`.`name` = 'name' AND `users`.`deleted_at` IS NULL ORDER BY `users`.`id` LIMIT 1;
// INSERT INTO `users` (`created_at`,`updated_at`,`deleted_at`,`name`,`avatar`) VALUES ('2023-03-11 10:11:08.869','2023-03-11 10:11:08.869',NULL,'name','avatar');
// UPDATE `users` SET `name`='name',avatar`='avatar',`updated_at`='2023-03-11 10:11:08.881' WHERE users`.`deleted_at` IS NULL AND `id` = 1;Delete by model, the number of rows affected by the statement is returned by the method:
var user models.User
facades.Orm().Query().Find(&user, 1)
res, err := facades.Orm().Query().Delete(&user)
res, err := facades.Orm().Query().Model(&models.User{}).Where("id", 1).Delete()
res, err := facades.Orm().Query().Table("users").Where("id", 1).Delete()
// DELETE FROM `users` WHERE `users`.`id` = 1;
num := res.RowsAffectedMultiple delete
facades.Orm().Query().Where("name = ?", "tom").Delete(&models.User{})
// DELETE FROM `users` WHERE name = 'tom';Want to force delete a soft-delete data.
facades.Orm().Query().Where("name", "tom").ForceDelete(&models.User{})
facades.Orm().Query().Model(&models.User{}).Where("name", "tom").ForceDelete()
facades.Orm().Query().Table("users").Where("name", "tom").ForceDelete()You can delete records with model associations via Select:
// Delete Account of user when deleting user
facades.Orm().Query().Select("Account").Delete(&user)
// Delete Orders and CreditCards of user when deleting user
facades.Orm().Query().Select("Orders", "CreditCards").Delete(&user)
// Delete all child associations of user when deleting user
facades.Orm().Query().Select(orm.Associations).Delete(&user)
// Delete all Account of users when deleting users
facades.Orm().Query().Select("Account").Delete(&users)Note: The associations will be deleted only if the primary key of the record is not empty, and Orm uses these primary keys as conditions to delete associated records:
// Delete user that name='goravel', but don't delete account of user
facades.Orm().Query().Select("Account").Where("name = ?", "goravel").Delete(&models.User{})
// Delete user that name='goravel' and id = 1, and delete account of user
facades.Orm().Query().Select("Account").Where("name = ?", "goravel").Delete(&models.User{ID: 1})
// Delete user that id = 1 and delete account of that user
facades.Orm().Query().Select("Account").Delete(&models.User{ID: 1})If execute batch delete without any conditions, ORM doesn't do that and returns an error. So you have to add some conditions, or use native SQL.
var user models.User
facades.Orm().Query().WithTrashed().First(&user)var users []models.User
facades.Orm().Query().Distinct("name").Find(&users)driver := facades.Orm().Query().Driver()
// Judge driver
if driver == orm.DriverMysql {}type Result struct {
ID int
Name string
Age int
}
var result Result
facades.Orm().Query().Raw("SELECT id, name, age FROM users WHERE name = ?", "tom").Scan(&result)The number of rows affected by the statement is returned by the method:
res, err := facades.Orm().Query().Exec("DROP TABLE users")
// DROP TABLE `users`;
num := res.RowsAffectedvar exists bool
facades.Orm().Query().Model(&models.User{}).Where("name", "tom").Exists(&exists)facades.Orm().Query().WithTrashed().Restore(&models.User{ID: 1})
facades.Orm().Query().Model(&models.User{ID: 1}).WithTrashed().Restore()
// UPDATE `users` SET `deleted_at`=NULL WHERE `id` = 1;You can execute a transaction by Transaction function.
import (
"github.com/goravel/framework/contracts/database/orm"
"github.com/goravel/framework/facades"
"goravel/app/models"
)
...
return facades.Orm().Transaction(func(tx orm.Query) error {
var user models.User
return tx.Find(&user, user.ID)
})You can also manually control the flow of the transaction yourself:
tx, err := facades.Orm().Query().Begin()
user := models.User{Name: "Goravel"}
if err := tx.Create(&user); err != nil {
err := tx.Rollback()
} else {
err := tx.Commit()
}Allows you to specify commonly used queries that can be referenced when method are called.
func Paginator(page string, limit string) func(methods orm.Query) orm.Query {
return func(query orm.Query) orm.Query {
page, _ := strconv.Atoi(page)
limit, _ := strconv.Atoi(limit)
offset := (page - 1) * limit
return query.Offset(offset).Limit(limit)
}
}
// scopes.Paginator is a custom function: func(ormcontract.Query) ormcontract.Query
facades.Orm().Query().Scopes(scopes.Paginator(page, limit)).Find(&entries)You can use the db.Raw method to update fields:
import "github.com/goravel/framework/database/db"
facades.Orm().Query().Model(&user).Update("age", db.Raw("age - ?", 1))
// UPDATE `users` SET `age`=age - 1,`updated_at`='2023-09-14 14:03:20.899' WHERE `users`.`deleted_at` IS NULL AND `id` = 1;The query builder also includes a few functions to help you achieve "pessimistic locking" when executing your select statements.
To execute a statement with a "shared lock", you may call the SharedLock method. A shared lock prevents the selected rows from being modified until your transaction is committed:
var users []models.User
facades.Orm().Query().Where("votes", ">", 100).SharedLock().Get(&users)Alternatively, you may use the LockForUpdate method. A "for update" lock prevents the selected records from being modified or from being selected with another shared lock:
var users []models.User
facades.Orm().Query().Where("votes", ">", 100).LockForUpdate().Get(&users)var sum int
if err := facades.Orm().Query().Model(models.User{}).Sum("id", &sum); err != nil {
return err
}
fmt.Println(sum)Orm models dispatch several events, allowing you to hook into the following moments in a model's lifecycle: Retrieved, Creating, Created, Updating, Updated, Saving, Saved, Deleting, Deleted, ForceDeleting, ForceDeleted, Restored, Restoring.
The Retrieved event will dispatch when an existing model is retrieved from the database. When a new model is saved for the first time, the Creating and Created events will dispatch. The Updating / Updated events will dispatch when an existing model is modified and the Save method is called. The Saving / Saved events will dispatch when a model is created or updated - even if the model's attributes have not been changed. Event names ending with -ing are dispatched before any changes to the model are persisted, while events ending with -ed are dispatched after the changes to the model are persisted.
To start listening to model events, define a DispatchesEvents method on your model. This property maps various points of the model's lifecycle to your own event classes.
import (
contractsorm "github.com/goravel/framework/contracts/database/orm"
"github.com/goravel/framework/database/orm"
)
type User struct {
orm.Model
Name string
}
func (u *User) DispatchesEvents() map[contractsorm.EventType]func(contractsorm.Event) error {
return map[contractsorm.EventType]func(contractsorm.Event) error{
contractsorm.EventCreating: func(event contractsorm.Event) error {
return nil
},
contractsorm.EventCreated: func(event contractsorm.Event) error {
return nil
},
contractsorm.EventSaving: func(event contractsorm.Event) error {
return nil
},
contractsorm.EventSaved: func(event contractsorm.Event) error {
return nil
},
contractsorm.EventUpdating: func(event contractsorm.Event) error {
return nil
},
contractsorm.EventUpdated: func(event contractsorm.Event) error {
return nil
},
contractsorm.EventDeleting: func(event contractsorm.Event) error {
return nil
},
contractsorm.EventDeleted: func(event contractsorm.Event) error {
return nil
},
contractsorm.EventForceDeleting: func(event contractsorm.Event) error {
return nil
},
contractsorm.EventForceDeleted: func(event contractsorm.Event) error {
return nil
},
contractsorm.EventRetrieved: func(event contractsorm.Event) error {
return nil
},
contractsorm.EventRestored: func(event contractsorm.Event) error {
return nil
},
contractsorm.EventRestoring: func(event contractsorm.Event) error {
return nil
},
}
}Note: Just register the events you need. Model events are not dispatched when doing batch operations through Orm.
If you are listening to many events on a given model, you may use observers to group all of your listeners into a single class. Observer classes have method names that reflect the Eloquent events you wish to listen for. Each of these methods receives the affected model as their only argument. The make:observer Artisan command is the easiest way to create a new observer class:
go run . artisan make:observer UserObserver
go run . artisan make:observer user/UserObserverThis command will place the new observer in your app/observers directory. If this directory does not exist, Artisan will create it for you. Your fresh observer will look like the following:
package observers
import (
"fmt"
"github.com/goravel/framework/contracts/database/orm"
)
type UserObserver struct{}
func (u *UserObserver) Created(event orm.Event) error {
return nil
}
func (u *UserObserver) Updated(event orm.Event) error {
return nil
}
func (u *UserObserver) Deleted(event orm.Event) error {
return nil
}
func (u *UserObserver) ForceDeleted(event orm.Event) error {
return nil
}The template observer only contains some events, you can add other events according to your needs.
To register an observer, you need to call the Observe method on the model you wish to observe. You may register observers in the Boot method of your application's app/providers/event_service_provider.go::Boot service provider:
package providers
import (
"github.com/goravel/framework/facades"
"goravel/app/models"
"goravel/app/observers"
)
type EventServiceProvider struct {
}
func (receiver *EventServiceProvider) Register(app foundation.Application) {
facades.Event().Register(receiver.listen())
}
func (receiver *EventServiceProvider) Boot(app foundation.Application) {
facades.Orm().Observe(models.User{}, &observers.UserObserver{})
}
func (receiver *EventServiceProvider) listen() map[event.Event][]event.Listener {
return map[event.Event][]event.Listener{}
}Note: If you set
DispatchesEventsandObserverat the same time, onlyDispatchesEventswill be applied.
The event parameter will be passed to all observers:
| Method | Action |
|---|---|
| Context | Get context that passed by facades.Orm().WithContext() |
| GetAttribute | Get the modified value, if not modified, get the original value, if there is no original value, return nil |
| GetOriginal | Get the original value, if there is no original value, return nil |
| IsDirty | Determine whether the field is modified |
| IsClean | IsDirty reverse |
| Query | Get a new Query, which can be used with transaction |
| SetAttribute | Set a new value for a field |
You may occasionally need to temporarily "mute" all events fired by a model. You may achieve this using the WithoutEvents method:
var user models.User
facades.Orm().Query().WithoutEvents().Find(&user, 1)Sometimes you may wish to "save" a given model without dispatching any events. You may accomplish this with the SaveQuietly method:
var user models.User
err := facades.Orm().Query().FindOrFail(&user, 1)
user.Name = "Goravel"
err := facades.Orm().Query().SaveQuietly(&user)