* @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2011 PradoSoft
* @license http://www.pradosoft.com/license/
* @version $Id$
* @package System.Data.ActiveRecord.Scaffold
*/
/**
* Load scaffold base.
*/
Prado::using('System.Data.ActiveRecord.Scaffold.TScaffoldBase');
/**
* Template control for editing an Active Record instance.
* The RecordClass determines the Active Record class to be edited.
* A particular record can be edited by specifying the {@link setRecordPk RecordPk}
* value (may be an array for composite keys).
*
* The default editor input controls are created based on the column types.
* The editor layout can be specified by a renderer by set the value
* of the {@link setEditRenderer EditRenderer} property to the class name of a
* class that implements TScaffoldEditRenderer. A renderer is an external
* template control that implements IScaffoldEditRenderer.
*
* The Data of the IScaffoldEditRenderer will be set as the current Active
* Record to be edited. The UpdateRecord() method of IScaffoldEditRenderer
* is called when request to save the record is requested.
*
* Validators in the custom external editor template should have the
* {@link TBaseValidator::setValidationGroup ValidationGroup} property set to the
* value of the {@link getValidationGroup} of the TScaffoldEditView instance
* (the edit view instance is the Parent of the IScaffoldEditRenderer in most
* cases.
*
* Cosmetic changes to the default editor should be done using Cascading Stylesheets.
* For example, a particular field/property can be hidden by specifying "display:none" for
* the corresponding style (each field/property has unique Css class name as "property_xxx", where
* xxx is the property name).
*
* @author Wei Zhuo
* @version $Id$
* @package System.Data.ActiveRecord.Scaffold
* @since 3.1
*/
class TScaffoldEditView extends TScaffoldBase
{
/**
* @var IScaffoldEditRenderer custom scaffold edit renderer
*/
private $_editRenderer;
/**
* Initialize the editor form if it is Visible.
*/
public function onLoad($param)
{
if($this->getVisible())
$this->initializeEditForm();
}
/**
* @return string the class name for scaffold editor. Defaults to empty, meaning not set.
*/
public function getEditRenderer()
{
return $this->getViewState('EditRenderer', '');
}
/**
* @param string the class name for scaffold editor. Defaults to empty, meaning not set.
*/
public function setEditRenderer($value)
{
$this->setViewState('EditRenderer', $value, '');
}
/**
* @param array Active Record primary key value to be edited.
*/
public function setRecordPk($value)
{
$this->clearRecordObject();
$val = TPropertyValue::ensureArray($value);
$this->setViewState('PK', count($val) > 0 ? $val : null);
}
/**
* @return array Active Record primary key value.
*/
public function getRecordPk()
{
return $this->getViewState('PK');
}
/**
* @return TActiveRecord current Active Record instance
*/
protected function getCurrentRecord()
{
return $this->getRecordObject($this->getRecordPk());
}
/**
* Initialize the editor form
*/
public function initializeEditForm()
{
$record = $this->getCurrentRecord();
$classPath = $this->getEditRenderer();
if($classPath === '')
{
$columns = $this->getTableInfo()->getColumns();
$this->getInputRepeater()->setDataSource($columns);
$this->getInputRepeater()->dataBind();
}
else
{
if($this->_editRenderer===null)
$this->createEditRenderer($record, $classPath);
else
$this->_editRenderer->setData($record);
}
}
/**
* Instantiate the external edit renderer.
* @param TActiveRecord record to be edited
* @param string external edit renderer class name.
* @throws TConfigurationException raised when renderer is not an
* instance of IScaffoldEditRenderer.
*/
protected function createEditRenderer($record, $classPath)
{
$this->_editRenderer = Prado::createComponent($classPath);
if($this->_editRenderer instanceof IScaffoldEditRenderer)
{
$index = $this->getControls()->remove($this->getInputRepeater());
$this->getControls()->insertAt($index,$this->_editRenderer);
$this->_editRenderer->setData($record);
}
else
{
throw new TConfigurationException(
'scaffold_invalid_edit_renderer', $this->getID(), get_class($record));
}
}
/**
* Initialize the default editor using the scaffold input builder.
*/
protected function createRepeaterEditItem($sender, $param)
{
$type = $param->getItem()->getItemType();
if($type==TListItemType::Item || $type==TListItemType::AlternatingItem)
{
$item = $param->getItem();
$column = $item->getDataItem();
if($column===null)
return;
$record = $this->getCurrentRecord();
$builder = $this->getScaffoldInputBuilder($record);
$builder->createScaffoldInput($this, $item, $column, $record);
}
}
/**
* Bubble the command name event. Stops bubbling when the page validator false.
* Otherwise, the bubble event is continued.
*/
public function bubbleEvent($sender, $param)
{
switch(strtolower($param->getCommandName()))
{
case 'save':
return $this->doSave() ? false : true;
case 'clear':
$this->setRecordPk(null);
$this->initializeEditForm();
return false;
default:
return false;
}
}
/**
* Check the validators, then tries to save the record.
* @return boolean true if the validators are true, false otherwise.
*/
protected function doSave()
{
if($this->getPage()->getIsValid())
{
$record = $this->getCurrentRecord();
if($this->_editRenderer===null)
{
$table = $this->getTableInfo();
$builder = $this->getScaffoldInputBuilder($record);
foreach($this->getInputRepeater()->getItems() as $item)
{
$column = $table->getColumn($item->getCustomData());
$builder->loadScaffoldInput($this, $item, $column, $record);
}
}
else
{
$this->_editRenderer->updateRecord($record);
}
$record->save();
return true;
}
else if($this->_editRenderer!==null)
{
//preserve the form data.
$this->_editRenderer->updateRecord($this->getCurrentRecord());
}
return false;
}
/**
* @return TRepeater default editor input controls repeater
*/
protected function getInputRepeater()
{
$this->ensureChildControls();
return $this->getRegisteredObject('_repeater');
}
/**
* @return TButton Button triggered to save the Active Record.
*/
public function getSaveButton()
{
$this->ensureChildControls();
return $this->getRegisteredObject('_save');
}
/**
* @return TButton Button to clear the editor inputs.
*/
public function getClearButton()
{
$this->ensureChildControls();
return $this->getRegisteredObject('_clear');
}
/**
* @return TButton Button to cancel the edit action (e.g. hide the edit view).
*/
public function getCancelButton()
{
$this->ensureChildControls();
return $this->getRegisteredObject('_cancel');
}
/**
* Create the default scaffold editor control factory.
* @param TActiveRecord record instance.
* @return TScaffoldInputBase scaffold editor control factory.
*/
protected function getScaffoldInputBuilder($record)
{
static $_builders=array();
$class = get_class($record);
if(!isset($_builders[$class]))
{
Prado::using('System.Data.ActiveRecord.Scaffold.InputBuilder.TScaffoldInputBase');
$_builders[$class] = TScaffoldInputBase::createInputBuilder($record);
}
return $_builders[$class];
}
/**
* @return string editor validation group name.
*/
public function getValidationGroup()
{
return 'group_'.$this->getUniqueID();
}
}
/**
* IScaffoldEditRenderer interface.
*
* IScaffoldEditRenderer defines the interface that an edit renderer
* needs to implement. Besides the {@link getData Data} property, an edit
* renderer also needs to provide {@link updateRecord updateRecord} method
* that is called before the save() method is called on the TActiveRecord.
*
* @author Wei Zhuo
* @version $Id$
* @package System.Data.ActiveRecord.Scaffold
* @since 3.1
*/
interface IScaffoldEditRenderer extends IDataRenderer
{
/**
* This method should update the record with the user input data.
* @param TActiveRecord record to be saved.
*/
public function updateRecord($record);
}