From 7fa1200b5e589a47884aa4d62630ce9099fccee1 Mon Sep 17 00:00:00 2001 From: wei <> Date: Tue, 30 Jan 2007 11:36:13 +0000 Subject: Add basic Scaffold view for Active Record --- .../Scaffold/InputBuilder/TMysqlScaffoldInput.php | 75 ++++++ .../Scaffold/InputBuilder/TPgsqlScaffoldInput.php | 48 ++++ .../Scaffold/InputBuilder/TScaffoldInputBase.php | 87 +++++++ .../Scaffold/InputBuilder/TScaffoldInputCommon.php | 280 +++++++++++++++++++++ .../Scaffold/InputBuilder/TSqliteScaffoldInput.php | 93 +++++++ .../Data/ActiveRecord/Scaffold/TScaffoldBase.php | 113 +++++++++ .../ActiveRecord/Scaffold/TScaffoldEditView.php | 119 +++++++++ .../ActiveRecord/Scaffold/TScaffoldEditView.tpl | 18 ++ .../ActiveRecord/Scaffold/TScaffoldListView.php | 172 +++++++++++++ .../ActiveRecord/Scaffold/TScaffoldListView.tpl | 56 +++++ .../Data/ActiveRecord/Scaffold/TScaffoldView.php | 72 ++++++ .../Data/ActiveRecord/Scaffold/TScaffoldView.tpl | 7 + framework/Data/ActiveRecord/Scaffold/style.css | 123 +++++++++ .../Vendor/TPgsqlMetaDataInspector.php | 2 +- 14 files changed, 1264 insertions(+), 1 deletion(-) create mode 100644 framework/Data/ActiveRecord/Scaffold/InputBuilder/TMysqlScaffoldInput.php create mode 100644 framework/Data/ActiveRecord/Scaffold/InputBuilder/TPgsqlScaffoldInput.php create mode 100644 framework/Data/ActiveRecord/Scaffold/InputBuilder/TScaffoldInputBase.php create mode 100644 framework/Data/ActiveRecord/Scaffold/InputBuilder/TScaffoldInputCommon.php create mode 100644 framework/Data/ActiveRecord/Scaffold/InputBuilder/TSqliteScaffoldInput.php create mode 100644 framework/Data/ActiveRecord/Scaffold/TScaffoldBase.php create mode 100644 framework/Data/ActiveRecord/Scaffold/TScaffoldEditView.php create mode 100644 framework/Data/ActiveRecord/Scaffold/TScaffoldEditView.tpl create mode 100644 framework/Data/ActiveRecord/Scaffold/TScaffoldListView.php create mode 100644 framework/Data/ActiveRecord/Scaffold/TScaffoldListView.tpl create mode 100644 framework/Data/ActiveRecord/Scaffold/TScaffoldView.php create mode 100644 framework/Data/ActiveRecord/Scaffold/TScaffoldView.tpl create mode 100644 framework/Data/ActiveRecord/Scaffold/style.css (limited to 'framework/Data') diff --git a/framework/Data/ActiveRecord/Scaffold/InputBuilder/TMysqlScaffoldInput.php b/framework/Data/ActiveRecord/Scaffold/InputBuilder/TMysqlScaffoldInput.php new file mode 100644 index 00000000..cb56d598 --- /dev/null +++ b/framework/Data/ActiveRecord/Scaffold/InputBuilder/TMysqlScaffoldInput.php @@ -0,0 +1,75 @@ +getType())) + { + case 'date': + return $this->createDateControl($container, $column, $record); + case 'blob': case 'tinyblob': case 'mediumblob': case 'longblob': + case 'text': case 'tinytext': case 'mediumtext': case 'longtext': + return $this->createMultiLineControl($container, $column, $record); + case 'year': + return $this->createYearControl($container, $column, $record); + case 'int': case 'integer': case 'tinyint': case 'smallint': case 'mediumint': case 'bigint': + return $this->createIntegerControl($container, $column, $record); + case 'decimal': case 'double': case 'float': + return $this->createFloatControl($container, $column, $record); + case 'time' : + return $this->createTimeControl($container, $column, $record); + case 'datetime': case 'timestamp': + return $this->createDateTimeControl($container, $column, $record); + case 'set': + return $this->createSetControl($container, $column, $record); + case 'enum': + return $this->createEnumControl($container, $column, $record); + default: + return $this->createDefaultControl($container, $column, $record); + } + } + + protected function getControlValue($container, $column, $record) + { + switch(strtolower($column->getType())) + { + case 'date': + return $container->findControl(self::DEFAULT_ID)->getDate(); + case 'year': + return $container->findControl(self::DEFAULT_ID)->getSelectedValue(); + case 'time': + return $this->getTimeValue($container, $column, $record); + case 'datetime': case 'timestamp': + return $this->getDateTimeValue($container,$column, $record); + case 'tinyint': + return $this->getIntBooleanValue($container,$column, $record); + case 'set': + return $this->getSetValue($container, $column, $record); + case 'enum': + return $this->getEnumValue($container, $column, $record); + default: + return $this->getDefaultControlValue($container,$column, $record); + } + } + + protected function createIntegerControl($container, $column, $record) + { + if($column->getLength()==1) + return $this->createBooleanControl($container, $column, $record); + else + parent::createIntegerControl($container, $column, $record); + } + + protected function getIntBooleanValue($container,$column, $record) + { + if($column->getLength()==1) + return (int)$container->findControl(self::DEFAULT_ID)->getChecked(); + else + return $this->getDefaultControlValue($container,$column, $record); + } +} + +?> \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Scaffold/InputBuilder/TPgsqlScaffoldInput.php b/framework/Data/ActiveRecord/Scaffold/InputBuilder/TPgsqlScaffoldInput.php new file mode 100644 index 00000000..40a14fbc --- /dev/null +++ b/framework/Data/ActiveRecord/Scaffold/InputBuilder/TPgsqlScaffoldInput.php @@ -0,0 +1,48 @@ +getType())) + { + case 'boolean': + return $this->createBooleanControl($container, $column, $record); + case 'date': + return $this->createDateControl($container, $column, $record); + case 'text': + return $this->createMultiLineControl($container, $column, $record); + case 'smallint': case 'integer': case 'bigint': + return $this->createIntegerControl($container, $column, $record); + case 'decimal': case 'numeric': case 'real': case 'double precision': + return $this->createFloatControl($container, $column, $record); + case 'time without time zone' : + return $this->createTimeControl($container, $column, $record); + case 'timestamp without time zone': + return $this->createDateTimeControl($container, $column, $record); + default: + return $this->createDefaultControl($container,$column, $record); + } + } + + protected function getControlValue($container, $column, $record) + { + switch(strtolower($column->getType())) + { + case 'boolean': + return $container->findControl(self::DEFAULT_ID)->getChecked(); + case 'date': + return $container->findControl(self::DEFAULT_ID)->getDate(); + case 'time without time zone': + return $this->getTimeValue($container, $column, $record); + case 'timestamp without time zone': + return $this->getDateTimeValue($container,$column, $record); + default: + return $this->getDefaultControlValue($container,$column, $record); + } + } +} + +?> \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Scaffold/InputBuilder/TScaffoldInputBase.php b/framework/Data/ActiveRecord/Scaffold/InputBuilder/TScaffoldInputBase.php new file mode 100644 index 00000000..c06f2fb6 --- /dev/null +++ b/framework/Data/ActiveRecord/Scaffold/InputBuilder/TScaffoldInputBase.php @@ -0,0 +1,87 @@ +_parent; + } + + public static function createInputBuilder($record) + { + $record->getDbConnection()->setActive(true); //must be connected before retrieving driver name! + $driver = $record->getDbConnection()->getDriverName(); + switch(strtolower($driver)) + { + case 'sqlite': //sqlite 3 + case 'sqlite2': //sqlite 2 + require_once(dirname(__FILE__).'/TSqliteScaffoldInput.php'); + return new TSqliteScaffoldInput($conn); + case 'mysqli': + case 'mysql': + require_once(dirname(__FILE__).'/TMysqlScaffoldInput.php'); + return new TMysqlScaffoldInput($conn); + case 'pgsql': + require_once(dirname(__FILE__).'/TPgsqlScaffoldInput.php'); + return new TPgsqlScaffoldInput($conn); + default: + throw new TConfigurationException( + 'scaffold_invalid_database_driver',$driver); + } + } + + public function createScaffoldInput($parent, $item, $column, $record) + { + $this->_parent=$parent; + $item->setCustomData($column->getProperty()); + $this->createControl($item->_input, $column, $record); + if($item->_input->findControl(self::DEFAULT_ID)) + $this->createControlLabel($item->_label, $column, $record); + } + + protected function createControlLabel($label, $column, $record) + { + $fieldname = ucwords(str_replace('_', ' ', $column->getProperty())).':'; + $label->setText($fieldname); + $label->setForControl(self::DEFAULT_ID); + } + + public function loadScaffoldInput($parent, $item, $column, $record) + { + $this->_parent=$parent; + if($this->getIsEnabled($column, $record)) + { + $prop = $column->getProperty(); + $record->{$prop} = $this->getControlValue($item->_input, $column, $record); + } + } + + protected function getIsEnabled($column, $record) + { + return !($this->getParent()->getRecordPk() !== null + && $column->getIsPrimaryKey() || $column->hasSequence()); + } + + protected function getRecordPropertyValue($column, $record) + { + return $record->{$column->getProperty()}; + } + + protected function setRecordPropertyValue($item, $record, $input) + { + $record->{$item->getCustomData()} = $input->getText(); + } + + protected function createControl($container, $column, $record) + { + } + + protected function getControlValue($container, $column, $record) + { + } +} + +?> \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Scaffold/InputBuilder/TScaffoldInputCommon.php b/framework/Data/ActiveRecord/Scaffold/InputBuilder/TScaffoldInputCommon.php new file mode 100644 index 00000000..049ceb1f --- /dev/null +++ b/framework/Data/ActiveRecord/Scaffold/InputBuilder/TScaffoldInputCommon.php @@ -0,0 +1,280 @@ +setID(self::DEFAULT_ID); + $control->setEnabled($this->getIsEnabled($column, $record)); + $container->Controls[] = $control; + } + + protected function setNotNullProperty($container, $control, $column, $record) + { + $this->setDefaultProperty($container, $control, $column, $record); + if($column->getNotNull() && !$column->hasSequence()) + $this->createRequiredValidator($container, $column, $record); + } + + protected function createBooleanControl($container, $column, $record) + { + $value = $this->getRecordPropertyValue($column, $record); + $control = new TCheckBox(); + $control->setChecked(TPropertyValue::ensureBoolean($value)); + $control->setCssClass('boolean-checkbox'); + $this->setDefaultProperty($container, $control, $column, $record); + return $control; + } + + protected function createDefaultControl($container, $column, $record) + { + $value = $this->getRecordPropertyValue($column, $record); + $control = new TTextBox(); + $control->setText($value); + $control->setCssClass('default-textbox scaffold_input'); + if(($len=$column->getLength())!==null) + $control->setMaxLength($len); + $this->setNotNullProperty($container, $control, $column, $record); + return $control; + } + + protected function getDefaultControlValue($container,$column, $record) + { + $control = $container->findControl(self::DEFAULT_ID); + if($control instanceof TCheckBox) + return $control->getChecked(); + else if($control instanceof TControl) + return $control->getText(); + } + + protected function createMultiLineControl($container, $column, $record) + { + $value = $this->getRecordPropertyValue($column, $record); + $control = new TTextBox(); + $control->setText($value); + $control->setTextMode(TTextBoxMode::MultiLine); + $control->setCssClass('multiline-textbox scaffold_input'); + $this->setNotNullProperty($container, $control, $column, $record); + return $control; + } + + protected function createYearControl($container, $column, $record) + { + $value = $this->getRecordPropertyValue($column, $record); + $control = new TDropDownList(); + $years = array(); + $current = intval(@date('Y')); + $from = $current-10; $to=$current+10; + for($i = $from; $i <= $to; $i++) + $years[$i] = $i; + $control->setDataSource($years); + $control->setSelectedValue(empty($value) ? $current : $value); + $control->setCssClass('year-dropdown'); + $this->setNotNullProperty($container, $control, $column, $record); + return $control; + } + + protected function createIntegerControl($container, $column, $record) + { + $control = $this->createDefaultControl($container, $column, $record); + $val = $this->createTypeValidator($container, $column, $record); + $val->setDataType(TValidationDataType::Integer); + $val->setErrorMessage('Please entery an integer.'); + return $control; + } + + protected function createFloatControl($container, $column, $record) + { + $control = $this->createDefaultControl($container, $column, $record); + $val = $this->createTypeValidator($container, $column, $record); + $val->setDataType(TValidationDataType::Float); + $val->setErrorMessage('Please entery a decimal number.'); + return $control; + } + + protected function createRequiredValidator($container, $column, $record) + { + $val = new TRequiredFieldValidator(); + $val->setErrorMessage('*'); + $val->setControlCssClass('required-input'); + $val->setCssClass('required'); + $val->setControlToValidate(self::DEFAULT_ID); + $val->setValidationGroup($this->getParent()->getValidationGroup()); + $val->setDisplay(TValidatorDisplayStyle::Dynamic); + $container->Controls[] = $val; + return $val; + } + + protected function createTypeValidator($container, $column, $record) + { + $val = new TDataTypeValidator(); + $val->setControlCssClass('required-input2'); + $val->setCssClass('required'); + $val->setControlToValidate(self::DEFAULT_ID); + $val->setValidationGroup($this->getParent()->getValidationGroup()); + $val->setDisplay(TValidatorDisplayStyle::Dynamic); + $container->Controls[] = $val; + return $val; + } + + protected function createTimeControl($container, $column, $record) + { + $value = $this->getRecordPropertyValue($column, $record); + $hours=array(); + for($i=0;$i<24;$i++) $hours[] = str_pad($i,2,'0',STR_PAD_LEFT); + $mins=array(); + for($i=0;$i<60;$i++) $mins[] = str_pad($i,2,'0',STR_PAD_LEFT); + $hour = intval(@date('H')); + $min = intval(@date('i')); + $sec = intval(@date('s')); + if(!empty($value)) + { + $match=array(); + if(preg_match('/(\d+):(\d+):?(\d+)?/', $value, $match)) + { + $hour = $match[1]; + $min = $match[2]; + if(isset($match[3])) + $sec=$match[3]; + } + } + + $hcontrol = new TDropDownList(); + $hcontrol->setDataSource($hours); + $hcontrol->setID(self::DEFAULT_ID); + $hcontrol->dataBind(); + $hcontrol->setSelectedValue(intval($hour)); + $container->Controls[] = $hcontrol; + $container->Controls[] = ' : '; + + $mcontrol = new TDropDownList(); + $mcontrol->setDataSource($mins); + $mcontrol->dataBind(); + $mcontrol->setID('scaffold_time_min'); + $mcontrol->setSelectedValue(intval($min)); + $container->Controls[] = $mcontrol; + $container->Controls[] = ' : '; + + $scontrol = new TDropDownList(); + $scontrol->setDataSource($mins); + $scontrol->dataBind(); + $scontrol->setID('scaffold_time_sec'); + $scontrol->setSelectedValue(intval($sec)); + $container->Controls[] = $scontrol; + + return array($hcontrol,$mcontrol,$scontrol); + } + + + protected function createDateControl($container, $column, $record) + { + $value = $this->getRecordPropertyValue($column, $record); + $control = new TDatePicker(); + $control->setInputMode(TDatePickerInputMode::DropDownList); + $control->setDateFormat('yyyy-MM-dd'); + if(!empty($value)) + $control->setDate(substr($value,0,10)); + $control->setCssClass('date-dropdown'); + $this->setNotNullProperty($container, $control, $column, $record); + return $control; + } + + protected function createDateTimeControl($container, $column, $record) + { + $value = $this->getRecordPropertyValue($column, $record); + $control = $this->createDateControl($container, $column, $record); + $container->Controls[] = ' @ '; + $time = $this->createTimeControl($container, $column, $record); + if(!empty($value)) + { + $match=array(); + if(preg_match('/(\d+):(\d+):?(\d+)?/', substr($value, 11), $match)) + { + $time[0]->setSelectedValue(intval($match[1])); + $time[1]->setSelectedValue(intval($match[2])); + if(isset($match[3])) + $time[2]->setSelectedValue(intval($match[3])); + } + } + $time[0]->setID('scaffold_time_hour'); + return array($control, $time[0], $time[1], $time[2]); + } + + protected function getDateTimeValue($container, $column, $record) + { + $date = $container->findControl(self::DEFAULT_ID)->getDate(); + $hour = $container->findControl('scaffold_time_hour')->getSelectedValue(); + $mins = $container->findControl('scaffold_time_min')->getSelectedValue(); + $secs = $container->findControl('scaffold_time_sec')->getSelectedValue(); + return "{$date} {$hour}:{$mins}:{$secs}"; + } + + protected function getTimeValue($container, $column, $record) + { + $hour = $container->findControl(self::DEFAULT_ID)->getSelectedValue(); + $mins = $container->findControl('scaffold_time_min')->getSelectedValue(); + $secs = $container->findControl('scaffold_time_sec')->getSelectedValue(); + return "{$hour}:{$mins}:{$secs}"; + } + + protected function createSetControl($container, $column, $record) + { + $value = $this->getRecordPropertyValue($column, $record); + $selectedValues = preg_split('/\s*,\s*/', $value); + $control = new TCheckBoxList(); + $values = $column->getTypeValues(); + $control->setDataSource($values); + $control->dataBind(); + $control->setSelectedIndices($this->getMatchingIndices($selectedValues, $values)); + $control->setID(self::DEFAULT_ID); + $control->setCssClass('set-checkboxes'); + $this->setNotNullProperty($container, $control, $column, $record); + return $control; + } + + protected function getMatchingIndices($checks, $values) + { + $index=array(); + for($i=0, $k=count($checks); $i<$k; $i++) + { + if(in_array($checks[$i], $values)) + $index[] = $i; + } + return $index; + } + + protected function createEnumControl($container, $column, $record) + { + $value = $this->getRecordPropertyValue($column, $record); + $selectedValues = preg_split('/\s*,\s*/', $value); + $control = new TRadioButtonList(); + $values = $column->getTypeValues(); + $control->setDataSource($values); + $control->dataBind(); + $index = $this->getMatchingIndices($selectedValues, $values); + if(count($index) > 0) + $control->setSelectedIndex($index[0]); + $control->setID(self::DEFAULT_ID); + $control->setCssClass('enum-radio-buttons'); + $this->setNotNullProperty($container, $control, $column, $record); + return $control; + } + + protected function getSetValue($container, $column, $record) + { + $value=array(); + foreach($container->findControl(self::DEFAULT_ID)->getItems() as $item) + { + if($item->getSelected()) + $value[] = $item->getText(); + } + return implode(',', $value); + } + + protected function getEnumValue($container, $column, $record) + { + return $container->findControl(self::DEFAULT_ID)->getSelectedItem()->getText(); + } +} + +?> \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Scaffold/InputBuilder/TSqliteScaffoldInput.php b/framework/Data/ActiveRecord/Scaffold/InputBuilder/TSqliteScaffoldInput.php new file mode 100644 index 00000000..b26d44fd --- /dev/null +++ b/framework/Data/ActiveRecord/Scaffold/InputBuilder/TSqliteScaffoldInput.php @@ -0,0 +1,93 @@ +getType())) + { + case 'boolean': + return $this->createBooleanControl($container, $column, $record); + case 'date': + return $this->createDateControl($container, $column, $record); + case 'blob': case 'tinyblob': case 'mediumblob': case 'longblob': + case 'text': case 'tinytext': case 'mediumtext': case 'longtext': + return $this->createMultiLineControl($container, $column, $record); + case 'year': + return $this->createYearControl($container, $column, $record); + case 'int': case 'integer': case 'tinyint': case 'smallint': case 'mediumint': case 'bigint': + return $this->createIntegerControl($container, $column, $record); + case 'decimal': case 'double': case 'float': + return $this->createFloatControl($container, $column, $record); + case 'time' : + return $this->createTimeControl($container, $column, $record); + case 'datetime': case 'timestamp': + return $this->createDateTimeControl($container, $column, $record); + default: + return $this->createDefaultControl($container,$column, $record); + } + } + + protected function getControlValue($container, $column, $record) + { + switch(strtolower($column->getType())) + { + case 'boolean': + return $container->findControl(self::DEFAULT_ID)->getChecked(); + case 'date': + return $container->findControl(self::DEFAULT_ID)->getDate(); + case 'year': + return $container->findControl(self::DEFAULT_ID)->getSelectedValue(); + case 'time': + return $this->getTimeValue($container, $column, $record); + case 'datetime': case 'timestamp': + return $this->getDateTimeValue($container,$column, $record); + default: + return $this->getDefaultControlValue($container,$column, $record); + } + } + + protected function createDateControl($container, $column, $record) + { + $control = parent::createDateControl($container, $column, $record); + $value = $this->getRecordPropertyValue($column, $record); + if(!empty($value) && preg_match('/timestamp/i', $column->getType())) + $control->setTimestamp(intval($value)); + return $control; + } + + protected function createDateTimeControl($container, $column, $record) + { + $value = $this->getRecordPropertyValue($column, $record); + $time = parent::createDateTimeControl($container, $column, $record); + if(!empty($value) && preg_match('/timestamp/i', $column->getType())) + { + $s = Prado::createComponent('System.Util.TDateTimeStamp'); + $date = $s->getDate(intval($value)); + $time[1]->setSelectedValue($date['hours']); + $time[2]->setSelectedValue($date['minutes']); + $time[3]->setSelectedValue($date['seconds']); + } + return $time; + } + + protected function getDateTimeValue($container, $column, $record) + { + if(preg_match('/timestamp/i', $column->getType())) + { + $time = $container->findControl(self::DEFAULT_ID)->getTimestamp(); + $s = Prado::createComponent('System.Util.TDateTimeStamp'); + $date = $s->getDate($time); + $hour = $container->findControl('scaffold_time_hour')->getSelectedValue(); + $mins = $container->findControl('scaffold_time_min')->getSelectedValue(); + $secs = $container->findControl('scaffold_time_sec')->getSelectedValue(); + return $s->getTimeStamp($hour,$mins,$secs,$date['mon'],$date['mday'],$date['year']); + } + else + return parent::getDateTimeValue($container, $column, $record); + } +} + +?> \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldBase.php b/framework/Data/ActiveRecord/Scaffold/TScaffoldBase.php new file mode 100644 index 00000000..dc464245 --- /dev/null +++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldBase.php @@ -0,0 +1,113 @@ +_meta===null) + { + $finder = $this->getRecordFinder(); + $gateway = $finder->getRecordManager()->getRecordGateWay(); + $this->_meta = $gateway->getMetaData($finder); + } + return $this->_meta; + } + + protected function getRecordProperties($record) + { + $data = array(); + foreach($this->getTableMetaData()->getColumns() as $name=>$column) + $data[] = $record->{$name}; + return $data; + } + + public function getRecordObjectPk($record) + { + $pk = array(); + foreach($this->getTableMetaData()->getColumns() as $name=>$column) + { + if($column->getIsPrimaryKey()) + $data[] = $record->{$name}; + } + return $data; + } + + public function getRecordClass() + { + return $this->getViewState('RecordClass'); + } + + public function setRecordClass($value) + { + $this->setViewState('RecordClass', $value); + } + + public function copyFrom(TScaffoldBase $obj) + { + $this->_record = $obj->_record; + $this->_meta = $obj->_meta; + $this->setRecordClass($obj->getRecordClass()); + } + + protected function clearRecordObject() + { + $this->_record=null; + $this->_meta=null; + } + + public function getRecordObject($pk=null) + { + if($this->_record===null) + { + if($pk!==null) + $this->_record=$this->getRecordFinder()->findByPk($pk); + else + { + $class = $this->getRecordClass(); + if($class!==null) + $this->_record=Prado::createComponent($class); + else + throw new TConfigurationException('scaffold_invalid_record_class', $this->getID()); + } + } + return $this->_record; + } + + public function getRecordFinder() + { + return TActiveRecord::getRecordFinder(get_class($this->getRecordObject())); + } + + public function setRecordObject($value) + { + if($value instanceof TActiveRecord) + $this->_record=$value; + else + throw new TConfigurationException('scaffold_object_must_be_tactiverecord', $this->getID()); + } + + public function getDefaultStyle() + { + return $this->getViewState('DefaultStyle', 'style'); + } + + public function setDefaultStyle($value) + { + $this->setViewState('DefaultStyle', TPropertyValue::ensureString($value), 'style'); + } + + public function onPreRender($param) + { + parent::onPreRender($param); + $url = $this->publishAsset($this->getDefaultStyle().'.css'); + $cs = $this->getPage()->getClientScript(); + $cs->registerStyleSheetFile($url,$url); + } +} + +?> \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldEditView.php b/framework/Data/ActiveRecord/Scaffold/TScaffoldEditView.php new file mode 100644 index 00000000..28fc8fb9 --- /dev/null +++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldEditView.php @@ -0,0 +1,119 @@ +initializeEditForm(); + } + + public function setRecordPk($value) + { + $this->clearRecordObject(); + $val = TPropertyValue::ensureArray($value); + $this->setViewState('PK', count($val) > 0 ? $val : null); + } + + public function getRecordPk() + { + return $this->getViewState('PK'); + } + + protected function getCurrentRecord() + { + return $this->getRecordObject($this->getRecordPk()); + } + + public function initializeEditForm() + { + $this->getCurrentRecord(); + $columns = $this->getTableMetaData()->getColumns(); + $this->_repeater->setDataSource($columns); + $this->_repeater->dataBind(); + } + + public function repeaterItemCreated($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); + } + } + + public function bubbleEvent($sender, $param) + { + switch(strtolower($param->getCommandName())) + { + case 'save': + if($this->getPage()->getIsValid()) + return $this->doSave() === true ? false : true; + return true; + case 'clear': + $this->setRecordPk(null); + $this->initializeEditForm(); + return false; + default: + return false; + } + } + + protected function doSave() + { + $record = $this->getCurrentRecord(); + $table = $this->getTableMetaData(); + $builder = $this->getScaffoldInputBuilder($record); + foreach($this->_repeater->getItems() as $item) + { + $column = $table->getColumn($item->getCustomData()); + $builder->loadScaffoldInput($this, $item, $column, $record); + } + $record->save(); + return true; + } + + public function getSaveButton() + { + $this->ensureChildControls(); + return $this->getRegisteredObject('_save'); + } + + public function getClearButton() + { + $this->ensureChildControls(); + return $this->getRegisteredObject('_clear'); + } + + public function getCancelButton() + { + $this->ensureChildControls(); + return $this->getRegisteredObject('_cancel'); + } + + protected function getScaffoldInputBuilder($record) + { + $class = get_class($record); + if(!isset(self::$_builders[$class])) + self::$_builders[$class] = TScaffoldInputBase::createInputBuilder($record); + return self::$_builders[$class]; + } + + public function getValidationGroup() + { + return 'group_'.$this->getUniqueID(); + } +} + +?> \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldEditView.tpl b/framework/Data/ActiveRecord/Scaffold/TScaffoldEditView.tpl new file mode 100644 index 00000000..fd599a20 --- /dev/null +++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldEditView.tpl @@ -0,0 +1,18 @@ +
+ + +
+ + + + +
+
+
+
+ +
+ValidationGroup %>/> + + +
\ No newline at end of file diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldListView.php b/framework/Data/ActiveRecord/Scaffold/TScaffoldListView.php new file mode 100644 index 00000000..98c0aab8 --- /dev/null +++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldListView.php @@ -0,0 +1,172 @@ +getPage()->getIsPostBack()) + $this->initializeSort(); + } + + protected function initializeSort() + { + $table = $this->getTableMetaData(); + $sorts = array('Sorty By', str_repeat('-',15)); + $headers = array(); + foreach($table->getColumns() as $name=>$colum) + { + $fname = ucwords(str_replace('_', ' ', $name)); + $sorts[$name.' ASC'] = $fname .' Ascending'; + $sorts[$name.' DESC'] = $fname .' Descending'; + $headers[] = $fname ; + } + $this->_sort->setDataSource($sorts); + $this->_sort->dataBind(); + $this->_header->setDataSource($headers); + $this->_header->dataBind(); + } + + public function onPreRender($param) + { + parent::onPreRender($param); + $this->initializeItemCount(); + $this->loadRecordData(); + } + + protected function initializeItemCount() + { + $this->_list->setVirtualItemCount($this->getRecordFinder()->count()); + } + + protected function loadRecordData() + { + $finder = $this->getRecordFinder(); + $criteria = $this->getPagingCriteria(); + $this->_list->setDataSource($finder->findAll($criteria)); + $this->_list->dataBind(); + } + + protected function getPagingCriteria() + { + $total = $this->_list->getVirtualItemCount(); + $limit = $this->_list->getPageSize(); + $offset = $this->_list->getCurrentPageIndex()*$limit; + if($offset + $limit > $total) + $limit = $total - $offset; + $criteria = new TActiveRecordCriteria; + $criteria->setLimit($limit); + $criteria->setOffset($offset); + $order = explode(' ',$this->_sort->getSelectedValue(), 2); + if(is_array($order) && count($order) === 2) + $criteria->OrdersBy[$order[0]] = $order[1]; + return $criteria; + } + + public function bubbleEvent($sender, $param) + { + switch(strtolower($param->getCommandName())) + { + case 'delete': + return $this->deleteRecord($sender, $param); + case 'edit': + if(($ctrl=$this->getEditViewControl())!==null) + { + if($param instanceof TRepeaterCommandEventParameter) + { + $pk = $param->getItem()->getCustomData(); + $ctrl->setRecordPk($pk); + $ctrl->initializeEditForm(); + } + } + } + $this->raiseBubbleEvent($this, $param); + return true; + } + + public function deleteRecord($sender, $param) + { + if($param instanceof TRepeaterCommandEventParameter) + { + $pk = $param->getItem()->getCustomData(); + $this->getRecordFinder()->deleteByPk($pk); + } + } + + protected function listItemCreated($sender, $param) + { + $type = $param->getItem()->getItemType(); + if($type==TListItemType::Item || $type==TListItemType::AlternatingItem) + $this->populateField($sender, $param); + } + + protected function populateField($sender, $param) + { + $item = $param->getItem(); + $data = $item->getDataItem(); + if($data !== null) + { + $item->setCustomData($this->getRecordObjectPk($data)); + + if(($prop = $item->findControl('_properties'))!==null) + { + $item->_properties->setDataSource($this->getRecordProperties($data)); + $item->_properties->dataBind(); + } + } + } + + protected function pageChanged($sender, $param) + { + $this->_list->setCurrentPageIndex($param->getNewPageIndex()); + } + + public function getList() + { + $this->ensureChildControls(); + return $this->getRegisteredObject('_list'); + } + + public function getPager() + { + $this->ensureChildControls(); + return $this->getRegisteredObject('_pager'); + } + + public function getSort() + { + $this->ensureChildControls(); + return $this->getRegisteredObject('_sort'); + } + + public function getHeader() + { + $this->ensureChildControls(); + return $this->getRegisteredObject('_header'); + } + + public function getEditViewID() + { + return $this->getViewState('EditViewID'); + } + + public function setEditViewID($value) + { + $this->setViewState('EditViewID', $value); + } + + protected function getEditViewControl() + { + if(($id=$this->getEditViewID())!==null) + { + $ctrl = $this->getParent()->findControl($id); + if($ctrl===null) + throw new TConfigurationException('scaffold_unable_to_find_edit_view', $id); + return $ctrl; + } + } +} + +?> \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldListView.tpl b/framework/Data/ActiveRecord/Scaffold/TScaffoldListView.tpl new file mode 100644 index 00000000..7b8854f0 --- /dev/null +++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldListView.tpl @@ -0,0 +1,56 @@ + +
+ + + DataItem %> CssClass="field field_<%# $this->ItemIndex %>"/> + + + + + + + +
+ +
+ + +
+ + + + + <%# htmlspecialchars($this->DataItem) %> + + + + + + NamingContainer->Parent->EditViewID !== Null %> + CommandName="edit" + CssClass="edit-button" + CausesValidation="false" /> + + + +
+
+
+
+ + \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldView.php b/framework/Data/ActiveRecord/Scaffold/TScaffoldView.php new file mode 100644 index 00000000..668ede61 --- /dev/null +++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldView.php @@ -0,0 +1,72 @@ +getListView()->copyFrom($this); + $this->getEditView()->copyFrom($this); + } + + public function getListView() + { + $this->ensureChildControls(); + return $this->getRegisteredObject('_listView'); + } + + public function getEditView() + { + $this->ensureChildControls(); + return $this->getRegisteredObject('_editView'); + } + + public function getAddButton() + { + $this->ensureChildControls(); + return $this->getRegisteredObject('_newButton'); + } + + public function bubbleEvent($sender,$param) + { + switch(strtolower($param->getCommandName())) + { + case 'edit': + return $this->showEditView($sender, $param); + case 'new': + return $this->showAddView($sender, $param); + default: + return $this->showListView($sender, $param); + } + return false; + } + + protected function showEditView($sender, $param) + { + $this->getListView()->setVisible(false); + $this->getEditView()->setVisible(true); + $this->getAddButton()->setVisible(false); + $this->getEditView()->getCancelButton()->setVisible(true); + $this->getEditView()->getClearButton()->setVisible(false); + } + + protected function showListView($sender, $param) + { + $this->getListView()->setVisible(true); + $this->getEditView()->setVisible(false); + $this->getAddButton()->setVisible(true); + } + + protected function showAddView($sender, $param) + { + $this->getEditView()->setRecordPk(null); + $this->getEditView()->initializeEditForm(); + $this->showEditView($sender, $param); + } +} + +?> \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldView.tpl b/framework/Data/ActiveRecord/Scaffold/TScaffoldView.tpl new file mode 100644 index 00000000..0ae8b8b0 --- /dev/null +++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldView.tpl @@ -0,0 +1,7 @@ + + +
+ +
+ + \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Scaffold/style.css b/framework/Data/ActiveRecord/Scaffold/style.css new file mode 100644 index 00000000..eb31e9a5 --- /dev/null +++ b/framework/Data/ActiveRecord/Scaffold/style.css @@ -0,0 +1,123 @@ +body +{ + font-family: Cambria, Georgia, "Times New Roman", Times, serif; +} + +.pager +{ + display: block; + border-top: 1px solid #ccc; + padding: 1em; +} + +.pager span, .pager a +{ + border: 1px solid #ccc; + padding: 0.3em 0.7em; + font-weight: bold; +} + +.pager a +{ + background-color: #E0FFFF; + border-color: #87CEFA; +} + +.pager a:hover +{ + background-color: White; +} + + +.item, .item-header +{ + border-top: 1px dashed #B0C4DE; + padding: 0.5em; + clear: both; +} + +.item-header +{ + border-top: 0 none; + font-weight: bold; +} + +.item_1 +{ + background-color: #F0F8FF; +} + +.field_0, .field +{ + padding: 0.2em; + float: left; + width: 150px; +} + +.field_0 +{ + width: 40px; + text-align: center; +} + +.auxilary-button +{ + padding: 1em; +} + +.edit-inputs label +{ + width: 150px; + float: left; + text-align: right; + padding: 0 0.5em; + font-weight: bold; +} + + +.item-input label +{ + float: none; + font-weight: normal; +} + + +.edit-page-buttons +{ + padding-left: 120px; + padding-top: 20px; +} + +.edit-item +{ + padding: 0.4em; +} + +.edit-inputs .scaffold_input +{ + width: 250px; + border: 1px solid Highlight; + padding: 0.2em; +} + +.edit-inputs .multiline-textbox +{ + width: 500px; + height: 100px; +} + +.edit-inputs .input_0 .scaffold_input +{ + width: 50px; +} + +.edit-inputs .required +{ + font-weight: bold; + padding: 0.2em; +} +.edit-inputs .required-input +{ + border: 1px solid red; + background-color: #FFF5EE; +} \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Vendor/TPgsqlMetaDataInspector.php b/framework/Data/ActiveRecord/Vendor/TPgsqlMetaDataInspector.php index 6f787942..2f7202cf 100644 --- a/framework/Data/ActiveRecord/Vendor/TPgsqlMetaDataInspector.php +++ b/framework/Data/ActiveRecord/Vendor/TPgsqlMetaDataInspector.php @@ -146,7 +146,7 @@ EOD; $type = $col['type']; // A specific constant in the 7.0 source, the length is offset by 4. - $length = $col['atttypmod'] > 0 ? $col['atttypmod'] - 4 : -1; + $length = $col['atttypmod'] > 0 ? $col['atttypmod'] - 4 : null; $notNull = $col['attnotnull']; $serial = $col['attisserial'] ? $schema.'.'.$this->getSerialName($col['adsrc']) : null; $default = $serial === null && $col['atthasdef'] ? $col['adsrc'] : null; -- cgit v1.2.3