From 903ae8a581fac1e6917fc3e31d2ad8fb91df80c3 Mon Sep 17 00:00:00 2001 From: ctrlaltca <> Date: Thu, 12 Jul 2012 11:21:01 +0000 Subject: standardize the use of unix eol; use svn properties to enforce native eol --- framework/Web/Services/TFeedService.php | 374 +++---- framework/Web/Services/TJsonService.php | 426 ++++---- framework/Web/Services/TPageService.php | 1786 +++++++++++++++---------------- 3 files changed, 1293 insertions(+), 1293 deletions(-) (limited to 'framework/Web/Services') diff --git a/framework/Web/Services/TFeedService.php b/framework/Web/Services/TFeedService.php index ab1b9c35..4f757d8f 100644 --- a/framework/Web/Services/TFeedService.php +++ b/framework/Web/Services/TFeedService.php @@ -1,187 +1,187 @@ - - * @author Knut Urdalen - * @link http://www.pradosoft.com - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.Services - */ - -/** - * TFeedService class - * - * TFeedService provides to end-users feed content. - * - * TFeedService manages a set of feeds. The service parameter, referring - * to the ID of the feed, specifies which feed content to be provided to end-users. - * - * To use TFeedService, configure it in application configuration as follows, - * - * - * - * - * - * - * - * where each <feed> element specifies a feed identified by its "id" value (case-sensitive). - * - * PHP configuration style: - * - * array( - * 'feed' => array( - * 'ch1' => array( - * 'class' => 'Path.To.FeedClass1', - * 'properties' => array( - * ... - * ), - * ), - * ) - * - * - * The class attribute indicates which PHP class will provide the actual feed - * content. Note, the class must implement {@link IFeedContentProvider} interface. - * Other initial properties for the feed class may also be specified in the - * corresponding <feed> element. - * - * To retrieve the feed content identified by "ch2", use the URL - * /path/to/index.php?feed=ch2 - * - * @author Qiang Xue - * @author Knut Urdalen - * @author Carl G. Mathisen - * @package System.Web.Services - * @since 3.1 - */ -class TFeedService extends TService -{ - private $_feeds=array(); - - /** - * Initializes this module. - * This method is required by the IModule interface. - * @param mixed configuration for this module, can be null - */ - public function init($config) - { - if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP) - { - if(is_array($config)) - { - foreach($config as $id => $feed) - $this->_feeds[$id] = $feed; - } - } - else - { - foreach($config->getElementsByTagName('feed') as $feed) - { - if(($id=$feed->getAttributes()->remove('id'))!==null) - $this->_feeds[$id]=$feed; - else - throw new TConfigurationException('feedservice_id_required'); - } - } - } - - /** - * @return string the requested feed path - */ - protected function determineRequestedFeedPath() - { - return $this->getRequest()->getServiceParameter(); - } - - /** - * Runs the service. - * This method is invoked by application automatically. - */ - public function run() - { - $id=$this->getRequest()->getServiceParameter(); - if(isset($this->_feeds[$id])) - { - $feedConfig=$this->_feeds[$id]; - $properties = array(); - $feed = null; - if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP) - { - if(isset($feedConfig['class'])) - { - $feed=Prado::createComponent($feedConfig['class']); - if($service instanceof IFeedContentProvider) - $properties=isset($feedConfig['properties'])?$feedConfig['properties']:array(); - else - throw new TConfigurationException('jsonservice_response_type_invalid',$id); - } - else - throw new TConfigurationException('jsonservice_class_required',$id); - } - else - { - $properties=$feedConfig->getAttributes(); - if(($class=$properties->remove('class'))!==null) - { - $feed=Prado::createComponent($class); - if(!($feed instanceof IFeedContentProvider)) - throw new TConfigurationException('feedservice_feedtype_invalid',$id); - } - else - throw new TConfigurationException('feedservice_class_required',$id); - } - - // init feed properties - foreach($properties as $name=>$value) - $feed->setSubproperty($name,$value); - $feed->init($feedConfig); - - $content=$feed->getFeedContent(); - //$this->getResponse()->setContentType('application/rss+xml'); - $this->getResponse()->setContentType($feed->getContentType()); - $this->getResponse()->write($content); - } - else - throw new THttpException(404,'feedservice_feed_unknown',$id); - } -} - -/** - * IFeedContentProvider interface. - * - * IFeedContentProvider interface must be implemented by a feed class who - * provides feed content. - * - * @author Qiang Xue - * @author Knut Urdalen - * @package System.Web.Services - * @since 3.1 - */ -interface IFeedContentProvider -{ - /** - * Initializes the feed content provider. - * This method is invoked (before {@link getFeedContent}) - * when the feed provider is requested by a user. - * @param TXmlElement configurations specified within the <feed> element - * corresponding to this feed provider when configuring {@link TFeedService}. - */ - public function init($config); - /** - * @return string feed content in proper XML format - */ - public function getFeedContent(); - /** - * Sets the content type of the feed content to be sent. - * Some examples are: - * RSS 1.0 feed: application/rdf+xml - * RSS 2.0 feed: application/rss+xml or application/xml or text/xml - * ATOM feed: application/atom+xml - * @return string the content type for the feed content. - * @since 3.1.1 - */ - public function getContentType(); -} - + + * @author Knut Urdalen + * @link http://www.pradosoft.com + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.Services + */ + +/** + * TFeedService class + * + * TFeedService provides to end-users feed content. + * + * TFeedService manages a set of feeds. The service parameter, referring + * to the ID of the feed, specifies which feed content to be provided to end-users. + * + * To use TFeedService, configure it in application configuration as follows, + * + * + * + * + * + * + * + * where each <feed> element specifies a feed identified by its "id" value (case-sensitive). + * + * PHP configuration style: + * + * array( + * 'feed' => array( + * 'ch1' => array( + * 'class' => 'Path.To.FeedClass1', + * 'properties' => array( + * ... + * ), + * ), + * ) + * + * + * The class attribute indicates which PHP class will provide the actual feed + * content. Note, the class must implement {@link IFeedContentProvider} interface. + * Other initial properties for the feed class may also be specified in the + * corresponding <feed> element. + * + * To retrieve the feed content identified by "ch2", use the URL + * /path/to/index.php?feed=ch2 + * + * @author Qiang Xue + * @author Knut Urdalen + * @author Carl G. Mathisen + * @package System.Web.Services + * @since 3.1 + */ +class TFeedService extends TService +{ + private $_feeds=array(); + + /** + * Initializes this module. + * This method is required by the IModule interface. + * @param mixed configuration for this module, can be null + */ + public function init($config) + { + if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP) + { + if(is_array($config)) + { + foreach($config as $id => $feed) + $this->_feeds[$id] = $feed; + } + } + else + { + foreach($config->getElementsByTagName('feed') as $feed) + { + if(($id=$feed->getAttributes()->remove('id'))!==null) + $this->_feeds[$id]=$feed; + else + throw new TConfigurationException('feedservice_id_required'); + } + } + } + + /** + * @return string the requested feed path + */ + protected function determineRequestedFeedPath() + { + return $this->getRequest()->getServiceParameter(); + } + + /** + * Runs the service. + * This method is invoked by application automatically. + */ + public function run() + { + $id=$this->getRequest()->getServiceParameter(); + if(isset($this->_feeds[$id])) + { + $feedConfig=$this->_feeds[$id]; + $properties = array(); + $feed = null; + if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP) + { + if(isset($feedConfig['class'])) + { + $feed=Prado::createComponent($feedConfig['class']); + if($service instanceof IFeedContentProvider) + $properties=isset($feedConfig['properties'])?$feedConfig['properties']:array(); + else + throw new TConfigurationException('jsonservice_response_type_invalid',$id); + } + else + throw new TConfigurationException('jsonservice_class_required',$id); + } + else + { + $properties=$feedConfig->getAttributes(); + if(($class=$properties->remove('class'))!==null) + { + $feed=Prado::createComponent($class); + if(!($feed instanceof IFeedContentProvider)) + throw new TConfigurationException('feedservice_feedtype_invalid',$id); + } + else + throw new TConfigurationException('feedservice_class_required',$id); + } + + // init feed properties + foreach($properties as $name=>$value) + $feed->setSubproperty($name,$value); + $feed->init($feedConfig); + + $content=$feed->getFeedContent(); + //$this->getResponse()->setContentType('application/rss+xml'); + $this->getResponse()->setContentType($feed->getContentType()); + $this->getResponse()->write($content); + } + else + throw new THttpException(404,'feedservice_feed_unknown',$id); + } +} + +/** + * IFeedContentProvider interface. + * + * IFeedContentProvider interface must be implemented by a feed class who + * provides feed content. + * + * @author Qiang Xue + * @author Knut Urdalen + * @package System.Web.Services + * @since 3.1 + */ +interface IFeedContentProvider +{ + /** + * Initializes the feed content provider. + * This method is invoked (before {@link getFeedContent}) + * when the feed provider is requested by a user. + * @param TXmlElement configurations specified within the <feed> element + * corresponding to this feed provider when configuring {@link TFeedService}. + */ + public function init($config); + /** + * @return string feed content in proper XML format + */ + public function getFeedContent(); + /** + * Sets the content type of the feed content to be sent. + * Some examples are: + * RSS 1.0 feed: application/rdf+xml + * RSS 2.0 feed: application/rss+xml or application/xml or text/xml + * ATOM feed: application/atom+xml + * @return string the content type for the feed content. + * @since 3.1.1 + */ + public function getContentType(); +} + diff --git a/framework/Web/Services/TJsonService.php b/framework/Web/Services/TJsonService.php index 13710101..b4e87e27 100644 --- a/framework/Web/Services/TJsonService.php +++ b/framework/Web/Services/TJsonService.php @@ -1,213 +1,213 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.Services - */ - -/** - * TJsonService class provides to end-users javascript content response in - * JSON format. - * - * TJsonService manages a set of {@link TJsonResponse}, each - * representing specific response with javascript content. - * The service parameter, referring to the ID of the service, specifies - * which javascript content to be provided to end-users. - * - * To use TJsonService, configure it in application configuration as follows, - * - * - * - * - * - * - * where each JSON response is specified via a <json> element. - * Initial property values can be configured in a <json> element. - * - * - * PHP configuration style: - * - * 'services' => array( - * 'get_article' => array( - * 'class' => 'Path.To.JsonResponseClass1', - * 'properties' => array( - * ... - * ) - * ) - * ) - * - * - * To retrieve the JSON content provided by "get_article", use the URL - * index.php?json=get_article - * - * @author Wei Zhuo - * @author Carl G. Mathisen - * @version $Id$ - * @package System.Web.Services - * @since 3.1 - */ -class TJsonService extends TService -{ - /** - * @var array registered services - */ - private $_services=array(); - - /** - * Initializes this module. - * This method is required by the IModule interface. - * @param mixed configuration for this module, can be null - */ - public function init($xml) - { - $this->loadJsonServices($xml); - } - - /** - * Load the service definitions. - * @param mixed configuration for this module, can be null - */ - protected function loadJsonServices($config) - { - if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP) - { - if(is_array($config)) - { - foreach($config['json'] as $id => $json) - $this->_services[$id] = $json; - } - } - else - { - foreach($config->getElementsByTagName('json') as $json) - { - if(($id=$json->getAttribute('id'))!==null) - $this->_services[$id]=$json; - else - throw new TConfigurationException('jsonservice_id_required'); - } - } - } - - /** - * Runs the service. - * This method is invoked by application automatically. - */ - public function run() - { - $id=$this->getRequest()->getServiceParameter(); - if(isset($this->_services[$id])) - { - $serviceConfig=$this->_services[$id]; - if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP) - { - if(isset($serviceConfig['class'])) - { - $service=Prado::createComponent($serviceConfig['class']); - if($service instanceof TJsonResponse) - { - $properties = isset($serviceConfig['properties'])?$serviceConfig['properties']:array(); - $this->createJsonResponse($service,$properties,$serviceConfig); - } - else - throw new TConfigurationException('jsonservice_response_type_invalid',$id); - } - else - throw new TConfigurationException('jsonservice_class_required',$id); - } - else - { - $properties=$serviceConfig->getAttributes(); - if(($class=$properties->remove('class'))!==null) - { - $service=Prado::createComponent($class); - if($service instanceof TJsonResponse) - $this->createJsonResponse($service,$properties,$serviceConfig); - else - throw new TConfigurationException('jsonservice_response_type_invalid',$id); - } - else - throw new TConfigurationException('jsonservice_class_required',$id); - } - } - else - throw new THttpException(404,'jsonservice_provider_unknown',$id); - } - - /** - * Renders content provided by TJsonResponse::getJsonContent() as - * javascript in JSON format. - */ - protected function createJsonResponse($service,$properties,$config) - { - // init service properties - foreach($properties as $name=>$value) - $service->setSubproperty($name,$value); - $service->init($config); - - //send content if not null - if(($content=$service->getJsonContent())!==null) - { - $response = $this->getResponse(); - $response->setContentType('text/javascript'); - $response->setCharset('UTF-8'); - //send content - $response->write(TJavaScript::jsonEncode($content)); - } - } -} - -/** - * TJsonResponse Class - * - * TJsonResponse is the base class for all JSON response provider classes. - * - * Derived classes must implement {@link getJsonContent()} to return - * an object or literals to be converted to JSON format. The response - * will be empty if the returned content is null. - * - * @author Wei Zhuo - * @version $Id$ - * @package System.Web.Services - * @since 3.1 - */ -abstract class TJsonResponse extends TApplicationComponent -{ - private $_id=''; - - /** - * Initializes the feed. - * @param TXmlElement configurations specified in {@link TJsonService}. - */ - public function init($config) - { - } - - /** - * @return string ID of this response - */ - public function getID() - { - return $this->_id; - } - - /** - * @param string ID of this response - */ - public function setID($value) - { - $this->_id=$value; - } - - /** - * @return object json response content, null to suppress output. - */ - abstract public function getJsonContent(); -} - -?> + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.Services + */ + +/** + * TJsonService class provides to end-users javascript content response in + * JSON format. + * + * TJsonService manages a set of {@link TJsonResponse}, each + * representing specific response with javascript content. + * The service parameter, referring to the ID of the service, specifies + * which javascript content to be provided to end-users. + * + * To use TJsonService, configure it in application configuration as follows, + * + * + * + * + * + * + * where each JSON response is specified via a <json> element. + * Initial property values can be configured in a <json> element. + * + * + * PHP configuration style: + * + * 'services' => array( + * 'get_article' => array( + * 'class' => 'Path.To.JsonResponseClass1', + * 'properties' => array( + * ... + * ) + * ) + * ) + * + * + * To retrieve the JSON content provided by "get_article", use the URL + * index.php?json=get_article + * + * @author Wei Zhuo + * @author Carl G. Mathisen + * @version $Id$ + * @package System.Web.Services + * @since 3.1 + */ +class TJsonService extends TService +{ + /** + * @var array registered services + */ + private $_services=array(); + + /** + * Initializes this module. + * This method is required by the IModule interface. + * @param mixed configuration for this module, can be null + */ + public function init($xml) + { + $this->loadJsonServices($xml); + } + + /** + * Load the service definitions. + * @param mixed configuration for this module, can be null + */ + protected function loadJsonServices($config) + { + if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP) + { + if(is_array($config)) + { + foreach($config['json'] as $id => $json) + $this->_services[$id] = $json; + } + } + else + { + foreach($config->getElementsByTagName('json') as $json) + { + if(($id=$json->getAttribute('id'))!==null) + $this->_services[$id]=$json; + else + throw new TConfigurationException('jsonservice_id_required'); + } + } + } + + /** + * Runs the service. + * This method is invoked by application automatically. + */ + public function run() + { + $id=$this->getRequest()->getServiceParameter(); + if(isset($this->_services[$id])) + { + $serviceConfig=$this->_services[$id]; + if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP) + { + if(isset($serviceConfig['class'])) + { + $service=Prado::createComponent($serviceConfig['class']); + if($service instanceof TJsonResponse) + { + $properties = isset($serviceConfig['properties'])?$serviceConfig['properties']:array(); + $this->createJsonResponse($service,$properties,$serviceConfig); + } + else + throw new TConfigurationException('jsonservice_response_type_invalid',$id); + } + else + throw new TConfigurationException('jsonservice_class_required',$id); + } + else + { + $properties=$serviceConfig->getAttributes(); + if(($class=$properties->remove('class'))!==null) + { + $service=Prado::createComponent($class); + if($service instanceof TJsonResponse) + $this->createJsonResponse($service,$properties,$serviceConfig); + else + throw new TConfigurationException('jsonservice_response_type_invalid',$id); + } + else + throw new TConfigurationException('jsonservice_class_required',$id); + } + } + else + throw new THttpException(404,'jsonservice_provider_unknown',$id); + } + + /** + * Renders content provided by TJsonResponse::getJsonContent() as + * javascript in JSON format. + */ + protected function createJsonResponse($service,$properties,$config) + { + // init service properties + foreach($properties as $name=>$value) + $service->setSubproperty($name,$value); + $service->init($config); + + //send content if not null + if(($content=$service->getJsonContent())!==null) + { + $response = $this->getResponse(); + $response->setContentType('text/javascript'); + $response->setCharset('UTF-8'); + //send content + $response->write(TJavaScript::jsonEncode($content)); + } + } +} + +/** + * TJsonResponse Class + * + * TJsonResponse is the base class for all JSON response provider classes. + * + * Derived classes must implement {@link getJsonContent()} to return + * an object or literals to be converted to JSON format. The response + * will be empty if the returned content is null. + * + * @author Wei Zhuo + * @version $Id$ + * @package System.Web.Services + * @since 3.1 + */ +abstract class TJsonResponse extends TApplicationComponent +{ + private $_id=''; + + /** + * Initializes the feed. + * @param TXmlElement configurations specified in {@link TJsonService}. + */ + public function init($config) + { + } + + /** + * @return string ID of this response + */ + public function getID() + { + return $this->_id; + } + + /** + * @param string ID of this response + */ + public function setID($value) + { + $this->_id=$value; + } + + /** + * @return object json response content, null to suppress output. + */ + abstract public function getJsonContent(); +} + +?> diff --git a/framework/Web/Services/TPageService.php b/framework/Web/Services/TPageService.php index 4576a080..2d74f2a1 100644 --- a/framework/Web/Services/TPageService.php +++ b/framework/Web/Services/TPageService.php @@ -1,893 +1,893 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 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. - * - * @author Qiang Xue - * @author Carl G. Mathisen - * @version $Id$ - * @package System.Web.Services - * @since 3.0 - */ -class TPageService extends TService -{ - /** - * 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'; - /** - * Fallback base path - used to be the default up to Prado < 3.2 - */ - const FALLBACK_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; - - /** - * 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()); - } - - /** - * @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)) - { - $basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::FALLBACK_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 - * @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) - { - $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) - throw new THttpException(404,'pageservice_page_unknown',$pagePath); - - 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->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); - } -} - - -/** - * 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) - { - $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); - } - } -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 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. + * + * @author Qiang Xue + * @author Carl G. Mathisen + * @version $Id$ + * @package System.Web.Services + * @since 3.0 + */ +class TPageService extends TService +{ + /** + * 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'; + /** + * Fallback base path - used to be the default up to Prado < 3.2 + */ + const FALLBACK_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; + + /** + * 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()); + } + + /** + * @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)) + { + $basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::FALLBACK_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 + * @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) + { + $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) + throw new THttpException(404,'pageservice_page_unknown',$pagePath); + + 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->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); + } +} + + +/** + * 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) + { + $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); + } + } +} + -- cgit v1.2.3