Util_Settings/src/Settings.php

348 lines
7.6 KiB
PHP

<?php
/* {{{ Copyright and License Notice
*
* Copyright © 2021 RaBe Websolutions
*
* This file is part of rabe/Util-Settings.
*
* rabe/Util-Settings is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* rabe/Util-Settings is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with rabe/Util-Settings. If not, see <https://www.gnu.org/licenses/>.
*
*///}}}
declare(strict_types=1);
namespace rabe\Util;
/**
* Settings Class to read Configuration Files
* @author Norbert.e.Wagner dev@norb.me
*/
class Settings implements \Iterator
{
private const SITE = 0x01;
private array $settings = [];
private string $appPath = './';
private string $pkgPath = './';
private string $site;
protected string $confDir = 'config/';
protected string $filePrefix = '';
protected string $filePostfix = 'conf.php';
protected array $modes = [
'prod' => 'default',
'test' => 'testing',
];
private string $mode;
// Constructor {{{
/** {{{
* Construct a new Settings Object
*
* @param array $settings an array of settings to be used directly
* @param string $mode One of the keys of $this->modes
*///}}}
public function __construct( ?array $settings=null, ?string $mode=null )
{
if (isset($settings)) $this->settings = $settings;
if (isset($mode)) $this->mode = $mode;
}// }}}
// appPath() {{{
/** {{{
* Sets the application path where the config/ dirtectory is located
* If the package path is not set, it is set to the appPath
* @param string $path
*///}}}
public function appPath( ?string $path=null )
{
if (! isset($path)) return $this->appPath;
if ($this->pkgPath === $this->appPath) $this->pkgPath = $path;
$this->appPath = $path;
return $this;
}// }}}
// pkgPath() {{{
/** {{{
* Sets the package path where the config/ dirtectory for the default and mode files is located
* @param string $path
*///}}}
public function pkgPath( string $path )
{
$this->pkgPath = $path;
return $this;
}// }}}
// prefix() {{{
/** {{{
*///}}}
public function prefix( ?string $prefix=null )
{
$this->filePrefix = (isset($prefix)) ? "$prefix." : '';
return $this;
}// }}}
// addModes() {{{
/** {{{
*///}}}
public function addModes( array $modes )
{
$this->modes += $modes;
return $this;
}// }}}
// site() {{{
/** {{{
*///}}}
public function site( string $site )
{
$this->site = $site;
return $this;
}// }}}
// load() method {{{
/** {{{
* Load the configuration from the files and merge them
*
* @param array $settings uses the Settings as an Array.<br>
*///}}}
public function load( ?array $settings=null )
{
if (isset($settings))
{
$this->settings = $settings;
}
else
{
$modes = $this->modes;
// load Prefix.default.conf.php
$defaultConf = $this->buildFileName( array_shift($modes) );
if ( file_exists($defaultConf) )
{
$this->settings = require( $defaultConf );
}
else
{
// echo "No settingsfile: $defaultConf";
throw new \Exception( "No settingsfile: $defaultConf" );
// throw new FileNotFoundException();
}
if (isset($this->settings['modes'])) {
$this->addModes($this->settings['modes']);
}
// load local config without merging - we need it here for the mode
$conf = $this->buildFileName();
$localConf = false;
if (file_exists($conf)) $localConf = require($conf);
if (! isset($this->mode))
{ // if a localConf Mode is set use it, or take the default conf mode
$this->mode = (isset($localConf['mode'])) ? $localConf['mode'] : $this->settings['mode'];
}
else
{
$this->settings['mode'] = $this->mode;
}
if ( isset($this->site) )
{
$siteConf = $this->buildFileName(self::SITE);
if (file_exists($siteConf))
{
$localConf = array_replace_recursive($this->settings, require($siteConf));
}
}
// load and merge Prefix.mode.conf.php
if ( isset( $this->modes[ $this->mode ] ) )
{
$modeConf = $this->buildFileName( $this->modes[ $this->mode ] );
if ( file_exists($modeConf) )
{
$this->settings = array_replace_recursive( $this->settings, require($modeConf) );
}
else
{
// log no mode config File
}
}
else
{
// log invalid mode
throw new \Exception( "The mode '{$this->mode}' is not valid" );
}
// merge Prefix.conf.php (localConf)
if ($localConf !== false)
{
$this->settings = array_replace_recursive( $this->settings, $localConf );
}
}
// echo "<pre>"; print_r( $this->settings ); echo "</pre>";
return $this;
}// }}}
// mergeFile() {{{
/** {{{
*///}}}
public function mergeFile( )
{
}// }}}
// create() {{{
/** {{{
* Creates a copy of the Settingsobject without the configuration directives
*
*///}}}
public function create( ?array $settings=null )
{
$cfg = clone $this;
if (isset($settings)) $cfg->load($settings);
return $cfg;
}// }}}
// buildFileName() method {{{
/** {{{
* Compose the filename of the configuration File
* @param string|hex $mode The name of the mode, null for localConf and self::SITE for the site config
*///}}}
public function buildFileName( $type=null )
{
$mode = '';
$path = $this->appPath.$this->confDir;
if ($type === self::SITE) $path .= $this->site.'/';
if (is_string( $type ) &! empty( $type ))
{
$mode = "$type.";
$path = $this->pkgPath.$this->confDir;
}
return $path.$this->filePrefix.$mode.$this->filePostfix;
}
// }}}
// toArray() method {{{
/**
* Return the internal settings array
*
* @return array
*/
public function toArray()
{
return $this->settings;
}// }}}
// __clone() {{{
/** {{{
*///}}}
public function __clone()
{
$this->settings = [];
}// }}}
// Iterator methods {{{
/**
* Rewind the Iterator to the first element
* @link https://www.php.net/iterator.rewind
*/
public function rewind()
{
reset( $this->settings);
}
/**
* Return the current element
* @link https://www.php.net/iterator.current
*/
public function current()
{
return current( $this->settings );
}
/**
* Return the key of the current element
* @link https://www.php.net/iterator.key
*/
public function key()
{
return key( $this->settings );
}
/**
* Move forward to next element
* @link https://www.php.net/iterator.next
*/
public function next()
{
return next( $this->settings );
}
/**
* Checks if current position is valid
* @link https://www.php.net/iterator.valid
*/
public function valid()
{
$key = key( $this->settings );
return ($key !== null && $key !== false);
}
// }}}
// Magic getter/setter methods {{{
public function __set( $name, $value )
{
throw new \Exception("Settings are read only. Unable to set $name to $value");
}
public function __get( $name )
{
if ( !isset( $this->settings[$name] ) )
{
throw new \OutOfRangeException("Setting '$name' not found");
}
return (is_array( $this->settings[$name] ))
? $this->create( $this->settings[$name] )
: $this->settings[$name];
}
public function __isset( $name )
{
return ( isset( $this->settings[$name] ) );
}
public function __unset( $name )
{
unset( $this->settings[$name] );
}
// }}}
}
/* jEdit buffer local properties {{{
* :folding=explicit:collapseFolds=1:
}}}*/