ConfigurationException If a requested configuration file * does not have an associated * configuration handler. * * @author ketter (ketter@laiketui.com) * @since 3.0.0 */ private static function callHandler ($handler, $config, $cache) { if (count(self::$handlers) == 0) { // we need to load the handlers first self::loadConfigHandlers(); } // grab the base name of the handler $basename = basename($handler); if (isset(self::$handlers[$handler])) { // we have a handler associated with the full configuration path // call the handler and retrieve the cache data $data =& self::$handlers[$handler]->execute($config); self::writeCacheFile($config, $cache, $data, false); return; } else if (isset(self::$handlers[$basename])) { // we have a handler associated with the configuration base name // call the handler and retrieve the cache data $data =& self::$handlers[$basename]->execute($config); self::writeCacheFile($config, $cache, $data, false); return; } else { // let's see if we have any wildcard handlers registered that match // this basename foreach (self::$handlers as $key => $handlerInstance) { // replace wildcard chars in the configuration $pattern = str_replace('.', '\.', $key); $pattern = str_replace('*', '.*?', $pattern); // create pattern from config $pattern = '#' . $pattern . '#'; if (preg_match($pattern, $handler)) { // we found a match! // call the handler and retrieve the cache data $data =& self::$handlers[$key]->execute($config); self::writeCacheFile($config, $cache, $data, false); return; } } } // we do not have a registered handler for this file $error = 'Configuration file "%s" does not have a ' . 'registered handler'; $error = sprintf($error, $config); throw new ConfigurationException($error); } // ------------------------------------------------------------------------- /** * Check to see if a configuration file has been modified and if so * recompile the cache file associated with it. * * If the configuration file path is relative, the path itself is relative * to the Mojavi MO_WEBAPP_DIR application setting. * * @param string A filesystem path to a configuration file. * * @return string An absolute filesystem path to the cache filename * associated with this specified configuration file. * * @throws ConfigurationException If a requested configuration file * does not exist. * * @author ketter (ketter@laiketui.com) * @since 3.0.0 */ public static function checkConfig ($config) { // the full filename path to the config $filename = $config; if (!Toolkit::isPathAbsolute($filename)) { $filename = MO_WEBAPP_DIR . '/' . $filename; } if (!is_readable($filename)) { // configuration file does not exist $error = 'Configuration file "%s" does not exist or is unreadable'; $error = sprintf($error, $filename); throw new ConfigurationException($error); } // the cache filename we'll be using $cache = self::getCacheName($config); if (!is_readable($cache) || filemtime($filename) > filemtime($cache)) { // configuration file has changed so we need to reparse it self::callHandler($config, $filename, $cache); } return $cache; } // ------------------------------------------------------------------------- /** * Clear all configuration cache files. * * @return void * * @author ketter (ketter@laiketui.com) * @since 3.0.0 */ public static function clear () { self::clearCache(MO_CACHE_DIR); } // ------------------------------------------------------------------------- /** * Clear all configuration cache files. * * This method exists to prevent accidental deletion of non-cache directory * files. * * @param string An absolute filesystem path to a cache directory. * * @return void * * @author ketter (ketter@laiketui.com) * @since 3.0.0 */ private static function clearCache ($directory) { // open a file point to the cache dir $fp = opendir($directory); // ignore names $ignore = array('.', '..', 'CVS', '.svn'); while (($file = readdir($fp)) !== false) { if (!in_array($file, $ignore)) { if (is_dir($file)) { // recurse through directory self::clearCache($file); // delete the directory rmdir($file); } else { // delete the file unlink($directory . '/' . $file); } } } // close file pointer closedir($fp); } // ------------------------------------------------------------------------- /** * Convert a normal filename into a cache filename. * * @param string A normal filename. * * @return string An absolute filesystem path to a cache filename. * * @author ketter (ketter@laiketui.com) * @since 3.0.0 */ public static function getCacheName ($config) { if (strlen($config) > 3 && ctype_alpha($config{0}) && $config{1} == ':' && $config{2} == '\\') { // file is a windows absolute path, strip off the drive letter $config = substr($config, 3); } // replace unfriendly filename characters with an underscore $config = str_replace(array('\\', '/'), '_', $config); $config .= '.php'; return MO_CACHE_DIR . '/' . $config; } // ------------------------------------------------------------------------- /** * Import a configuration file. * * If the configuration file path is relative, the path itself is relative * to the Mojavi MO_WEBAPP_DIR application setting. * * @param string A filesystem path to a configuration file. * @param bool Only allow this configuration file to be included once per * request? * * @return void * * @author ketter (ketter@laiketui.com) * @since 3.0.0 */ public static function import ($config, $once = true) { // check the config file $cache = self::checkConfig($config); // include cache file if ($once) { include_once($cache); } else { include($cache); } } // ------------------------------------------------------------------------- /** * Load all configuration application and module level handlers. * * @return void * * @throws ConfigurationException If a configuration related error * occurs. * * @author ketter (ketter@laiketui.com) * @since 3.0.0 */ private static function loadConfigHandlers () { // manually create our config_handlers.ini handler self::$handlers['config_handlers.ini'] = new RootConfigHandler(); self::$handlers['config_handlers.ini']->initialize(); // application configuration handlers require_once(ConfigCache::checkConfig('config/config_handlers.ini')); // module level configuration handlers // make sure our modules directory exists if (is_readable(MO_MODULE_DIR)) { // ignore names $ignore = array('.', '..', 'CVS', '.svn'); // create a file pointer to the module dir $fp = opendir(MO_MODULE_DIR); // loop through the directory and grab the modules while (($directory = readdir($fp)) !== false) { if (!in_array($directory, $ignore)) { $config = MO_MODULE_DIR . '/' . $directory . '/config/config_handlers.ini'; if (is_readable($config)) { // initialize the root configuration handler with this // module name $params = array('module_level' => true, 'module_name' => $directory); self::$handlers['config_handlers.ini']->initialize($params); // replace module dir path with a special keyword that // checkConfig knows how to use $config = 'modules/' . $directory . '/config/config_handlers.ini'; require_once(ConfigCache::checkConfig($config)); } } } // close file pointer closedir($fp); } else { // module directory doesn't exist or isn't readable $error = 'Module directory "%s" does not exist or is not readable'; $error = sprintf($error, MO_MODULE_DIR); throw new ConfigurationException($error); } } // ------------------------------------------------------------------------- /** * Write a cache file. * * @param string An absolute filesystem path to a configuration file. * @param string An absolute filesystem path to the cache file that will * be written. * @param string Data to be written to the cache file. * @param string Should we append the data? * * @throws CacheException If the cache file cannot be written. * * @author ketter (ketter@laiketui.com) * @since 3.0.0 */ private static function writeCacheFile ($config, $cache, &$data, $append) { $flags = ($append) ? FILE_APPEND : 0; if (@file_put_contents($cache, $data, $flags) === false) { // cannot write cache file $error = 'Failed to write cache file "%s" generated from ' . 'configuration file "%s"'; $error = sprintf($error, $cache, $config); throw new CacheException($error); } } } ?>