From fd4b8d9f45d1707035021bc19b8d5bc17ede66ce Mon Sep 17 00:00:00 2001 From: wei <> Date: Mon, 12 Feb 2007 12:46:11 +0000 Subject: Add IBM DB2 driver for active record. --- .../Data/ActiveRecord/Exceptions/messages.txt | 3 +- .../Scaffold/InputBuilder/TMysqlScaffoldInput.php | 2 +- .../Scaffold/InputBuilder/TPgsqlScaffoldInput.php | 2 +- .../Data/ActiveRecord/Scaffold/TScaffoldBase.php | 115 ++++++++++++-- .../ActiveRecord/Scaffold/TScaffoldEditView.php | 168 ++++++++++++++++++--- .../ActiveRecord/Scaffold/TScaffoldEditView.tpl | 6 +- .../ActiveRecord/Scaffold/TScaffoldListView.php | 85 ++++++++--- .../ActiveRecord/Scaffold/TScaffoldListView.tpl | 19 +-- .../Data/ActiveRecord/Scaffold/TScaffoldSearch.php | 89 +++++++++++ .../Data/ActiveRecord/Scaffold/TScaffoldSearch.tpl | 4 + .../Data/ActiveRecord/Scaffold/TScaffoldView.php | 10 ++ .../Data/ActiveRecord/Scaffold/TScaffoldView.tpl | 10 +- framework/Data/ActiveRecord/Scaffold/style.css | 3 +- framework/Data/ActiveRecord/TActiveRecord.php | 46 +++++- .../Data/ActiveRecord/TActiveRecordManager.php | 3 + framework/Data/ActiveRecord/Vendor/TDbMetaData.php | 38 ++++- .../Data/ActiveRecord/Vendor/TDbMetaDataCommon.php | 2 +- .../ActiveRecord/Vendor/TIbmColumnMetaData.php | 149 ++++++++++++++++++ .../Data/ActiveRecord/Vendor/TIbmMetaData.php | 80 ++++++++++ .../ActiveRecord/Vendor/TIbmMetaDataInspector.php | 113 ++++++++++++++ .../Data/ActiveRecord/Vendor/TMysqlMetaData.php | 22 ++- .../Vendor/TMysqlMetaDataInspector.php | 7 +- .../ActiveRecord/Vendor/TPgsqlColumnMetaData.php | 19 ++- .../Data/ActiveRecord/Vendor/TPgsqlMetaData.php | 26 +++- .../Vendor/TPgsqlMetaDataInspector.php | 19 ++- .../Data/ActiveRecord/Vendor/TSqliteMetaData.php | 19 ++- .../Vendor/TSqliteMetaDataInspector.php | 5 +- 27 files changed, 947 insertions(+), 117 deletions(-) create mode 100644 framework/Data/ActiveRecord/Scaffold/TScaffoldSearch.php create mode 100644 framework/Data/ActiveRecord/Scaffold/TScaffoldSearch.tpl create mode 100644 framework/Data/ActiveRecord/Vendor/TIbmColumnMetaData.php create mode 100644 framework/Data/ActiveRecord/Vendor/TIbmMetaData.php create mode 100644 framework/Data/ActiveRecord/Vendor/TIbmMetaDataInspector.php (limited to 'framework/Data') diff --git a/framework/Data/ActiveRecord/Exceptions/messages.txt b/framework/Data/ActiveRecord/Exceptions/messages.txt index 53d8f4e3..2af62bb5 100644 --- a/framework/Data/ActiveRecord/Exceptions/messages.txt +++ b/framework/Data/ActiveRecord/Exceptions/messages.txt @@ -13,4 +13,5 @@ ar_invalid_tablename_property = ActiveRecord tablename property '{0}::${1}' m ar_value_must_not_be_null = Property '{0}::${2}' must not be null as defined by column '{2}' in table '{1}'. ar_missing_pk_values = Missing primary key values in forming IN(key1, key2, ...) for table '{0}'. ar_pk_value_count_mismatch = Composite key value count mismatch in forming IN( (key1, key2, ..), (key3, key4, ..)) for table '{0}'. -ar_must_copy_from_array_or_object = $data in {0}::copyFrom($data) must be an object or an array. \ No newline at end of file +ar_must_copy_from_array_or_object = $data in {0}::copyFrom($data) must be an object or an array. +ar_mismatch_column_names = In dynamic __call() method '{0}', no matching columns were found, valid columns for table '{2}' are '{1}'. \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Scaffold/InputBuilder/TMysqlScaffoldInput.php b/framework/Data/ActiveRecord/Scaffold/InputBuilder/TMysqlScaffoldInput.php index c6fc6902..89df0f2e 100644 --- a/framework/Data/ActiveRecord/Scaffold/InputBuilder/TMysqlScaffoldInput.php +++ b/framework/Data/ActiveRecord/Scaffold/InputBuilder/TMysqlScaffoldInput.php @@ -2,7 +2,7 @@ Prado::using('System.Data.ActiveRecord.Scaffold.InputBuilder.TScaffoldInputCommon'); -class MysqlScaffoldInput extends TScaffoldInputCommon +class TMysqlScaffoldInput extends TScaffoldInputCommon { protected function createControl($container, $column, $record) { diff --git a/framework/Data/ActiveRecord/Scaffold/InputBuilder/TPgsqlScaffoldInput.php b/framework/Data/ActiveRecord/Scaffold/InputBuilder/TPgsqlScaffoldInput.php index 40a14fbc..f5e11eae 100644 --- a/framework/Data/ActiveRecord/Scaffold/InputBuilder/TPgsqlScaffoldInput.php +++ b/framework/Data/ActiveRecord/Scaffold/InputBuilder/TPgsqlScaffoldInput.php @@ -2,7 +2,7 @@ Prado::using('System.Data.ActiveRecord.Scaffold.InputBuilder.TScaffoldInputCommon'); -class PgsqlScaffoldInput extends ScaffoldInputCommon +class TPgsqlScaffoldInput extends TScaffoldInputCommon { protected function createControl($container, $column, $record) { diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldBase.php b/framework/Data/ActiveRecord/Scaffold/TScaffoldBase.php index dc464245..b55ceedc 100644 --- a/framework/Data/ActiveRecord/Scaffold/TScaffoldBase.php +++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldBase.php @@ -1,12 +1,49 @@ + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2007 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Data.ActiveRecord.Scaffold + */ + +/** + * Include the base Active Record class. + */ Prado::using('System.Data.ActiveRecord.TActiveRecord'); +/** + * Base class for Active Record scaffold views. + * + * Provides common properties for all scaffold views (such as, TScaffoldListView, + * TScaffoldEditView, TScaffoldListView and TScaffoldView). + * + * During the OnPrRender stage the default css style file (filename style.css) + * is published and registered. To override the default style, provide your own stylesheet + * file explicitly. + * + * @author Wei Zhuo + * @version $Id$ + * @package System.Data.ActiveRecord.Scaffold + * @since 3.1 + */ abstract class TScaffoldBase extends TTemplateControl { + /** + * @var TActiveRecord record instance (may be new or retrieved from db) + */ private $_record; + /** + * @var TDbMetaData table/view information. + */ private $_meta; + /** + * @return TDbMetaData table/view information + */ protected function getTableMetaData() { if($this->_meta===null) @@ -18,7 +55,11 @@ abstract class TScaffoldBase extends TTemplateControl return $this->_meta; } - protected function getRecordProperties($record) + /** + * @param TActiveRecord record instance + * @return array record property values + */ + protected function getRecordPropertyValues($record) { $data = array(); foreach($this->getTableMetaData()->getColumns() as $name=>$column) @@ -26,7 +67,11 @@ abstract class TScaffoldBase extends TTemplateControl return $data; } - public function getRecordObjectPk($record) + /** + * @param TActiveRecord record instance + * @return array record primary key values. + */ + protected function getRecordPkValues($record) { $pk = array(); foreach($this->getTableMetaData()->getColumns() as $name=>$column) @@ -37,76 +82,116 @@ abstract class TScaffoldBase extends TTemplateControl return $data; } + /** + * Name of the Active Record class to be viewed or scaffolded. + * @return string Active Record class name. + */ public function getRecordClass() { return $this->getViewState('RecordClass'); } + /** + * Name of the Active Record class to be viewed or scaffolded. + * @param string Active Record class name. + */ public function setRecordClass($value) { $this->setViewState('RecordClass', $value); } - public function copyFrom(TScaffoldBase $obj) + /** + * Copy the view details from another scaffold view instance. + * @param TScaffoldBase scaffold view. + */ + protected function copyFrom(TScaffoldBase $obj) { $this->_record = $obj->_record; $this->_meta = $obj->_meta; $this->setRecordClass($obj->getRecordClass()); } + /** + * Unset the current record instance and table information. + */ protected function clearRecordObject() { $this->_record=null; $this->_meta=null; } - public function getRecordObject($pk=null) + /** + * Gets the current Active Record instance. Creates new instance if the + * primary key value is null otherwise the record is fetched from the db. + * @param array primary key value + * @return TActiveRecord record instance + */ + protected function getRecordObject($pk=null) { if($this->_record===null) { if($pk!==null) + { $this->_record=$this->getRecordFinder()->findByPk($pk); + if($this->_record===null) + throw new TConfigurationException('scaffold_invalid_record_pk', + $this->getRecordClass(), $pk); + } else { $class = $this->getRecordClass(); if($class!==null) $this->_record=Prado::createComponent($class); else - throw new TConfigurationException('scaffold_invalid_record_class', $this->getID()); + { + throw new TConfigurationException('scaffold_invalid_record_class', + $this->getRecordClass(),$this->getID()); + } } } return $this->_record; } - public function getRecordFinder() + /** + * @param TActiveRecord Active Record instance. + */ + protected function setRecordObject(TActiveRecord $value) { - return TActiveRecord::getRecordFinder(get_class($this->getRecordObject())); + $this->_record=$value; } - public function setRecordObject($value) + /** + * @return TActiveRecord Active Record finder instance + */ + protected function getRecordFinder() { - if($value instanceof TActiveRecord) - $this->_record=$value; - else - throw new TConfigurationException('scaffold_object_must_be_tactiverecord', $this->getID()); + return TActiveRecord::getRecordFinder($this->getRecordClass()); } + /** + * @return string default scaffold stylesheet name + */ public function getDefaultStyle() { return $this->getViewState('DefaultStyle', 'style'); } + /** + * @param string default scaffold stylesheet name + */ public function setDefaultStyle($value) { $this->setViewState('DefaultStyle', TPropertyValue::ensureString($value), 'style'); } + /** + * Publish the default stylesheet file. + */ public function onPreRender($param) { parent::onPreRender($param); $url = $this->publishAsset($this->getDefaultStyle().'.css'); - $cs = $this->getPage()->getClientScript(); - $cs->registerStyleSheetFile($url,$url); + $this->getPage()->getClientScript()->registerStyleSheetFile($url,$url); } } diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldEditView.php b/framework/Data/ActiveRecord/Scaffold/TScaffoldEditView.php index a8faa6c8..a792aeb9 100644 --- a/framework/Data/ActiveRecord/Scaffold/TScaffoldEditView.php +++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldEditView.php @@ -1,29 +1,82 @@ + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2007 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Data.ActiveRecord.Scaffold + */ +/** + * Load scaffold base. + */ Prado::using('System.Data.ActiveRecord.Scaffold.TScaffoldBase'); -Prado::using('System.Data.ActiveRecord.Scaffold.InputBuilder.TScaffoldInputBase'); +/** + * Template control for editing an Active Record instance. + * + * The default editor input controls are created based on the column types. + * + * The editor layout can be specified by a renderer. 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. + * + * 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). + * + * @author Wei Zhuo + * @version $Id$ + * @package System.Data.ActiveRecord.Scaffold + * @since 3.1 + */ class TScaffoldEditView extends TScaffoldBase { - private static $_builders=array(); + /** + * @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(); @@ -31,16 +84,25 @@ class TScaffoldEditView extends TScaffoldBase $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(); @@ -60,6 +122,13 @@ class TScaffoldEditView extends TScaffoldBase } } + /** + * 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); @@ -76,7 +145,10 @@ class TScaffoldEditView extends TScaffoldBase } } - protected function repeaterItemCreated($sender, $param) + /** + * 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) @@ -92,14 +164,16 @@ class TScaffoldEditView extends TScaffoldBase } } + /** + * 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': - if($this->getPage()->getIsValid()) - return $this->doSave() === true ? false : true; - return true; + return $this->doSave() ? false : true; case 'clear': $this->setRecordPk(null); $this->initializeEditForm(); @@ -109,68 +183,116 @@ class TScaffoldEditView extends TScaffoldBase } } + /** + * Check the validators, then tries to save the record. + * @return boolean true if the validators are true, false otherwise. + */ protected function doSave() { - $record = $this->getCurrentRecord(); - if($this->_editRenderer===null) + if($this->getPage()->getIsValid()) { - $table = $this->getTableMetaData(); - $builder = $this->getScaffoldInputBuilder($record); - foreach($this->getInputRepeater()->getItems() as $item) + $record = $this->getCurrentRecord(); + if($this->_editRenderer===null) { - $column = $table->getColumn($item->getCustomData()); - $builder->loadScaffoldInput($this, $item, $column, $record); + $table = $this->getTableMetaData(); + $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 - { - $this->_editRenderer->updateRecord($record); - } - - $record->save(); - return true; + 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(self::$_builders[$class])) - self::$_builders[$class] = TScaffoldInputBase::createInputBuilder($record); - return self::$_builders[$class]; + 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); } diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldEditView.tpl b/framework/Data/ActiveRecord/Scaffold/TScaffoldEditView.tpl index 8cba7ec4..884ec2a3 100644 --- a/framework/Data/ActiveRecord/Scaffold/TScaffoldEditView.tpl +++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldEditView.tpl @@ -1,7 +1,8 @@ +
- + -
ItemIndex % 2 %> input_<%# $this->ItemIndex %> property_<%# $this->DataItem->Property %>"> @@ -16,4 +17,5 @@ ValidationGroup %>/> +
\ No newline at end of file diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldListView.php b/framework/Data/ActiveRecord/Scaffold/TScaffoldListView.php index 35c53473..2ac3fe99 100644 --- a/framework/Data/ActiveRecord/Scaffold/TScaffoldListView.php +++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldListView.php @@ -1,7 +1,28 @@ + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2007 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Data.ActiveRecord.Scaffold + */ + +/** + * Load the scaffold base class. + */ Prado::using('System.Data.ActiveRecord.Scaffold.TScaffoldBase'); +/** + * TScaffoldListView displays instance of Active Record class. + * + * @author Wei Zhuo + * @version $Id$ + * @package System.Data.ActiveRecord.Scaffold + * @since 3.1 + */ class TScaffoldListView extends TScaffoldBase { public function onLoad($param) @@ -32,31 +53,26 @@ class TScaffoldListView extends TScaffoldBase public function onPreRender($param) { parent::onPreRender($param); - $this->initializeItemCount(); $this->loadRecordData(); } - protected function initializeItemCount() - { - $this->_list->setVirtualItemCount($this->getRecordFinder()->count()); - } - protected function loadRecordData() { + $this->_list->setVirtualItemCount($this->getRecordFinder()->count()); $finder = $this->getRecordFinder(); - $criteria = $this->getPagingCriteria(); + $criteria = $this->getRecordCriteria(); $this->_list->setDataSource($finder->findAll($criteria)); $this->_list->dataBind(); } - protected function getPagingCriteria() + protected function getRecordCriteria() { $total = $this->_list->getVirtualItemCount(); $limit = $this->_list->getPageSize(); $offset = $this->_list->getCurrentPageIndex()*$limit; if($offset + $limit > $total) $limit = $total - $offset; - $criteria = new TActiveRecordCriteria; + $criteria = new TActiveRecordCriteria($this->getSearchCondition(), $this->getSearchParameters()); $criteria->setLimit($limit); $criteria->setOffset($offset); $order = explode(' ',$this->_sort->getSelectedValue(), 2); @@ -65,6 +81,26 @@ class TScaffoldListView extends TScaffoldBase return $criteria; } + public function setSearchCondition($value) + { + $this->setViewState('SearchCondition', $value); + } + + public function getSearchCondition() + { + return $this->getViewState('SearchCondition'); + } + + public function setSearchParameters($value) + { + $this->setViewState('SearchParameters', TPropertyValue::ensureArray($value),array()); + } + + public function getSearchParameters() + { + return $this->getViewState('SearchParameters', array()); + } + public function bubbleEvent($sender, $param) { switch(strtolower($param->getCommandName())) @@ -72,21 +108,26 @@ class TScaffoldListView extends TScaffoldBase 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->initializeEdit($sender, $param); } $this->raiseBubbleEvent($this, $param); return true; } - public function deleteRecord($sender, $param) + protected function initializeEdit($sender, $param) + { + if(($ctrl=$this->getEditViewControl())!==null) + { + if($param instanceof TRepeaterCommandEventParameter) + { + $pk = $param->getItem()->getCustomData(); + $ctrl->setRecordPk($pk); + $ctrl->initializeEditForm(); + } + } + } + + protected function deleteRecord($sender, $param) { if($param instanceof TRepeaterCommandEventParameter) { @@ -111,10 +152,10 @@ class TScaffoldListView extends TScaffoldBase $item = $param->getItem(); if(($data = $item->getData()) !== null) { - $item->setCustomData($this->getRecordObjectPk($data)); + $item->setCustomData($this->getRecordPkValues($data)); if(($prop = $item->findControl('_properties'))!==null) { - $item->_properties->setDataSource($this->getRecordProperties($data)); + $item->_properties->setDataSource($this->getRecordPropertyValues($data)); $item->_properties->dataBind(); } } diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldListView.tpl b/framework/Data/ActiveRecord/Scaffold/TScaffoldListView.tpl index 7b8854f0..c70e864d 100644 --- a/framework/Data/ActiveRecord/Scaffold/TScaffoldListView.tpl +++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldListView.tpl @@ -1,4 +1,4 @@ - +
@@ -21,7 +21,7 @@ PageSize="10">
- + @@ -29,20 +29,20 @@ - + - NamingContainer->Parent->EditViewID !== Null %> - CommandName="edit" + CommandName="edit" CssClass="edit-button" CausesValidation="false" /> - - +
@@ -53,4 +53,5 @@ ControlToPaginate="_list" PageButtonCount="10" Mode="Numeric" - OnPageIndexChanged="pageChanged" /> \ No newline at end of file + OnPageIndexChanged="pageChanged" /> +
\ No newline at end of file diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldSearch.php b/framework/Data/ActiveRecord/Scaffold/TScaffoldSearch.php new file mode 100644 index 00000000..a47a1a47 --- /dev/null +++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldSearch.php @@ -0,0 +1,89 @@ +_list===null && ($id = $this->getListViewID()) !== null) + { + $this->_list = $this->getParent()->findControl($id); + if($this->_list ===null) + throw new TConfigurationException('scaffold_unable_to_find_list_view', $id); + } + return $this->_list; + } + + public function setListView($value) + { + $this->_list = $value; + } + + public function setListViewID($value) + { + $this->setViewState('ListViewID', $value); + } + + public function getListViewID() + { + return $this->getViewState('ListViewID'); + } + + public function bubbleEvent($sender, $param) + { + if(strtolower($param->getCommandName())==='search') + { + if(($list = $this->getListView()) !== null) + { + $list->setSearchCondition($this->createSearchCondition()); + $list->setSearchParameters(array()); + return false; + } + } + $this->raiseBubbleEvent($this, $param); + return true; + } + + protected function createSearchCondition() + { + $table = $this->getTableMetaData(); + if(strlen($str=$this->getSearchText()->getText()) > 0) + return $table->getSearchRegExpCriteria($this->getFields(), $str); + } + + protected function getFields() + { + if(strlen(trim($str=$this->getSearchableFields()))>0) + $fields = preg_split('/\s*,\s*/', $str); + else + $fields = array_keys($this->getTableMetaData()->getColumns()); + return $fields; + } + + public function getSearchableFields() + { + return $this->getViewState('SearchableFields',''); + } + + public function setSearchableFields($value) + { + $this->setViewState('SearchableFields', $value, ''); + } + + public function getSearchButton() + { + $this->ensureChildControls(); + return $this->getRegisteredObject('_search'); + } + + public function getSearchText() + { + $this->ensureChildControls(); + return $this->getRegisteredObject('_textbox'); + } +} + +?> \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldSearch.tpl b/framework/Data/ActiveRecord/Scaffold/TScaffoldSearch.tpl new file mode 100644 index 00000000..a5f56b55 --- /dev/null +++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldSearch.tpl @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldView.php b/framework/Data/ActiveRecord/Scaffold/TScaffoldView.php index 668ede61..5401c764 100644 --- a/framework/Data/ActiveRecord/Scaffold/TScaffoldView.php +++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldView.php @@ -3,6 +3,7 @@ Prado::using('System.Data.ActiveRecord.Scaffold.TScaffoldBase'); Prado::using('System.Data.ActiveRecord.Scaffold.TScaffoldListView'); Prado::using('System.Data.ActiveRecord.Scaffold.TScaffoldEditView'); +Prado::using('System.Data.ActiveRecord.Scaffold.TScaffoldSearch'); class TScaffoldView extends TScaffoldBase { @@ -11,6 +12,7 @@ class TScaffoldView extends TScaffoldBase parent::onLoad($param); $this->getListView()->copyFrom($this); $this->getEditView()->copyFrom($this); + $this->getSearchControl()->copyFrom($this); } public function getListView() @@ -25,6 +27,12 @@ class TScaffoldView extends TScaffoldBase return $this->getRegisteredObject('_editView'); } + public function getSearchControl() + { + $this->ensureChildControls(); + return $this->getRegisteredObject('_search'); + } + public function getAddButton() { $this->ensureChildControls(); @@ -50,6 +58,7 @@ class TScaffoldView extends TScaffoldBase $this->getListView()->setVisible(false); $this->getEditView()->setVisible(true); $this->getAddButton()->setVisible(false); + $this->getSearchControl()->setVisible(false); $this->getEditView()->getCancelButton()->setVisible(true); $this->getEditView()->getClearButton()->setVisible(false); } @@ -59,6 +68,7 @@ class TScaffoldView extends TScaffoldBase $this->getListView()->setVisible(true); $this->getEditView()->setVisible(false); $this->getAddButton()->setVisible(true); + $this->getSearchControl()->setVisible(true); } protected function showAddView($sender, $param) diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldView.tpl b/framework/Data/ActiveRecord/Scaffold/TScaffoldView.tpl index 0ae8b8b0..01cceb07 100644 --- a/framework/Data/ActiveRecord/Scaffold/TScaffoldView.tpl +++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldView.tpl @@ -1,7 +1,9 @@ +
+ - -
+ -
+ - \ No newline at end of file + +
\ No newline at end of file diff --git a/framework/Data/ActiveRecord/Scaffold/style.css b/framework/Data/ActiveRecord/Scaffold/style.css index eb31e9a5..a1fc7a16 100644 --- a/framework/Data/ActiveRecord/Scaffold/style.css +++ b/framework/Data/ActiveRecord/Scaffold/style.css @@ -1,3 +1,4 @@ +/* $Id$ */ body { font-family: Cambria, Georgia, "Times New Roman", Times, serif; @@ -116,7 +117,7 @@ body font-weight: bold; padding: 0.2em; } -.edit-inputs .required-input +.edit-inputs .required-input, .edit-inputs .required-input2 { border: 1px solid red; background-color: #FFF5EE; diff --git a/framework/Data/ActiveRecord/TActiveRecord.php b/framework/Data/ActiveRecord/TActiveRecord.php index 91ae971a..bdb03596 100644 --- a/framework/Data/ActiveRecord/TActiveRecord.php +++ b/framework/Data/ActiveRecord/TActiveRecord.php @@ -384,6 +384,8 @@ abstract class TActiveRecord extends TComponent /** * Find records using full SQL, returns corresponding record object. + * The names of the column retrieved must be defined in your Active Record + * class. * @param string select SQL * @param array $parameters * @return array matching active records. @@ -439,8 +441,8 @@ abstract class TActiveRecord extends TComponent * $finder->find('Name = ?', $name); * * - * $finder->findByUsernameAndPassword($name,$pass); - * $finder->findBy_Username_And_Password($name,$pass); + * $finder->findByUsernameAndPassword($name,$pass); // OR may be used + * $finder->findBy_Username_And_Password($name,$pass); // _OR_ may be used * $finder->find('Username = ? AND Password = ?', $name, $pass); * * @@ -481,13 +483,43 @@ abstract class TActiveRecord extends TComponent */ private function createCriteriaFromString($method, $condition, $args) { - $fields = array(); - foreach(preg_split('/and|_and_/i',$condition) as $field) - $fields[] = $field.' = ?'; + $fields = $this->extractMatchingConditions($method, $condition); $args=count($args) === 1 && is_array($args[0]) ? $args[0] : $args; if(count($fields)>count($args)) - throw new TActiveRecordException('ar_mismatch_args_exception',$method,count($fields),count($args)); - return new TActiveRecordCriteria(implode(' AND ',$fields),$args); + { + throw new TActiveRecordException('ar_mismatch_args_exception', + $method,count($fields),count($args)); + } + return new TActiveRecordCriteria(implode(' ',$fields),$args); + } + + /** + * Calculates the AND/OR condition from dynamic method substrings using + * table meta data, allows for any AND-OR combinations. + * @param string dynamic method name + * @param string dynamic method search criteria + * @return array search condition substrings + */ + private function extractMatchingConditions($method, $condition) + { + $meta = $this->getRecordManager()->getRecordGateway()->getMetaData($this); + $search = implode('|', $meta->getColumnNames()); + $regexp = '/('.$search.')(and|_and_|or|_or_)?/i'; + $matches = array(); + if(!preg_match_all($regexp, strtolower($condition), $matches,PREG_SET_ORDER)) + { + throw new TActiveRecordException('ar_mismatch_column_names', + $method, implode(', ', $meta->getColumnNames()), $meta->getTableName()); + } + $fields = array(); + foreach($matches as $match) + { + $sql = $meta->getColumn($match[1])->getName() . ' = ? '; + if(count($match) > 2) + $sql .= strtoupper(str_replace('_', '', $match[2])); + $fields[] = $sql; + } + return $fields; } } ?> \ No newline at end of file diff --git a/framework/Data/ActiveRecord/TActiveRecordManager.php b/framework/Data/ActiveRecord/TActiveRecordManager.php index 7f239a34..bd672c3b 100644 --- a/framework/Data/ActiveRecord/TActiveRecordManager.php +++ b/framework/Data/ActiveRecord/TActiveRecordManager.php @@ -164,6 +164,9 @@ class TActiveRecordManager extends TComponent case 'sqlite2': //sqlite 2 Prado::using('System.Data.ActiveRecord.Vendor.TSqliteMetaDataInspector'); return new TSqliteMetaDataInspector($conn); + case 'ibm': + Prado::using('System.Data.ActiveRecord.Vendor.TIbmMetaDataInspector'); + return new TIbmMetaDataInspector($conn); default: throw new TActiveRecordConfigurationException( 'ar_invalid_database_driver',$driver); diff --git a/framework/Data/ActiveRecord/Vendor/TDbMetaData.php b/framework/Data/ActiveRecord/Vendor/TDbMetaData.php index 38a82aef..3a959ba4 100644 --- a/framework/Data/ActiveRecord/Vendor/TDbMetaData.php +++ b/framework/Data/ActiveRecord/Vendor/TDbMetaData.php @@ -20,8 +20,7 @@ * @version $Id$ * @package System.Data.ActiveRecord.Vendor * @since 3.1 - */ - + */ abstract class TDbMetaData extends TComponent { private $_primaryKeys=array(); @@ -91,6 +90,11 @@ abstract class TDbMetaData extends TComponent return $this->_columns[$name]; } + public function getColumnNames() + { + return array_keys($this->_columns); + } + /** * Post process the rows after returning from a 1 row query. * @param mixed row data, may be null. @@ -187,7 +191,7 @@ abstract class TDbMetaData extends TComponent foreach($keys as $i => $key) { $value = isset($values[$i]) ? $values[$i] : $values[$key]; - $command->bindValue(':'.$key, $value); + $this->bindValue($command, ':'.$key, $value); } $command->prepare(); } @@ -249,7 +253,7 @@ abstract class TDbMetaData extends TComponent /** * Gets a comma delimited string of name parameters for update. -x * @param array name value pairs of columns for update. + * @param array name value pairs of columns for update. * @return string update named parameter string. */ protected function getUpdateBindings($columns) @@ -294,19 +298,27 @@ x * @param array name value pairs of columns for update. if($criteria->getIsNamedParameters()) { foreach($criteria->getParameters() as $name=>$value) - $command->bindValue($name,$value); + $this->bindValue($command, $name, $value); } else { $index=1; foreach($criteria->getParameters() as $value) - $command->bindValue($index++,$value); + $this->bindValue($command, $index++,$value); } } $command->prepare(); return $command; } + protected function bindValue($command, $name, $value) + { + if(is_bool($value)) + $command->bindValue($name,$value, PDO::PARAM_BOOL); + else + $command->bindValue($name,$value); + } + /** * Bind parameter values. */ @@ -316,9 +328,9 @@ x * @param array name value pairs of columns for update. foreach($parameters as $key=>$value) { if(is_string($key)) - $command->bindValue($key,$value); + $this->bindValue($command,$key,$value); else - $command->bindValue($index++,$value); + $this->bindValue($command, $index++,$value); } $command->prepare(); } @@ -345,5 +357,15 @@ x * @param array name value pairs of columns for update. return implode(', ', $fields); } + /** + * @param string ordering column name + * @param string ordering direction + * @return string DESC or ASC + */ + protected function getOrdering($by, $direction) + { + $dir = strtolower($direction) == 'desc' ? 'DESC' : 'ASC'; + return $this->getColumn($by)->getName(). ' '.$dir; + } } ?> \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Vendor/TDbMetaDataCommon.php b/framework/Data/ActiveRecord/Vendor/TDbMetaDataCommon.php index 826654dc..a41e87ad 100644 --- a/framework/Data/ActiveRecord/Vendor/TDbMetaDataCommon.php +++ b/framework/Data/ActiveRecord/Vendor/TDbMetaDataCommon.php @@ -186,7 +186,7 @@ abstract class TDbMetaDataCommon extends TDbMetaData return $command; } - + /** * SQL command to delete records by criteria * @param TDbConnection database connection. diff --git a/framework/Data/ActiveRecord/Vendor/TIbmColumnMetaData.php b/framework/Data/ActiveRecord/Vendor/TIbmColumnMetaData.php new file mode 100644 index 00000000..65e40a59 --- /dev/null +++ b/framework/Data/ActiveRecord/Vendor/TIbmColumnMetaData.php @@ -0,0 +1,149 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2007 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Data.ActiveRecord.Vendor + */ + +/** + * TIbmColumnMetaData class. + * + * Column details for IBM DB2 database. Using php_pdo_ibm.dll extension. + * + * @author Cesar Ramos + * @version $Id$ + * @package System.Data.ActiveRecord.Vendor + * @since 3.1 + */ +class TIbmColumnMetaData extends TComponent +{ + private $_name; + private $_type; + private $_length; + private $_autoIncrement; + private $_default; + private $_notNull=true; + + private $_isPrimary=null; + + private $_property; + + /** + * Initialize column meta data. + * + * @param string column name. + * @param string column data type. + * @param string column data length. + * @param boolean column can not be null. + * @param string serial name. + * @param string default value. + */ + public function __construct($name,$type,$length,$notNull,$autoIncrement,$default,$primary) + { + $this->_property = $name; + $this->_name=$name; + $this->_type=$type; + $this->_length=$length; + $this->_notNull=$notNull; + $this->_autoIncrement=$autoIncrement; + $this->_default=$default; + $this->_isPrimary=$primary; + } + + /** + * @return string quoted column name. + */ + public function getName() + { + return $this->_name; + } + + /** + * @return string active record property name + */ + public function getProperty() + { + return $this->_property; + } + + /** + * @return boolean true if column is a sequence, false otherwise. + */ + public function hasSequence() + { + return $this->_autoIncrement; + } + + /** + * @return null no sequence name. + */ + public function getSequenceName() + { + return null; + } + + /** + * @return boolean true if the column is a primary key, or part of a composite primary key. + */ + public function getIsPrimaryKey() + { + return $this->_isPrimary; + } + + /** + * @return string column type + */ + public function getType() + { + return $this->_type; + } + + + /** + * @return boolean false if column can be null, true otherwise. + */ + public function getNotNull() + { + return $this->_notNull; + } + + /** + * @return boolean true if column has default value, false otherwise. + */ + public function hasDefault() + { + return $this->_default !== null; + } + + /** + * @return string default column value. + */ + public function getDefaultValue() + { + return $this->_default; + } + + /** + * @return string PHP primative type derived from the column type. + */ + public function getPHPType() + { + switch(strtolower($this->_type)) + { + case 'smallint': case 'integer': + return 'integer'; + case 'real': case 'float': case 'double': case 'decimal': case 'bigint': + return 'float'; + default: + return 'string'; + } + } + +} + +?> \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Vendor/TIbmMetaData.php b/framework/Data/ActiveRecord/Vendor/TIbmMetaData.php new file mode 100644 index 00000000..4f923406 --- /dev/null +++ b/framework/Data/ActiveRecord/Vendor/TIbmMetaData.php @@ -0,0 +1,80 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2007 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Data.ActiveRecord.Vendor + */ +Prado::using('System.Data.ActiveRecord.Vendor.TDbMetaDataCommon'); + +/** + * TIbmMetaData class. + * + * Column details for IBM DB2 database. Using php_pdo_ibm.dll extension. + * + * Does not support LIMIT and OFFSET criterias. + * + * @author Cesar Ramos + * @version $Id$ + * @package System.Data.ActiveRecord.Vendor + * @since 3.1 + */ +class TIbmMetaData extends TDbMetaDataCommon +{ + /** + * Build the SQL search string from the criteria object for IBM DB2 database. + * @param TDbConnection database connection. + * @param TActiveRecordCriteria search criteria. + * @return string SQL search. + */ + protected function getSqlFromCriteria($conn, $criteria) + { + if($criteria===null) return ''; + $sql = ''; + if(($condition = $criteria->getCondition())!==null) + $sql .= ' WHERE '.$condition; + $orders=array(); + foreach($criteria->getOrdersBy() as $by=>$ordering) + $orders[] = $this->getOrdering($by, $ordering); + if(count($orders) > 0) + $sql .= ' ORDER BY '.implode(', ', $orders); + //if(($limit = $criteria->getLimit())!==null) + //{ + // $sql .= ' FETCH FIRST '.intval($limit).' ROWS ONLY'; + //} + return strlen($sql) > 0 ? $sql : ''; + } + + /** + * Lowercase the data keys, IBM DB2 returns uppercase column names + * @param mixed record row + * @return array record row + */ + public function postQueryRow($row) + { + if(!is_array($row)) return $row; + $result=array(); + foreach($row as $k=>$v) + $result[strtolower($k)]=$v; + return $result; + } + + /** + * Lowercase the data keys, IBM DB2 returns uppercase column names + * @param mixed record row + * @return array record row + */ + public function postQuery($rows) + { + $data = array(); + foreach($rows as $k=>$v) + $data[$k] = $this->postQueryRow($v); + return $data; + } +} +?> \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Vendor/TIbmMetaDataInspector.php b/framework/Data/ActiveRecord/Vendor/TIbmMetaDataInspector.php new file mode 100644 index 00000000..0ccc05ae --- /dev/null +++ b/framework/Data/ActiveRecord/Vendor/TIbmMetaDataInspector.php @@ -0,0 +1,113 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2007 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Data.ActiveRecord.Vendor + */ +Prado::using('System.Data.ActiveRecord.Vendor.TDbMetaDataInspector'); +Prado::using('System.Data.ActiveRecord.Vendor.TIbmColumnMetaData'); +Prado::using('System.Data.ActiveRecord.Vendor.TIbmMetaData'); + +/** + * TIbmMetaDataInspector class. + * + * Column details for IBM DB2 database. Using php_pdo_ibm.dll extension. + * + * @author Cesar Ramos + * @version $Id$ + * @package System.Data.ActiveRecord.Vendor + * @since 3.1 + */ +class TIbmMetaDataInspector extends TDbMetaDataInspector +{ + private $_schema; + + /** + * @param string default schema. + */ + public function setSchema($schema) + { + $this->_schema=$schema; + } + + /** + * @return string default schema. + */ + public function getSchema() + { + return $this->_schema; + } + /** + * Get the column definitions for given table. + * @param string table name. + * @return array column name value pairs of column meta data. + */ + protected function getColumnDefinitions($table) + { + if(count($parts= explode('.', $table)) > 1) + { + $tablename = $parts[1]; + $schema = $parts[0]; + } + else + { + $tablename = $parts[0]; + $schema = $this->getSchema(); + } + $sql="SELECT * FROM SYSCAT.COLUMNS WHERE TABNAME='".strtoupper($tablename)."'"; + if ($schema) + $sql=$sql." AND TABSCHEMA='".strtoupper($schema)."'"; + + $conn = $this->getDbConnection(); + $conn->setActive(true); + $command = $conn->createCommand($sql); + $command->prepare(); + $result=$command->query($sql); + foreach ($result as $col) + $cols[strtolower($col['COLNAME'])] = $this->getColumnMetaData($col); + return $cols; + } + + protected function getColumnMetaData($col) + { + $name = strtolower($col['COLNAME']); + $type = $col['TYPENAME']; + $length = $col['LENGTH']; + $notNull = $col['NULLS']==='N'; + $autoIncrement=$col['IDENTITY']==='N'; + $default = $col['DEFAULT']; + $primaryKey = $col['KEYSEQ']?1:0; + return new TIbmColumnMetaData($name,$type,$length,$notNull,$autoIncrement,$default,$primaryKey); + } + + /** + * Not implemented, IBM does not always have foreign key constraints. + */ + protected function getConstraintKeys($table) + { + return array('primary'=>array(), 'foreign'=>array()); + } + + /** + * Create a new instance of meta data. + * @param string table name + * @param array column meta data + * @param array primary key meta data + * @param array foreign key meta data. + * @return TDbMetaData table meta data. + */ + protected function createMetaData($table, $columns, $primary, $foreign) + { + $pks = array(); + foreach($columns as $name=>$column) + if($column->getIsPrimaryKey()) + $pks[] = $name; + return new TIbmMetaData($table,$columns,$pks); + } +} +?> \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Vendor/TMysqlMetaData.php b/framework/Data/ActiveRecord/Vendor/TMysqlMetaData.php index 0cbd0b7c..03aba53f 100644 --- a/framework/Data/ActiveRecord/Vendor/TMysqlMetaData.php +++ b/framework/Data/ActiveRecord/Vendor/TMysqlMetaData.php @@ -1,4 +1,4 @@ - 0 ? $sql : ''; } - protected function getOrdering($by, $direction) + public function getSearchRegExpCriteria($fields, $keywords) { - $dir = strtolower($direction) == 'desc' ? 'DESC' : 'ASC'; - return $this->getColumn($by)->getName(). ' '.$dir; + if(strlen(trim($keywords)) == 0) return ''; + $words = preg_split('/\s/', preg_quote($keywords, '\'')); + $result = array(); + foreach($fields as $field) + { + $column = $this->getColumn($field); + $result[] = $this->getRegexpCriteriaStr($column->getName(), $words); + } + return '('.implode(' OR ', $result).')'; + } + + protected function getRegexpCriteriaStr($column, $words) + { + $regexp = implode('|', $words); + return "({$column} REGEXP '{$regexp}')"; } + } ?> \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Vendor/TMysqlMetaDataInspector.php b/framework/Data/ActiveRecord/Vendor/TMysqlMetaDataInspector.php index 5e438e37..23c483d1 100644 --- a/framework/Data/ActiveRecord/Vendor/TMysqlMetaDataInspector.php +++ b/framework/Data/ActiveRecord/Vendor/TMysqlMetaDataInspector.php @@ -1,4 +1,4 @@ -createCommand($sql); $command->prepare(); foreach($command->query() as $col) - $cols[$col['Field']] = $this->getColumnMetaData($col); + $cols[strtolower($col['Field'])] = $this->getColumnMetaData($col); return $cols; } @@ -51,7 +51,8 @@ class TMysqlMetaDataInspector extends TDbMetaDataInspector $autoIncrement=is_int(strpos(strtolower($col['Extra']), 'auto_increment')); $default = $col['Default']; $primaryKey = $col['Key']==='PRI'; - return new TMysqlColumnMetaData($col['Field'],$name,$type,$notNull,$autoIncrement,$default,$primaryKey); + return new TMysqlColumnMetaData(strtolower($col['Field']),$name,$type, + $notNull,$autoIncrement,$default,$primaryKey); } /** diff --git a/framework/Data/ActiveRecord/Vendor/TPgsqlColumnMetaData.php b/framework/Data/ActiveRecord/Vendor/TPgsqlColumnMetaData.php index a51c435d..2774bb54 100644 --- a/framework/Data/ActiveRecord/Vendor/TPgsqlColumnMetaData.php +++ b/framework/Data/ActiveRecord/Vendor/TPgsqlColumnMetaData.php @@ -44,13 +44,30 @@ class TPgsqlColumnMetaData extends TComponent { $this->_property=$property; $this->_name=$name; - $this->_type=$type; $this->_length=$length; + $this->processType($type); $this->_notNull=$notNull; $this->_sequenceName=$serial; $this->_default=$default; } + protected function processType($type) + { + if(is_int($pos=strpos($type, '('))) + { + $match=array(); + if(preg_match('/\((.*)\)/', $type, $match)) + { + $this->_length=floatval($match[1]); + $this->_type = substr($type,0,$pos); + } + else + $this->_type = $type; + } + else + $this->_type = $type; + } + /** * @return string quoted column name. */ diff --git a/framework/Data/ActiveRecord/Vendor/TPgsqlMetaData.php b/framework/Data/ActiveRecord/Vendor/TPgsqlMetaData.php index d968267a..45e9c7e4 100644 --- a/framework/Data/ActiveRecord/Vendor/TPgsqlMetaData.php +++ b/framework/Data/ActiveRecord/Vendor/TPgsqlMetaData.php @@ -48,11 +48,31 @@ class TPgsqlMetaData extends TDbMetaDataCommon return strlen($sql) > 0 ? $sql : ''; } - protected function getOrdering($by, $direction) + public function getSearchRegExpCriteria($fields, $keywords) { - $dir = strtolower($direction) == 'desc' ? 'DESC' : 'ASC'; - return $this->getColumn($by)->getName(). ' '.$dir; + if(strlen(trim($keywords)) == 0) return ''; + $words = preg_split('/\s/', preg_quote($keywords, '\'')); + $result = array(); + foreach($fields as $field) + { + $column = $this->getColumn($field); + if($this->isSearchableColumn($column)) + $result[] = $this->getRegexpCriteriaStr($column->getName(), $words); + } + return '('.implode(' OR ', $result).')'; } + + protected function isSearchableColumn($column) + { + $type = strtolower($column->getType()); + return $type === 'character varying' || $type === 'varchar' || + $type === 'character' || $type === 'char' || $type === 'text'; + } + protected function getRegexpCriteriaStr($column, $words) + { + $regexp = implode('|', $words); + return "({$column} ~ '{$regexp}')"; + } } ?> \ No newline at end of file diff --git a/framework/Data/ActiveRecord/Vendor/TPgsqlMetaDataInspector.php b/framework/Data/ActiveRecord/Vendor/TPgsqlMetaDataInspector.php index 2f7202cf..16326353 100644 --- a/framework/Data/ActiveRecord/Vendor/TPgsqlMetaDataInspector.php +++ b/framework/Data/ActiveRecord/Vendor/TPgsqlMetaDataInspector.php @@ -130,7 +130,7 @@ EOD; $command->bindValue(':schema', $schema); $cols = array(); foreach($command->query() as $col) - $cols[$col['attname']] = $this->getColumnMetaData($schema,$col); + $cols[strtolower($col['attname'])] = $this->getColumnMetaData($schema,$col); return $cols; } @@ -148,19 +148,26 @@ EOD; // A specific constant in the 7.0 source, the length is offset by 4. $length = $col['atttypmod'] > 0 ? $col['atttypmod'] - 4 : null; $notNull = $col['attnotnull']; - $serial = $col['attisserial'] ? $schema.'.'.$this->getSerialName($col['adsrc']) : null; + $nextval_serial = substr($col['adsrc'],0,8) === 'nextval('; + $serial = $col['attisserial'] || $nextval_serial ? $this->getSerialName($schema,$col['adsrc']) : null; $default = $serial === null && $col['atthasdef'] ? $col['adsrc'] : null; - return new TPgsqlColumnMetaData($col['attname'],$name,$type,$length,$notNull,$serial,$default); + return new TPgsqlColumnMetaData(strtolower($col['attname']),$name, + $type,$length,$notNull,$serial,$default); } /** * @return string serial name if found, null otherwise. */ - protected function getSerialName($src) + protected function getSerialName($schema,$src) { $matches = array(); - if(preg_match('/nextval\(\'([^\']+)\'::regclass\)/i',$src,$matches)) - return $matches[1]; + if(preg_match('/nextval\([^\']*\'([^\']+)\'[^\)]*\)/i',$src,$matches)) + { + if(is_int(strpos($matches[1], '.'))) + return $matches[1]; + else + return $schema.'.'.$matches[1]; + } } /** diff --git a/framework/Data/ActiveRecord/Vendor/TSqliteMetaData.php b/framework/Data/ActiveRecord/Vendor/TSqliteMetaData.php index c82a99ad..c44d73cb 100644 --- a/framework/Data/ActiveRecord/Vendor/TSqliteMetaData.php +++ b/framework/Data/ActiveRecord/Vendor/TSqliteMetaData.php @@ -48,10 +48,23 @@ class TSqliteMetaData extends TDbMetaDataCommon return strlen($sql) > 0 ? $sql : ''; } - protected function getOrdering($by, $direction) + public function getSearchRegExpCriteria($fields, $keywords) { - $dir = strtolower($direction) == 'desc' ? 'DESC' : 'ASC'; - return $this->getColumn($by)->getName(). ' '.$dir; + if(strlen(trim($keywords)) == 0) return ''; + $words = array(); + preg_match_all('/([a-zA-Z0-9-+]+)/', $keywords, $words); + $result = array(); + foreach($fields as $field) + $result[] = $this->getLikeCriteriaStr($this->getColumn($field)->getName(), $words[0]); + return '('.implode(' OR ', $result).')'; + } + + protected function getLikeCriteriaStr($column, $words) + { + $result=array(); + foreach($words as $word) + $result[] = "({$column} LIKE \"%{$word}%\")"; + return '('.implode(' AND ', $result).')'; } /** diff --git a/framework/Data/ActiveRecord/Vendor/TSqliteMetaDataInspector.php b/framework/Data/ActiveRecord/Vendor/TSqliteMetaDataInspector.php index 3621c666..1d4599a8 100644 --- a/framework/Data/ActiveRecord/Vendor/TSqliteMetaDataInspector.php +++ b/framework/Data/ActiveRecord/Vendor/TSqliteMetaDataInspector.php @@ -55,7 +55,7 @@ class TSqliteMetaDataInspector extends TDbMetaDataInspector $command->prepare(); $cols = array(); foreach($command->query() as $col) - $cols[$col['name']] = $this->getColumnMetaData($col); + $cols[strtolower($col['name'])] = $this->getColumnMetaData($col); return $cols; } @@ -73,7 +73,8 @@ class TSqliteMetaDataInspector extends TDbMetaDataInspector $primary = $col['pk']==='1'; $autoIncrement = strtolower($type)==='integer' && $primary; $default = $col['dflt_value']; - return new TSqliteColumnMetaData($col['name'],$name,$type,$notNull,$autoIncrement,$default,$primary); + return new TSqliteColumnMetaData(strtolower($col['name']),$name,$type, + $notNull,$autoIncrement,$default,$primary); } /** -- cgit v1.2.3