radiergummi/libconfig

Configuration object creation for PHP apps

v1.0 2015-06-04 13:02 UTC

This package is auto-updated.

Last update: 2024-03-29 02:34:04 UTC


README

Simple php class to create a key-value storage. Basically, you can just throw your configuration at it, be it arrays, json, files or even directories, and libconfig will make it accessible in an intuitive way. You can get, set and add it, count it, iterate over it or access it as an array. Each method has its tricks up its sleeve. More on that below.
 

Note: I also made a singleton version of this which is available here.
Why? Because using stuff like Config::get('key') from anywhere without an instance is pretty darn comfortable.

Installation

###Installation via Composer (Packagist):

  1. Include the following in your composer.json file:

     "require": {
         ...
         "radiergummi\libconfig": "~1.0"
     }
    
  2. Then, run php composer.phar install

###Installation via source:

  1. Download from Github
  2. Drop the src/libconfig folder into your codebase at vendor/Radiergummi (you don't need the parent folders)
  3. Use a PSR-4 Autoloader to include it!

Usage

Creating a Config object

Create a config object like this:

  $config = new Config($data);

where $data can be an array or a json string, a file or folder path.
 

Creating a Config object with a file as a parameter

To directly include a json file, use

$config = new Config(PATH . 'example.json');

The only requirement is the complete path to be valid.  

I often use php files like the one below to store configuration. So you could also use

$config = new Config(PATH . 'example.php');

PHP Config file:

<?
return array(
  'foo' => 'bar'
);

 

Creating a Config object with a folder as a parameter

To parse a folder containing your configuration files, use

$config = new Config(PATH . 'app/config');

The only requirement is the complete path to be valid.  

A note on INI files: Honestly, why would you want to use those for configuration when you have php and json at hand? Maybe when I get a good idea on how to implement that in an elegant way.  
 

Advice on implementation

Incorporate this into your project: Set the namespace to that of your app and keep it in the app system directory. That way, you can access the config the most hassle-free way.
Catch possible exceptions: Libconfig will throw a RuntimeException immediately if data cannot be read. If you know something could go wrong, set up try-catch blocks.
Don't hardcode: Use config files whenever possible - for files, routes, i18n, paths and classlists, ... .
Be reasonable: There comes a point where redis or a real DB might make more sense. Reevaluate from time to time.
Hack the code however you like: You are free to use this library in any project, commercial or not (see the license). However, it would be nice of you to drop a curious fella a note what you used my work for and what you changed :).  
 

Methods

set

inserts a value into a key:

$config->set('foo', 'bar');

That will add the following to the config array:

Array
(
    [foo] => bar
)

To set nested config values, you can use dots to seperate keys:

$config->set('font.roboto.italic.regular', 'roboto-regular-italic.woff');

That will add the following to the config array:

Array
(
  [font] => Array
    (
      [roboto] => Array
        (
          [italic] => Array
            (
              [regular] => roboto-regular-italic.woff
            )
        )
    )
)

 
 

get

returns the value for a given key:

$config->get('foo'); // bar

To access nested config values, you can use dots to seperate keys:

$fontlist = $config->get('font.roboto.italic'); // Array
$fontfile = $config->get('font.roboto.italic.regular'); // roboto-regular-italic.woff

You can optionally specify a fallback value in case the desired key is not present:

$config->get('app.server.port', '8080');

To retrieve the whole configuration, just call get without arguments:

$config->get();

 
 

has

checks wether a setting exists or not

$config->has('foo.sub.key'); // true

 
 

erase

removes a key from the settings

$config->erase('foo.sub.key');

 
 

add

Adds another array to the configuration. The data is merged, which means that keys with the same name will overwrite previously existing ones. Maybe a possibility to insert them with changed names should be implemented here?

$config->add(file_get_contents('another.json'));

 
 

Magic methods

__tostring

returns the complete data array:

print_r($config); // Array

(Note: This is redundant. You can either call $config->get() or just $config, same effect. I find it to be not very self-documenting, but who am I to tell you how to code.)

 
 

Implemented Interfaces

Array access

You can also access and edit all data as an array:

$port = $config['app']['server']['port']; // 8080

 
 

Countable

The Config object can be counted:

$settings = count($config);

 
 

Iterator

You are able to iterate over the Config object:

array_walk_recursive($config, function ($value, $key) {
    echo "$key holds $value\n";
});

 
 

Some thoughts on Exceptions

I have only implemented RuntimeException as the exception type throughout libconfig. Why? Possible things that can go wrong are files not being found or data not being parsable. In either case, you've got a problem you should catch:

try {
  $config->add('inexistent/path/to/file.json');
} catch (Exception $e) {
  $app->shutdown(502);
  if (ENV === 'dev') throw new \MyApp\Exceptions\FileNotFoundException($e);
}

That way, exception handling is bound to your app and you don't have a few more arbitrary exception types to deal with.

 
 

TODO

Bugs

  • Counting the object recursively has no effect currently, and I don't know why.
  • Sometimes while parsing JSON, a JSON_LAST_ERROR 1 is thrown, meaning the maximum depth is reached, even if handling JSON with no nesting at all. There must be some recursion going on. (Fixed)

Improvements

  • Parts of the code are a bit messy right now, especially the add-method.
  • I would like to modularize the internals a bit - parsing input should be done via drivers or at least inside of specialized methods for each content type. (In progress)
  • libconfig should be unit tested (Done)

Features

  • INI Support (but just to stay competitive) (In progress)
  • ?

 
 

How to contribute

I would love to see other people contribute their ideas to this project. However to ease the process, please keep the following in mind:

  • If you find a bug, please create an issue for it, tag the issue with bug and include the code to reproduce it.
  • If you want to request or discuss a feature, please create an issue for it, tag it with enhancement and discribe it as detailed as possible.
  • If you want to contribute actual code, please fork the repository, create a new branch in your fork (eg. feature-ini-support), make your changes in it, and create a pull request.

Thank you!