xp-framework/rfc

JSON as default preferences format

thekid opened this issue · 3 comments

Scope of Change

This RFC suggests replacing .ini with JSON as default preferences format

Rationale

Originally motivated by comparing .ini-file parsing performance to JSON decoding, after xp-framework/core#167 is merged, much of the disadvantage has been solved and it now boils down to readability.

Functionality

Comparison

[static]
resources=".css$:{DOCUMENT_ROOT}|^/image/:{DOCUMENT_ROOT}"

[app]
mappings[/rss]=rss
mappings[/]=dialog

[app::dialog]
init-params="de.thekid.dialog.scriptlet|{WEBROOT}/xsl"

[app::rss]
...

Although not as compact, the JSON syntax is standardized, can be syntax-checked, and pretty-printed using standard tooling. JSON also supports arbitrary nesting, so we could reimagine the above file in a much more concise way, and implement reading in an easier and faster way.

{
  "static" : {
    ".css$"    : "{DOCUMENT_ROOT}",
    "^/image/" : "{DOCUMENT_ROOT}"
  },
  "app" : {
    "/" : {
      "init-params" : ["de.thekid.dialog.scriptlet", "{WEBROOT}/xsl"]
    },
    "/rss" : {
      ...
    }
  }
}

Example dialog.json

{
  "database" : {
    "dsn"    : "mysql://…",
    "create" : false
  }
}

API

class util.Settings {

  __construct(util.Config|util.PropertyAccess|string... $sources)

  util.Setting named($path)
  var value(string $path, var $default) throws util.NoSuchElementException
}

Examples

// Read from both ./dialog.json & ~/.xp/dialog.json & /etc/dialog.json
$settings= new Settings('preferences://dialog');

// Read from ./dialog.json, ~/.xp/dialog.json, /etc/dialog.json
$settings= new Settings('dialog');
$settings= new Settings('user://dialog');
$settings= new Settings('system://dialog');

// Reading from src/main/etc/dialog.json
$settings= new Settings('src/main/etc/dialog');

// Inheriting from user configuration
$settings= new Settings(new Config(Config::$USER, 'dialog'), new Config($path, 'dialog'));

// Accessing settings
$setting= $settings->named('database/dsn');
$setting->value();               // "mysql://…"
$setting->value('string');       // With primitive type
$setting->value(DSN::class);     // With class type, calls "new"
$setting->present();             // true
$setting->orElse(null)->value(); // With default

// Access value directly, raises exception if not present
$conn= DriverManager::getConnection($settings->value('database/dsn'));

// Access with default
$create= $settings->value('database/create', false);

BC

For BC reasons, an adapter class for util.Properties will be created.

Security considerations

Speed impact

Dependencies

Related documents

http://json.org/index.html - Introducing JSON

Hi,
since settings are written and maintained by humans i would strongly disagree with using JSON as the default. This is because JSON does not allow comments (you could use comment-elements...).

Tools exist to make it easier for humans, not the other way around.

I personally would suggest using/supporting YAML, if not already present.

my 2 cents

YAML means importing quite an extensive API (if you want to support all of it). Also, it is not natively supported by PHP - there is no yaml_parse() in core.

But you're right, JSON has the problem of not offering comments, which are used quite often in INI files to explain options.

Maybe https://github.com/toml-lang/toml would be better: Like .ini, has comments, but supports nesting, dates and other handy features.

Maybe https://github.com/toml-lang/toml would be better

Yes.