summaryrefslogtreecommitdiff
path: root/framework/Web/UI/TThemeManager.php
diff options
context:
space:
mode:
Diffstat (limited to 'framework/Web/UI/TThemeManager.php')
-rw-r--r--framework/Web/UI/TThemeManager.php150
1 files changed, 121 insertions, 29 deletions
diff --git a/framework/Web/UI/TThemeManager.php b/framework/Web/UI/TThemeManager.php
index b2b205ed..5d7319e8 100644
--- a/framework/Web/UI/TThemeManager.php
+++ b/framework/Web/UI/TThemeManager.php
@@ -15,9 +15,21 @@
*
* TThemeManager manages the themes used in a Prado application.
*
- * Themes are stored in under {@link setBasePath BasePath} that can be accessed
- * via URL {@link setBaseUrl BaseUrl}. Each theme is defined by a subdirectory
- * and all the files under that directory.
+ * Themes are stored under the directory specified by the
+ * {@link setBasePath BasePath} property. The themes can be accessed
+ * via URL {@link setBaseUrl BaseUrl}. Each theme is represented by a subdirectory
+ * and all the files under that directory. The name of a theme is the name
+ * of the corresponding subdirectory.
+ * By default, the base path of all themes is a directory named "themes"
+ * under the directory containing the application entry script.
+ * To get a theme (normally you do not need to), call {@link getTheme}.
+ *
+ * TThemeManager may be configured within page service tag in application
+ * configuration file as follows,
+ * <module id="themes" type="System.Web.UI.TThemeManager"
+ * BasePath="Application.themes" BaseUrl="/themes" />
+ * where {@link getCacheExpire CacheExpire}, {@link getCacheControl CacheControl}
+ * and {@link getBufferOutput BufferOutput} are configurable properties of THttpResponse.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Revision: $ $Date: $
@@ -26,7 +38,9 @@
*/
class TThemeManager extends TComponent implements IModule
{
- const THEME_CACHE_PREFIX='prado:theme:';
+ /**
+ * default themes base path
+ */
const DEFAULT_BASEPATH='themes';
/**
* @var string module ID
@@ -40,6 +54,9 @@ class TThemeManager extends TComponent implements IModule
* @var string the directory containing all themes
*/
private $_basePath=null;
+ /**
+ * @var string the base URL for all themes
+ */
private $_baseUrl=null;
/**
* @var TApplication application
@@ -55,11 +72,6 @@ class TThemeManager extends TComponent implements IModule
public function init($application,$config)
{
$this->_application=$application;
- if($this->_basePath===null)
- $this->_basePath=dirname($application->getRequest()->getPhysicalApplicationPath()).'/'.self::DEFAULT_BASEPATH;
- if(($basePath=realpath($this->_basePath))===false || !is_dir($basePath))
- throw new TConfigurationException('thememanager_basepath_invalid',$this->_basePath);
- $this->_basePath=$basePath;
$this->_initialized=true;
$application->getService()->setThemeManager($this);
}
@@ -80,30 +92,38 @@ class TThemeManager extends TComponent implements IModule
$this->_id=$value;
}
+ /**
+ * @param string name of the theme to be retrieved
+ * @return TTheme the theme retrieved
+ */
public function getTheme($name)
{
- if(($themePath=realpath($this->_basePath.'/'.$name))===false || !is_dir($themePath))
- throw new TConfigurationException('thememanager_theme_inexistent',$name);
-
- if($this->_baseUrl===null)
- {
- $appPath=dirname(Prado::getApplication()->getRequest()->getPhysicalApplicationPath());
- if(strpos($themePath,$appPath)===false)
- throw new TConfigurationException('theme_baseurl_required');
- $appUrl=dirname(Prado::getApplication()->getRequest()->getApplicationPath());
- $themeUrl=$appUrl.'/'.strtr(substr($themePath,strlen($appPath)),'\\','/');
- }
- else
- $themeUrl=$this->_baseUrl.'/'.basename($themePath);
+ $themePath=$this->getBasePath().'/'.$name;
+ $themeUrl=$this->getBaseUrl().'/'.$name;
return new TTheme($this->_application,$themePath,$themeUrl);
}
+ /**
+ * @return string the base path for all themes. It is returned as an absolute path.
+ * @throws TConfigurationException if base path is not set and "themes" directory does not exist.
+ */
public function getBasePath()
{
+ if($this->_basePath===null)
+ {
+ $this->_basePath=dirname($this->_application->getRequest()->getPhysicalApplicationPath()).'/'.self::DEFAULT_BASEPATH;
+ if(($basePath=realpath($this->_basePath))===false || !is_dir($basePath))
+ throw new TConfigurationException('thememanager_basepath_invalid',$this->_basePath);
+ $this->_basePath=$basePath;
+ }
return $this->_basePath;
}
+ /**
+ * @param string the base path for all themes. It must be in the format of a namespace.
+ * @throws TInvalidDataValueException if the base path is not a proper namespace.
+ */
public function setBasePath($value)
{
if($this->_initialized)
@@ -117,25 +137,89 @@ class TThemeManager extends TComponent implements IModule
}
}
+ /**
+ * @return string the base URL for all themes.
+ * @throws TConfigurationException If base URL is not set and a correct one cannot be determined by Prado.
+ */
public function getBaseUrl()
{
+ if($this->_baseUrl===null)
+ {
+ $appPath=dirname($this->_application->getRequest()->getPhysicalApplicationPath());
+ $basePath=$this->getBasePath();
+ if(strpos($basePath,$appPath)===false)
+ throw new TConfigurationException('thememanager_baseurl_required');
+ $appUrl=dirname($this->_application->getRequest()->getApplicationPath());
+ $this->_baseUrl=$appUrl.'/'.strtr(substr($basePath,strlen($appPath)),'\\','/');
+ }
return $this->_baseUrl;
}
+ /**
+ * @param string the base URL for all themes.
+ */
public function setBaseUrl($value)
{
- $this->_baseUrl=$value;
+ $this->_baseUrl=rtrim($value,'/');
}
}
+/**
+ * TTheme class
+ *
+ * TTheme represents a particular theme. It is merely a collection of skins
+ * that are applicable to the corresponding controls.
+ *
+ * Each theme is stored as a directory and files under that directory.
+ * The theme name is the directory name. When TTheme is created, the files
+ * whose name has the extension ".skin" are parsed and saved as controls skins.
+ *
+ * A skin is essentially a list of initial property values that are to be applied
+ * to a control when the skin is applied.
+ * Each type of control can have multiple skins identified by the SkinID.
+ * If a skin does not have SkinID, it is the default skin that will be applied
+ * to controls that do not specify particular SkinID.
+ *
+ * Whenever possible, TTheme will try to make use of available cache to save
+ * the parsing time.
+ *
+ * To apply a theme to a particular control, call {@link applySkin}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Revision: $ $Date: $
+ * @package System.Web.UI
+ * @since 3.0
+ */
class TTheme extends TComponent
{
+ /**
+ * prefix for cache variable name used to store parsed themes
+ */
const THEME_CACHE_PREFIX='prado:theme:';
+ /**
+ * Extension name of skin files
+ */
const SKIN_FILE_EXT='.skin';
+ /**
+ * @var string theme path
+ */
private $_themePath;
+ /**
+ * @var string theme url
+ */
private $_themeUrl;
+ /**
+ * @var array list of skins for the theme
+ */
private $_skins=null;
+ /**
+ * Constructor.
+ * @param TApplication application instance
+ * @param string theme path
+ * @param string theme URL
+ * @throws TConfigurationException if theme path does not exist or any parsing error of the skin files
+ */
public function __construct($application,$themePath,$themeUrl)
{
$this->_themeUrl=$themeUrl;
@@ -176,18 +260,18 @@ class TTheme extends TComponent
foreach($template->getItems() as $skin)
{
if($skin[0]!==-1)
- throw new TConfigurationException('theme_control_nested',$skin[1]);
+ throw new TConfigurationException('theme_control_nested',$skin[1],dirname($themePath));
else if(!isset($skin[2])) // a text string, ignored
continue;
$type=$skin[1];
$id=isset($skin[2]['skinid'])?$skin[2]['skinid']:0;
unset($skin[2]['skinid']);
if(isset($this->_skins[$type][$id]))
- throw new TConfigurationException('theme_skinid_duplicated',$type,$id);
+ throw new TConfigurationException('theme_skinid_duplicated',$type,$id,dirname($themePath));
foreach($skin[2] as $name=>$value)
{
if(is_array($value) && $value[0]===0)
- throw new TConfigurationException('theme_databind_forbidden',$type,$id,$name);
+ throw new TConfigurationException('theme_databind_forbidden',dirname($themePath),$type,$id);
}
$this->_skins[$type][$id]=$skin[2];
}
@@ -199,6 +283,15 @@ class TTheme extends TComponent
}
}
+ /**
+ * Applies the theme to a particular control.
+ * The control's class name and SkinID value will be used to
+ * identify which skin to be applied. If the control's SkinID is empty,
+ * the default skin will be applied.
+ * @param TControl the control to be applied with a skin
+ * @return boolean if a skin is successfully applied
+ * @throws TConfigurationException if any error happened during the skin application
+ */
public function applySkin($control)
{
$type=get_class($control);
@@ -225,12 +318,12 @@ class TTheme extends TComponent
$control->$setter($value);
}
else
- throw new TConfigurationException('theme_property_readonly',get_class($control),$name);
+ throw new TConfigurationException('theme_property_readonly',$type,$name);
}
else if($control->getAllowCustomAttributes())
$control->getAttributes()->add($name,$value);
else
- throw new TConfigurationException('theme_property_undefined',get_class($control),$name);
+ throw new TConfigurationException('theme_property_undefined',$type,$name);
}
else // complex property
$control->setSubProperty($name,$value);
@@ -242,5 +335,4 @@ class TTheme extends TComponent
}
}
-
?> \ No newline at end of file