* @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2010 PradoSoft
* @license http://www.pradosoft.com/license/
* @version $Id$
* @package System.Web.Services
*/
/**
* Include classes to be used by page service
*/
Prado::using('System.Web.UI.TPage');
Prado::using('System.Web.UI.TTemplateManager');
Prado::using('System.Web.UI.TThemeManager');
/**
* TPageService class.
*
* TPageService implements the service for serving user page requests.
*
* Pages that are available to client users are stored under a directory specified by
* {@link setBasePath BasePath}. The directory may contain subdirectories.
* Pages serving for a similar goal are usually placed under the same directory.
* A directory may contain a configuration file config.xml whose content
* is similar to that of application configuration file.
*
* A page is requested via page path, which is a dot-connected directory names
* appended by the page name. Assume '/Users/Admin' is the directory
* containing the page 'Update'. Then the page can be requested via 'Users.Admin.Update'.
* By default, the {@link setBasePath BasePath} of the page service is the "pages"
* directory under the application base path. You may change this default
* by setting {@link setBasePath BasePath} with a different path you prefer.
*
* Page name refers to the file name (without extension) of the page template.
* In order to differentiate from the common control template files, the extension
* name of the page template files must be '.page'. If there is a PHP file with
* the same page name under the same directory as the template file, that file
* will be considered as the page class file and the file name is the page class name.
* If such a file is not found, the page class is assumed as {@link TPage}.
*
* Modules can be configured and loaded in page directory configurations.
* Configuration of a module in a subdirectory will overwrite its parent
* directory's configuration, if both configurations refer to the same module.
*
* By default, TPageService will automatically load two modules:
* - {@link TTemplateManager} : manages page and control templates
* - {@link TThemeManager} : manages themes used in a Prado application
*
* In page directory configurations, static authorization rules can also be specified,
* which governs who and which roles can access particular pages.
* Refer to {@link TAuthorizationRule} for more details about authorization rules.
* Page authorization rules can be configured within an tag in
* each page directory configuration as follows,
*
*
*
*
*
* where the 'pages' attribute may be filled with a sequence of comma-separated
* page IDs. If 'pages' attribute does not appear in a rule, the rule will be
* applied to all pages in this directory and all subdirectories (recursively).
* Application of authorization rules are in a bottom-up fashion, starting from
* the directory containing the requested page up to all parent directories.
* The first matching rule will be used. The last rule always allows all users
* accessing to any resources.
*
* The TPageService replicates the {@link TPage} events through {@link IPageEvents}.
* When the TPage is run, the TPageService events attach to all the corresponding TPage
* events. This allows modules to handle page events.
*
* @author Qiang Xue
* @author Carl G. Mathisen
* @author Brad Anderson
* @version $Id$
* @package System.Web.Services
* @since 3.0
*/
class TPageService extends TService implements IPageEvents
{
/**
* Configuration file name
*/
const CONFIG_FILE_XML='config.xml';
/**
* Configuration file name
*/
const CONFIG_FILE_PHP='config.php';
/**
* Default base path
*/
const DEFAULT_BASEPATH='pages';
/**
* Prefix of ID used for storing parsed configuration in cache
*/
const CONFIG_CACHE_PREFIX='prado:pageservice:';
/**
* Page template file extension
*/
const PAGE_FILE_EXT='.page';
/**
* @var string root path of pages
*/
private $_basePath=null;
/**
* @var string base path class in namespace format
*/
private $_basePageClass='TPage';
/**
* @var string clientscript manager class in namespace format
* @since 3.1.7
*/
private $_clientScriptManagerClass='System.Web.UI.TClientScriptManager';
/**
* @var string default page
*/
private $_defaultPage='Home';
/**
* @var string requested page (path)
*/
private $_pagePath=null;
/**
* @var TPage the requested page
*/
private $_page=null;
/**
* @var array list of initial page property values
*/
private $_properties=array();
/**
* @var boolean whether service is initialized
*/
private $_initialized=false;
/**
* @var TThemeManager theme manager
*/
private $_themeManager=null;
/**
* @var TTemplateManager template manager
*/
private $_templateManager=null;
/**
* @var boolean if the onPageNotFound event is specifically blocked
*/
private $_blockOnPageNotFound = false;
/**
* Initializes the service.
* This method is required by IService interface and is invoked by application.
* @param TXmlElement service configuration
*/
public function init($config)
{
Prado::trace("Initializing TPageService",'System.Web.Services.TPageService');
$pageConfig=$this->loadPageConfig($config);
$this->initPageContext($pageConfig);
$this->_initialized=true;
}
/**
* Initializes page context.
* Page context includes path alias settings, namespace usages,
* parameter initialization, module loadings, page initial properties
* and authorization rules.
* @param TPageConfiguration
*/
protected function initPageContext($pageConfig)
{
$application=$this->getApplication();
foreach($pageConfig->getApplicationConfigurations() as $appConfig)
$application->applyConfiguration($appConfig);
$this->applyConfiguration($pageConfig);
}
/**
* Applies a page configuration.
* @param TPageConfiguration the configuration
*/
protected function applyConfiguration($config)
{
// initial page properties (to be set when page runs)
$this->_properties=array_merge($this->_properties, $config->getProperties());
$this->getApplication()->getAuthorizationRules()->mergeWith($config->getRules());
$pagePath=$this->getRequestedPagePath();
// external configurations
foreach($config->getExternalConfigurations() as $filePath=>$params)
{
list($configPagePath,$condition)=$params;
if($condition!==true)
$condition=$this->evaluateExpression($condition);
if($condition)
{
if(($path=Prado::getPathOfNamespace($filePath,Prado::getApplication()->getConfigurationFileExt()))===null || !is_file($path))
throw new TConfigurationException('pageservice_includefile_invalid',$filePath);
$c=new TPageConfiguration($pagePath);
$c->loadFromFile($path,$configPagePath);
$this->applyConfiguration($c);
}
}
}
/**
* Determines the requested page path.
* @return string page path requested
*/
protected function determineRequestedPagePath()
{
$pagePath=$this->getRequest()->getServiceParameter();
if(empty($pagePath))
$pagePath=$this->getDefaultPage();
return $pagePath;
}
/**
* Collects configuration for a page.
* @param TXmlElement additional configuration specified in the application configuration
* @return TPageConfiguration
*/
protected function loadPageConfig($config)
{
$application=$this->getApplication();
$pagePath=$this->getRequestedPagePath();
if(($cache=$application->getCache())===null)
{
$pageConfig=new TPageConfiguration($pagePath);
if($config!==null)
{
if($application->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
$pageConfig->loadPageConfigurationFromPhp($config,$application->getBasePath(),'');
else
$pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
}
$pageConfig->loadFromFiles($this->getBasePath());
}
else
{
$configCached=true;
$currentTimestamp=array();
$arr=$cache->get(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath);
if(is_array($arr))
{
list($pageConfig,$timestamps)=$arr;
if($application->getMode()!==TApplicationMode::Performance)
{
foreach($timestamps as $fileName=>$timestamp)
{
if($fileName===0) // application config file
{
$appConfigFile=$application->getConfigurationFile();
$currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
if($currentTimestamp[0]>$timestamp || ($timestamp>0 && !$currentTimestamp[0]))
$configCached=false;
}
else
{
$currentTimestamp[$fileName]=@filemtime($fileName);
if($currentTimestamp[$fileName]>$timestamp || ($timestamp>0 && !$currentTimestamp[$fileName]))
$configCached=false;
}
}
}
}
else
{
$configCached=false;
$paths=explode('.',$pagePath);
$configPath=$this->getBasePath();
$fileName = $this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP
? self::CONFIG_FILE_PHP
: self::CONFIG_FILE_XML;
foreach($paths as $path)
{
$configFile=$configPath.DIRECTORY_SEPARATOR.$fileName;
$currentTimestamp[$configFile]=@filemtime($configFile);
$configPath.=DIRECTORY_SEPARATOR.$path;
}
$appConfigFile=$application->getConfigurationFile();
$currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
}
if(!$configCached)
{
$pageConfig=new TPageConfiguration($pagePath);
if($config!==null)
{
if($application->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
$pageConfig->loadPageConfigurationFromPhp($config,$application->getBasePath(),'');
else
$pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
}
$pageConfig->loadFromFiles($this->getBasePath());
$cache->set(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath,array($pageConfig,$currentTimestamp));
}
}
return $pageConfig;
}
/**
* @return TTemplateManager template manager
*/
public function getTemplateManager()
{
if(!$this->_templateManager)
{
$this->_templateManager=new TTemplateManager;
$this->_templateManager->init(null);
}
return $this->_templateManager;
}
/**
* @param TTemplateManager template manager
*/
public function setTemplateManager(TTemplateManager $value)
{
$this->_templateManager=$value;
}
/**
* @return TThemeManager theme manager
*/
public function getThemeManager()
{
if(!$this->_themeManager)
{
$this->_themeManager=new TThemeManager;
$this->_themeManager->init(null);
}
return $this->_themeManager;
}
/**
* @param TThemeManager theme manager
*/
public function setThemeManager(TThemeManager $value)
{
$this->_themeManager=$value;
}
/**
* @return string the requested page path
*/
public function getRequestedPagePath()
{
if($this->_pagePath===null)
{
$this->_pagePath=strtr($this->determineRequestedPagePath(),'/\\','..');
if(empty($this->_pagePath))
throw new THttpException(404,'pageservice_page_required');
}
return $this->_pagePath;
}
/**
* @return TPage the requested page
*/
public function getRequestedPage()
{
return $this->_page;
}
/**
* @return string default page path to be served if no explicit page is request. Defaults to 'Home'.
*/
public function getDefaultPage()
{
return $this->_defaultPage;
}
/**
* @param string default page path to be served if no explicit page is request
* @throws TInvalidOperationException if the page service is initialized
*/
public function setDefaultPage($value)
{
if($this->_initialized)
throw new TInvalidOperationException('pageservice_defaultpage_unchangeable');
else
$this->_defaultPage=$value;
}
/**
* @return string the URL for the default page
*/
public function getDefaultPageUrl()
{
return $this->constructUrl($this->getDefaultPage());
}
/**
* This event is triggered when a 404 in the normal page tree hierarchy is generated
* @param mixed $sender
* @param mixed $param
*/
public function onPageNotFound($sender, $param) {
}
/**
* @return boolean whether the onPageNotFound event is blocked
*/
public function getBlockOnPageNotFoundEvent() { return $this->_blockOnPageNotFound; }
/**
* For security reasons, you may want to turn off the onPageNotFound event. For instance,
* if your website has a "maintenence mode" where the website is offline and want to ensure
* that modules cannot use this event and provide content when they shouldn't be.
* @param boolean whether the onPageNotFound event is blocked
*/
public function setBlockOnPageNotFoundEvent($v) {
$this->_blockOnPageNotFound = TPropertyValue::ensureBoolean($v);
}
/**
* @return string the root directory for storing pages. Defaults to the 'pages' directory under the application base path.
*/
public function getBasePath()
{
if($this->_basePath===null)
{
$basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
throw new TConfigurationException('pageservice_basepath_invalid',$basePath);
}
return $this->_basePath;
}
/**
* @param string root directory (in namespace form) storing pages
* @throws TInvalidOperationException if the service is initialized already or basepath is invalid
*/
public function setBasePath($value)
{
if($this->_initialized)
throw new TInvalidOperationException('pageservice_basepath_unchangeable');
else if(($path=Prado::getPathOfNamespace($value))===null || !is_dir($path))
throw new TConfigurationException('pageservice_basepath_invalid',$value);
$this->_basePath=realpath($path);
}
/**
* Sets the base page class name (in namespace format).
* If a page only has a template file without page class file,
* this base page class will be instantiated.
* @param string class name
*/
public function setBasePageClass($value)
{
$this->_basePageClass=$value;
}
/**
* @return string base page class name in namespace format. Defaults to 'TPage'.
*/
public function getBasePageClass()
{
return $this->_basePageClass;
}
/**
* Sets the clientscript manager class (in namespace format).
* @param string class name
* @since 3.1.7
*/
public function setClientScriptManagerClass($value)
{
$this->_clientScriptManagerClass=$value;
}
/**
* @return string clientscript manager class in namespace format. Defaults to 'System.Web.UI.TClientScriptManager'.
* @since 3.1.7
*/
public function getClientScriptManagerClass()
{
return $this->_clientScriptManagerClass;
}
/**
* Runs the service.
* This will create the requested page, initializes it with the property values
* specified in the configuration, and executes the page.
*/
public function run()
{
Prado::trace("Running page service",'System.Web.Services.TPageService');
$this->_page=$this->createPage($this->getRequestedPagePath());
$this->runPage($this->_page,$this->_properties);
}
/**
* Creates a page instance based on requested page path.
* @param string requested page path
* @param (boolean|null) can specify if this is allowed to call onPageNotFound if no page is found; defaults to true.
* @return TPage the requested page instance
* @throws THttpException if requested page path is invalid
* @throws TConfigurationException if the page class cannot be found
*/
protected function createPage($pagePath, $doOnPageNotFound = true)
{
$path=$this->getBasePath().DIRECTORY_SEPARATOR.strtr($pagePath,'.',DIRECTORY_SEPARATOR);
$hasTemplateFile=is_file($path.self::PAGE_FILE_EXT);
$hasClassFile=is_file($path.Prado::CLASS_FILE_EXT);
if(!$hasTemplateFile && !$hasClassFile) {
$param = new TPageNotFoundEventParameter($pagePath);
if(!$this->BlockOnPageNotFoundEvent && $doOnPageNotFound)
$this->raiseEvent('onPageNotFound', $this, $param);
if(!$param->FoundPage)
throw new THttpException(404,'pageservice_page_unknown',$pagePath);
return $param->FoundPage;
}
if($hasClassFile)
{
$className=basename($path);
if(!class_exists($className,false))
include_once($path.Prado::CLASS_FILE_EXT);
}
else
{
$className=$this->getBasePageClass();
Prado::using($className);
if(($pos=strrpos($className,'.'))!==false)
$className=substr($className,$pos+1);
}
if(!class_exists($className,false) || ($className!=='TPage' && !is_subclass_of($className,'TPage')))
throw new THttpException(404,'pageservice_page_unknown',$pagePath);
$page=new $className;
$page->setPagePath($pagePath);
if($hasTemplateFile)
$page->setTemplate($this->getTemplateManager()->getTemplateByFileName($path.self::PAGE_FILE_EXT));
return $page;
}
/**
* Executes a page.
* @param TPage the page instance to be run
* @param array list of initial page properties
*/
protected function runPage($page,$properties)
{
foreach($properties as $name=>$value)
$page->setSubProperty($name,$value);
$page->OnDataBinding[] = array($this, 'OnDataBinding');
$page->OnPreInit[] = array($this, 'OnPreInit');
$page->OnInit[] = array($this, 'OnInit');
$page->OnInitComplete[] = array($this, 'OnInitComplete');
$page->OnPreLoad[] = array($this, 'OnPreLoad');
$page->OnLoad[] = array($this, 'OnLoad');
$page->OnLoadComplete[] = array($this, 'OnLoadComplete');
$page->OnPreRender[] = array($this, 'OnPreRender');
$page->OnPreRenderComplete[] = array($this, 'OnPreRenderComplete');
$page->OnSaveStateComplete[] = array($this, 'OnSaveStateComplete');
$page->OnUnload[] = array($this, 'OnUnload');
$page->run($this->getResponse()->createHtmlWriter());
}
/**
* Constructs a URL with specified page path and GET parameters.
* @param string page path
* @param array list of GET parameters, null if no GET parameters required
* @param boolean whether to encode the ampersand in URL, defaults to true.
* @param boolean whether to encode the GET parameters (their names and values), defaults to true.
* @return string URL for the page and GET parameters
*/
public function constructUrl($pagePath,$getParams=null,$encodeAmpersand=true,$encodeGetItems=true)
{
return $this->getRequest()->constructUrl($this->getID(),$pagePath,$getParams,$encodeAmpersand,$encodeGetItems);
}
/**
* Raises 'OnDataBinding' event. (inherited from TControl)
*/
public function onDataBinding($param) {
Prado::trace("onDataBinding",'System.Web.Services.TPageService');
$this->raiseEvent('OnDataBinding',$this,$param);
}
/**
* This method is invoked when the control enters 'OnInit' stage. (inherited from TControl)
*/
public function onInit($param) {
Prado::trace("onInit",'System.Web.Services.TPageService');
$this->raiseEvent('OnInit',$this,$param);
}
/**
* Raises OnInitComplete event.
*/
public function onInitComplete($param) {
Prado::trace("onInitComplete",'System.Web.Services.TPageService');
$this->raiseEvent('OnInitComplete',$this,$param);
}
/**
* This method is invoked when the control enters 'OnLoad' stage. (inherited from TControl)
*/
public function onLoad($param) {
Prado::trace("OnLoad",'System.Web.Services.TPageService');
$this->raiseEvent('OnLoad',$this,$param);
}
/**
* Raises OnLoadComplete event.
*/
public function onLoadComplete($param) {
Prado::trace("OnLoadComplete",'System.Web.Services.TPageService');
$this->raiseEvent('OnLoadComplete',$this,$param);
}
/**
* Raises OnPreInit event.
*/
public function onPreInit($param) {
Prado::trace("OnPreInit",'System.Web.Services.TPageService');
$this->raiseEvent('OnPreInit',$this,$param);
}
/**
* Raises OnPreLoad event.
*/
public function onPreLoad($param) {
Prado::trace("OnPreLoad",'System.Web.Services.TPageService');
$this->raiseEvent('OnPreLoad',$this,$param);
}
/**
* This method is invoked when the control enters 'OnPreRender' stage. (inherited from TControl)
*/
public function onPreRender($param) {
Prado::trace("OnPreRender",'System.Web.Services.TPageService');
$this->raiseEvent('OnPreRender',$this,$param);
}
/**
* Raises OnPreRenderComplete event.
*/
public function onPreRenderComplete($param) {
Prado::trace("OnPreRenderComplete",'System.Web.Services.TPageService');
$this->raiseEvent('OnPreRenderComplete',$this,$param);
}
/**
* Raises OnSaveStateComplete event.
*/
public function onSaveStateComplete($param) {
Prado::trace("OnSaveStateComplete",'System.Web.Services.TPageService');
$this->raiseEvent('OnSaveStateComplete',$this,$param);
}
/**
* This method is invoked when the control enters 'OnUnload' stage. (inherited from TControl)
*/
public function onUnload($param) {
Prado::trace("OnUnload",'System.Web.Services.TPageService');
$this->raiseEvent('OnUnload',$this,$param);
}
}
/**
* TPageNotFoundEventParameter class.
* TPageNotFoundEventParameter is the parameter sent when no page is found and the code is allowed to call the onPageNotFound.
*
* @author Brad Anderson
* @version $Id$
* @package System.Web.Services
* @since 3.2a
*/
class TPageNotFoundEventParameter extends TEventParameter {
private $_foundpage;
private $_path;
/**
* Holds the parameters for the Class Behavior Events
* @param string $class this is the class to get the behavior
* @param string $name the name of the behavior
* @param object $behavior this is the behavior to implement the class behavior
*/
public function __construct($path) {
parent::__construct();
$this->_path = $path;
}
/**
* This is the path of the page to be found
* @return string the page path to find
*/
public function getPath() { return $this->_path; }
/**
* the found TPage, if found
* @return string the name to get the behavior
*/
public function getFoundPage() { return $this->_foundpage; }
/**
* This sets the found page
*/
public function setFoundPage($value) { $this->_foundpage = $value; }
}
/**
* TPageConfiguration class
*
* TPageConfiguration represents the configuration for a page.
* The page is specified by a dot-connected path.
* Configurations along this path are merged together to be provided for the page.
*
* @author Qiang Xue
* @version $Id$
* @package System.Web.Services
* @since 3.0
*/
class TPageConfiguration extends TComponent
{
/**
* @var array list of application configurations
*/
private $_appConfigs=array();
/**
* @var array list of page initial property values
*/
private $_properties=array();
/**
* @var TAuthorizationRuleCollection list of authorization rules
*/
private $_rules=array();
/**
* @var array list of included configurations
*/
private $_includes=array();
/**
* @var string the currently request page in the format of Path.To.PageName
*/
private $_pagePath='';
/**
* Constructor.
* @param string the currently request page in the format of Path.To.PageName
*/
public function __construct($pagePath)
{
parent::__construct();
$this->_pagePath=$pagePath;
}
/**
* @return array list of external configuration files. Each element is like $filePath=>$condition
*/
public function getExternalConfigurations()
{
return $this->_includes;
}
/**
* Returns list of page initial property values.
* Each array element represents a single property with the key
* being the property name and the value the initial property value.
* @return array list of page initial property values
*/
public function getProperties()
{
return $this->_properties;
}
/**
* Returns list of authorization rules.
* The authorization rules are aggregated (bottom-up) from configuration files
* along the path to the specified page.
* @return TAuthorizationRuleCollection collection of authorization rules
*/
public function getRules()
{
return $this->_rules;
}
/**
* @return array list of application configurations specified along page path
*/
public function getApplicationConfigurations()
{
return $this->_appConfigs;
}
/**
* Loads configuration for a page specified in a path format.
* @param string root path for pages
*/
public function loadFromFiles($basePath)
{
$paths=explode('.',$this->_pagePath);
$page=array_pop($paths);
$path=$basePath;
$configPagePath='';
$fileName = Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP
? TPageService::CONFIG_FILE_PHP
: TPageService::CONFIG_FILE_XML;
foreach($paths as $p)
{
$this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath);
$path.=DIRECTORY_SEPARATOR.$p;
if($configPagePath==='')
$configPagePath=$p;
else
$configPagePath.='.'.$p;
}
$this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath);
$this->_rules=new TAuthorizationRuleCollection($this->_rules);
}
/**
* Loads a specific config file.
* @param string config file name
* @param string the page path that the config file is associated with. The page path doesn't include the page name.
*/
public function loadFromFile($fname,$configPagePath)
{
Prado::trace("Loading page configuration file $fname",'System.Web.Services.TPageService');
if(empty($fname) || !is_file($fname))
return;
if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
{
$fcontent = include $fname;
$this->loadFromPhp($fcontent,dirname($fname),$configPagePath);
}
else
{
$dom=new TXmlDocument;
if($dom->loadFromFile($fname))
$this->loadFromXml($dom,dirname($fname),$configPagePath);
else
throw new TConfigurationException('pageserviceconf_file_invalid',$fname);
}
}
public function loadFromPhp($config,$configPath,$configPagePath)
{
$this->loadApplicationConfigurationFromPhp($config,$configPath);
$this->loadPageConfigurationFromPhp($config,$configPath,$configPagePath);
}
/**
* Loads a page configuration.
* The configuration includes information for both application
* and page service.
* @param TXmlElement config xml element
* @param string the directory containing this configuration
* @param string the page path that the config XML is associated with. The page path doesn't include the page name.
*/
public function loadFromXml($dom,$configPath,$configPagePath)
{
$this->loadApplicationConfigurationFromXml($dom,$configPath);
$this->loadPageConfigurationFromXml($dom,$configPath,$configPagePath);
}
public function loadApplicationConfigurationFromPhp($config,$configPath)
{
$appConfig=new TApplicationConfiguration;
$appConfig->loadFromPhp($config,$configPath);
$this->_appConfigs[]=$appConfig;
}
/**
* Loads the configuration specific for application part
* @param TXmlElement config xml element
* @param string base path corresponding to this xml element
*/
public function loadApplicationConfigurationFromXml($dom,$configPath)
{
$appConfig=new TApplicationConfiguration;
$appConfig->loadFromXml($dom,$configPath);
$this->_appConfigs[]=$appConfig;
}
public function loadPageConfigurationFromPhp($config, $configPath, $configPagePath)
{
// authorization
if(isset($config['authorization']) && is_array($config['authorization']))
{
$rules = array();
foreach($config['authorization'] as $authorization)
{
$patterns=isset($authorization['pages'])?$authorization['pages']:'';
$ruleApplies=false;
if(empty($patterns) || trim($patterns)==='*') // null or empty string
$ruleApplies=true;
else
{
foreach(explode(',',$patterns) as $pattern)
{
if(($pattern=trim($pattern))!=='')
{
// we know $configPagePath and $this->_pagePath
if($configPagePath!=='') // prepend the pattern with ConfigPagePath
$pattern=$configPagePath.'.'.$pattern;
if(strcasecmp($pattern,$this->_pagePath)===0)
{
$ruleApplies=true;
break;
}
if($pattern[strlen($pattern)-1]==='*') // try wildcard matching
{
if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
{
$ruleApplies=true;
break;
}
}
}
}
}
if($ruleApplies)
{
$action = isset($authorization['action'])?$authorization['action']:'';
$users = isset($authorization['users'])?$authorization['users']:'';
$roles = isset($authorization['roles'])?$authorization['roles']:'';
$verb = isset($authorization['verb'])?$authorization['verb']:'';
$ips = isset($authorization['ips'])?$authorization['ips']:'';
$rules[]=new TAuthorizationRule($action,$users,$roles,$verb,$ips);
}
}
$this->_rules=array_merge($rules,$this->_rules);
}
// pages
if(isset($config['pages']) && is_array($config['pages']))
{
if(isset($config['pages']['properties']))
{
$this->_properties = array_merge($this->_properties, $config['pages']['properties']);
unset($config['pages']['properties']);
}
foreach($config['pages'] as $id => $page)
{
$properties = array();
if(isset($page['properties']))
{
$properties=$page['properties'];
unset($page['properties']);
}
$matching=false;
$id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
if(strcasecmp($id,$this->_pagePath)===0)
$matching=true;
else if($id[strlen($id)-1]==='*') // try wildcard matching
$matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
if($matching)
$this->_properties=array_merge($this->_properties,$properties);
}
}
// external configurations
if(isset($config['includes']) && is_array($config['includes']))
{
foreach($config['includes'] as $include)
{
$when = isset($include['when'])?true:false;
if(!isset($include['file']))
throw new TConfigurationException('pageserviceconf_includefile_required');
$filePath = $include['file'];
if(isset($this->_includes[$filePath]))
$this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
else
$this->_includes[$filePath]=array($configPagePath,$when);
}
}
}
/**
* Loads the configuration specific for page service.
* @param TXmlElement config xml element
* @param string base path corresponding to this xml element
* @param string the page path that the config XML is associated with. The page path doesn't include the page name.
*/
public function loadPageConfigurationFromXml($dom,$configPath,$configPagePath)
{
// authorization
if(($authorizationNode=$dom->getElementByTagName('authorization'))!==null)
{
$rules=array();
foreach($authorizationNode->getElements() as $node)
{
$patterns=$node->getAttribute('pages');
$ruleApplies=false;
if(empty($patterns) || trim($patterns)==='*') // null or empty string
$ruleApplies=true;
else
{
foreach(explode(',',$patterns) as $pattern)
{
if(($pattern=trim($pattern))!=='')
{
// we know $configPagePath and $this->_pagePath
if($configPagePath!=='') // prepend the pattern with ConfigPagePath
$pattern=$configPagePath.'.'.$pattern;
if(strcasecmp($pattern,$this->_pagePath)===0)
{
$ruleApplies=true;
break;
}
if($pattern[strlen($pattern)-1]==='*') // try wildcard matching
{
if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
{
$ruleApplies=true;
break;
}
}
}
}
}
if($ruleApplies)
$rules[]=new TAuthorizationRule($node->getTagName(),$node->getAttribute('users'),$node->getAttribute('roles'),$node->getAttribute('verb'),$node->getAttribute('ips'));
}
$this->_rules=array_merge($rules,$this->_rules);
}
// pages
if(($pagesNode=$dom->getElementByTagName('pages'))!==null)
{
$this->_properties=array_merge($this->_properties,$pagesNode->getAttributes()->toArray());
// at the page folder
foreach($pagesNode->getElementsByTagName('page') as $node)
{
$properties=$node->getAttributes();
$id=$properties->remove('id');
if(empty($id))
throw new TConfigurationException('pageserviceconf_page_invalid',$configPath);
$matching=false;
$id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
if(strcasecmp($id,$this->_pagePath)===0)
$matching=true;
else if($id[strlen($id)-1]==='*') // try wildcard matching
$matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
if($matching)
$this->_properties=array_merge($this->_properties,$properties->toArray());
}
}
// external configurations
foreach($dom->getElementsByTagName('include') as $node)
{
if(($when=$node->getAttribute('when'))===null)
$when=true;
if(($filePath=$node->getAttribute('file'))===null)
throw new TConfigurationException('pageserviceconf_includefile_required');
if(isset($this->_includes[$filePath]))
$this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
else
$this->_includes[$filePath]=array($configPagePath,$when);
}
}
}