Container files are written in a very simple meta language.
The language supports the following scalar types:
'hello'
& "world"
3.14
, 42
true
and false
.null
{'A', 'B', 'C'}
, {'A': 10, 'B': 20}
Container files do not differentiate between different number types because it would be an unnecessary overhead, we forward that job directly to PHP.
42 # Int
42.01 # Float
-42.12345678912345 # Double
That means that also the floating point precision is handled by PHP. All values are interpreted means large doubles might be stored rounded.
Strings must always be encapsulated with a single '
or double "
quote. This serves mainly a comfort purpose when having many quotes inside your string not having to escape them all.
Escaping of special characters works just the usual way.
:say: 'Hello it\'s me!'`
Beloved or Hated emojis will also work just fine.
:snails: '🐌🐌🐌'
There is not much to say about them:
:nothing: null
:positive: true
:negative: false
It's important to notice that all arrays are internally associative. When defining a simple list the associative key is automatically generated and represents the index of the item.
This means that the array {'A', 'B'}
equals {0: 'A', 1: 'B'}
.
Arrays can be defined multidimensional:
{
'title': 'Some catchy title with Star Wars',
'tags': {'top10', 'movies', 'space'},
'body': 'Lorem ipsum ...',
'comments':
{
{
'text': 'Awesome!',
'by': 'Some Dude',
}
}
}
Parameters or configuration values can also be defined inside the container files.
A parameter is always prefixed with a :
character.
:database.hostname: "production.db.example.com"
:database.port: 7878
:database.cache: true
A service definition is always named and must be prefixed with a @
character.
# <service name>: <class name>
@log.adapter: FileAdapter
The class name can contain the full namespace.
@log.adapter: Acme\Log\FileAdapter
Constructor arguments can be passed after the class name.
@dude: Person("Jeffery Lebowski")
Arguments can reference a parameter or service.
:name: 'Jeffery Lebowski'
@dude: Person(:name)
@mysql: MySQLAdapter('localhost', 'root', '')
@repository.posts: Repositories/Post(@mysql)
Method calls can be assigned to a service definition.
@jones: Person('Duncan Jones')
@sam: Person('Sam Rockwell')
@movie.moon: Movie('Moon')
- setDirector(@jones)
- addCast(@sam)
- setTags({'Sci-fi', 'Space'})
Metadata can be assigned to every service definition.
Its then possible to fetch the services matching a metadata key.
@controller.auth.sign_in: Controller\Auth\SignInController(@auth)
= route: {'GET', 'POST'}, '/signin'
The metadata key is always a vector / array so you can add multiple of the same type:
@controller.auth.sign_in: Controller\Auth\SignInController(@auth)
= route: {'GET', 'POST'}, '/signin'
= tag: 'users'
= tag: 'auth'
The elements inside the metadata definition can have named keys:
@app.bootstrap: Bootstrap()
= on: 'app.start' call: 'onAppStart'
It is possible to update already defined services with more construction calls and metadata. This is quite handy to organize large amount of dependencies with a dynamic lookups.
You could for example define your logger in one file.
@logger.main: Acme\Logger
And add observers using a construction call where you need them.
@logger.observers.email_devs: Acme\EmailLogObserver('[email protected]')
@logger.observers.email_support: Acme\EmailLogObserver('[email protected]')
@logger.main
- addObserver(@logger.observers.email_devs)
- addObserver(@logger.observers.email_support)
Other container files can be imported from the container namespace.
import config
import app/dashboard
import app/user
import app/shop
Services and Parameters have been explicit overwritten if they have already been defined.
:ship: 'Star Destroyer'
override :ship: 'X-Wing'