A new pattern for wiring up models for the upcoming 0.12 release #1705
dschissler
started this conversation in
Show and tell
Replies: 1 comment
-
I changed the design to what I suggested at the end of the last post. The reason is that it simplifies the hook wiring helper, and the hook controller doesn't need to know about where it's being bound to. I'm using only a single At any rate, here is another example. hook.WireModel(app, models.UsersCollectionName, user_model.NewHooks(env))
hook.WireModel(app, models.ArticlesCollectionName, article_model.NewHooks(env)) func WireModel(app core.App, tag string, hooks any) {
if h, ok := hooks.(beforeCreateModelHook); ok {
app.OnModelBeforeCreate(tag).Add(recordHandler(h.BeforeCreate))
}
if h, ok := hooks.(afterCreateModelHook); ok {
app.OnModelAfterCreate(tag).Add(recordHandler(h.AfterCreate))
}
if h, ok := hooks.(beforeUpdateModelHook); ok {
app.OnModelBeforeUpdate(tag).Add(recordHandler(h.BeforeUpdate))
}
if h, ok := hooks.(afterUpdateModelHook); ok {
app.OnModelAfterUpdate(tag).Add(recordHandler(h.AfterUpdate))
}
if h, ok := hooks.(beforeDeleteModelHook); ok {
app.OnModelBeforeDelete(tag).Add(recordHandler(h.BeforeDelete))
}
if h, ok := hooks.(afterDeleteModelHook); ok {
app.OnModelAfterDelete(tag).Add(recordHandler(h.AfterDelete))
}
}
type beforeCreateModelHook interface {
BeforeCreate(m *models.Record) error
}
type afterCreateModelHook interface {
AfterCreate(m *models.Record) error
}
type beforeUpdateModelHook interface {
BeforeUpdate(m *models.Record) error
}
type afterUpdateModelHook interface {
AfterUpdate(m *models.Record) error
}
type beforeDeleteModelHook interface {
BeforeDelete(m *models.Record) error
}
type afterDeleteModelHook interface {
AfterDelete(m *models.Record) error
}
func recordHandler(fn hook.Handler[*models.Record]) hook.Handler[*core.ModelEvent] {
return func(e *core.ModelEvent) error {
if m, ok := e.Model.(*models.Record); ok {
return fn(m)
}
return nil
}
} // User Hooks controller
func NewHooks(env *env.Env) *Hooks {
return &Hooks{Env: env}
}
type Hooks struct {
*env.Env
}
func (h *Hooks) BeforeCreate(m *pbmodels.Record) error {
fmt.Println("UserBeforeCreate")
return nil
}
func (h *Hooks) AfterCreate(m *pbmodels.Record) error {
fmt.Println("UserAfterCreate")
if m.GetString("avatar") == "" {
return h.generateAvatar(m)
}
return nil
} |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
I noticed that @ganigeorgiev put in some model hook goodies in the develop tree. So I decided to create a pattern for my projects.
In my case I don't care about ever using generic
models.Model
because I'll always be usingmodels.Record
. So I created a wrapper to check for that. Each model can return a hook controller that implements the new Pocketbasehook.Tagger
interface, and any number of methods namedBeforeCreate
,AfterCreate
,BeforeUpdate
,AfterUpdate
,BeforeDelete
,AfterDelete
.The hook tool / helper that I made works with only Pocketbase modules and so this could easily be included into any project. The part that could easily differ between projects is the creation of the hook controller for each model. In my case I'm using a
env
struct that wrapsapp
and adds other services to it. You could basically consider it to be a dependency injector. Any services that are necessary project wide will be in it. Then each model hook controller can have services that need to be long-lived but are only relevant to the hooks for that model. For example I'm having the HTML sanitizer for articles in the hook controller.I'm changing the actual setup a bit to more easily demonstrate how to use this:
You can change this design by removing the
Tags() []string
requirement from each hook controller to instead decide outside (when calling Wire) how to bind it. So Wire could be changed fromWire(app core.App, hooks hook.Tagger)
toWire(app core.App, hooks any, tags ...string)
.Beta Was this translation helpful? Give feedback.
All reactions