summaryrefslogtreecommitdiff
path: root/lib/prado/framework/Web/UI/TTemplateControl.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/prado/framework/Web/UI/TTemplateControl.php')
-rw-r--r--lib/prado/framework/Web/UI/TTemplateControl.php327
1 files changed, 327 insertions, 0 deletions
diff --git a/lib/prado/framework/Web/UI/TTemplateControl.php b/lib/prado/framework/Web/UI/TTemplateControl.php
new file mode 100644
index 0000000..4917d4b
--- /dev/null
+++ b/lib/prado/framework/Web/UI/TTemplateControl.php
@@ -0,0 +1,327 @@
+<?php
+/**
+ * TTemplateControl class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI
+ */
+
+/**
+ * Includes TCompositeControl class
+ */
+Prado::using('System.Web.UI.TCompositeControl');
+
+/**
+ * TTemplateControl class.
+ * TTemplateControl is the base class for all controls that use templates.
+ * By default, a control template is assumed to be in a file under the same
+ * directory with the control class file. They have the same file name and
+ * different extension name. For template file, the extension name is ".tpl".
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TTemplateControl extends TCompositeControl
+{
+ /**
+ * template file extension.
+ */
+ const EXT_TEMPLATE='.tpl';
+
+ /**
+ * @var ITemplate the parsed template structure shared by the same control class
+ */
+ private static $_template=array();
+ /**
+ * @var ITemplate the parsed template structure specific for this control instance
+ */
+ private $_localTemplate=null;
+ /**
+ * @var TTemplateControl the master control if any
+ */
+ private $_master=null;
+ /**
+ * @var string master control class name
+ */
+ private $_masterClass='';
+ /**
+ * @var array list of TContent controls
+ */
+ private $_contents=array();
+ /**
+ * @var array list of TContentPlaceHolder controls
+ */
+ private $_placeholders=array();
+
+ /**
+ * Returns the template object associated with this control object.
+ * @return ITemplate|null the parsed template, null if none
+ */
+ public function getTemplate()
+ {
+ if($this->_localTemplate===null)
+ {
+ $class=get_class($this);
+ if(!isset(self::$_template[$class]))
+ self::$_template[$class]=$this->loadTemplate();
+ return self::$_template[$class];
+ }
+ else
+ return $this->_localTemplate;
+ }
+
+ /**
+ * Sets the parsed template.
+ * Note, the template will be applied to the whole control class.
+ * This method should only be used by framework and control developers.
+ * @param ITemplate the parsed template
+ */
+ public function setTemplate($value)
+ {
+ $this->_localTemplate=$value;
+ }
+
+ /**
+ * @return boolean whether this control is a source template control.
+ * A source template control loads its template from external storage,
+ * such as file, db, rather than from within another template.
+ */
+ public function getIsSourceTemplateControl()
+ {
+ if(($template=$this->getTemplate())!==null)
+ return $template->getIsSourceTemplate();
+ else
+ return false;
+ }
+
+ /**
+ * @return string the directory containing the template. Empty if no template available.
+ */
+ public function getTemplateDirectory()
+ {
+ if(($template=$this->getTemplate())!==null)
+ return $template->getContextPath();
+ else
+ return '';
+ }
+
+ /**
+ * Loads the template associated with this control class.
+ * @return ITemplate the parsed template structure
+ */
+ protected function loadTemplate()
+ {
+ Prado::trace("Loading template ".get_class($this),'System.Web.UI.TTemplateControl');
+ $template=$this->getService()->getTemplateManager()->getTemplateByClassName(get_class($this));
+ return $template;
+ }
+
+ /**
+ * Creates child controls.
+ * This method is overridden to load and instantiate control template.
+ * This method should only be used by framework and control developers.
+ */
+ public function createChildControls()
+ {
+ if($tpl=$this->getTemplate())
+ {
+ foreach($tpl->getDirective() as $name=>$value)
+ {
+ if(is_string($value))
+ $this->setSubProperty($name,$value);
+ else
+ throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name);
+ }
+ $tpl->instantiateIn($this);
+ }
+ }
+
+ /**
+ * Registers a content control.
+ * @param string ID of the content
+ * @param TContent
+ */
+ public function registerContent($id,TContent $object)
+ {
+ if(isset($this->_contents[$id]))
+ throw new TConfigurationException('templatecontrol_contentid_duplicated',$id);
+ else
+ $this->_contents[$id]=$object;
+ }
+
+ /**
+ * Registers a content placeholder to this template control.
+ * This method should only be used by framework and control developers.
+ * @param string placeholder ID
+ * @param TContentPlaceHolder placeholder control
+ */
+ public function registerContentPlaceHolder($id,TContentPlaceHolder $object)
+ {
+ if(isset($this->_placeholders[$id]))
+ throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id);
+ else
+ $this->_placeholders[$id]=$object;
+ }
+
+ /**
+ * @return string master class name (in namespace form)
+ */
+ public function getMasterClass()
+ {
+ return $this->_masterClass;
+ }
+
+ /**
+ * @param string master control class name (in namespace form)
+ */
+ public function setMasterClass($value)
+ {
+ $this->_masterClass=$value;
+ }
+
+ /**
+ * @return TTemplateControl|null master control associated with this control, null if none
+ */
+ public function getMaster()
+ {
+ return $this->_master;
+ }
+
+ /**
+ * Injects all content controls (and their children) to the corresponding content placeholders.
+ * This method should only be used by framework and control developers.
+ * @param string ID of the content control
+ * @param TContent the content to be injected
+ */
+ public function injectContent($id,$content)
+ {
+ if(isset($this->_placeholders[$id]))
+ {
+ $placeholder=$this->_placeholders[$id];
+ $controls=$placeholder->getParent()->getControls();
+ $loc=$controls->remove($placeholder);
+ $controls->insertAt($loc,$content);
+ }
+ else
+ throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id);
+ }
+
+ /**
+ * Performs the OnInit step for the control and all its child controls.
+ * This method overrides the parent implementation
+ * by ensuring child controls are created first,
+ * and if master class is set, master will be applied.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function initRecursive($namingContainer=null)
+ {
+ $this->ensureChildControls();
+ if($this->_masterClass!=='')
+ {
+ $master=Prado::createComponent($this->_masterClass);
+ if(!($master instanceof TTemplateControl))
+ throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid');
+ $this->_master=$master;
+ $this->getControls()->clear();
+ $this->getControls()->add($master);
+ $master->ensureChildControls();
+ foreach($this->_contents as $id=>$content)
+ $master->injectContent($id,$content);
+ }
+ else if(!empty($this->_contents))
+ throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this));
+ parent::initRecursive($namingContainer);
+ }
+
+ /**
+ * Function to update view controls with data in a given AR object.
+ * View controls and AR object need to have the same name in IDs and Attrs respectively.
+ * @param TActiveRecord $arObj
+ * @param Boolean $throwExceptions Wheter or not to throw exceptions
+ * @author Daniel Sampedro <darthdaniel85@gmail.com>
+ */
+ public function tryToUpdateView($arObj, $throwExceptions = false)
+ {
+ $objAttrs = get_class_vars(get_class($arObj));
+ foreach (array_keys($objAttrs) as $key)
+ {
+ try
+ {
+ if ($key != "RELATIONS")
+ {
+ $control = $this->{$key};
+ if ($control instanceof TTextBox)
+ $control->Text = $arObj->{$key};
+ elseif ($control instanceof TCheckBox)
+ $control->Checked = (boolean) $arObj->{$key};
+ elseif ($control instanceof TDatePicker)
+ $control->Date = $arObj->{$key};
+ }
+ else
+ {
+ foreach ($objAttrs["RELATIONS"] as $relKey => $relValues)
+ {
+ $relControl = $this->{$relKey};
+ switch ($relValues[0])
+ {
+ case TActiveRecord::BELONGS_TO:
+ case TActiveRecord::HAS_ONE:
+ $relControl->Text = $arObj->{$relKey};
+ break;
+ case TActiveRecord::HAS_MANY:
+ if ($relControl instanceof TListControl)
+ {
+ $relControl->DataSource = $arObj->{$relKey};
+ $relControl->dataBind();
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ catch (Exception $ex)
+ {
+ if ($throwExceptions)
+ throw $ex;
+ }
+ }
+ }
+
+ /**
+ * Function to try to update an AR object with data in view controls.
+ * @param TActiveRecord $arObj
+ * @param Boolean $throwExceptions Wheter or not to throw exceptions
+ * @author Daniel Sampedro <darthdaniel85@gmail.com>
+ */
+ public function tryToUpdateAR($arObj, $throwExceptions = false)
+ {
+ $objAttrs = get_class_vars(get_class($arObj));
+ foreach (array_keys($objAttrs) as $key)
+ {
+ try
+ {
+ if ($key == "RELATIONS")
+ break;
+ $control = $this->{$key};
+ if ($control instanceof TTextBox)
+ $arObj->{$key} = $control->Text;
+ elseif ($control instanceof TCheckBox)
+ $arObj->{$key} = $control->Checked;
+ elseif ($control instanceof TDatePicker)
+ $arObj->{$key} = $control->Date;
+ }
+ catch (Exception $ex)
+ {
+ if ($throwExceptions)
+ throw $ex;
+ }
+ }
+ }
+}
+