In this short tutorial we will implement a simple example of interop-config. This example tries to give you a better understanding of what interop-config is and why you should use it.
To implement interop-config we need a few components to glue it together.
We use the following simple folder structure for the example application:
─── application_root/
├── composer.json
├── config/
│ └── main.php
├── public/
│ └── index.php
└── src/
└── SomVendorName/
├── Exception/
│ └── RuntimeException.php
└── MyComponent/
├── MyComponentFactory.php
└── MyFirstComponent.php
Since we have Composer it is really easy to manage our php packages. First of all we need Composer run. For that go to
your application_root
directory and setup a Composer.json file with the following listing.
{
"name": "test",
"autoload": {
"psr-4": {
"SomeVendorName\\": "src/"
}
}
}
To use Composer we need to download the composer.phar
from getcomposer.org.
If you have installed Composer, you can get the PHP packages we setup in the composer.json via php composer.phar require sandrokeil/interop-config
If you need more help look at getcomposer.org.
Put the following code to the public/index.php
to get the class auto loading, so we do not have to include/require
classes before using them.
// this makes our life easier, everything is relative to application root now
chdir(dirname(__DIR__));
require 'vendor/autoload.php';
// ...
The following code is located in config/main.php
and holds the main configuration array
of the project.
return [
'some_vendor_name' => [
'my_component_configuration' => [
'debug' => false,
'routes' => [
'key1' => 'value1',
'key2' => 'value2',
'key3' => 'value3',
]
]
]
];
The ServiceLocator
holds the application configuration and some plugin manager classes.
The ServiceLocator
is the main entry point if you need to instantiate classes in your application.
namespace SomeVendorName;
class ServiceLocator
{
/**
* Some factory classes
*
* @var array
*/
private $factories = array(
'config' => array(),
'my_component_factory' => 'SomeVendorName\MyComponent\MyComponentFactory'
// ...
);
public function __construct(array $config)
{
$this->factories['config'] = $config;
}
/**
* Get some simple factories
*
* @param $name
* @return mixed
*/
public function get($name)
{
// return config simple
if ($name === 'config' && isset($this->factories['config'])) {
return $this->factories['config'];
}
if (isset($this->factories[$name])) {
$FactoryClass = new $this->factories[$name]();
// if your factory implements a factory interface you should check it at this place
return $FactoryClass->__invoke($this);
}
}
/**
* Check if factory exists
*
* @param $name
* @return bool
*/
public function has($name): bool
{
return isset($this->factories[$name]);
}
}
To throw useful exceptions we have a RuntimeException
in our namespace. There are many more exception types, but for
this simple example we satisfied by the RuntimeException
. The following code is located in
src/SomeVendorName/Exception/RuntimeException.php
.
namespace SomeVendorName\Exception;
class RuntimeException extends \Exception {
}
The factory class implements OptainOptions
and uses the ConfigurationTrait
. The factory class creates components
with the configuration we explicitly setup before. Every component created by this factory will get the same configuration parameters.
namespace SomeVendorName\MyComponent;
use SomeVendorName\ServiceLocator;
use SomeVendorName\Exception\RuntimeException;
use SomeVendorName\MyComponent\MyFirstComponent;
use Interop\Config\RequiresConfig;
use Interop\Config\ConfigurationTrait;
class MyComponentFactory implements ObtainsOptions
{
use ConfigurationTrait;
public function dimensions(): iterable
{
return ['some_vendor_name', 'my_component_configuration'];
}
public function __invoke(ServiceLocator $ServiceLocator): MyFirstComponent
{
$options = $this->options($ServiceLocator->get('config'));
// check if mandatory options are available or use \Interop\Config\RequiresMandatoryOptions
if (empty($options['routes'])) {
throw new RuntimeException('routes not defined');
}
if (empty($options['debug'])) {
throw new RuntimeException('debug not defined');
}
return new MyFirstComponent($options['routes'], $options['debug']);
}
}
Finally we have the component class where we need the configuration.
namespace SomeVendorName\MyComponent;
use SomeVendorName\Exception\RuntimeException;
class MyFirstComponent
{
public function __construct($routes, $debug){
var_dump(routes, debug);
}
}
To run the example application we just need the following few lines in the public/index.php:
// this makes our life easier, everything is relative to application root now
chdir(dirname(__DIR__));
require 'vendor/autoload.php';
$ServiceLocator = new SomeVendorName\ServiceLocator('config/main.php');
$MyComponentFactory = $ServiceLocator->get('my_component_factory');
If you see some output different from fatal error you have successfully implemented interop-config. Take a look at the Quick-Start section to see what interop-config can do for you.