Hiraeth uses Jsonified Ini Notation (JIN) for all configuration files and its .env
. Without going into too much detail, these files use an INI structure with JSON-like values. The language is extremely similar to TOML, but does not attempt to be compatible or maintain feature parity. Like TOML, it’s also quite intuitive, so while it’s probably quite easy to pick up, there are some things you should be aware of.
A simple example of a configuration might look like the following:
[middleware]
disabled = false
class = Acme\Middleware
Want to test some JIN? You can use our simple online JIN playground to check for errors, play with the language, and see what it looks like converted to JSON.
Basic Structures
JIN ultimately compiles down to nested arrays (associative or otherwise). How the keys / values correspond depends on how you express it. Let’s cover the basics.
Comments
Comments are preceded with a semi-colon (;
). Unless part of a quoted string, everything after the semi-colon will be part of the comment:
field1 = This is a simple string ; but this is a comment
In contrast:
field2 = "This is also a string ; but it contains a semi-colon"
Sections
Sections, as in the above example use square brackets ([]
). This is a common feature of INI files, and since JIN uses both JSON and INI notation, it is the most common way to create a keyed array structure.
[foo]
Compiles to:
[
"foo" => []
]
You can also use the common JavaScript/JSON dot notation for nested keys:
[foo]
[foo.bar]
Compiles to:
[
"foo" => [
"bar" => []
]
]
It is very common to use section headers to create deeply nested structures. In order to make those structures easier to maintain, you can reference parent levels using an ampersand (&
) so if you change the name of parent sections, child sections don’t need to be updated
[root]
[&.level-1-1]
[&&.level-2-1]
[&.level-1-2]
From this, we get:
[
"root" => [
"level-1-1" => [
"level-2-1" => []
],
"level-1-2" => []
]
]
The indentation is optional and does not affect the level parsing. Only the &
determines the level in relation to the nearest root section.
Keys and Values
Values are converted to their implicit native types. So setting key = 2
will not result in a string of “2”, but an actual integer. Here’s a quick look at all the scalar types:
null = null
integer = 1
float = 3.14159
boolean = true
Strings can be unquoted or quoted as we saw in the comments section above. Quoted strings are only particularly useful in the case you need to include a semi-colon (rare). You can also do multi-line strings, however, multi-line strings using <>
:
quoted = <"
This is a quoted multi-line string
containing a semi-colon (;) that
will not be interpreted as a comment.
">
unquoted = <
This is a multi-line string
but as you can see... ; this is a a comment
>
As promised, values can also be JSON-like. JIN uses its host language’s native JSON parsing abilities. Since in our case that’s PHP, this means that valid JSON values will generally need to be strict JSON with quoted keys (for objects). The only two exceptions which are part of standard JIN are:
- The slash character (
\
) is not escaped. Consequently, escaped characters, e.g.\n
and\t
are not supported in any strings embedded in JSON structures. - You can always have trailing commas for arrays and objects which will be clipped before the JSON is parsed by the native library.
Here’s a simple array example:
array = [
"apple",
"orange",
"cherry",
]
And an object (associative array):
assoc = {
"fruits": [
"apple",
"orange",
"cherry",
],
"classes": [
"Acme\User\Entity",
"Acme\User\Repository",
],
}
There are many more advanced concepts in JIN, including functions, some of which are specific to Hiraeth, some of which are built in to JIN. Check out the example JIN file in the playground to get a better understanding of built-in functions like env()
and how to used def()
to define and use templates, maps, and inclusions.
Custom Functions
JIN has a number of built-in functions and also supports mapping functions in the host language to custom JIN functions. These can be useful to get information that requires some logic in order to generate or retrieve. Hiraeth registers three important functions that allow you to write more flexible configs.
The env() Function
While JIN has a standard env()
function, it’s overloaded in Hiraeth in order to allow implicit type casting based on the default value. To get environment variables’ values, including those set in your .env
file in their native type, use.
[config]
setting = env(VALUE)
See the documentation on querying to understand how environment variable references are flattened for compatibility.
With a default value if not found:
[config]
setting = env(VALUE, true)
As mentioned at the start, by providing a default value which is a boolean, the value will be implicitly casted to a boolean, so a string of “true” or “1” becomes an actual boolean true
.
The dir() Function
If you need to get an “application root” relative directory, you can use the dir()
function. This is equivalent to $app->getDirectory()
(See: Files and Directories), however, the full path name is resolved back down to a string (as opposed to an SplFileInfo
object).
[config]
directory = dir(storage/cache/acme)
You can also pass an array of strings to get back an array of directory paths:
directories = dir([
"storage/dir1",
"storage/dir2",
])
Using the dir()
function will always try to create the directory if it does not exist, so you shouldn’t use it as a fallback for referencing directories outside of storage (or any other writable directory) that aren’t yet created.
The file() Function
The file()
function works precisely as the dir()
function, except for files:
[config]
file = file(storage/example.txt)
Also, with arrays:
files = file([
"storage/file1",
"storage/file2",
])
Unlike dir()
, using the file()
function will not create the file if it does not exist. So it’s safer to use, but you may need additional checks to ensure the file is real before using other functions on it.