data = array(); foreach ($data as $key => $value) { if (is_array($value)) { $this->data[$key] = new static($value); } else { $this->data[$key] = $value; } } } /** * Return this config's file path * * @return string */ public function getConfigFile() { return $this->configFile; } /** * Set this config's file path * * @param string $filepath The path to the config file * * @return self */ public function setConfigFile($filepath) { $this->configFile = $filepath; return $this; } /** * Deep clone this config */ public function __clone() { $array = array(); foreach ($this->data as $key => $value) { if ($value instanceof self) { $array[$key] = clone $value; } else { $array[$key] = $value; } } $this->data = $array; } /** * Return the count of available sections and properties * * @return int */ public function count() { return count($this->data); } /** * Reset the current position of $this->data * * @return mixed */ public function rewind() { return reset($this->data); } /** * Return the section's or property's value of the current iteration * * @return mixed */ public function current() { return current($this->data); } /** * Return whether the position of the current iteration is valid * * @return bool */ public function valid() { return key($this->data) !== null; } /** * Return the section's or property's name of the current iteration * * @return mixed */ public function key() { return key($this->data); } /** * Advance the position of the current iteration and return the new section's or property's value * * @return mixed */ public function next() { return next($this->data); } /** * Return whether the given section or property is set * * @param string $key The name of the section or property * * @return bool */ public function __isset($key) { return isset($this->data[$key]); } /** * Return the value for the given property or the config for the given section * * @param string $key The name of the property or section * * @return mixed|NULL The value or NULL in case $key does not exist */ public function __get($key) { if (array_key_exists($key, $this->data)) { return $this->data[$key]; } } /** * Add a new property or section * * @param string $key The name of the new property or section * @param mixed $value The value to set for the new property or section */ public function __set($key, $value) { if (is_array($value)) { $this->data[$key] = new static($value); } else { $this->data[$key] = $value; } } /** * Remove the given property or section * * @param string $key The property or section to remove */ public function __unset($key) { unset($this->data[$key]); } /** * Return whether the given section or property is set * * @param string $key The name of the section or property * * @return bool */ public function offsetExists($key) { return isset($this->$key); } /** * Return the value for the given property or the config for the given section * * @param string $key The name of the property or section * * @return mixed|NULL The value or NULL in case $key does not exist */ public function offsetGet($key) { return $this->$key; } /** * Add a new property or section * * @param string $key The name of the new property or section * @param mixed $value The value to set for the new property or section */ public function offsetSet($key, $value) { if ($key === null) { throw new LogicException('Appending values without an explicit key is not supported'); } $this->$key = $value; } /** * Remove the given property or section * * @param string $key The property or section to remove */ public function offsetUnset($key) { unset($this->$key); } /** * Return whether this config has any data * * @return bool */ public function isEmpty() { return $this->count() === 0; } /** * Return the value for the given property or the config for the given section * * @param string $key The name of the property or section * @param mixed $default The value to return in case the property or section is missing * * @return mixed */ public function get($key, $default = null) { $value = $this->$key; if ($default !== null && $value === null) { $value = $default; } return $value; } /** * Return all section and property names * * @return array */ public function keys() { return array_keys($this->data); } /** * Return this config's data as associative array * * @return array */ public function toArray() { $array = array(); foreach ($this->data as $key => $value) { if ($value instanceof self) { $array[$key] = $value->toArray(); } else { $array[$key] = $value; } } return $array; } /** * Merge the given data with this config * * @param array|Config $data An array or a config * * @return self */ public function merge($data) { if ($data instanceof self) { $data = $data->toArray(); } foreach ($data as $key => $value) { if (array_key_exists($key, $this->data)) { if (is_array($value)) { if ($this->data[$key] instanceof self) { $this->data[$key]->merge($value); } else { $this->data[$key] = new static($value); } } else { $this->data[$key] = $value; } } else { $this->data[$key] = is_array($value) ? new static($value) : $value; } } } /** * Return the value from a section's property * * @param string $section The section where the given property can be found * @param string $key The section's property to fetch the value from * @param mixed $default The value to return in case the section or the property is missing * * @return mixed * * @throws UnexpectedValueException In case the given section does not hold any configuration */ public function fromSection($section, $key, $default = null) { $value = $this->$section; if ($value instanceof self) { $value = $value->$key; } elseif ($value !== null) { throw new UnexpectedValueException( sprintf('Value "%s" is not of type "Config" or a sub-type of it', $value) ); } if ($value === null && $default !== null) { $value = $default; } return $value; } /** * Load configuration from the given INI file * * @param string $file The file to parse * * @throws NotReadableError When the file does not exist or cannot be read */ public static function fromIni($file) { $config = new static(); $filepath = realpath($file); if ($filepath === false) { $config->setConfigFile($file); } elseif (is_readable($filepath)) { $config->setConfigFile($filepath); $config->merge(parse_ini_file($filepath, true)); } else { throw new NotReadableError(t('Cannot read config file "%s". Permission denied'), $filepath); } return $config; } /** * Prepend configuration base dir to the given relative path * * @param string $path A relative path * * @return string */ public static function resolvePath($path) { return self::$configDir . DIRECTORY_SEPARATOR . ltrim($path, DIRECTORY_SEPARATOR); } /** * Retrieve a application config * * @param string $configname The configuration name (without ini suffix) to read and return * @param bool $fromDisk When set true, the configuration will be read from disk, even * if it already has been read * * @return Config The requested configuration */ public static function app($configname = 'config', $fromDisk = false) { if (!isset(self::$app[$configname]) || $fromDisk) { self::$app[$configname] = static::fromIni(static::resolvePath($configname . '.ini')); } return self::$app[$configname]; } /** * Retrieve a module config * * @param string $modulename The name of the module where to look for the requested configuration * @param string $configname The configuration name (without ini suffix) to read and return * @param string $fromDisk When set true, the configuration will be read from disk, even * if it already has been read * * @return Config The requested configuration */ public static function module($modulename, $configname = 'config', $fromDisk = false) { if (!isset(self::$modules[$modulename])) { self::$modules[$modulename] = array(); } $moduleConfigs = self::$modules[$modulename]; if (!isset($moduleConfigs[$configname]) || $fromDisk) { $moduleConfigs[$configname] = static::fromIni( static::resolvePath('modules/' . $modulename . '/' . $configname . '.ini') ); } return $moduleConfigs[$configname]; } }