Initializing Gacela
Gacela should be bootstrapped using the Gacela::bootstrap
function.
- The first parameter is the application root directory and is mandatory
- The second one is an optional
Closure(GacelaConfig)
configuration
The gacela.php
file
You can define the configuration as the second parameter in the Gacela::bootstrap()
in your index.php
or, alternatively,
you can create a gacela.php
file in your application root directory which returns a Closure(GacelaConfig)
function.
Different environments
You can define a gacela configuration file for different environments using the APP_ENV
environment variable.
Where you have a Gacela file with the suffix of the environment in the file name, it will load that configuration.
For example:
APP_ENV=dev
-> will loadgacela-dev.php
APP_ENV=prod
-> will loadgacela-prod.php
APP_ENV=anything
-> will loadgacela-anything.php
The loading of this particular file will happen after the default gacela.php
(if exists). So it will override (or add)
the possible values you might have defined in the default gacela.php
file.
(A similar behaviour already exists for your app config files. See: Config files for diff env.)
Note: If you are working "on top" of another project which is using gacela, you can always define your custom
gacela.php
file and define yourGacelaConfig
configuration, which will be combined with thegacela.php
of the vendor project itself.
GacelaConfig
As we just mentioned, you can customize some Gacela behaviours while bootstrapping without the need of a gacela.php
in the
root of your project, however, if this file exists, it will be combined with the configuration from Gacela::bootstrap()
.
It is not mandatory but recommended having a gacela.php
file in order to decouple and centralize the custom Gacela configuration.
In other words, you can modify some Gacela behaviour from two different places:
- Directly with
Gacela::bootstrap()
- Or using
gacela.php
Application Config
Using the GacelaConfig object you can add different paths and use different config file types, even with custom config
readers. The PhpConfigReader
is used by default.
Config PHP files
You can add to addAppConfig()
method as many config locations as you want.
path
: this is the path of the folder which contains your application configuration. You can use ? or * in order to match 1 or multiple characters. Check glob() function for more info.pathLocal
: this is the last file loaded, which means, it will override the previous configuration, so you can easily add it to your .gitignore and set your local config values in case you want to have something different for some cases.reader
: Define the reader class which will read and parse the config files. It must implementConfigReaderInterface
.
Multiple and different environment config files
Mapping Interfaces
You can define a map between an interface and the concrete class that you want to create (or use) when that interface is found during the process of auto-wiring in any Factory's Module dependencies via its constructor. Let's see an example:
The addMappingInterface()
method will let you bind a class with another class
interface => concreteClass|callable|string-class
that you want to resolve. For example:
In the example above, whenever OneInterface::class
is found then OneConcrete::class
will be resolved.
Using externalServices
First, we set a global service using GacelaConfig->addExternalService(string, class-string|object|callable)
(you can
set as many as you need). In this example 'concreteClass'
:
This way we can access the value of that key 'concreteClass'
in the gacela.php
from $config->getExternalService(string)
.
For example:
In the example above, whenever AnInterface::class
is found then ConcreteClass::class
will be resolved.
Suffix Types
Apart from the known Gacela suffix classes: Factory
, Config
, and DependencyProvider
, you can define other suffixes to be
resolved for your different modules. You can do this by adding custom gacela resolvable types.
In the example above, you'll be able to create a gacela module with these file names:
Project Namespaces
You can add your project namespaces to be able to resolve gacela classes with priorities.
Gacela will start looking on your project namespaces when trying to resolve any gacela resolvable classes, eg:
Facade
, Factory
, Config
, or DependencyProvider
.
Let's visualize it with an example. Consider this structure:
├── gacela.php
├── index.php # entry point
├── src
│ └── Main
│ └── ModuleA
│ └── Factory.php
└── vendor
└── third-party
└── ModuleA
├── Facade.php
└── Factory.php
Because you have defined Main
as your project namespace, when you use the ModuleA\Facade
from vendor, that Facade
will load the Factory from src/Main/ModuleA/Factory
and not vendor/third-party/ModuleA/Factory
because Main
has
priority (over third-party
, in this case).
TL;DR: You can override gacela resolvable classes by copying the directory structure from vendor modules in your project namespaces.
Gacela File Cache
When the method setFileCacheEnabled()
is true
, a new .gacela/cache
folder will be created in the root of
your project with the resolved classes.
You can customize the file cache directory name considering the root app directory. This is the first argument you pass when bootstrapping gacela:
Gacela::bootstrap(__DIR__)
.
You can also enable or disable the gacela file cache system via your project config values.
Listening internal gacela events
Gacela has an internal event-listener system that dispatches a variety of events. These are read-only events interesting for tracing, debugging or act on them as you want.
Register a generic listener to all internal gacela events
Register a specific listener to one internal gacela event
List of supported events
Gacela\Framework\Event\ClassResolver\ClassNameFinder
- ClassNameInvalidCandidateFoundEvent
- ClassNameNotFoundEvent
- ClassNameCachedFoundEvent
- ClassNameValidCandidateFoundEvent
Gacela\Framework\Event\ConfigReader
- ReadPhpConfigEvent
Gacela\Framework\Event\ClassResolver
- AbstractGacelaClassResolverEvent
- ResolvedClassCachedEvent
- ResolvedClassCreatedEvent
- ResolvedCreatedDefaultClassEvent
- ResolvedClassTriedFromParentEvent
Gacela\Framework\Event\ClassResolver\Cache
- ClassNameCacheCachedEvent
- ClassNamePhpCacheCreatedEvent
- ClassNameInMemoryCacheCreatedEvent
- CustomServicesCacheCachedEvent
- CustomServicesPhpCacheCreatedEvent
- CustomServicesInMemoryCacheCreatedEvent
Reset internal InMemoryCache
If you are working with integration tests, this option can be helpful to avoid false-positives, as Gacela
works as a
global singleton pattern to store the resolved dependencies. This value by default is false
.
Extend Service
You are able to extend any service functionality. The extendService()
receives the service name that will be defined in
any DependencyProvider
, and a callable
which receives the service itself as 1st arg, and the Container
as 2nd arg.
A complete example using gacela.php
Accessing a Doctrine-Repository from a Gacela-Factory
The Gacela Factory has auto-wiring that will resolve its dependencies. The only exception is for interfaces, because there is no way to discover what want to inject there. For this purpose, you need to define the mapping between the interfaces and to what do you want them to be resolved.
In our current example (using Symfony) we want to use the doctrine service from the kernel.container
and not just "a new
one". A new one wouldn't have all services and stuff already defined as the original one would have.
Extra: using the
fn() => ...
as value when doingaddMappingInterface()
allows us to delay the execution of getContainer() to when it is really needed i.e. "lazy loading".