From 70944795827cffd1bd5a27a9c4a99eb1434f905f Mon Sep 17 00:00:00 2001 From: xue <> Date: Sat, 15 Apr 2006 14:35:46 +0000 Subject: Merge from branch 3.0 till 913. --- framework/Web/UI/TControl.php | 143 ++++++++++++++++++++++++++++- framework/Web/UI/TTemplateManager.php | 105 ++------------------- framework/Web/UI/WebControls/TRepeater.php | 52 +++++++++++ 3 files changed, 203 insertions(+), 97 deletions(-) (limited to 'framework/Web') diff --git a/framework/Web/UI/TControl.php b/framework/Web/UI/TControl.php index 78c5bdfc..9ede6be5 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 @@ -722,7 +723,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 unset($this->_rf[self::RF_DATA_BINDINGS][$name]); } + /** + * 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. */ @@ -760,8 +774,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)); } } @@ -1159,6 +1189,8 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable { if($this->_stagegetTemplateControl())===null) + $context=$this; if(isset($this->_rf[self::RF_ADAPTER])) $this->_rf[self::RF_ADAPTER]->onLoad(null); else @@ -1167,8 +1199,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_stage=self::CS_LOADED; @@ -1180,6 +1214,8 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable */ protected function preRenderRecursive() { + $this->autoDataBindProperties(); + if($this->getVisible(false)) { $this->ensureChildControls(); @@ -1190,8 +1226,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; @@ -2030,4 +2070,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 + * @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 7961a121..488a3a3b 100644 --- a/framework/Web/UI/TTemplateManager.php +++ b/framework/Web/UI/TTemplateManager.php @@ -397,7 +397,6 @@ class TTemplate extends TApplicationComponent implements ITemplate */ protected function configureProperty($component,$name,$value) { - $setter='set'.$name; if(is_array($value)) { switch($value[0]) @@ -406,19 +405,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 @@ -426,7 +429,10 @@ class TTemplate extends TApplicationComponent implements ITemplate } } else + { + $setter='set'.$name; $component->$setter($value); + } } /** @@ -817,7 +823,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) { @@ -846,95 +852,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 - * @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 +?> diff --git a/framework/Web/UI/WebControls/TRepeater.php b/framework/Web/UI/WebControls/TRepeater.php index 3d57fbd5..1acdc766 100644 --- a/framework/Web/UI/WebControls/TRepeater.php +++ b/framework/Web/UI/WebControls/TRepeater.php @@ -258,6 +258,35 @@ class TRepeater extends TDataBoundControl implements INamingContainer return $this->_items; } + /** + * @return string the field of the data source that provides the keys of the list items. + */ + public function getDataKeyField() + { + return $this->getViewState('DataKeyField',''); + } + + /** + * @param string the field of the data source that provides the keys of the list items. + */ + public function setDataKeyField($value) + { + $this->setViewState('DataKeyField',$value,''); + } + + /** + * @return TList the keys used in the data listing control. + */ + public function getDataKeys() + { + if(($dataKeys=$this->getViewState('DataKeys',null))===null) + { + $dataKeys=new TList; + $this->setViewState('DataKeys',$dataKeys,null); + } + return $dataKeys; + } + /** * Creates a repeater item instance based on the item type and index. * @param integer zero-based item index @@ -405,11 +434,18 @@ class TRepeater extends TDataBoundControl implements INamingContainer protected function performDataBinding($data) { $this->reset(); + + $keys=$this->getDataKeys(); + $keys->clear(); + $keyField=$this->getDataKeyField(); + $items=$this->getItems(); $itemIndex=0; $hasSeparator=$this->_separatorTemplate!==null; foreach($data as $dataItem) { + if($keyField!=='') + $keys->add($this->getDataFieldValue($dataItem,$keyField)); if($itemIndex===0 && $this->_headerTemplate!==null) $this->_header=$this->createItemInternal(-1,self::IT_HEADER,true,null); if($hasSeparator && $itemIndex>0) @@ -493,6 +529,22 @@ class TRepeater extends TDataBoundControl implements INamingContainer { $this->raiseEvent('OnItemCommand',$this,$param); } + + /** + * Returns the value of the data at the specified field. + * If data is an array, TMap or TList, the value will be returned at the index + * of the specified field. If the data is a component with a property named + * as the field name, the property value will be returned. + * Otherwise, an exception will be raised. + * @param mixed data item + * @param mixed field name + * @return mixed data value at the specified field + * @throws TInvalidDataValueException if the data is invalid + */ + protected function getDataFieldValue($data,$field) + { + return TDataFieldAccessor::getDataFieldValue($data,$field); + } } /** -- cgit v1.2.3