_directorySeparator = preg_quote(DIRECTORY_SEPARATOR); $this->_skipFolders[] = basename(EDITOR_PATH); $this->_moduleFolderRegExp = '#' . $this->_directorySeparator . '(core|modules' . $this->_directorySeparator . '.*?)' . $this->_directorySeparator . '#'; } /** * Sets data from cache to object * * @param Array $data * @access public */ public function setFromCache(&$data) { $this->prefixFiles = $data['ConfigReader.prefixFiles']; } /** * Gets object data for caching * * @access public * @return Array */ public function getToCache() { return Array ( 'ConfigReader.prefixFiles' => $this->prefixFiles, ); } function scanModules($folderPath, $cache = true) { if (defined('IS_INSTALL') && IS_INSTALL && !defined('FORCE_CONFIG_CACHE')) { // disable config caching during installation $cache = false; } if ($cache) { $restored = $this->Application->cacheManager->LoadUnitCache(); if ($restored) { if ( defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode() ) { $this->Application->Debugger->appendHTML('UnitConfigReader: Restoring Cache'); } return; } } if ( defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode() ) { $this->Application->Debugger->appendHTML('UnitConfigReader: Generating Cache'); } $this->ProcessAllConfigs = true; $this->includeConfigFiles($folderPath, $cache); $this->ParseConfigs(); // tell AfterConfigRead to store cache if needed // can't store it here because AfterConfigRead needs ability to change config data $this->StoreCache = $cache; if ( !$this->Application->InitDone ) { // scanModules is called multiple times during installation process $this->Application->InitManagers(); // get build-in rewrite listeners ONLY to be able to parse mod-rewrite url when unit config cache is missing $this->retrieveCollections(); $this->_sortRewriteListeners(); } $this->Application->cacheManager->applyDelayedUnitProcessing(); if ( !$this->Application->InitDone && $cache ) { // Allow hooks to modify "m:QueryString" before URL parsing is started during cold start. $this->runAfterConfigRead('m'); } } function findConfigFiles($folderPath, $level = 0) { // If FULL_PATH = "/" ensure, that all "/" in $folderPath are not deleted. $reg_exp = '/^' . preg_quote(FULL_PATH, '/') . '/'; // This make sense, since $folder_path may NOT contain FULL_PATH. $folderPath = preg_replace($reg_exp, '', $folderPath, 1); $base_folder = FULL_PATH . $folderPath . DIRECTORY_SEPARATOR; $sub_folders = glob($base_folder . '*', GLOB_ONLYDIR); if (!$sub_folders) { return ; } foreach ($sub_folders as $full_path) { $sub_folder = substr($full_path, strlen($base_folder)); if (in_array($sub_folder, $this->_skipFolders)) { continue; } if (substr($sub_folder, 0, 1) == '.') { // Don't scan ".folders". continue; } $config_name = $this->getConfigName($folderPath . DIRECTORY_SEPARATOR . $sub_folder); if (file_exists(FULL_PATH . $config_name)) { $this->configFiles[] = $config_name; } $this->findConfigFiles($full_path, $level + 1); } } function includeConfigFiles($folderPath, $cache = true) { $data = false; $this->Application->refreshModuleInfo(); if ( $cache ) { if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) { $data = $this->Application->getCache( 'master:config_files', false, CacheSettings::$unitCacheRebuildTime ); } else { $data = $this->Application->getDBCache( 'config_files', CacheSettings::$unitCacheRebuildTime ); } } if ( $data ) { $this->configFiles = unserialize($data); if ( !(defined('DBG_VALIDATE_CONFIGS') && DBG_VALIDATE_CONFIGS) ) { shuffle($this->configFiles); } } else { /*if ( $this->Application->isDebugMode() ) { $this->Application->Debugger->profileStart('fcf'); }*/ $this->findConfigFiles(FULL_PATH . DIRECTORY_SEPARATOR . 'core'); // Search from core directory. $this->findConfigFiles($folderPath); // Search from modules directory. /*if ( $this->Application->isDebugMode() ) { $this->Application->Debugger->profileFinish( 'fcf', 'findConfigFiles [' . count($this->configFiles) . ']' ); }*/ if ( $cache ) { if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) { $this->Application->setCache('master:config_files', serialize($this->configFiles), 0); } else { $this->Application->setDBCache('config_files', serialize($this->configFiles), 0); } } } foreach ($this->configFiles as $filename) { $prefix = $this->PreloadConfigFile($filename); if (!$prefix) { throw new Exception('Prefix not defined in config file ' . $filename . ''); } } if ($cache) { unset($this->configFiles); } } /** * Process all read config files - called ONLY when there is no cache! * */ function ParseConfigs() { // 1. process normal configs $prioritized_configs = array(); foreach ($this->configData as $prefix => $config) { if (isset($config['ConfigPriority'])) { $prioritized_configs[$prefix] = $config['ConfigPriority']; continue; } $this->parseConfig($prefix); } foreach ($this->configData as $prefix => $config) { $this->postProcessConfig($prefix, 'AggregateConfigs', 'sub_prefix'); $clones = $this->postProcessConfig($prefix, 'Clones', 'prefix'); } // 2. process prioritized configs asort($prioritized_configs); foreach ($prioritized_configs as $prefix => $priority) { $this->parseConfig($prefix); } } function AfterConfigRead($store_cache = null) { // if (!$this->ProcessAllConfigs) return ; $this->FinalStage = true; foreach ($this->configData as $prefix => $config) { $this->runAfterConfigRead($prefix); } if ( !isset($store_cache) ) { // $store_cache not overridden -> use global setting $store_cache = $this->StoreCache; } if ($store_cache || (defined('IS_INSTALL') && IS_INSTALL)) { // cache is not stored during install, but dynamic clones should be processed in any case $this->processDynamicClones(); $this->retrieveCollections(); } if ($store_cache) { $this->_sortRewriteListeners(); $this->Application->HandleEvent(new kEvent('adm:OnAfterCacheRebuild')); $this->Application->cacheManager->UpdateUnitCache(); if (defined('DEBUG_MODE') && DEBUG_MODE && defined('DBG_VALIDATE_CONFIGS') && DBG_VALIDATE_CONFIGS) { // validate configs here to have changes from OnAfterConfigRead hooks to prefixes foreach ($this->configData as $prefix => $config) { if (!isset($config['TableName'])) continue; $this->ValidateConfig($prefix); } } } } /** * Sort rewrite listeners according to RewritePriority (non-prioritized listeners goes first) * */ function _sortRewriteListeners() { $listeners = Array (); $prioritized_listeners = Array (); // process non-prioritized listeners foreach ($this->Application->RewriteListeners as $prefix => $listener_data) { if ($listener_data['priority'] === false) { $listeners[$prefix] = $listener_data; } else { $prioritized_listeners[$prefix] = $listener_data['priority']; } } // process prioritized listeners asort($prioritized_listeners, SORT_NUMERIC); foreach ($prioritized_listeners as $prefix => $priority) { $listeners[$prefix] = $this->Application->RewriteListeners[$prefix]; } $this->Application->RewriteListeners = $listeners; } /** * Re-reads all configs * */ function ReReadConfigs() { // don't reset prefix file, since file scanning could slow down the process $prefix_files_backup = $this->prefixFiles; $this->Application->cacheManager->EmptyUnitCache(); $this->prefixFiles = $prefix_files_backup; // parse all configs $this->ProcessAllConfigs = true; $this->AfterConfigProcessed = Array (); $this->includeConfigFiles(MODULES_PATH, false); $this->ParseConfigs(); $this->AfterConfigRead(false); $this->processDynamicClones(); // don't call kUnitConfigReader::retrieveCollections since it // will overwrite what we already have in kApplication class instance } /** * Process clones, that were defined via OnAfterConfigRead event * */ function processDynamicClones() { $new_clones = Array(); foreach ($this->configData as $prefix => $config) { $clones = $this->postProcessConfig($prefix, 'Clones', 'prefix'); if ($clones) { $new_clones = array_merge($new_clones, $clones); } } // execute delayed methods for cloned unit configs $this->Application->cacheManager->applyDelayedUnitProcessing(); // call OnAfterConfigRead for cloned configs $new_clones = array_unique($new_clones); foreach ($new_clones as $prefix) { $this->runAfterConfigRead($prefix); } } /** * Process all collectible unit config options here to also catch ones, defined from OnAfterConfigRead events * */ function retrieveCollections() { foreach ($this->configData as $prefix => $config) { // collect replacement templates if (array_key_exists('ReplacementTemplates', $config) && $config['ReplacementTemplates']) { $this->Application->ReplacementTemplates = array_merge($this->Application->ReplacementTemplates, $config['ReplacementTemplates']); } // collect rewrite listeners if (array_key_exists('RewriteListener', $config) && $config['RewriteListener']) { $rewrite_listeners = $config['RewriteListener']; if (!is_array($rewrite_listeners)) { // when one method is used to build and parse url $rewrite_listeners = Array ($rewrite_listeners, $rewrite_listeners); } foreach ($rewrite_listeners as $index => $rewrite_listener) { if (strpos($rewrite_listener, ':') === false) { $rewrite_listeners[$index] = $prefix . '_EventHandler:' . $rewrite_listener; } } $rewrite_priority = array_key_exists('RewritePriority', $config) ? $config['RewritePriority'] : false; $this->Application->RewriteListeners[$prefix] = Array ('listener' => $rewrite_listeners, 'priority' => $rewrite_priority); } } } /** * Register nessasary classes * This method should only process the data which is cached! * * @param string $prefix * @access private */ function parseConfig($prefix) { $this->parseClasses($prefix); $this->parseScheduledTasks($prefix); $this->parseHooks($prefix); $this->parseAggregatedTags($prefix); } protected function parseClasses($prefix) { $config =& $this->configData[$prefix]; $register_classes = $this->getClasses($prefix); foreach ($register_classes as $class_info) { $this->Application->registerClass( $class_info['class'], $config['BasePath'] . DIRECTORY_SEPARATOR . $class_info['file'], $class_info['pseudo'] ); if ( isset($class_info['build_event']) && $class_info['build_event'] ) { $this->Application->delayUnitProcessing('registerBuildEvent', Array ($class_info['pseudo'], $class_info['build_event'])); } } } protected function parseScheduledTasks($prefix) { $config =& $this->configData[$prefix]; if ( !isset($config['ScheduledTasks']) || !$config['ScheduledTasks'] ) { return ; } $scheduled_tasks = $config['ScheduledTasks']; foreach ($scheduled_tasks as $short_name => $scheduled_task_info) { $event_status = array_key_exists('Status', $scheduled_task_info) ? $scheduled_task_info['Status'] : STATUS_ACTIVE; $this->Application->delayUnitProcessing('registerScheduledTask', Array ( $short_name, $config['Prefix'] . ':' . $scheduled_task_info['EventName'], $scheduled_task_info['RunSchedule'], $event_status )); } } protected function parseHooks($prefix) { $config =& $this->configData[$prefix]; if ( !isset($config['Hooks']) || !$config['Hooks'] ) { return ; } $hooks = $config['Hooks']; foreach ($hooks as $hook) { // Don't attempt to register a hook to a module isn't installed. if ( isset($hook['HookToModule']) && !isset($this->Application->ModuleInfo[$hook['HookToModule']]) ) { continue; } if ( isset($config['ParentPrefix']) && ($hook['HookToPrefix'] == $config['ParentPrefix']) ) { trigger_error('Depricated Hook Usage [prefix: ' . $config['Prefix'] . '; do_prefix: ' . $hook['DoPrefix'] . '] use #PARENT# as HookToPrefix value, where HookToPrefix is same as ParentPrefix', defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_NOTICE); } if ($hook['HookToPrefix'] == '') { // new: set hooktoprefix to current prefix if not set $hook['HookToPrefix'] = $config['Prefix']; } if ( isset($config['ParentPrefix']) ) { // new: allow to set hook to parent prefix what ever it is if ($hook['HookToPrefix'] == '#PARENT#') { $hook['HookToPrefix'] = $config['ParentPrefix']; } if ($hook['DoPrefix'] == '#PARENT#') { $hook['DoPrefix'] = $config['ParentPrefix']; } } elseif ($hook['HookToPrefix'] == '#PARENT#' || $hook['DoPrefix'] == '#PARENT#') { // we need parent prefix but it's not set ! continue; } $hook_events = (array)$hook['HookToEvent']; $do_prefix = $hook['DoPrefix'] == '' ? $config['Prefix'] : $hook['DoPrefix']; foreach ($hook_events as $hook_event) { $hook_event = $hook['HookToPrefix'] . '.' . $hook['HookToSpecial'] . ':' . $hook_event; $do_event = $do_prefix . '.' . $hook['DoSpecial'] . ':' . $hook['DoEvent']; $this->Application->delayUnitProcessing('registerHook', Array ($hook_event, $do_event, $hook['Mode'], $hook['Conditional'])); } } } protected function parseAggregatedTags($prefix) { $config =& $this->configData[$prefix]; $aggregated_tags = isset($config['AggregateTags']) ? $config['AggregateTags'] : Array (); foreach ($aggregated_tags as $aggregate_tag) { if ( isset($config['ParentPrefix']) ) { if ($aggregate_tag['AggregateTo'] == $config['ParentPrefix']) { trigger_error('Depricated Aggregate Tag Usage [prefix: '.$config['Prefix'].'; AggregateTo: '.$aggregate_tag['AggregateTo'].'] use #PARENT# as AggregateTo value, where AggregateTo is same as ParentPrefix', defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_NOTICE); } if ($aggregate_tag['AggregateTo'] == '#PARENT#') { $aggregate_tag['AggregateTo'] = $config['ParentPrefix']; } } $aggregate_tag['LocalPrefix'] = $config['Prefix']; $this->Application->delayUnitProcessing('registerAggregateTag', Array ($aggregate_tag)); } } function ValidateConfig($prefix) { global $debugger; $config =& $this->configData[$prefix]; $tablename = $config['TableName']; $float_types = Array ('float', 'double', 'numeric'); $table_found = $this->Conn->Query('SHOW TABLES LIKE "'.$tablename.'"'); if (!$table_found) { // config present, but table missing, strange kUtil::safeDefine('DBG_RAISE_ON_WARNINGS', 1); $debugger->appendHTML("Config Warning: Table $tablename missing, but prefix ".$config['Prefix']." requires it!"); $debugger->WarningCount++; return ; } $res = $this->Conn->Query('DESCRIBE '.$tablename); $config_link = $debugger->getFileLink(FULL_PATH.$this->prefixFiles[$config['Prefix']], 1, $config['Prefix']); $error_messages = Array ( 'field_not_found' => 'Field %s exists in the database, but is not defined in config', 'default_missing' => 'Default value for field %s not set in config', 'not_null_error1' => 'Field %s is NOT NULL in the database, but is not configured as not_null', // or required', 'not_null_error2' => 'Field %s is described as NOT NULL in config, but does not have DEFAULT value', 'not_null_error3' => 'Field %s is described as NOT NULL in config, but is NULL in db', 'invalid_default' => 'Default value for field %s%s not sync. to db (in config = %s, in db = %s)', 'date_column_not_null_error' => 'Field %s must be NULL in config and database, since it contains date', 'user_column_default_error' => 'Field %s must be have NULL as default value, since it holds user id', 'type_missing' => 'Type definition for field %s missing in config', 'virtual_type_missing' => 'Type definition for virtual field %s missing in config', 'virtual_default_missing' => 'Default value for virtual field %s not set in config', 'virtual_not_null_error' => 'Virtual field %s cannot be not null, since it doesn\'t exist in database', 'invalid_calculated_field' => 'Calculated field %s is missing corresponding virtual field', ); $config_errors = Array (); $tablename = preg_replace('/^'.preg_quote(TABLE_PREFIX, '/').'(.*)/', '\\1', $tablename); // remove table prefix // validate unit config field declaration in relation to database table structure foreach ($res as $field) { $f_name = $field['Field']; if (getArrayValue($config, 'Fields')) { if (preg_match('/l[\d]+_[\w]/', $f_name)) { // skip multilingual fields continue; } if (!array_key_exists ($f_name, $config['Fields'])) { $config_errors[] = sprintf($error_messages['field_not_found'], $f_name); } else { $db_default = $field['Default']; if (is_numeric($db_default)) { $db_default = preg_match('/[\.,]/', $db_default) ? (float)$db_default : (int)$db_default; } $default_missing = false; $options = $config['Fields'][$f_name]; $not_null = isset($options['not_null']) && $options['not_null']; $formatter = array_key_exists('formatter', $options) ? $options['formatter'] : false; if (!array_key_exists('default', $options)) { $config_errors[] = sprintf($error_messages['default_missing'], $f_name); $default_missing = true; } if ($field['Null'] != 'YES') { // field is NOT NULL in database (MySQL5 for null returns "NO", but MySQL4 returns "") if ( $f_name != $config['IDField'] && !isset($options['not_null']) /*&& !isset($options['required'])*/ ) { $config_errors[] = sprintf($error_messages['not_null_error1'], $f_name); } if ($not_null && !isset($options['default']) ) { $config_errors[] = sprintf($error_messages['not_null_error2'], $f_name); } } elseif ($not_null) { $config_errors[] = sprintf($error_messages['not_null_error3'], $f_name); } if (($formatter == 'kDateFormatter') && $not_null) { $config_errors[] = sprintf($error_messages['date_column_not_null_error'], $f_name); } // columns, holding userid should have NULL as default value if (array_key_exists('type', $options) && !$default_missing) { // both type and default value set if (preg_match('/ById$/', $f_name) && $options['default'] !== null) { $config_errors[] = sprintf($error_messages['user_column_default_error'], $f_name); } } if (!array_key_exists('type', $options)) { $config_errors[] = sprintf($error_messages['type_missing'], $f_name); } if (!$default_missing && ($field['Type'] != 'text')) { if ( is_null($db_default) && $not_null ) { $db_default = $options['type'] == 'string' ? '' : 0; } if ($f_name == $config['IDField'] && $options['type'] != 'string' && $options['default'] !== 0) { $config_errors[] = sprintf($error_messages['invalid_default'], 'IDField ', $f_name, $this->varDump($options['default']), $this->varDump($field['Default'])); } else if (((string)$options['default'] != '#NOW#') && ($db_default !== $options['default']) && !in_array($options['type'], $float_types)) { $config_errors[] = sprintf($error_messages['invalid_default'], '', $f_name, $this->varDump($options['default']), $this->varDump($db_default)); } } } } } // validate virtual fields if ( array_key_exists('VirtualFields', $config) ) { foreach ($config['VirtualFields'] as $f_name => $options) { if (!array_key_exists('type', $options)) { $config_errors[] = sprintf($error_messages['virtual_type_missing'], $f_name); } if (array_key_exists('not_null', $options)) { $config_errors[] = sprintf($error_messages['virtual_not_null_error'], $f_name); } if (!array_key_exists('default', $options)) { $config_errors[] = sprintf($error_messages['virtual_default_missing'], $f_name); } } } // validate calculated fields if ( array_key_exists('CalculatedFields', $config) ) { foreach ($config['CalculatedFields'] as $special => $calculated_fields) { foreach ($calculated_fields as $calculated_field => $calculated_field_expr) { if ( !isset($config['VirtualFields'][$calculated_field]) ) { $config_errors[] = sprintf($error_messages['invalid_calculated_field'], $calculated_field); } } } $config_errors = array_unique($config_errors); } if ($config_errors) { $error_prefix = 'Config Error'.(count($config_errors) > 1 ? 's' : '').': for prefix '.$config_link.' ('.$tablename.') in unit config:
'; $config_errors = $error_prefix.'   '.implode('
   ', $config_errors); kUtil::safeDefine('DBG_RAISE_ON_WARNINGS', 1); $debugger->appendHTML($config_errors); $debugger->WarningCount++; } } function varDump($value) { return ''.var_export($value, true).' of '.gettype($value); } function postProcessConfig($prefix, $config_key, $dst_prefix_var) { $main_config =& $this->configData[$prefix]; $sub_configs = isset($main_config[$config_key]) && $main_config[$config_key] ? $main_config[$config_key] : Array (); if ( !$sub_configs ) { return Array (); } unset($main_config[$config_key]); $processed = array(); foreach ($sub_configs as $sub_prefix => $sub_config) { if ($config_key == 'AggregateConfigs' && !isset($this->configData[$sub_prefix])) { $this->loadConfig($sub_prefix); } $sub_config['Prefix'] = $sub_prefix; $this->configData[$sub_prefix] = kUtil::array_merge_recursive($this->configData[$$dst_prefix_var], $sub_config); // when merging empty array to non-empty results non-empty array, but empty is required foreach ($sub_config as $sub_key => $sub_value) { if (!$sub_value) { unset($this->configData[$sub_prefix][$sub_key]); } } if ($config_key == 'Clones') { $this->prefixFiles[$sub_prefix] = $this->prefixFiles[$prefix]; } $this->postProcessConfig($sub_prefix, $config_key, $dst_prefix_var); if ($config_key == 'AggregateConfigs') { $processed = array_merge($this->postProcessConfig($sub_prefix, 'Clones', 'prefix'), $processed); } elseif ($this->ProcessAllConfigs) { $this->parseConfig($sub_prefix); } array_push($processed, $sub_prefix); } if (!$prefix) { // configs, that used only for cloning & not used ifself unset($this->configData[$prefix]); } return array_unique($processed); } function PreloadConfigFile($filename) { $config_found = file_exists(FULL_PATH . $filename) && $this->configAllowed($filename); if (defined('DEBUG_MODE') && DEBUG_MODE && defined('DBG_PROFILE_INCLUDES') && DBG_PROFILE_INCLUDES) { if ( in_array($filename, get_included_files()) ) { return ''; } global $debugger; if ($config_found) { $file = FULL_PATH . $filename; $file_crc = crc32($file); $debugger->ProfileStart('inc_' . $file_crc, $file); include_once($file); $debugger->ProfileFinish('inc_' . $file_crc); $debugger->profilerAddTotal('includes', 'inc_' . $file_crc); } } elseif ($config_found) { include_once(FULL_PATH . $filename); } if ($config_found) { if (isset($config) && $config) { // config file is included for 1st time -> save it's content for future processing $prefix = array_key_exists('Prefix', $config) ? $config['Prefix'] : ''; preg_match($this->_moduleFolderRegExp, $filename, $rets); $config['ModuleFolder'] = str_replace(DIRECTORY_SEPARATOR, '/', $rets[1]); $config['BasePath'] = dirname(FULL_PATH . $filename); if (array_key_exists('AdminTemplatePath', $config)) { // append template base folder for admin templates path of this prefix $module_templates = $rets[1] == 'core' ? '' : substr($rets[1], 8) . '/'; $config['AdminTemplatePath'] = $module_templates . $config['AdminTemplatePath']; } if (array_key_exists($prefix, $this->prefixFiles) && ($this->prefixFiles[$prefix] != $filename)) { trigger_error( 'Single unit config prefix "' . $prefix . '" ' . 'is used in multiple unit config files: ' . '"' . $this->prefixFiles[$prefix] . '", "' . $filename . '"', E_USER_WARNING ); } $this->configData[$prefix] = $config; $this->prefixFiles[$prefix] = $filename; return $prefix; } else { $prefix = array_search($filename, $this->prefixFiles); if ( $prefix ) { // attempt is made to include config file twice or more, but include_once prevents that, // but file exists on hdd, then it is already saved to all required arrays, just return it's prefix return $prefix; } } } return 'dummy'; } function loadConfig($prefix) { if ( !isset($this->prefixFiles[$prefix]) ) { throw new Exception('Configuration file for prefix "' . $prefix . '" is unknown'); return ; } $file = $this->prefixFiles[$prefix]; $prefix = $this->PreloadConfigFile($file); if ( $this->FinalStage || $prefix == 'm' ) { // Run prefix OnAfterConfigRead so all hooks to it can define their clones. // Allow hooks to modify "m:QueryString" before URL parsing is started during warm start. $this->runAfterConfigRead($prefix); } $clones = $this->postProcessConfig($prefix, 'AggregateConfigs', 'sub_prefix'); $clones = array_merge($this->postProcessConfig($prefix, 'Clones', 'prefix'), $clones); if ($this->FinalStage) { $clones = array_unique($clones); foreach ($clones as $a_prefix) { $this->runAfterConfigRead($a_prefix); } } } function runAfterConfigRead($prefix) { if (in_array($prefix, $this->AfterConfigProcessed)) { return ; } $this->Application->HandleEvent( new kEvent($prefix . ':OnAfterConfigRead') ); if (!(defined('IS_INSTALL') && IS_INSTALL)) { // allow to call OnAfterConfigRead multiple times during install array_push($this->AfterConfigProcessed, $prefix); } } /** * Reads unit (specified by $prefix) * option specified by $option * * @param string $prefix * @param string $name * @param mixed $default * @return string * @access public */ function getUnitOption($prefix, $name, $default = false) { if (preg_match('/(.*)\.(.*)/', $prefix, $rets)) { if (!isset($this->configData[$rets[1]])) { $this->loadConfig($rets[1]); } $ret = isset($this->configData[$rets[1]][$name][$rets[2]]) ? $this->configData[$rets[1]][$name][$rets[2]] : false; // $ret = getArrayValue($this->configData, $rets[1], $name, $rets[2]); } else { if (!isset($this->configData[$prefix])) { $this->loadConfig($prefix); } $ret = isset($this->configData[$prefix][$name]) ? $this->configData[$prefix][$name] : false; // $ret = getArrayValue($this->configData, $prefix, $name); } return $ret === false ? $default : $ret; } /** * Read all unit with $prefix options * * @param string $prefix * @return Array * @access public */ function getUnitOptions($prefix) { if (!isset($this->configData[$prefix])) { $this->loadConfig($prefix); } return $this->configData[$prefix]; } /** * Set's new unit option value * * @param string $prefix * @param string $name * @param string $value * @access public */ function setUnitOption($prefix, $name, $value) { if ( preg_match('/(.*)\.(.*)/', $prefix, $rets) ) { if ( !isset($this->configData[$rets[1]]) ) { $this->loadConfig($rets[1]); } $this->configData[$rets[1]][$name][$rets[2]] = $value; } else { if ( !isset($this->configData[$prefix]) ) { $this->loadConfig($prefix); } $this->configData[$prefix][$name] = $value; } } protected function getClasses($prefix) { $config =& $this->configData[$prefix]; $class_params = Array ('ItemClass', 'ListClass', 'EventHandlerClass', 'TagProcessorClass'); $register_classes = isset($config['RegisterClasses']) ? $config['RegisterClasses'] : Array (); foreach ($class_params as $param_name) { if ( !isset($config[$param_name]) ) { continue; } $config[$param_name]['pseudo'] = $this->getPseudoByOptionName($param_name, $prefix); $register_classes[] = $config[$param_name]; } return $register_classes; } protected function getPseudoByOptionName($option_name, $prefix) { $pseudo_class_map = Array ( 'ItemClass' => '%s', 'ListClass' => '%s_List', 'EventHandlerClass' => '%s_EventHandler', 'TagProcessorClass' => '%s_TagProcessor' ); return sprintf($pseudo_class_map[$option_name], $prefix); } /** * Get's config file name based * on folder name supplied * * @param string $folderPath * @return string * @access private */ function getConfigName($folderPath) { return $folderPath . DIRECTORY_SEPARATOR . basename($folderPath) . '_config.php'; } /** * Checks if config file is allowed for includion (if module of config is installed) * * @param string $config_path relative path from in-portal directory */ function configAllowed($config_path) { static $module_paths = null; if (defined('IS_INSTALL') && IS_INSTALL) { // at installation start no modules in db and kernel configs could not be read return true; } if (preg_match('#^' . $this->_directorySeparator . 'core#', $config_path)) { // always allow to include configs from "core" module's folder return true; } if (!$this->Application->ModuleInfo) { return false; } if (!isset($module_paths)) { $module_paths = Array (); foreach ($this->Application->ModuleInfo as $module_name => $module_info) { $module_paths[] = str_replace('/', DIRECTORY_SEPARATOR, rtrim($module_info['Path'], '/')); } $module_paths = array_unique($module_paths); } preg_match($this->_moduleFolderRegExp, $config_path, $rets); // config file path starts with module folder path return in_array($rets[1], $module_paths); } /** * Returns true if config exists and is allowed for reading * * @param string $prefix * @return bool */ function prefixRegistred($prefix) { return isset($this->prefixFiles[$prefix]) ? true : false; } /** * Returns config file for given prefix * * @param string $prefix * @return string */ function getPrefixFile($prefix) { return array_key_exists($prefix, $this->prefixFiles) ? $this->prefixFiles[$prefix] : false; } function iterateConfigs($callback_function, $params) { $this->includeConfigFiles(MODULES_PATH); //make sure to re-read all configs $this->AfterConfigRead(); foreach ($this->configData as $prefix => $config_data) { call_user_func_array( $callback_function, array($prefix, &$config_data, $params) ); } } }