Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F1050379
unit_config_reader.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Wed, Jul 2, 3:16 AM
Size
18 KB
Mime Type
text/x-php
Expires
Fri, Jul 4, 3:16 AM (4 h, 15 m)
Engine
blob
Format
Raw Data
Handle
678652
Attached To
rINP In-Portal
unit_config_reader.php
View Options
<?php
/**
* @version $Id: unit_config_reader.php 16181 2015-05-15 16:54:20Z alex $
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined
(
'FULL_PATH'
)
or
die
(
'restricted access!'
);
class
kUnitConfigReader
extends
kBase
implements
kiCacheable
{
/**
* Unit config data storage.
*
* @var kUnitConfig[]
*/
protected
$configData
=
array
();
/**
* List of discovered unit config files.
*
* @var array
*/
protected
$configFiles
=
array
();
/**
* Mapping between unit config prefixes and files, where they data is stored.
*
* @var array
*/
protected
$prefixFiles
=
array
();
/**
* Tells, that it's final stage of application initialization, where OnAfterConfigRead events can be called.
*
* @var boolean
*/
protected
$finalStage
=
false
;
/**
* Determines if cache should be stored.
*
* @var boolean
*/
protected
$storeCache
=
false
;
/**
* List of unit configs, that have called their OnAfterConfigRead event.
*
* @var array
*/
protected
$afterConfigProcessed
=
array
();
/**
* Escaped directory separator for using in regular expressions
*
* @var string
*/
protected
$directorySeparator
=
''
;
/**
* Regular expression for detecting module folder
*
* @var string
*/
protected
$moduleFolderRegExp
=
''
;
/**
* Folders to skip during unit config search
*
* @var array
*/
protected
$skipFolders
=
array
(
'CVS'
,
'.svn'
,
'admin_templates'
,
'libchart'
);
/**
* Cloner.
*
* @var kUnitConfigCloner
*/
protected
$cloner
;
/**
* Creates instance of unit config reader.
*/
public
function
__construct
()
{
parent
::
__construct
();
$this
->
directorySeparator
=
preg_quote
(
DIRECTORY_SEPARATOR
);
$editor_path
=
explode
(
'/'
,
trim
(
EDITOR_PATH
,
'/'
));
$this
->
skipFolders
[]
=
array_pop
(
$editor_path
);
// last of cmseditor folders
$this
->
moduleFolderRegExp
=
'#'
.
$this
->
directorySeparator
.
'(core|modules'
.
$this
->
directorySeparator
.
'.*?)'
.
$this
->
directorySeparator
.
'#'
;
$this
->
cloner
=
$this
->
Application
->
makeClass
(
'kUnitConfigCloner'
,
array
(
$this
));
}
/**
* Sets data from cache to object
*
* @param Array $data
*/
public
function
setFromCache
(&
$data
)
{
$this
->
cloner
->
setFromCache
(
$data
);
$this
->
prefixFiles
=
$data
[
'ConfigReader.prefixFiles'
];
}
/**
* Gets object data for caching
*
* @return Array
*/
public
function
getToCache
()
{
return
array_merge
(
$this
->
cloner
->
getToCache
(),
array
(
'ConfigReader.prefixFiles'
=>
$this
->
prefixFiles
,
)
);
}
public
function
scanModules
(
$folder_path
,
$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'
);
}
// === lines below would only executed on cold start (no unit config cache) ===
// no cache found -> include all unit configs to create it !
$this
->
includeConfigFiles
(
$folder_path
,
$cache
);
$this
->
parseConfigs
();
$this
->
sortRouters
();
// 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
();
}
$this
->
Application
->
cacheManager
->
applyDelayedUnitProcessing
();
}
/**
* Locates (recursively) and reads all unit configs at given path.
*
* @param string $folder_path Folder path.
* @param boolean $cache Store information to cache.
*
* @throws Exception When unit config file is missing a prefix defined inside it.
*/
protected
function
includeConfigFiles
(
$folder_path
,
$cache
=
true
)
{
$this
->
Application
->
refreshModuleInfo
();
if
(
$this
->
Application
->
isCachingType
(
CACHING_TYPE_MEMORY
)
)
{
$data
=
$this
->
Application
->
getCache
(
'master:config_files'
,
false
,
$cache
?
CacheSettings
::
$unitCacheRebuildTime
:
0
);
}
else
{
$data
=
$this
->
Application
->
getDBCache
(
'config_files'
,
$cache
?
CacheSettings
::
$unitCacheRebuildTime
:
0
);
}
if
(
$data
)
{
$this
->
configFiles
=
unserialize
(
$data
);
if
(
!(
defined
(
'DBG_VALIDATE_CONFIGS'
)
&&
DBG_VALIDATE_CONFIGS
)
)
{
shuffle
(
$this
->
configFiles
);
}
}
else
{
$this
->
findConfigFiles
(
FULL_PATH
.
DIRECTORY_SEPARATOR
.
'core'
);
// search from "core" directory
$this
->
findConfigFiles
(
$folder_path
);
// search from "modules" directory
if
(
$cache
)
{
if
(
$this
->
Application
->
isCachingType
(
CACHING_TYPE_MEMORY
)
)
{
$this
->
Application
->
setCache
(
'master:config_files'
,
serialize
(
$this
->
configFiles
));
}
else
{
$this
->
Application
->
setDBCache
(
'config_files'
,
serialize
(
$this
->
configFiles
));
}
}
}
foreach
(
$this
->
configFiles
as
$filename
)
{
$prefix
=
$this
->
PreloadConfigFile
(
$filename
);
if
(
!
$prefix
)
{
throw
new
Exception
(
'Prefix not defined in config file <strong>'
.
$filename
.
'</strong>'
);
}
}
// TODO: needed?
if
(
$cache
)
{
unset
(
$this
->
configFiles
);
}
}
/**
* Recursively searches for unit configs in given folder.
*
* @param string $folder_path Path to the folder.
* @param int $level Deep level of the folder.
*
* @return void
*/
protected
function
findConfigFiles
(
$folder_path
,
$level
=
0
)
{
// if FULL_PATH = "/" ensure, that all "/" in $folderPath are not deleted
$reg_exp
=
'/^'
.
preg_quote
(
FULL_PATH
,
'/'
)
.
'/'
;
$folder_path
=
preg_replace
(
$reg_exp
,
''
,
$folder_path
,
1
);
// this make sense, since $folderPath may NOT contain FULL_PATH
$base_folder
=
FULL_PATH
.
$folder_path
.
DIRECTORY_SEPARATOR
;
$sub_folders
=
glob
(
$base_folder
.
'*'
,
GLOB_ONLYDIR
);
if
(
!
$sub_folders
)
{
return
;
}
if
(
$level
==
0
)
{
// don't scan Front-End themes because of extensive directory structure
$sub_folders
=
array_diff
(
$sub_folders
,
array
(
$base_folder
.
'themes'
,
$base_folder
.
'tools'
));
}
foreach
(
$sub_folders
as
$full_path
)
{
$sub_folder
=
substr
(
$full_path
,
strlen
(
$base_folder
));
if
(
in_array
(
$sub_folder
,
$this
->
skipFolders
)
||
preg_match
(
'/^
\.
/'
,
$sub_folder
)
)
{
// don't scan skipped or hidden folders
continue
;
}
$config_name
=
$this
->
getConfigName
(
$folder_path
.
DIRECTORY_SEPARATOR
.
$sub_folder
);
if
(
file_exists
(
FULL_PATH
.
$config_name
)
)
{
$this
->
configFiles
[]
=
$config_name
;
}
$this
->
findConfigFiles
(
$full_path
,
$level
+
1
);
}
}
/**
* Process all read config files - called ONLY when there is no cache!
*
* @return void
*/
protected
function
parseConfigs
()
{
$this
->
parseUnitConfigs
(
$this
->
getUnitConfigsWithoutPriority
());
$this
->
parseUnitConfigs
(
$this
->
getUnitConfigsWithPriority
());
}
/**
* Parses unit config sub-set.
*
* @param array $prefixes Unit config prefixes.
*
* @return array
*/
protected
function
parseUnitConfigs
(
array
$prefixes
)
{
foreach
(
$prefixes
as
$prefix
)
{
$this
->
configData
[
$prefix
]->
parse
();
}
$this
->
cloner
->
extrudeAndParse
(
$prefixes
);
}
/**
* Returns unit configs prefixes without priority defined.
*
* @return array
*/
public
function
getUnitConfigsWithoutPriority
()
{
$ret
=
array
();
foreach
(
$this
->
configData
as
$prefix
=>
$config
)
{
if
(
$config
->
getConfigPriority
()
===
false
)
{
$ret
[]
=
$prefix
;
}
}
return
$ret
;
}
/**
* Returns unit configs prefixes with priority defined.
*
* @return array
*/
public
function
getUnitConfigsWithPriority
()
{
$ret
=
array
();
foreach
(
$this
->
configData
as
$prefix
=>
$config
)
{
$priority
=
$config
->
getConfigPriority
();
if
(
$priority
!==
false
)
{
$ret
[
$prefix
]
=
$priority
;
}
}
asort
(
$ret
);
return
array_keys
(
$ret
);
}
public
function
AfterConfigRead
(
$store_cache
=
null
)
{
$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
->
cloner
->
processDynamicallyAdded
();
$this
->
retrieveCollections
();
}
if
(
$store_cache
)
{
$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
$config
)
{
if
(
!
$config
->
getTableName
()
)
{
continue
;
}
$config
->
validate
();
}
}
}
}
/**
* Sort routers according to their weight (non-prioritized routers goes first).
*
* @return void
*/
protected
function
sortRouters
()
{
$sorted_routers
=
array
();
$prioritized_routers
=
array
();
$routers
=
$this
->
collectRouters
();
// Process non-prioritized routers.
foreach
(
$routers
as
$prefix
=>
$router_data
)
{
if
(
$router_data
[
'priority'
]
===
false
)
{
$sorted_routers
[
$prefix
]
=
$router_data
;
}
else
{
$prioritized_routers
[
$prefix
]
=
$router_data
[
'priority'
];
}
}
// Process prioritized routers.
asort
(
$prioritized_routers
,
SORT_NUMERIC
);
foreach
(
$prioritized_routers
as
$prefix
=>
$priority
)
{
$sorted_routers
[
$prefix
]
=
$routers
[
$prefix
];
}
$this
->
Application
->
routers
=
$sorted_routers
;
}
/**
* Collects routers.
*
* @return array
*/
protected
function
collectRouters
()
{
$routers
=
array
();
$router_classes
=
$this
->
Application
->
getSubClasses
(
'AbstractRouter'
);
foreach
(
$router_classes
as
$router_class
)
{
if
(
!
class_exists
(
$router_class
)
)
{
// This can happen, when:
// - router class (coming from cache) was renamed;
// - new cache is built based on outdated class map.
continue
;
}
/** @var AbstractRouter $router */
$router
=
new
$router_class
();
$routers
[
$router
->
getPrefix
()]
=
array
(
'class'
=>
$router_class
,
'priority'
=>
$router
->
getWeight
(),
);
}
return
$routers
;
}
/**
* Re-reads all configs.
*
* @return void
*/
public
function
ReReadConfigs
()
{
if
(
$this
->
storeCache
&&
$this
->
finalStage
)
{
// Building cache right now, so all unit configs are read anyway.
return
;
}
// 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
->
afterConfigProcessed
=
array
();
$this
->
includeConfigFiles
(
MODULES_PATH
,
false
);
$this
->
parseConfigs
();
$this
->
sortRouters
();
$this
->
AfterConfigRead
(
false
);
$this
->
cloner
->
processDynamicallyAdded
();
$this
->
retrieveCollections
();
}
/**
* Process all collectible unit config options here to also catch ones, defined from OnAfterConfigRead events
*
*/
protected
function
retrieveCollections
()
{
foreach
(
$this
->
configData
as
$prefix
=>
$config
)
{
// collect replacement templates
if
(
$config
->
getReplacementTemplates
()
)
{
$this
->
Application
->
ReplacementTemplates
=
array_merge
(
$this
->
Application
->
ReplacementTemplates
,
$config
->
getReplacementTemplates
());
}
}
}
public
function
loadConfig
(
$prefix
)
{
$preloaded_prefix
=
$this
->
PreloadConfigFile
(
$this
->
getPrefixFile
(
$prefix
));
if
(
$this
->
finalStage
)
{
// run prefix OnAfterConfigRead so all hooks to it can define their clones
$this
->
runAfterConfigRead
(
$preloaded_prefix
);
}
// Only use cached clones for calls in the middle of initialization (e.g. url parsing).
$clones
=
$this
->
cloner
->
extrude
(
$preloaded_prefix
,
!
$this
->
finalStage
);
if
(
$this
->
finalStage
)
{
foreach
(
$clones
as
$a_prefix
)
{
$this
->
runAfterConfigRead
(
$a_prefix
);
}
}
}
/**
* Runs OnAfterConfigRead event for given prefix once.
*
* @param string $prefix Unit config prefix.
*
* @return void
*/
public
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
);
}
}
/**
* Loads unit config file contents from disk.
*
* @param string $filename Unit config filename.
*
* @return string
*/
protected
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
)
{
/* @var $config kUnitConfig|Array */
if
(
isset
(
$config
)
&&
$config
)
{
// config file is included for 1st time -> save it's content for future processing
if
(
!
is_object
(
$config
)
)
{
$prefix
=
array_key_exists
(
'Prefix'
,
$config
)
?
$config
[
'Prefix'
]
:
''
;
$config
=
new
kUnitConfig
(
$prefix
,
$config
);
}
else
{
$prefix
=
$config
->
getPrefix
();
}
preg_match
(
$this
->
moduleFolderRegExp
,
$filename
,
$regs
);
$config
->
setModuleFolder
(
str_replace
(
DIRECTORY_SEPARATOR
,
'/'
,
$regs
[
1
]));
$config
->
setBasePath
(
dirname
(
FULL_PATH
.
$filename
));
if
(
$config
->
getAdminTemplatePath
()
!==
false
)
{
// append template base folder for admin templates path of this prefix
$module_templates
=
$regs
[
1
]
==
'core'
?
''
:
substr
(
$regs
[
1
],
8
)
.
'/'
;
$config
->
setAdminTemplatePath
(
$module_templates
.
$config
->
getAdminTemplatePath
());
}
if
(
array_key_exists
(
$prefix
,
$this
->
prefixFiles
)
&&
(
$this
->
prefixFiles
[
$prefix
]
!=
$filename
)
)
{
trigger_error
(
'Single unit config prefix "<strong>'
.
$prefix
.
'</strong>" '
.
'is used in multiple unit config files: '
.
'"<strong>'
.
$this
->
prefixFiles
[
$prefix
]
.
'</strong>", "<strong>'
.
$filename
.
'</strong>"'
,
E_USER_WARNING
);
}
$this
->
add
(
$config
,
$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'
;
}
/**
* Sets a file, for a given prefix.
*
* @param kUnitConfig $config Unit config.
* @param string $filename File.
*
* @return void
*/
public
function
add
(
kUnitConfig
$config
,
$filename
)
{
$config
->
setFilename
(
$filename
);
$prefix
=
$config
->
getPrefix
();
$this
->
configData
[
$prefix
]
=
$config
;
$this
->
prefixFiles
[
$prefix
]
=
$filename
;
}
/**
* Removes unit config.
*
* @param string $prefix Unit config prefix.
*
* @return void
*/
public
function
remove
(
$prefix
)
{
unset
(
$this
->
configData
[
$prefix
],
$this
->
prefixFiles
[
$prefix
]);
}
/**
* Returns unit config for given prefix
*
* @param string $prefix
* @return kUnitConfig
*/
public
function
getUnitConfig
(
$prefix
=
null
)
{
if
(
!
isset
(
$this
->
configData
[
$prefix
])
)
{
$this
->
loadConfig
(
$prefix
);
}
return
$this
->
configData
[
$prefix
];
}
/**
* Returns prefixes of unit configs, that were registered.
*
* @param boolean $loaded_only Only return prefixes, that were loaded till now.
*
* @return array
*/
public
function
getPrefixes
(
$loaded_only
=
true
)
{
if
(
$loaded_only
)
{
return
array_keys
(
$this
->
configData
);
}
return
array_keys
(
$this
->
prefixFiles
);
}
/**
* Get's config file name based
* on folder name supplied
*
* @param string $folder_path
* @return string
*/
protected
function
getConfigName
(
$folder_path
)
{
return
$folder_path
.
DIRECTORY_SEPARATOR
.
basename
(
$folder_path
)
.
'_config.php'
;
}
/**
* Checks if config file is allowed for inclusion (if module of config is installed).
*
* @param string $config_path Relative path from In-Portal directory.
*
* @return boolean
*/
protected
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_info
)
{
$module_paths
[]
=
str_replace
(
'/'
,
DIRECTORY_SEPARATOR
,
rtrim
(
$module_info
[
'Path'
],
'/'
));
}
$module_paths
=
array_unique
(
$module_paths
);
}
preg_match
(
$this
->
moduleFolderRegExp
,
$config_path
,
$regs
);
// config file path starts with module folder path
return
in_array
(
$regs
[
1
],
$module_paths
);
}
/**
* Returns true if config exists and is allowed for reading
*
* @param string $prefix Unit config prefix.
*
* @return boolean
*/
public
function
prefixRegistered
(
$prefix
)
{
return
isset
(
$this
->
prefixFiles
[
$prefix
]);
}
/**
* Returns unit config file location by it's prefix.
*
* @param string $prefix Unit config prefix.
*
* @return string
* @throws InvalidArgumentException When unit config is not found.
*/
public
function
getPrefixFile
(
$prefix
)
{
if
(
!
isset
(
$this
->
prefixFiles
[
$prefix
])
)
{
throw
new
InvalidArgumentException
(
'Configuration file for prefix "<strong>'
.
$prefix
.
'</strong>" is unknown'
);
}
return
$this
->
prefixFiles
[
$prefix
];
}
}
Event Timeline
Log In to Comment