summaryrefslogtreecommitdiff
path: root/framework
diff options
context:
space:
mode:
authorxue <>2006-04-15 14:21:40 +0000
committerxue <>2006-04-15 14:21:40 +0000
commitb07499534b6d0ed57a2b80c4d95354ca3791c236 (patch)
tree29bfeefb0b543abee915dd4051652dabb413005a /framework
parent0f380cd025dd9530b8faee7061d1957c5fd6cd9c (diff)
Breaking change! Changed context of the expressions in template to the template control. Evaluations of <%= %> are now all in PreRender stage.
Diffstat (limited to 'framework')
-rw-r--r--framework/Exceptions/messages.txt2
-rw-r--r--framework/Web/UI/TControl.php143
-rw-r--r--framework/Web/UI/TTemplateManager.php104
3 files changed, 152 insertions, 97 deletions
diff --git a/framework/Exceptions/messages.txt b/framework/Exceptions/messages.txt
index dd680098..e11d4261 100644
--- a/framework/Exceptions/messages.txt
+++ b/framework/Exceptions/messages.txt
@@ -110,7 +110,7 @@ template_property_unknown = {0} has no property called '{1}'.
template_event_unknown = {0} has no event called '{1}'.
template_property_readonly = {0} has a read-only property '{1}'.
template_event_forbidden = {0} is a non-control component. No handler can be attached to its event '{1}' in a template.
-template_databind_forbidden = {0} is a non-control component. No databinding expression can be set to its property '{1}'.
+template_databind_forbidden = {0} is a non-control component. Expressions cannot be bound to its property '{1}'.
template_component_required = '{0}' is not a component. Only components can appear in a template.
template_format_invalid = Error in {0} (line {1}) : {2}
template_format_invalid2 = Error at line {0} of the following template: {1} {2}
diff --git a/framework/Web/UI/TControl.php b/framework/Web/UI/TControl.php
index 7b22760f..2a3a6a30 100644
--- a/framework/Web/UI/TControl.php
+++ b/framework/Web/UI/TControl.php
@@ -122,6 +122,7 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable
const RF_CONTROLSTATE=7; // controlstate
const RF_NAMED_OBJECTS=8; // controls declared with ID on template
const RF_ADAPTER=9; // adapter
+ const RF_AUTO_BINDINGS=10; // auto data bindings
/**
* @var string control ID
@@ -721,7 +722,7 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable
/**
* Sets up the binding between a property (or property path) and an expression.
- * The context of the expression is the control itself.
+ * The context of the expression is the template control (or the control itself if it is a page).
* @param string the property name, or property path
* @param string the expression
*/
@@ -740,6 +741,19 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable
}
/**
+ * Sets up the binding between a property (or property path) and an expression.
+ * Unlike regular databinding, the expression bound by this method
+ * is automatically evaluated during {@link prerenderRecursive()}.
+ * The context of the expression is the template control (or the control itself if it is a page).
+ * @param string the property name, or property path
+ * @param string the expression
+ */
+ public function autoBindProperty($name,$expression)
+ {
+ $this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
+ }
+
+ /**
* Performs the databinding for this control.
*/
public function dataBind()
@@ -759,8 +773,24 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable
{
if(isset($this->_rf[self::RF_DATA_BINDINGS]))
{
+ if(($context=$this->getTemplateControl())===null)
+ $context=$this;
foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
- $this->setSubProperty($property,$this->evaluateExpression($expression));
+ $this->setSubProperty($property,$context->evaluateExpression($expression));
+ }
+ }
+
+ /**
+ * Auto databinding properties of the control.
+ */
+ protected function autoDataBindProperties()
+ {
+ if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
+ {
+ if(($context=$this->getTemplateControl())===null)
+ $context=$this;
+ foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
+ $this->setSubProperty($property,$context->evaluateExpression($expression));
}
}
@@ -1157,6 +1187,8 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable
{
if($this->_stage<self::CS_LOADED)
{
+ if(($context=$this->getTemplateControl())===null)
+ $context=$this;
if(isset($this->_rf[self::RF_ADAPTER]))
$this->_rf[self::RF_ADAPTER]->onLoad(null);
else
@@ -1165,8 +1197,10 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable
if($this->getHasControls())
{
foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
if($control instanceof TControl)
$control->loadRecursive();
+ }
}
if($this->_stage<self::CS_LOADED)
$this->_stage=self::CS_LOADED;
@@ -1178,6 +1212,8 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable
*/
protected function preRenderRecursive()
{
+ $this->autoDataBindProperties();
+
if($this->getVisible(false))
{
$this->ensureChildControls();
@@ -1188,8 +1224,12 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable
if($this->getHasControls())
{
foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
if($control instanceof TControl)
$control->preRenderRecursive();
+ else if($control instanceof TCompositeLiteral)
+ $control->evaluateDynamicContent();
+ }
}
}
$this->_stage=self::CS_PRERENDERED;
@@ -2016,4 +2056,103 @@ class TCommandEventParameter extends TEventParameter
}
}
+
+/**
+ * TCompositeLiteral class
+ *
+ * TCompositeLiteral is used internally by {@link TTemplate} for representing
+ * consecutive static strings, expressions and statements.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Revision: $ $Date: $
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TCompositeLiteral extends TComponent implements IRenderable, IBindable
+{
+ const TYPE_EXPRESSION=0;
+ const TYPE_STATEMENTS=1;
+ const TYPE_DATABINDING=2;
+ private $_container=null;
+ private $_items=array();
+ private $_expressions=array();
+ private $_statements=array();
+ private $_bindings=array();
+
+ /**
+ * Constructor.
+ * @param array list of items to be represented by TCompositeLiteral
+ */
+ public function __construct($items)
+ {
+ $this->_items=array();
+ $this->_expressions=array();
+ $this->_statements=array();
+ foreach($items as $id=>$item)
+ {
+ if(is_array($item))
+ {
+ if($item[0]===self::TYPE_EXPRESSION)
+ $this->_expressions[$id]=$item[1];
+ else if($item[0]===self::TYPE_STATEMENTS)
+ $this->_statements[$id]=$item[1];
+ else if($item[0]===self::TYPE_DATABINDING)
+ $this->_bindings[$id]=$item[1];
+ $this->_items[$id]='';
+ }
+ else
+ $this->_items[$id]=$item;
+ }
+ }
+
+ /**
+ * @return TComponent container of this component. It serves as the evaluation context of expressions and statements.
+ */
+ public function getContainer()
+ {
+ return $this->_container;
+ }
+
+ /**
+ * @param TComponent container of this component. It serves as the evaluation context of expressions and statements.
+ */
+ public function setContainer(TComponent $value)
+ {
+ $this->_container=$value;
+ }
+
+ /**
+ * Evaluates the expressions and/or statements in the component.
+ */
+ public function evaluateDynamicContent()
+ {
+ $context=$this->_container===null?$this:$this->_container;
+ foreach($this->_expressions as $id=>$expression)
+ $this->_items[$id]=$context->evaluateExpression($expression);
+ foreach($this->_statements as $id=>$statement)
+ $this->_items[$id]=$context->evaluateStatements($statement);
+ }
+
+ /**
+ * Performs databindings.
+ * This method is required by {@link IBindable}
+ */
+ public function dataBind()
+ {
+ $context=$this->_container===null?$this:$this->_container;
+ foreach($this->_bindings as $id=>$binding)
+ $this->_items[$id]=$context->evaluateExpression($binding);
+ }
+
+ /**
+ * Renders the content stored in this component.
+ * This method is required by {@link IRenderable}
+ * @param ITextWriter
+ */
+ public function render($writer)
+ {
+ $writer->write(implode('',$this->_items));
+ }
+}
+
?> \ No newline at end of file
diff --git a/framework/Web/UI/TTemplateManager.php b/framework/Web/UI/TTemplateManager.php
index fa4cbcbf..dd3f7af8 100644
--- a/framework/Web/UI/TTemplateManager.php
+++ b/framework/Web/UI/TTemplateManager.php
@@ -312,6 +312,7 @@ class TTemplate extends TApplicationComponent implements ITemplate
{
if($object[1] instanceof TCompositeLiteral)
{
+ // need to clone a new object because the one in template is reused
$o=clone $object[1];
$o->setContainer($tplControl);
$parent->addParsedObject($o);
@@ -374,7 +375,6 @@ class TTemplate extends TApplicationComponent implements ITemplate
*/
protected function configureProperty($component,$name,$value)
{
- $setter='set'.$name;
if(is_array($value))
{
switch($value[0])
@@ -383,19 +383,23 @@ class TTemplate extends TApplicationComponent implements ITemplate
$component->bindProperty($name,$value[1]);
break;
case self::CONFIG_EXPRESSION:
- $component->$setter($component->evaluateExpression($value[1]));
+ $component->autoBindProperty($name,$value[1]);
break;
case self::CONFIG_TEMPLATE:
+ $setter='set'.$name;
$component->$setter($value[1]);
break;
case self::CONFIG_ASSET: // asset URL
+ $setter='set'.$name;
$url=$this->publishFilePath($this->_contextPath.'/'.$value[1]);
$component->$setter($url);
break;
case self::CONFIG_PARAMETER: // application parameter
+ $setter='set'.$name;
$component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
break;
case self::CONFIG_LOCALIZATION:
+ $setter='set'.$name;
$component->$setter(Prado::localize($value[1]));
break;
default: // an error if reaching here
@@ -403,7 +407,10 @@ class TTemplate extends TApplicationComponent implements ITemplate
}
}
else
+ {
+ $setter='set'.$name;
$component->$setter($value);
+ }
}
/**
@@ -794,7 +801,7 @@ class TTemplate extends TApplicationComponent implements ITemplate
{
foreach($attributes as $name=>$att)
{
- if(is_array($att) && $att[0]===self::CONFIG_DATABIND)
+ if(is_array($att) && ($att[0]===self::CONFIG_DATABIND || $att[0]===self::CONFIG_EXPRESSION))
throw new TConfigurationException('template_databind_forbidden',$type,$name);
if(($pos=strpos($name,'.'))!==false)
{
@@ -823,95 +830,4 @@ class TTemplate extends TApplicationComponent implements ITemplate
}
}
-/**
- * TCompositeLiteral class
- *
- * TCompositeLiteral is used internally by {@link TTemplate} for representing
- * consecutive static strings, expressions and statements.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Revision: $ $Date: $
- * @package System.Web.UI
- * @since 3.0
- */
-class TCompositeLiteral extends TComponent implements IRenderable, IBindable
-{
- const TYPE_EXPRESSION=0;
- const TYPE_STATEMENTS=1;
- const TYPE_DATABINDING=2;
- private $_container=null;
- private $_items=array();
- private $_expressions=array();
- private $_statements=array();
- private $_bindings=array();
-
- /**
- * Constructor.
- * @param array list of items to be represented by TCompositeLiteral
- */
- public function __construct($items)
- {
- $this->_items=array();
- $this->_expressions=array();
- $this->_statements=array();
- foreach($items as $id=>$item)
- {
- if(is_array($item))
- {
- if($item[0]===self::TYPE_EXPRESSION)
- $this->_expressions[$id]=$item[1];
- else if($item[0]===self::TYPE_STATEMENTS)
- $this->_statements[$id]=$item[1];
- else if($item[0]===self::TYPE_DATABINDING)
- $this->_bindings[$id]=$item[1];
- $this->_items[$id]='';
- }
- else
- $this->_items[$id]=$item;
- }
- }
-
- /**
- * @return TComponent container of this component. It serves as the evaluation context of expressions and statements.
- */
- public function getContainer()
- {
- return $this->_container;
- }
-
- /**
- * @param TComponent container of this component. It serves as the evaluation context of expressions and statements.
- */
- public function setContainer(TComponent $value)
- {
- $this->_container=$value;
- }
-
- /**
- * Renders the content stored in this component.
- * This method is required by {@link IRenderable}
- * @param ITextWriter
- */
- public function render($writer)
- {
- $context=$this->_container===null?$this:$this->_container;
- foreach($this->_expressions as $id=>$expression)
- $this->_items[$id]=$context->evaluateExpression($expression);
- foreach($this->_statements as $id=>$statement)
- $this->_items[$id]=$context->evaluateStatements($statement);
- $writer->write(implode('',$this->_items));
- }
-
- /**
- * Performs databindings.
- * This method is required by {@link IBindable}
- */
- public function dataBind()
- {
- $context=$this->_container===null?$this:$this->_container;
- foreach($this->_bindings as $id=>$binding)
- $this->_items[$id]=$context->evaluateExpression($binding);
- }
-}
-
?> \ No newline at end of file