Files
sm-seo-plugin/classes/service.go
2026-10-27 10:45:30 +01:00

77 lines
2.2 KiB
Go

// Package classes holds the SEO plugin's logic: the service every writer
// goes through, the entry store and the effective-SEO resolver.
package classes
import (
"context"
"errors"
"git.golem15.com/golem15/summercms/modules/backpack"
"git.golem15.com/golem15/summercms/modules/cabana"
"git.golem15.com/golem15/summercms/modules/compass"
"git.golem15.com/golem15/summercms/modules/signpost"
"gorm.io/gorm"
)
// ErrNotBooted is returned when the service has no booted application.
var ErrNotBooted = errors.New("golem15.seo: app is not booted")
// Service is the plugin's single entry point for reads and writes of SEO
// data. The admin extension, the admin controllers, the listeners, the job
// and the API all call it, so every write goes through the same checks and
// history.
type Service struct {
app *backpack.App
}
// NewService returns the service of a booted application. The database
// and the signpost registry are looked up when used, so a binary that runs
// a console command without a database still boots.
func NewService(app *backpack.App) (*Service, error) {
if app == nil {
return nil, ErrNotBooted
}
return &Service{app: app}, nil
}
// App returns the booted application.
func (s *Service) App() *backpack.App {
if s == nil {
return nil
}
return s.app
}
// DB returns the write transaction carried by ctx (cabana.TxFromContext),
// else the application's database bound to ctx.
func (s *Service) DB(ctx context.Context) (*gorm.DB, error) {
if tx, ok := cabana.TxFromContext(ctx); ok && tx != nil {
return tx, nil
}
if s == nil || s.app == nil {
return nil, ErrNotBooted
}
db, ok := s.app.Lookup[*gorm.DB]()
if !ok || db == nil {
return nil, errors.New("golem15.seo: database is not configured")
}
return db.WithContext(ctx), nil
}
// Registry returns the menu item type registry, nil when none is published.
func (s *Service) Registry() *signpost.Registry {
if s == nil || s.app == nil {
return nil
}
reg, _ := s.app.Lookup[*signpost.Registry]()
return reg
}
// Config returns the application config, nil when there is none.
func (s *Service) Config() *compass.Config {
if s == nil || s.app == nil {
return nil
}
return s.app.Config
}