github.com/goravel/framework@v1.13.9/foundation/container.go (about)

     1  package foundation
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	"github.com/gookit/color"
     8  
     9  	"github.com/goravel/framework/auth"
    10  	"github.com/goravel/framework/cache"
    11  	"github.com/goravel/framework/config"
    12  	"github.com/goravel/framework/console"
    13  	authcontract "github.com/goravel/framework/contracts/auth"
    14  	accesscontract "github.com/goravel/framework/contracts/auth/access"
    15  	cachecontract "github.com/goravel/framework/contracts/cache"
    16  	configcontract "github.com/goravel/framework/contracts/config"
    17  	consolecontract "github.com/goravel/framework/contracts/console"
    18  	cryptcontract "github.com/goravel/framework/contracts/crypt"
    19  	ormcontract "github.com/goravel/framework/contracts/database/orm"
    20  	seerdercontract "github.com/goravel/framework/contracts/database/seeder"
    21  	eventcontract "github.com/goravel/framework/contracts/event"
    22  	filesystemcontract "github.com/goravel/framework/contracts/filesystem"
    23  	foundationcontract "github.com/goravel/framework/contracts/foundation"
    24  	grpccontract "github.com/goravel/framework/contracts/grpc"
    25  	hashcontract "github.com/goravel/framework/contracts/hash"
    26  	httpcontract "github.com/goravel/framework/contracts/http"
    27  	logcontract "github.com/goravel/framework/contracts/log"
    28  	mailcontract "github.com/goravel/framework/contracts/mail"
    29  	queuecontract "github.com/goravel/framework/contracts/queue"
    30  	routecontract "github.com/goravel/framework/contracts/route"
    31  	schedulecontract "github.com/goravel/framework/contracts/schedule"
    32  	testingcontract "github.com/goravel/framework/contracts/testing"
    33  	validationcontract "github.com/goravel/framework/contracts/validation"
    34  	"github.com/goravel/framework/crypt"
    35  	"github.com/goravel/framework/database"
    36  	"github.com/goravel/framework/event"
    37  	"github.com/goravel/framework/filesystem"
    38  	"github.com/goravel/framework/grpc"
    39  	"github.com/goravel/framework/hash"
    40  	"github.com/goravel/framework/http"
    41  	goravellog "github.com/goravel/framework/log"
    42  	"github.com/goravel/framework/mail"
    43  	"github.com/goravel/framework/queue"
    44  	"github.com/goravel/framework/route"
    45  	"github.com/goravel/framework/schedule"
    46  	"github.com/goravel/framework/testing"
    47  	"github.com/goravel/framework/validation"
    48  )
    49  
    50  type instance struct {
    51  	concrete any
    52  	shared   bool
    53  }
    54  
    55  type Container struct {
    56  	bindings  sync.Map
    57  	instances sync.Map
    58  }
    59  
    60  func NewContainer() *Container {
    61  	return &Container{}
    62  }
    63  
    64  func (c *Container) Bind(key any, callback func(app foundationcontract.Application) (any, error)) {
    65  	c.bindings.Store(key, instance{concrete: callback, shared: false})
    66  }
    67  
    68  func (c *Container) BindWith(key any, callback func(app foundationcontract.Application, parameters map[string]any) (any, error)) {
    69  	c.bindings.Store(key, instance{concrete: callback, shared: false})
    70  }
    71  
    72  func (c *Container) Instance(key any, ins any) {
    73  	c.bindings.Store(key, instance{concrete: ins, shared: true})
    74  }
    75  
    76  func (c *Container) Make(key any) (any, error) {
    77  	return c.make(key, nil)
    78  }
    79  
    80  func (c *Container) MakeArtisan() consolecontract.Artisan {
    81  	instance, err := c.Make(console.Binding)
    82  	if err != nil {
    83  		color.Redln(err)
    84  		return nil
    85  	}
    86  
    87  	return instance.(consolecontract.Artisan)
    88  }
    89  
    90  func (c *Container) MakeAuth() authcontract.Auth {
    91  	instance, err := c.Make(auth.BindingAuth)
    92  	if err != nil {
    93  		color.Redln(err)
    94  		return nil
    95  	}
    96  
    97  	return instance.(authcontract.Auth)
    98  }
    99  
   100  func (c *Container) MakeCache() cachecontract.Cache {
   101  	instance, err := c.Make(cache.Binding)
   102  	if err != nil {
   103  		color.Redln(err)
   104  		return nil
   105  	}
   106  
   107  	return instance.(cachecontract.Cache)
   108  }
   109  
   110  func (c *Container) MakeConfig() configcontract.Config {
   111  	instance, err := c.Make(config.Binding)
   112  	if err != nil {
   113  		color.Redln(err)
   114  		return nil
   115  	}
   116  
   117  	return instance.(configcontract.Config)
   118  }
   119  
   120  func (c *Container) MakeCrypt() cryptcontract.Crypt {
   121  	instance, err := c.Make(crypt.Binding)
   122  	if err != nil {
   123  		color.Redln(err)
   124  		return nil
   125  	}
   126  
   127  	return instance.(cryptcontract.Crypt)
   128  }
   129  
   130  func (c *Container) MakeEvent() eventcontract.Instance {
   131  	instance, err := c.Make(event.Binding)
   132  	if err != nil {
   133  		color.Redln(err)
   134  		return nil
   135  	}
   136  
   137  	return instance.(eventcontract.Instance)
   138  }
   139  
   140  func (c *Container) MakeGate() accesscontract.Gate {
   141  	instance, err := c.Make(auth.BindingGate)
   142  	if err != nil {
   143  		color.Redln(err)
   144  		return nil
   145  	}
   146  
   147  	return instance.(accesscontract.Gate)
   148  }
   149  
   150  func (c *Container) MakeGrpc() grpccontract.Grpc {
   151  	instance, err := c.Make(grpc.Binding)
   152  	if err != nil {
   153  		color.Redln(err)
   154  		return nil
   155  	}
   156  
   157  	return instance.(grpccontract.Grpc)
   158  }
   159  
   160  func (c *Container) MakeHash() hashcontract.Hash {
   161  	instance, err := c.Make(hash.Binding)
   162  	if err != nil {
   163  		color.Redln(err)
   164  		return nil
   165  	}
   166  
   167  	return instance.(hashcontract.Hash)
   168  }
   169  
   170  func (c *Container) MakeLog() logcontract.Log {
   171  	instance, err := c.Make(goravellog.Binding)
   172  	if err != nil {
   173  		color.Redln(err)
   174  		return nil
   175  	}
   176  
   177  	return instance.(logcontract.Log)
   178  }
   179  
   180  func (c *Container) MakeMail() mailcontract.Mail {
   181  	instance, err := c.Make(mail.Binding)
   182  	if err != nil {
   183  		color.Redln(err)
   184  		return nil
   185  	}
   186  
   187  	return instance.(mailcontract.Mail)
   188  }
   189  
   190  func (c *Container) MakeOrm() ormcontract.Orm {
   191  	instance, err := c.Make(database.BindingOrm)
   192  	if err != nil {
   193  		color.Redln(err)
   194  		return nil
   195  	}
   196  
   197  	return instance.(ormcontract.Orm)
   198  }
   199  
   200  func (c *Container) MakeQueue() queuecontract.Queue {
   201  	instance, err := c.Make(queue.Binding)
   202  	if err != nil {
   203  		color.Redln(err)
   204  		return nil
   205  	}
   206  
   207  	return instance.(queuecontract.Queue)
   208  }
   209  
   210  func (c *Container) MakeRateLimiter() httpcontract.RateLimiter {
   211  	instance, err := c.Make(http.BindingRateLimiter)
   212  	if err != nil {
   213  		color.Redln(err)
   214  		return nil
   215  	}
   216  
   217  	return instance.(httpcontract.RateLimiter)
   218  }
   219  
   220  func (c *Container) MakeRoute() routecontract.Route {
   221  	instance, err := c.Make(route.Binding)
   222  	if err != nil {
   223  		color.Redln(err)
   224  		return nil
   225  	}
   226  
   227  	return instance.(routecontract.Route)
   228  }
   229  
   230  func (c *Container) MakeSchedule() schedulecontract.Schedule {
   231  	instance, err := c.Make(schedule.Binding)
   232  	if err != nil {
   233  		color.Redln(err)
   234  		return nil
   235  	}
   236  
   237  	return instance.(schedulecontract.Schedule)
   238  }
   239  
   240  func (c *Container) MakeStorage() filesystemcontract.Storage {
   241  	instance, err := c.Make(filesystem.Binding)
   242  	if err != nil {
   243  		color.Redln(err)
   244  		return nil
   245  	}
   246  
   247  	return instance.(filesystemcontract.Storage)
   248  }
   249  
   250  func (c *Container) MakeTesting() testingcontract.Testing {
   251  	instance, err := c.Make(testing.Binding)
   252  	if err != nil {
   253  		color.Redln(err)
   254  		return nil
   255  	}
   256  
   257  	return instance.(testingcontract.Testing)
   258  }
   259  
   260  func (c *Container) MakeValidation() validationcontract.Validation {
   261  	instance, err := c.Make(validation.Binding)
   262  	if err != nil {
   263  		color.Redln(err)
   264  		return nil
   265  	}
   266  
   267  	return instance.(validationcontract.Validation)
   268  }
   269  
   270  func (c *Container) MakeView() httpcontract.View {
   271  	instance, err := c.Make(http.BindingView)
   272  	if err != nil {
   273  		color.Redln(err)
   274  		return nil
   275  	}
   276  
   277  	return instance.(httpcontract.View)
   278  }
   279  
   280  func (c *Container) MakeSeeder() seerdercontract.Facade {
   281  	instance, err := c.Make(database.BindingSeeder)
   282  
   283  	if err != nil {
   284  		color.Redln(err)
   285  		return nil
   286  	}
   287  
   288  	return instance.(seerdercontract.Facade)
   289  }
   290  
   291  func (c *Container) MakeWith(key any, parameters map[string]any) (any, error) {
   292  	return c.make(key, parameters)
   293  }
   294  
   295  func (c *Container) Singleton(key any, callback func(app foundationcontract.Application) (any, error)) {
   296  	c.bindings.Store(key, instance{concrete: callback, shared: true})
   297  }
   298  
   299  func (c *Container) make(key any, parameters map[string]any) (any, error) {
   300  	binding, ok := c.bindings.Load(key)
   301  	if !ok {
   302  		return nil, fmt.Errorf("binding not found: %+v", key)
   303  	}
   304  
   305  	if parameters == nil {
   306  		instance, ok := c.instances.Load(key)
   307  		if ok {
   308  			return instance, nil
   309  		}
   310  	}
   311  
   312  	bindingImpl := binding.(instance)
   313  	switch concrete := bindingImpl.concrete.(type) {
   314  	case func(app foundationcontract.Application) (any, error):
   315  		concreteImpl, err := concrete(App)
   316  		if err != nil {
   317  			return nil, err
   318  		}
   319  		if bindingImpl.shared {
   320  			c.instances.Store(key, concreteImpl)
   321  		}
   322  
   323  		return concreteImpl, nil
   324  	case func(app foundationcontract.Application, parameters map[string]any) (any, error):
   325  		concreteImpl, err := concrete(App, parameters)
   326  		if err != nil {
   327  			return nil, err
   328  		}
   329  
   330  		return concreteImpl, nil
   331  	default:
   332  		c.instances.Store(key, concrete)
   333  
   334  		return concrete, nil
   335  	}
   336  }