Erweiterung Konfiguration
Diese Seite beschreibt eine für das Release 1.13 bereits implementierte Funktionalität (Stand 07.11.2010). Die offizielle Dokumentation findet sich unter Konfiguration (ab Version 1.13).
Inhaltsverzeichnis |
Einleitung
Diese Seite beschreibt ein Proposal zur Erweiterung der Konfiguration des APF. Ziel ist es - wie im Thread Erweiterung Konfiguration besprochen - die Flexibilität zu erhöhen und gleichzeitig die Konfiguration zu vereinfachen. Context- und Umgebungs-abhängige Konfigurationen werden zum einen nicht immer benötigt, zum anderen soll ein anderes Ordner-Layout auf einfache Weise umgesetzt werden können.
Grundsätze
- Die Konfiguration ist zentraler Bestandteil des APF und die ausgelieferten Konfigurations-Komponenten sollen daher wie vor dem Release 1.13 agieren.
- Die Erweiterung/Konfiguration einer Konfigurations-Komponente erfolgt auf Basis von Providern (ähnlich dem CacheManager). Diese implementieren ein Interface und sind daher sehr leicht austauschbar.
- Aus Gründen der einfacheren Handhabung soll die Konfiguration des Providers nicht über den DIServiceManager sondern über die Registry vorgenommen werden.
- Die neue Konfigurations-Komponente(n) sollen mehrere Formate im lesenden und schreibenden Zugriff behandeln können.
Code-Beispiele
/** * defines the configuration object returned by the configuration component. * each implementation defines it's own interfaces and implementations but * respecting the global definition. */ interface Configuration { } /** * defines the structure of all configuration provider implementations. */ interface ConfigurationProvider { /** * @return Configuration The desired configuration. */ function loadConfiguration(String $namespace, String $context, String $language, String $environment, String $name); function saveConfiguration(Configuration $config); } abstract class APFObject { ... protected function loadConfiguration(String $namespace, String $name){ $provider = Registry::retrieve('apf::core','ConfigurationProvider'); if($provider === null){ $provider = new DefaultConfigurationProvider(); } return $provider->loadConfiguration($namespace, $this->getContext(), $this->getLanguage(), Registry::retrieve('apf::core','Environment'), $name); } ... }
Offene Punkte
- Wie werden unterschiedliche Formate abgebildet? Idee: ein globaler ConfigurationManager, bei dem Provider für ein Format (Datei-Endung) registriert werden können.
Implementierungs-Beispiel
Die folgenden Code-Blöcke zeigen ein Implementierungs-Beispiel für den Config-Provider und seine Verwendung.
Interfaces
interface ConfigurationProvider { function loadConfiguration($namespace, $context, $language, $environment, $name); function saveConfiguration($namespace, $context, $language, $environment, $name, XConfiguration $config); } interface XConfiguration { /** * @return string */ function getValue($name); /** * @return XConfiguration */ function getSection($name); function setValue($name, $value); function setSection($name, XConfiguration $section); }
Manager
class XConfigurationManager { /** * * @var ConfigurationProvider The configuration provider instance. */ private static $PROVIDER = array(); public static function registerProvider($extension, ConfigurationProvider $provider) { self::$PROVIDER[strtolower($extension)] = $provider; } public static function removeProvider($extension) { unset(self::$PROVIDER[strtolower($extension)]); } public static function displayRegisteredProviders() { foreach (self::$PROVIDER as $ext => $provider) { echo $ext . ': ' . get_class($provider) . '<br />'; } } public static function getConfiguration($namespace, $context, $language, $environment, $name) { return self::getProvider($name)->loadConfiguration($namespace, $context, $language, $environment, $name); } private static function getProvider($name) { $extPos = strripos($name, '.'); if ($extPos === false) { throw new InvalidArgumentException('Provider cannot be loaded, because the given configuration "' . $name . '" has no extensions!', E_USER_ERROR); } $ext = strtolower(substr($name, $extPos + 1)); if (isset(self::$PROVIDER[$ext])) { return self::$PROVIDER[$ext]; } throw new InvalidArgumentException('Provider with extension "' . $ext . '" is not registered!', E_USER_ERROR); } }
Konkrete Implementierung für ini-Dateien
class IniConfigurationProvider implements ConfigurationProvider { private $omitConfigPrefix; public function __construct($omitConfigPrefix = false) { $this->omitConfigPrefix = $omitConfigPrefix; } public function loadConfiguration($namespace, $context, $language, $environment, $name) { $fileName = $this->getFilePath($namespace, $context, $language, $environment, $name); $rawConfig = parse_ini_file($fileName, true); $config = new IniConfiguration(); foreach ($rawConfig as $name => $values) { $config->setSection($name, $this->parseSection($values)); } return $config; } private function parseSection($entries) { $config = new IniConfiguration(); foreach ($entries as $name => $value) { $config->setValue($name, $value); } return $config; } public function saveConfiguration($namespace, $context, $language, $environment, $name, XConfiguration $config) { $fileName = $this->getFilePath($namespace, $context, $language, $environment, $name); file_put_contents($fileName, $config); } private function getFilePath($namespace, $context, $language, $environment, $name) { // using APPS__PATH is about 50 times faster than the registry! $prefix = $this->omitConfigPrefix ? '' : '/config'; return APPS__PATH . $prefix . '/' . str_replace('::', '/', $namespace) . '/' . str_replace('::', '/', $context) . '/' . $environment . '_' . $name; } }
Anwendung
Konfiguration in der index.php. Wird in der pagecontroller.php (Bootstrap-Datei) bereits vorbelegt.
XConfigurationManager::registerProvider('ini', new IniConfigurationProvider());
Manuelle Anwendung in einer PHP-Datei:
$config = XConfigurationManager::getConfiguration( 'foo::bar', 'test', 'de', Registry::retrieve('apf::core', 'Environment'), 'bar.ini');
Anwendung innerhalb einer Klasse, die von APFObject erbt:
class foo_controller extends base_controller { public function transformContent() { $config = $this->loadConfiguration('foo::bar', 'bar.ini'); ... $section = $config->getSection('default'); $section->setValue('name','value'); $config->setSection('default',$section); $this->saveConfiguration('foo::bar', 'bar.ini', $config); } }