summaryrefslogtreecommitdiff
path: root/framework/DataAccess/SQLMap
diff options
context:
space:
mode:
Diffstat (limited to 'framework/DataAccess/SQLMap')
-rw-r--r--framework/DataAccess/SQLMap/Configuration/TConfigDeserialize.php171
-rw-r--r--framework/DataAccess/SQLMap/Configuration/TDiscriminator.php86
-rw-r--r--framework/DataAccess/SQLMap/Configuration/TDomSqlMapBuilder.php481
-rw-r--r--framework/DataAccess/SQLMap/Configuration/TInlineParameterMapParser.php50
-rw-r--r--framework/DataAccess/SQLMap/Configuration/TParameterMap.php95
-rw-r--r--framework/DataAccess/SQLMap/Configuration/TParameterProperty.php68
-rw-r--r--framework/DataAccess/SQLMap/Configuration/TResultMap.php63
-rw-r--r--framework/DataAccess/SQLMap/Configuration/TResultProperty.php164
-rw-r--r--framework/DataAccess/SQLMap/Configuration/TSqlMapCacheModel.php131
-rw-r--r--framework/DataAccess/SQLMap/Configuration/TSqlMapDelete.php7
-rw-r--r--framework/DataAccess/SQLMap/Configuration/TSqlMapInsert.php15
-rw-r--r--framework/DataAccess/SQLMap/Configuration/TSqlMapSelect.php11
-rw-r--r--framework/DataAccess/SQLMap/Configuration/TSqlMapSelectKey.php26
-rw-r--r--framework/DataAccess/SQLMap/Configuration/TSqlMapStatement.php109
-rw-r--r--framework/DataAccess/SQLMap/Configuration/TSqlMapUpdate.php11
-rw-r--r--framework/DataAccess/SQLMap/DataMapper/TDataMapperException.php65
-rw-r--r--framework/DataAccess/SQLMap/DataMapper/TLazyLoadList.php87
-rw-r--r--framework/DataAccess/SQLMap/DataMapper/TPropertyAccess.php91
-rw-r--r--framework/DataAccess/SQLMap/DataMapper/TSqlMapCache.php165
-rw-r--r--framework/DataAccess/SQLMap/DataMapper/TSqlMapPagedList.php156
-rw-r--r--framework/DataAccess/SQLMap/DataMapper/TTypeHandlerFactory.php134
-rw-r--r--framework/DataAccess/SQLMap/DataMapper/messages.txt61
-rw-r--r--framework/DataAccess/SQLMap/Statements/IMappedStatement.php71
-rw-r--r--framework/DataAccess/SQLMap/Statements/TCachingStatement.php102
-rw-r--r--framework/DataAccess/SQLMap/Statements/TDeleteMappedStatement.php7
-rw-r--r--framework/DataAccess/SQLMap/Statements/TInsertMappedStatement.php32
-rw-r--r--framework/DataAccess/SQLMap/Statements/TMappedStatement.php988
-rw-r--r--framework/DataAccess/SQLMap/Statements/TPreparedCommand.php60
-rw-r--r--framework/DataAccess/SQLMap/Statements/TPreparedStatement.php26
-rw-r--r--framework/DataAccess/SQLMap/Statements/TPreparedStatementFactory.php47
-rw-r--r--framework/DataAccess/SQLMap/Statements/TSelectMappedStatement.php19
-rw-r--r--framework/DataAccess/SQLMap/Statements/TStaticSql.php19
-rw-r--r--framework/DataAccess/SQLMap/Statements/TUpdateMappedStatement.php32
-rw-r--r--framework/DataAccess/SQLMap/TMapper.php60
-rw-r--r--framework/DataAccess/SQLMap/TSqlMapClient.php81
-rw-r--r--framework/DataAccess/SQLMap/TSqlMapper.php543
36 files changed, 4334 insertions, 0 deletions
diff --git a/framework/DataAccess/SQLMap/Configuration/TConfigDeserialize.php b/framework/DataAccess/SQLMap/Configuration/TConfigDeserialize.php
new file mode 100644
index 00000000..250133b9
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Configuration/TConfigDeserialize.php
@@ -0,0 +1,171 @@
+<?php
+
+class TConfigDeserialize
+{
+ private $_properties;
+
+ public function __construct($properties)
+ {
+ $this->_properties = $properties;
+ }
+
+ public function loadConfiguration($object, $node, $file)
+ {
+ foreach($node->attributes() as $k=>$v)
+ {
+ if($object->canSetProperty($k))
+ $object->{'set'.$k}($this->replaceProperties((string)($v)));
+ else
+ throw new TUndefinedAttributeException($k,$node,$object,$file);
+ }
+ }
+
+ public function replaceProperties($string)
+ {
+ foreach($this->_properties as $find => $replace)
+ $string = str_replace('${'.$find.'}', $replace, $string);
+ return $string;
+ }
+
+ public function parameterMap($node, $sqlMap, $file)
+ {
+ $parameterMap = new TParameterMap;
+ $this->loadConfiguration($parameterMap, $node, $file);
+ foreach($node->parameter as $parameter)
+ {
+ $property = $this->parameterProperty($parameter, $sqlMap, $file);
+ $property->initialize($sqlMap);
+ $parameterMap->addParameterProperty($property);
+ }
+ return $parameterMap;
+ }
+
+ public function parameterProperty($node, $sqlMap, $file)
+ {
+ $property = new TParameterProperty;
+ $this->loadConfiguration($property, $node, $file);
+ return $property;
+ }
+
+ public function select($node, $sqlMap, $file)
+ {
+ $select = new TSqlMapSelect;
+ $this->loadConfiguration($select, $node, $file);
+ $select->initialize($sqlMap);
+ return $select;
+ }
+
+ public function update($node, $sqlMap, $file)
+ {
+ $update = new TSqlMapUpdate;
+ $this->loadConfiguration($update, $node, $file);
+ $update->initialize($sqlMap);
+ return $update;
+ }
+
+ public function delete($node, $sqlMap, $file)
+ {
+ $delete = new TSqlMapDelete;
+ $this->loadConfiguration($delete, $node, $file);
+ $delete->initialize($sqlMap);
+ return $delete;
+ }
+
+
+ public function insert($node, $sqlMap, $file)
+ {
+ $insert = new TSqlMapInsert;
+ $this->loadConfiguration($insert, $node, $file);
+ if(isset($node->selectKey))
+ {
+ $selectKey = new TSqlMapSelectKey;
+ $this->loadConfiguration($selectKey, $node->selectKey, $file);
+ $type = $selectKey->getType();
+ $selectKey->setType(strtolower($type) == 'post' ? 'post' : 'pre');
+ $insert->setSelectKey($selectKey);
+ }
+ if(isset($node->generate))
+ {
+ var_dump("add generate");
+ }
+
+ $insert->initialize($sqlMap);
+ return $insert;
+ }
+
+ public function statement($node, $sqlMap, $file)
+ {
+ $statement = new TSqlMapStatement;
+ $this->loadConfiguration($statement, $node, $file);
+ $statement->initialize($sqlMap);
+ return $statement;
+ }
+
+ public function resultMap($node, $sqlMap, $file)
+ {
+ $resultMap = new TResultMap;
+ $this->loadConfiguration($resultMap, $node, $file);
+ foreach($node->result as $result)
+ {
+ $property = $this->resultProperty($result, $sqlMap, $file);
+ $property->initialize($sqlMap, $resultMap);
+ $resultMap->addResultProperty($property);
+ }
+ $discriminator = null;
+ if(isset($node->discriminator))
+ {
+ $discriminator = new TDiscriminator;
+ $this->loadConfiguration($discriminator, $node->discriminator, $file);
+ $discriminator->initMapping($sqlMap, $resultMap);
+ }
+ foreach($node->subMap as $subMapNode)
+ {
+ if(is_null($discriminator))
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_undefined_discriminator', $resultMap->getID(), $file);
+ $subMap = new TSubMap;
+ $this->loadConfiguration($subMap, $subMapNode, $file);
+ $discriminator->add($subMap);
+ }
+ if(!is_null($discriminator))
+ $resultMap->setDiscriminator($discriminator);
+
+ return $resultMap;
+ }
+
+ public function resultProperty($node, $sqlMap, $file)
+ {
+ $resultProperty = new TResultProperty;
+ $this->loadConfiguration($resultProperty, $node, $file);
+ return $resultProperty;
+ }
+
+ public function cacheModel($node, $sqlMap, $file)
+ {
+ $cacheModel = new TSqlMapCacheModel;
+ $this->loadConfiguration($cacheModel, $node, $file);
+ if(isset($node->flushInterval))
+ {
+ $interval = $node->flushInterval;
+ $span = 0; //span in seconds
+ if(isset($interval['hours']))
+ $span += intval($interval['hours'])*60*60;
+ if(isset($interval['minutes']))
+ $span += intval($interval['minutes'])*60;
+ if(isset($interval['seconds']))
+ $span += intval($interval['seconds']);
+ if($span > 0)
+ $cacheModel->setFlushInterval($span);
+ }
+ if(isset($node->property))
+ {
+ foreach($node->property as $property)
+ $cacheModel->addProperty((string)$property['name'],
+ (string)$property['value']);
+ }
+ return $cacheModel;
+ }
+}
+
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Configuration/TDiscriminator.php b/framework/DataAccess/SQLMap/Configuration/TDiscriminator.php
new file mode 100644
index 00000000..0ee34e3e
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Configuration/TDiscriminator.php
@@ -0,0 +1,86 @@
+<?php
+
+class TDiscriminator extends TComponent
+{
+ private $_column='';
+ private $_type='';
+ private $_typeHandler=null;
+ private $_dbType='';
+ private $_columnIndex='';
+ private $_nullValue='';
+ private $_mapping='';
+ private $_resultMaps=array();
+ private $_subMaps=array();
+
+ public function getColumn(){ return $this->_column; }
+ public function setColumn($value){ $this->_column = $value; }
+
+ public function getType(){ return $this->_type; }
+ public function setType($value){ $this->_type = $value; }
+
+ public function getTypeHandler(){ return $this->_typeHandler; }
+ public function setTypeHandler($value){ $this->_typeHandler = $value; }
+
+ public function getDbType(){ return $this->_dbType; }
+ public function setDbType($value){ $this->_dbType = $value; }
+
+ public function getColumnIndex(){ return $this->_columnIndex; }
+ public function setColumnIndex($value){ $this->_columnIndex = $value; }
+
+ public function getNullValue(){ return $this->_nullValue; }
+ public function setNullValue($value){ $this->_nullValue = $value; }
+
+ public function getMapping(){ return $this->_mapping; }
+
+ public function getResultMaps(){ return $this->_resultMaps; }
+ public function setResultMaps($value){ $this->_resultMaps = $value; }
+
+ public function add($subMap)
+ {
+ $this->_subMaps[] = $subMap;
+ }
+
+ public function getSubMap($value)
+ {
+ if(isset($this->_resultMaps[$value]))
+ return $this->_resultMaps[$value];
+ else
+ return null;
+ }
+
+ public function initMapping($sqlMap, $resultMap)
+ {
+ $this->_mapping = new TResultProperty;
+ $this->_mapping->setColumn($this->getColumn());
+ $this->_mapping->setColumnIndex($this->getColumnIndex());
+ $this->_mapping->setType($this->getType());
+ $this->_mapping->setTypeHandler($this->getTypeHandler());
+ $this->_mapping->setDbType($this->getDbType());
+ $this->_mapping->setNullValue($this->getNullValue());
+ $this->_mapping->initialize($sqlMap, $resultMap);
+ }
+
+ public function initialize($sqlMap)
+ {
+ foreach($this->_subMaps as $subMap)
+ {
+ $this->_resultMaps[$subMap->getValue()] =
+ $sqlMap->getResultMap($subMap->getResultMapping());
+ }
+ }
+}
+
+
+class TSubMap extends TComponent
+{
+ private $_value='';
+ private $_resultMapping='';
+
+ public function getValue(){ return $this->_value; }
+ public function setValue($value){ $this->_value = $value; }
+
+ public function getResultMapping(){ return $this->_resultMapping; }
+ public function setResultMapping($value){ $this->_resultMapping = $value; }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Configuration/TDomSqlMapBuilder.php b/framework/DataAccess/SQLMap/Configuration/TDomSqlMapBuilder.php
new file mode 100644
index 00000000..d3059dd7
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Configuration/TDomSqlMapBuilder.php
@@ -0,0 +1,481 @@
+<?php
+
+class TDomSqlMapBuilder
+{
+ const DEFAULT_CONFIG_FILE = 'sqlmap.xml';
+
+ private $_document;
+
+ private $_sqlMapper;
+
+ private $_configFile;
+
+ private $_properties;
+
+ private $_deserialize;
+
+ private $_useNamespaces = false;
+
+ private $_FlushOnExecuteStatements=array();
+
+ public function __construct($cachedir='./cache')
+ {
+ $this->_properties = new TMap;
+ $this->_deserialize = new TConfigDeserialize($this->_properties);
+ }
+
+ public function configure($resource=null)
+ {
+ if($resource instanceof SimpleXMLElement)
+ return $this->build($resource);
+
+ if(!is_string($resource))
+ $resource = self::DEFAULT_CONFIG_FILE;
+
+ $this->_configFile = $resource;
+ if(!is_file($resource))
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_unable_to_find_config', $resource);
+
+ return $this->build($this->getConfigAsXmlDocument($resource));
+ }
+
+ protected function getConfigAsXmlDocument($file)
+ {
+ return simplexml_load_file($file);
+ }
+
+ public function build(SimpleXMLElement $document)
+ {
+ $this->_document = $document;
+ $this->initialize($document);
+ return $this->_sqlMapper;
+ }
+
+ protected function initialize($document)
+ {
+ $this->_sqlMapper = new TSqlMapper(new TTypeHandlerFactory);
+
+ if(isset($document->properties))
+ {
+ $this->loadGlobalProperties($document->properties);
+ }
+
+ if(isset($document->settings) && isset($document->settings->setting))
+ $this->configureSettings($document->settings);
+
+ //load database provider
+ if(isset($document->provider) && isset($document->provider->datasource))
+ {
+ $this->loadProvider($document->provider,
+ $document->provider->datasource, $document, $this->_configFile);
+ }
+ else
+ {
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_unable_to_find_db_config', $this->_configFile);
+ }
+
+ if(isset($document->sqlMaps) && isset($document->sqlMaps->sqlMap))
+ $this->loadSqlMappingFiles($document->sqlMaps);
+
+ if($this->_sqlMapper->getIsCacheModelsEnabled())
+ $this->attachCacheModel();
+ }
+
+ protected function configureSettings($node)
+ {
+ foreach($node->setting as $setting)
+ {
+ if(isset($setting['useStatementNamespaces']))
+ {
+ $this->_useNamespaces =
+ TPropertyValue::ensureBoolean(
+ (string)$setting['useStatementNamespaces']);
+ }
+
+ if(isset($setting['cacheModelsEnabled']))
+ {
+ $this->_sqlMapper->setCacheModelsEnabled(
+ TPropertyValue::ensureBoolean(
+ (string)$setting['cacheModelsEnabled']));
+ }
+ }
+ }
+
+ /**
+ * Attach CacheModel to statement and register trigger statements for
+ * cache models
+ */
+ protected function attachCacheModel()
+ {
+ foreach($this->_sqlMapper->getStatements() as $mappedStatement)
+ {
+ if(strlen($model = $mappedStatement->getStatement()->getCacheModel()) > 0)
+ {
+ $cache = $this->_sqlMapper->getCache($model);
+ //var_dump($model);
+ $mappedStatement->getStatement()->setCache($cache);
+ }
+ }
+
+ foreach($this->_FlushOnExecuteStatements as $cacheID => $statementIDs)
+ {
+ if(count($statementIDs) > 0)
+ {
+ foreach($statementIDs as $statementID)
+ {
+ $cacheModel = $this->_sqlMapper->getCache($cacheID);
+ $statement = $this->_sqlMapper->getMappedStatement($statementID);
+ $cacheModel->registerTriggerStatement($statement);
+ }
+ }
+ }
+ }
+
+ protected function loadGlobalProperties($node)
+ {
+ if(isset($node['resource']))
+ $this->loadPropertyResource($node);
+
+ foreach($node->children() as $child)
+ {
+ if(isset($child['resource']))
+ $this->loadPropertyResource($child);
+ $this->_properties[(string)$child['key']] = (string)$child['value'];
+ }
+ }
+
+ protected function loadPropertyResource($node)
+ {
+ $resource = $this->getResourceFromPath((string)$node['resource']);
+ $properties = $this->getConfigAsXmlDocument($resource);
+ $this->loadGlobalProperties($properties);
+ }
+
+ protected function loadProvider($providerNode, $node, $document, $file)
+ {
+ //$id = (string)$node['id'];
+ $class = (string)$providerNode['class'];
+ if(strlen($class) > 0 && class_exists($class,false))
+ {
+ $provider = new $class;
+ $this->_deserialize->loadConfiguration($provider, $node,$file);
+ $this->_sqlMapper->setDataProvider($provider);
+ }
+ else
+ {
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_unable_find_provider_class', $file);
+ }
+ //var_dump($node);
+ }
+/*
+ protected function loadTypeHandlers()
+ {
+ }
+*/
+ protected function loadSqlMappingFiles($sqlmappings)
+ {
+ foreach($sqlmappings->sqlMap as $node)
+ {
+ $resource = $this->getResourceFromPath((string)$node['resource']);
+ $sqlmap = $this->getConfigAsXmlDocument($resource);
+ $this->configureSqlMap($sqlmap,$resource);
+ }
+
+ $this->resolveResultMapping();
+ }
+
+ protected function getResourceFromPath($resource)
+ {
+ $basedir = dirname($this->_configFile);
+ $file = realpath($basedir.'/'.$resource);
+ if(!is_string($file) || !is_file($file))
+ $file = realpath($resource);
+ if(is_string($file) && is_file($file))
+ return $file;
+ else
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_unable_to_find_resource', $resource);
+ }
+
+ protected function configureSqlMap($document,$file)
+ {
+ // if(isset($document->typeAlias))
+ // foreach($document->typeAlias as $node)
+ // TTypeAliasDeSerializer::Deserialize($node, $this->_sqlMapper);
+ if(isset($document->resultMap))
+ foreach($document->resultMap as $node)
+ $this->loadResultMap($node,$document,$file);
+ if(isset($document->parameterMap))
+ foreach($document->parameterMap as $node)
+ $this->loadParameterMap($node, $document, $file);
+ if(isset($document->statement))
+ foreach($document->statement as $node)
+ $this->loadStatementTag($node, $document,$file);
+ if(isset($document->select))
+ foreach($document->select as $node)
+ $this->loadSelectTag($node, $document, $file);
+ if(isset($document->insert))
+ foreach($document->insert as $node)
+ $this->loadInsertTag($node, $document, $file);
+ if(isset($document->update))
+ foreach($document->update as $node)
+ $this->loadUpdateTag($node, $document, $file);
+ if(isset($document->delete))
+ foreach($document->delete as $node)
+ $this->loadDeleteTag($node, $document, $file);
+/* if(isset($document->procedure))
+ foreach($document->procedure as $node)
+ $this->loadProcedureTag($node);
+*/
+ if($this->_sqlMapper->getIsCacheModelsEnabled())
+ {
+ if(isset($document->cacheModel))
+ foreach($document->cacheModel as $node)
+ $this->loadCacheModel($node, $document, $file);
+ }
+ }
+
+ protected function loadCacheModel($node, $document, $file)
+ {
+ $cacheModel = $this->_deserialize->cacheModel($node, $this->_sqlMapper, $file);
+ if(isset($node->flushOnExecute))
+ {
+ foreach($node->flushOnExecute as $flush)
+ {
+ $id = $cacheModel->getID();
+ if(!isset($this->_FlushOnExecuteStatements[$id]))
+ $this->_FlushOnExecuteStatements[$id] = array();
+
+ $this->_FlushOnExecuteStatements[$id][] = (string)$flush['statement'];
+ }
+ }
+ //var_dump($cacheModel);
+ $cacheModel->initialize($this->_sqlMapper);
+ $this->_sqlMapper->addCache($cacheModel);
+ }
+
+ protected function loadUpdateTag($node, $document, $file)
+ {
+ $update = $this->_deserialize->insert($node, $this->_sqlMapper, $file);
+ if(!is_null($update->getGenerate()))
+ {
+ var_dump('generate update');
+ }
+ else
+ {
+ $this->processSqlStatement($update, $document, $node, $file);
+ }
+ $mappedStatement = new TUpdateMappedStatement($this->_sqlMapper, $update);
+ $this->_sqlMapper->addMappedStatement($mappedStatement);
+ }
+
+ protected function loadDeleteTag($node, $document, $file)
+ {
+ $delete = $this->_deserialize->delete($node, $this->_sqlMapper, $file);
+ if(!is_null($delete->getGenerate()))
+ {
+ var_dump('generate delete');
+ }
+ else
+ {
+ $this->processSqlStatement($delete, $document, $node, $file);
+ }
+ $mappedStatement = new TDeleteMappedStatement($this->_sqlMapper, $delete);
+ $this->_sqlMapper->addMappedStatement($mappedStatement);
+ }
+
+
+ protected function loadParameterMap($node, $document, $file)
+ {
+ $id = (string)$node['id'];
+ if($this->_sqlMapper->getParameterMaps()->contains($id))
+ return;
+ $parameterMap = $this->_deserialize->parameterMap($node, $this->_sqlMapper, $file);
+ $extendMap = $parameterMap->getExtends();
+ if(strlen($extendMap) > 0)
+ {
+ if($this->_sqlMapper->getParameterMaps()->contains($extendMap) == false)
+ {
+ $nodes = $document->xpath("//parameterMap[@id='{$extendMap}']");
+ if(isset($nodes[0]))
+ $this->loadParameterMap($nodes[0],$document,$file);
+ else
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_unable_to_find_parent_parameter_map', $extendMap, $file);
+ }
+ $superMap = $this->_sqlMapper->getParameterMap($extendMap);
+ $index = 0;
+ foreach($superMap->getPropertyNames() as $propertyName)
+ {
+ $parameterMap->insertParameterProperty($index++,
+ $superMap->getProperty($propertyName));
+ }
+ }
+ $this->_sqlMapper->addParameterMap($parameterMap);
+ }
+
+ protected function loadInsertTag($node, $document, $file)
+ {
+ $insert = $this->_deserialize->insert($node, $this->_sqlMapper, $file);
+ if(!is_null($insert->getGenerate()))
+ {
+ var_dump("generate insert");
+ }
+ else
+ {
+ $this->processSqlStatement($insert, $document, $node, $file);
+ }
+
+ $mappedStatement = new TInsertMappedStatement($this->_sqlMapper, $insert);
+ $this->_sqlMapper->addMappedStatement($mappedStatement);
+ if(!is_null($insert->getSelectKey()))
+ {
+ $selectKey = $insert->getSelectKey();
+ $selectKey->setID($insert->getID());
+ $selectKey->initialize($this->_sqlMapper);
+ $selectKey->setID($insert->getID().'.SelectKey');
+ $this->processSqlStatement($selectKey,
+ $document, $node->selectKey, $file);
+ $mappedStatement = new TMappedStatement($this->_sqlMapper, $selectKey);
+ $this->_sqlMapper->addMappedStatement($mappedStatement);
+ }
+ }
+
+ protected function processSqlStatement($statement, $document, $node, $file)
+ {
+ $commandText = (string)$node;
+ if(strlen($extend = $statement->getExtends()) > 0)
+ {
+ $superNodes = $document->xpath("//*[@id='{$extend}']");
+ if(isset($superNodes[0]))
+ $commandText = (string)$superNodes[0] . $commandText;
+ else
+ throw TSqlMapConfigurationException(
+ 'sqlmap_unable_to_find_parent_sql', $extend, $file);
+ }
+
+ //$sql = new TStaticSql();
+ //$sql->buildPreparedStatement($statement, (string)$node);
+ $commandText = $this->_deserialize->replaceProperties($commandText);
+ $this->applyInlineParameterMap($statement, $commandText, $node, $file);
+ //$statement->setSql($sql);
+ }
+
+ protected function applyInlineParameterMap($statement, $sqlStatement, $node, $file)
+ {
+ if($statement->parameterMap() == null)
+ {
+ $scope['statement'] = $statement->getID();
+ $scope['file'] = $file;
+
+ // Build a Parametermap with the inline parameters.
+ // if they exist. Then delete inline infos from sqltext.
+ $parameterParser = new TInlineParameterMapParser;
+ $sqlText = $parameterParser->parseInlineParameterMap(
+ $this->_sqlMapper, $statement, $sqlStatement, $scope);
+ if(count($sqlText['parameters']) > 0)
+ {
+ $map = new TParameterMap();
+ $map->setID($statement->getID().'-InLineParameterMap');
+ $statement->setInlineParameterMap($map);
+ foreach($sqlText['parameters'] as $property)
+ $map->addParameterProperty($property);
+ }
+ $sqlStatement = $sqlText['sql'];
+ }
+ $sql = new TStaticSql();
+ $sql->buildPreparedStatement($statement, $sqlStatement);
+ $statement->setSql($sql);
+ }
+
+ protected function resolveResultMapping()
+ {
+ $maps = $this->_sqlMapper->getResultMaps();
+ foreach($maps as $entry)
+ {
+ foreach($entry->getColumns() as $item)
+ {
+ $resultMap = $item->getResultMapping();
+ if(strlen($resultMap) > 0)
+ {
+ if($maps->contains($resultMap))
+ $item->setNestedResultMap($maps[$resultMap]);
+ else
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_unable_to_find_result_mapping',
+ $resultMap, $this->_configFile, $entry->getID());
+ }
+ }
+ if(!is_null($entry->getDiscriminator()))
+ {
+ $entry->getDiscriminator()->initialize($this->_sqlMapper);
+ }
+ }
+ }
+
+ protected function loadSelectTag($node, $document, $file)
+ {
+ $select = $this->_deserialize->select($node, $this->_sqlMapper, $file);
+ if(!is_null($select->getGenerate()))
+ {
+ var_dump("generate select");
+ }
+ else
+ {
+ $this->processSqlStatement($select, $document, $node, $file);
+ /*$sql = new TStaticSql();
+ $sql->buildPreparedStatement($select, (string)$node);
+ $select->setSql($sql);*/
+ }
+
+ $mappedStatement = new TMappedStatement($this->_sqlMapper, $select);
+ if($this->_sqlMapper->getIsCacheModelsEnabled() &&
+ strlen($select->getCacheModel()) > 0)
+ {
+ $mappedStatement = new TCachingStatement($mappedStatement);
+ }
+
+ $this->_sqlMapper->addMappedStatement($mappedStatement);
+ }
+
+ protected function loadResultMap($node,$document,$file)
+ {
+ $resultMap = $this->_deserialize->resultMap($node, $this->_sqlMapper,$file);
+ $extendMap = $resultMap->getExtends();
+ if(strlen($extendMap) > 0)
+ {
+ if(!$this->_sqlMapper->getResultMaps()->contains($extendMap))
+ {
+ $nodes = $document->xpath("//resultMap[@id='{$extendMap}']");
+ if(isset($nodes[0]))
+ $this->loadResultMap($nodes[0],$document,$file);
+ else
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_unable_to_find_parent_result_map', $extendMap, $file);
+ }
+ $superMap = $this->_sqlMapper->getResultMap($extendMap);
+ $resultMap->getColumns()->mergeWith($superMap->getColumns());
+ }
+ if(!$this->_sqlMapper->getResultMaps()->contains($resultMap->getID()))
+ $this->_sqlMapper->addResultMap($resultMap);
+ }
+
+
+ protected function loadStatementTag($node, $document, $file)
+ {
+ $statement = $this->_deserialize->statement($node, $this->_sqlMapper, $file);
+
+ /*$sql = new TStaticSql();
+ $sql->buildPreparedStatement($statement, (string)$node);
+ $statement->setSql($sql);*/
+ $this->processSqlStatement($statement, $document, $node, $file);
+
+ $mappedStatement = new TMappedStatement($this->_sqlMapper, $statement);
+ $this->_sqlMapper->addMappedStatement($mappedStatement);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Configuration/TInlineParameterMapParser.php b/framework/DataAccess/SQLMap/Configuration/TInlineParameterMapParser.php
new file mode 100644
index 00000000..8b1ecf04
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Configuration/TInlineParameterMapParser.php
@@ -0,0 +1,50 @@
+<?php
+
+class TInlineParameterMapParser
+{
+ private $PARAMETER_TOKEN_REGEXP = '/#(#?[^#]+#?)#/';
+
+ public function parseInlineParameterMap($sqlMap, $statement, $sqlText, $scope)
+ {
+ $parameterClass = !is_null($statement)
+ ? $statement->getParameterClass() : null;
+ $matches = array();
+ $mappings = array();
+ preg_match_all($this->PARAMETER_TOKEN_REGEXP, $sqlText, $matches);
+
+ for($i = 0, $k=count($matches[1]); $i<$k; $i++)
+ {
+ $mappings[] = $this->parseMapping($matches[1][$i],
+ $parameterClass, $sqlMap, $scope);
+ $sqlText = str_replace($matches[0][$i], '?', $sqlText);
+ }
+ return array('sql'=>$sqlText, 'parameters'=>$mappings);
+ }
+
+ /**
+ * Parse inline parameter with syntax as
+ * #propertyName,type=string,dbype=Varchar,nullValue=N/A,handler=string#
+ */
+ protected function parseMapping($token, $parameterClass, $sqlMap, $scope)
+ {
+ $mapping = new TParameterProperty;
+ $properties = explode(',', $token);
+ $mapping->setProperty(trim(array_shift($properties)));
+ //var_dump($properties);
+ foreach($properties as $property)
+ {
+ $prop = explode('=',$property);
+ $name = trim($prop[0]); $value=trim($prop[1]);
+ if($mapping->canSetProperty($name))
+ $mapping->{'set'.$name}($value);
+ else
+ throw new TSqlMapUndefinedException(
+ 'sqlmap_undefined_property_inline_map',
+ $name, $scope['statement'], $scope['file']);
+ }
+ $mapping->initialize($sqlMap);
+ return $mapping;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Configuration/TParameterMap.php b/framework/DataAccess/SQLMap/Configuration/TParameterMap.php
new file mode 100644
index 00000000..8e1c757d
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Configuration/TParameterMap.php
@@ -0,0 +1,95 @@
+<?php
+
+class TParameterMap extends TComponent
+{
+ private $_ID='';
+ private $_extend='';
+ private $_properties;
+ private $_propertyMap;
+ private $_extendMap;
+
+ public function __construct()
+ {
+ $this->_properties = new TList;
+ $this->_propertyMap = new TMap;
+ }
+
+ public function getProperties(){ return $this->_properties; }
+
+ public function getID(){ return $this->_ID; }
+ public function setID($value){ $this->_ID = $value; }
+
+ public function getExtends(){ return $this->_extend; }
+ public function setExtends($value){ $this->_extend = $value; }
+
+ public function getProperty($index)
+ {
+ if(is_string($index))
+ return $this->_propertyMap->itemAt($index);
+ else if(is_int($index))
+ return $this->_properties->itemAt($index);
+ else
+ throw new TDataMapperException(
+ 'sqlmap_index_must_be_string_or_int', $index);
+ }
+
+ public function addParameterProperty(TParameterProperty $property)
+ {
+ $this->_propertyMap->add($property->getProperty(), $property);
+ $this->_properties->add($property);
+ }
+
+ public function insertParameterProperty($index, TParameterProperty $property)
+ {
+ $this->_propertyMap->add($property->getProperty(), $property);
+ $this->_properties->insertAt($index, $property);
+ }
+
+ public function getPropertyNames()
+ {
+ return $this->_propertyMap->getKeys();
+ }
+
+ public function getParameter($mapping, $parameterValue, $statement)
+ {
+ $value = $parameterValue;
+ $typeHandler = $mapping->getTypeHandler();
+ try
+ {
+ $value = TPropertyAccess::get($parameterValue, $mapping->getProperty());
+ }
+ catch (TInvalidPropertyException $e)
+ {
+ throw new TSqlMapExecutionException(
+ 'sqlmap_unable_to_get_property_for_parameter',$this->getID(),
+ $mapping->getProperty(), get_class($parameterValue),
+ $e->getMessage(), $statement->getID());
+ }
+
+ if(!is_null($typeHandler))
+ {
+ try
+ {
+ $value = $typeHandler->getParameter($value);
+ }
+ catch (Exception $e)
+ {
+ throw new TSqlMapExecutionException(
+ 'sqlmap_error_in_parameter_from_handler',$this->getID(),
+ $value, get_class($typeHandler), $e->getMessage());
+ }
+ }
+
+ if(!is_null($nullValue = $mapping->getNullValue()))
+ {
+ if($nullValue === $value)
+ $value = null;
+ }
+
+ if(!is_null($type = $mapping->getType()))
+ $value = TTypeHandlerFactory::convertToType($type, $value);
+
+ return $value;
+ }
+}
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Configuration/TParameterProperty.php b/framework/DataAccess/SQLMap/Configuration/TParameterProperty.php
new file mode 100644
index 00000000..2ff55f73
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Configuration/TParameterProperty.php
@@ -0,0 +1,68 @@
+<?php
+
+class TParameterProperty extends TComponent
+{
+ private $_typeHandler=null;
+ private $_type=null;
+ private $_column='';
+ private $_dbType='';
+ private $_property='';
+ private $_nullValue=null;
+ private $_typeHandlerFactory;
+
+ private $_size;
+ private $_precision;
+ private $_scale;
+ private $_direction;
+
+ public function getTypeHandler()
+ {
+ if(is_null($this->_typeHandlerFactory)) return null;
+ if(!is_null($this->_typeHandler))
+ return $this->_typeHandlerFactory->getTypeHandler($this->_typeHandler);
+ else if(!is_null($this->getType()))
+ return $this->_typeHandlerFactory->getTypeHandler($this->getType());
+ else
+ return null;
+ }
+ public function setTypeHandler($value){ $this->_typeHandler = $value; }
+
+ public function getType(){ return $this->_type; }
+ public function setType($value){ $this->_type = $value; }
+
+ public function getColumn(){ return $this->_column; }
+ public function setColumn($value){ $this->_column = $value; }
+
+ public function getDbType(){ return $this->_dbType; }
+ public function setDbType($value){ $this->_dbType = $value; }
+
+ public function getProperty(){ return $this->_property; }
+ public function setProperty($value){ $this->_property = $value; }
+
+ public function getNullValue(){ return $this->_nullValue; }
+ public function setNullValue($value){ $this->_nullValue = $value; }
+
+ public function getSize(){ return $this->_size; }
+ public function setSize($value){ $this->_size = $value; }
+
+ public function getPrecision(){ return $this->_precision; }
+ public function setPrecision($value){ $this->_precision = $value; }
+
+ public function getScale(){ return $this->_scale; }
+ public function setScale($value){ $this->_scale = $value; }
+
+
+ public function getDirection(){ return $this->_direction; }
+ public function setDirection($value){ $this->_direction = $value; }
+
+ public function initialize($sqlMap)
+ {
+ $this->_typeHandlerFactory = $sqlMap->getTypeHandlerFactory();
+ // $type = !is_null($this->_typeHandler) ? $this->_typeHandler: $this->_type;
+ // $this->setTypeHandler($sqlMap->getTypeHandlerFactory()->getTypeHandler($type));
+ // if(!is_null($type))
+ // var_dump($sqlMap->getTypeHandlerFactory());
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Configuration/TResultMap.php b/framework/DataAccess/SQLMap/Configuration/TResultMap.php
new file mode 100644
index 00000000..0f09a1ba
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Configuration/TResultMap.php
@@ -0,0 +1,63 @@
+<?php
+
+class TResultMap extends TComponent
+{
+ private $_ID='';
+ private $_className='';
+ private $_columns='';
+ private $_extendMap='';
+ private $_groupBy='';
+ private $_discriminator=null;
+
+ public function __construct()
+ {
+ $this->_columns = new TMap;
+ }
+
+ public function getID(){ return $this->_ID; }
+ public function setID($value){ $this->_ID = $value; }
+
+ public function getClass(){ return $this->_className; }
+ public function setClass($value){ $this->_className = $value; }
+
+ public function getColumns(){ return $this->_columns; }
+ public function setColumns($value){ $this->_columns = $value; }
+
+ public function getExtends(){ return $this->_extendMap; }
+ public function setExtends($value){ $this->_extendMap = $value; }
+
+ public function getGroupBy(){ return $this->_groupBy; }
+ public function setGroupBy($value){ $this->_groupBy = $value; }
+
+ public function getDiscriminator(){ return $this->_discriminator; }
+ public function setDiscriminator($value){ $this->_discriminator = $value; }
+
+ public function addResultProperty(TResultProperty $property)
+ {
+ $this->_columns->add($property->getProperty(), $property);
+ }
+
+ public function createInstanceOfResult()
+ {
+ return TTypeHandlerFactory::createInstanceOf($this->getClass());
+ }
+
+ public function resolveSubMap($row)
+ {
+ $subMap = $this;
+ if(!is_null($disc = $this->getDiscriminator()))
+ {
+ $mapping = $disc->getMapping();
+ $dataValue = $mapping->getDatabaseValue($row);
+ $subMap = $disc->getSubMap((string)$dataValue);
+
+ if(is_null($subMap))
+ $subMap = $this;
+ else if($subMap !== $this)
+ $subMap = $subMap->resolveSubMap($row);
+ }
+ return $subMap;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Configuration/TResultProperty.php b/framework/DataAccess/SQLMap/Configuration/TResultProperty.php
new file mode 100644
index 00000000..9cc0df3a
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Configuration/TResultProperty.php
@@ -0,0 +1,164 @@
+<?php
+
+class TResultProperty extends TComponent
+{
+ private $_nullValue=null;
+ private $_propertyName='';
+ private $_columnName='';
+ private $_columnIndex=-1;
+ private $_nestedResultMapName='';
+ private $_nestedResultMap=null;
+ private $_valueType=null;
+ private $_typeHandler=null;
+ private $_isLazyLoad=false;
+ private $_select='';
+ private $_dbType='';
+ private $_typeHandlerFactory;
+ private $_hostResultMapID='inplicit internal mapping';
+
+ const LIST_TYPE = 0;
+ const ARRAY_TYPE = 1;
+ const OBJECT_TYPE = 2;
+
+ public function getNullValue(){ return $this->_nullValue; }
+ public function setNullValue($value){ $this->_nullValue = $value; }
+
+ public function getProperty(){ return $this->_propertyName; }
+ public function setProperty($value){ $this->_propertyName = $value; }
+
+ public function getColumn(){ return $this->_columnName; }
+ public function setColumn($value){ $this->_columnName = $value; }
+
+ public function getColumnIndex(){ return $this->_columnIndex; }
+ public function setColumnIndex($value){ $this->_columnIndex = TPropertyValue::ensureInteger($value,-1); }
+
+ public function getResultMapping(){ return $this->_nestedResultMapName; }
+ public function setResultMapping($value){ $this->_nestedResultMapName = $value; }
+
+ public function getNestedResultMap(){ return $this->_nestedResultMap; }
+ public function setNestedResultMap($value){ $this->_nestedResultMap = $value; }
+
+ public function getType(){ return $this->_valueType; }
+ public function setType($value) { $this->_valueType = $value; }
+
+ public function getTypeHandler()
+ {
+ if(is_null($this->_typeHandlerFactory)) return null;
+ if(!is_null($this->_typeHandler))
+ return $this->_typeHandlerFactory->getTypeHandler($this->_typeHandler);
+ else if(!is_null($this->getType()))
+ return $this->_typeHandlerFactory->getTypeHandler($this->getType());
+ else
+ return null;
+ }
+ public function setTypeHandler($value) { $this->_typeHandler = $value; }
+
+ public function getSelect(){ return $this->_select; }
+ public function setSelect($value){ $this->_select = $value; }
+
+ public function getLazyLoad(){ return $this->_isLazyLoad; }
+ public function setLazyLoad($value){ $this->_isLazyLoad = TPropertyValue::ensureBoolean($value,false); }
+
+ public function getDbType(){ return $this->_dbType; }
+ public function setDbType($value){ $this->_dbType = $value; }
+
+ public function initialize($sqlMap, $resultMap=null)
+ {
+ $this->_typeHandlerFactory = $sqlMap->getTypeHandlerFactory();
+ if(!is_null($resultMap))
+ $this->_hostResultMapID = $resultMap->getID();
+// $type = !is_null($this->_typeHandler) ? $this->_typeHandler: $this->_valueType;
+// $this->setTypeHandler($sqlMap->getTypeHandlerFactory()->getTypeHandler($type));
+ }
+
+ public function getDatabaseValue($row,$forceType=true)
+ {
+ $value = null;
+ if($this->_columnIndex > 0 && isset($row[$this->_columnIndex]))
+ $value = $this->getTypedValue($row[$this->_columnIndex], $forceType);
+ else if(isset($row[$this->_columnName]))
+ $value = $this->getTypedValue($row[$this->_columnName],$forceType);
+ if(is_null($value) && !is_null($this->_nullValue))
+ $value = $this->getTypedValue($this->_nullValue,$forceType);
+ return $value;
+ }
+
+ public function getOrdinalValue($row)
+ {
+ return $this->getDatabaseValue($row,false);
+ }
+
+ private function getTypedValue($value, $forceType=true)
+ {
+ if(!$forceType) return $value;
+ if(is_null($this->getTypeHandler()))
+ {
+ return TTypeHandlerFactory::convertToType($this->_valueType, $value);
+ }
+ else
+ {
+ try
+ {
+ return $this->getTypeHandler()->getResult($value);
+ }
+ catch (Exception $e)
+ {
+ throw new TSqlMapExecutionException(
+ 'sqlmap_error_in_result_property_from_handler',$this->_hostResultMapID,
+ $value, get_class($this->getTypeHandler()), $e->getMessage());
+ }
+ }
+ }
+
+
+ public function getPropertyType($type=null)
+ {
+ if(is_null($type))
+ $type = $this->getType();
+ if(class_exists($type, false)) //NO force autoloading
+ {
+ $class = new ReflectionClass($type);
+ if($class->isSubclassOf('TList'))
+ return self::LIST_TYPE;
+ if($class->inmplementsInterface('ArrayAccess'))
+ return self::ARRAY_TYPE;
+ }
+ if(strtolower($type) == 'array')
+ return self::ARRAY_TYPE;
+ return self::OBJECT_TYPE;
+ }
+
+ public function isListType($target)
+ {
+ if(is_null($this->getType()))
+ {
+ $prop = TPropertyAccess::get($target,$this->getProperty());
+ return $prop instanceof TList;
+ }
+ return $this->getPropertyType() == self::LIST_TYPE;
+ }
+
+ public function isArrayType($target)
+ {
+ if(is_null($this->getType()))
+ {
+ $prop = TPropertyAccess::get($target,$this->getProperty());
+ if(is_object($prop))
+ return $prop instanceof ArrayAccess;
+ return is_array($prop);
+ }
+ return $this->getPropertyType() == self::ARRAY_TYPE;
+ }
+
+ public function isObjectType($target)
+ {
+ if(is_null($this->getType()))
+ {
+ $prop = TPropertyAccess::get($target,$this->getProperty());
+ return is_object($prop);
+ }
+ return $this->getPropertyType() == self::OBJECT_TYPE;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Configuration/TSqlMapCacheModel.php b/framework/DataAccess/SQLMap/Configuration/TSqlMapCacheModel.php
new file mode 100644
index 00000000..6c945155
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Configuration/TSqlMapCacheModel.php
@@ -0,0 +1,131 @@
+<?php
+
+class TSqlMapCacheModel extends TComponent
+{
+ private $_cache;
+ private $_flushInterval = -1;
+ private $_hits = 0;
+ private $_requests = 0;
+ private $_id;
+ private $_lastFlush;
+ private $_implementation;
+ private $_properties = array();
+
+
+ public function getID(){ return $this->_id; }
+ public function setID($value){ $this->_id = $value; }
+
+ public function getImplementation(){ return $this->_implementation; }
+ public function setImplementation($value){ $this->_implementation = $value; }
+
+ public function getFlushInterval(){ return $this->_flushInterval; }
+ public function setFlushInterval($value){ $this->_flushInterval = $value; }
+
+ public function initialize($sqlMap)
+ {
+ $implementation = $this->getImplementationClass(
+ $sqlMap->getTypeHandlerFactory());
+ $this->_cache = new $implementation;
+ $this->_cache->configure($this->_properties);
+ }
+
+ protected function getImplementationClass($typeFactory)
+ {
+ switch(strtolower($this->_implementation))
+ {
+ case 'fifo': return 'TSqlMapFifoCache';
+ case 'lru' : return 'TSqlMapLruCache';
+ }
+
+ if(class_exists($this->_implementation, false))
+ $class = $this->_implementation;
+ else
+ $class = $typeFactory->getTypeHandler($this->_implementation);
+ if(!is_null($class))
+ return $class;
+ else
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_unable_to_find_implemenation', $this->_implementation);
+ }
+
+ public function addProperty($name, $value)
+ {
+ $this->_properties[strtolower($name)] = $value;
+ }
+
+ public function registerTriggerStatement($mappedStatement)
+ {
+ $mappedStatement->attachEventHandler('OnExecuteQuery',
+ array($this, 'flushHandler'));
+ }
+
+ protected function flushHandler($sender, $param)
+ {
+ $this->flush();
+ }
+
+ public function flush()
+ {
+ var_dump("flush!");
+ $this->_cache->flush();
+ }
+
+ public function get($key)
+ {
+ if($key instanceof TSqlMapCacheKey)
+ $key = $key->getHash();
+
+ //if flush ?
+ $value = $this->_cache->get($key);
+ $this->_requests++;
+ if(!is_null($value))
+ $this->_hits++;
+ return $value;
+ }
+
+ public function set($key, $value)
+ {
+ if($key instanceof TSqlMapCacheKey)
+ $key = $key->getHash();
+
+ if(!is_null($value))
+ $this->_cache->set($key, $value);
+ }
+
+ public function getHitRatio()
+ {
+ if($this->_requests != 0)
+ return $this->_hits / $this->_requests;
+ else
+ return 0;
+ }
+}
+
+
+class TSqlMapCacheKey
+{
+ private $_key;
+
+ public function __construct($object)
+ {
+ $this->_key = $this->generateKey(serialize($object));
+ }
+
+ protected function generateKey($string)
+ {
+ return sprintf('%x',crc32($string));
+ }
+
+ public function getHash()
+ {
+ return $this->_key;
+ }
+
+ public function __toString()
+ {
+ return $this->getHash();
+ }
+}
+
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Configuration/TSqlMapDelete.php b/framework/DataAccess/SQLMap/Configuration/TSqlMapDelete.php
new file mode 100644
index 00000000..9ca3843a
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Configuration/TSqlMapDelete.php
@@ -0,0 +1,7 @@
+<?php
+
+class TSqlMapDelete extends TSqlMapUpdate
+{
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Configuration/TSqlMapInsert.php b/framework/DataAccess/SQLMap/Configuration/TSqlMapInsert.php
new file mode 100644
index 00000000..c8d798c5
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Configuration/TSqlMapInsert.php
@@ -0,0 +1,15 @@
+<?php
+
+class TSqlMapInsert extends TSqlMapStatement
+{
+ private $_selectKey=null;
+ private $_generate=null;
+
+ public function getSelectKey(){ return $this->_selectKey; }
+ public function setSelectKey($value){ $this->_selectKey = $value; }
+
+ public function getGenerate(){ return $this->_generate; }
+ public function setGenerate($value){ $this->_generate = $value; }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Configuration/TSqlMapSelect.php b/framework/DataAccess/SQLMap/Configuration/TSqlMapSelect.php
new file mode 100644
index 00000000..b33bc27e
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Configuration/TSqlMapSelect.php
@@ -0,0 +1,11 @@
+<?php
+
+class TSqlMapSelect extends TSqlMapStatement
+{
+ private $_generate;
+
+ public function getGenerate(){ return $this->_generate; }
+ public function setGenerate($value){ $this->_generate = $value; }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Configuration/TSqlMapSelectKey.php b/framework/DataAccess/SQLMap/Configuration/TSqlMapSelectKey.php
new file mode 100644
index 00000000..b73d4ef0
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Configuration/TSqlMapSelectKey.php
@@ -0,0 +1,26 @@
+<?php
+
+class TSqlMapSelectKey extends TSqlMapStatement
+{
+ private $_type = 'post';
+ private $_property = '';
+
+ public function getType(){ return $this->_type; }
+ public function setType($value){ $this->_type = $value; }
+
+ public function getProperty(){ return $this->_property; }
+ public function setProperty($value){ $this->_property = $value; }
+
+ public function setExtends($value)
+ {
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_can_not_extend_select_key');
+ }
+
+ public function getIsAfter()
+ {
+ return $this->_type == 'post';
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Configuration/TSqlMapStatement.php b/framework/DataAccess/SQLMap/Configuration/TSqlMapStatement.php
new file mode 100644
index 00000000..228b37d6
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Configuration/TSqlMapStatement.php
@@ -0,0 +1,109 @@
+<?php
+
+class TSqlMapStatement extends TComponent
+{
+ private $_ID='';
+ private $_parameterMapName='';
+ private $_parameterMap;
+ private $_parameterClassName='';
+// private $_parameterClass;
+ private $_resultMapName='';
+ private $_resultMap;
+ private $_resultClassName='';
+// private $_resultClass;
+ private $_cacheModelName='';
+ private $_remapResults=false;
+ private $_SQL='';
+ private $_listClass='';
+ private $_typeHandler;
+ private $_extendStatement='';
+ private $_cache;
+
+ public function getID(){ return $this->_ID; }
+ public function setID($value){ $this->_ID = $value; }
+
+ public function getParameterMap(){ return $this->_parameterMapName; }
+ public function setParameterMap($value){ $this->_parameterMapName = $value; }
+
+ public function getParameterClass(){ return $this->_parameterClassName; }
+ public function setParameterClass($value){ $this->_parameterClassName = $value; }
+
+ public function getResultMap(){ return $this->_resultMapName; }
+ public function setResultMap($value){ $this->_resultMapName = $value; }
+
+ public function getResultClass(){ return $this->_resultClassName; }
+ public function setResultClass($value){ $this->_resultClassName = $value; }
+
+ public function getCacheModel(){ return $this->_cacheModelName; }
+ public function setCacheModel($value){ $this->_cacheModelName = $value; }
+
+ public function getCache(){ return $this->_cache; }
+ public function setCache($value){ $this->_cache = $value; }
+
+ public function getRemapResults(){ return $this->_remapResults; }
+ public function setRemapResults($value){ $this->_remapResults = TPropertyValue::ensureBoolean($value,false); }
+
+ public function getSQL(){ return $this->_SQL; }
+ public function setSQL($value){ $this->_SQL = $value; }
+
+ public function getListClass(){ return $this->_listClass; }
+ public function setListClass($value){ $this->_listClass = $value; }
+
+ public function getExtends(){ return $this->_extendStatement; }
+ public function setExtends($value){ $this->_extendStatement = $value; }
+
+ public function resultMap(){ return $this->_resultMap; }
+ public function parameterMap(){ return $this->_parameterMap; }
+
+ public function setInlineParameterMap($map)
+ {
+ $this->_parameterMap = $map;
+ }
+// public function parameterClass(){ return $this->_parameterClass; }
+// public function resultClass(){ return $this->_resultClass; }
+
+ public function initialize($sqlMap)
+ {
+ $this->_typeHandler = $sqlMap->getTypeHandlerFactory();
+ if(strlen($this->_resultMapName) > 0)
+ $this->_resultMap = $sqlMap->getResultMap($this->_resultMapName);
+ if(strlen($this->_parameterMapName) > 0)
+ $this->_parameterMap = $sqlMap->getParameterMap($this->_parameterMapName);
+ }
+
+
+ public function createInstanceOfListClass()
+ {
+ if(strlen($type = $this->getListClass()) > 0)
+ return $this->createInstanceOf($type);
+ return array(); //new TList;
+ }
+
+ protected function createInstanceOf($type)
+ {
+ $handler = $this->_typeHandler->getTypeHandler($type);
+
+ try
+ {
+ if(!is_null($handler))
+ return $handler->createNewInstance();
+ else
+ return TTypeHandlerFactory::createInstanceOf($type);
+ }
+ catch (TDataMapperException $e)
+ {
+ throw new TSqlMapExecutionException(
+ 'sqlmap_unable_to_create_new_instance',
+ $type, get_class($handler), $this->getID());
+ }
+
+ }
+
+ public function createInstanceOfResultClass()
+ {
+ if(strlen($type= $this->getResultClass()) > 0)
+ return $this->createInstanceOf($type);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Configuration/TSqlMapUpdate.php b/framework/DataAccess/SQLMap/Configuration/TSqlMapUpdate.php
new file mode 100644
index 00000000..26d00e39
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Configuration/TSqlMapUpdate.php
@@ -0,0 +1,11 @@
+<?php
+
+class TSqlMapUpdate extends TSqlMapStatement
+{
+ private $_generate;
+
+ public function getGenerate(){ return $this->_generate; }
+ public function setGenerate($value){ $this->_generate = $value; }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/DataMapper/TDataMapperException.php b/framework/DataAccess/SQLMap/DataMapper/TDataMapperException.php
new file mode 100644
index 00000000..7cb74244
--- /dev/null
+++ b/framework/DataAccess/SQLMap/DataMapper/TDataMapperException.php
@@ -0,0 +1,65 @@
+<?php
+
+class TDataMapperException extends TException
+{
+ /**
+ * @return string path to the error message file
+ */
+ protected function getErrorMessageFile()
+ {
+ $lang=Prado::getPreferredLanguage();
+ $msgFile=Prado::getFrameworkPath().'/DataAccess/SQLMap/DataMapper/messages-'.$lang.'.txt';
+ if(!is_file($msgFile))
+ $msgFile=Prado::getFrameworkPath().'/DataAccess/SQLMap/DataMapper/messages.txt';
+ return $msgFile;
+ }
+}
+
+class TSqlMapConfigurationException extends TDataMapperException
+{
+
+}
+
+class TUndefinedAttributeException extends TSqlMapConfigurationException
+{
+ public function __construct($attr, $node, $object, $file)
+ {
+ parent::__construct(
+ 'sqlmap_undefined_attribute', get_class($object), $attr,
+ htmlentities($node->asXml()),$file);
+ }
+}
+
+class TSqlMapExecutionException extends TDataMapperException
+{
+}
+
+class TSqlMapQueryExecutionException extends TSqlMapExecutionException
+{
+ protected $parent;
+ public function __construct($statement, $exception)
+ {
+ $this->parent = $exception;
+ parent::__construct('sqlmap_query_execution_error',
+ $statement->getID(), $exception->getMessage());
+ }
+}
+
+class TSqlMapUndefinedException extends TDataMapperException
+{
+
+}
+
+class TSqlMapDuplicateException extends TDataMapperException
+{
+}
+
+class TSqlMapConnectionException extends TDataMapperException
+{
+}
+
+class TInvalidPropertyException extends TDataMapperException
+{
+
+}
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/DataMapper/TLazyLoadList.php b/framework/DataAccess/SQLMap/DataMapper/TLazyLoadList.php
new file mode 100644
index 00000000..465dcaac
--- /dev/null
+++ b/framework/DataAccess/SQLMap/DataMapper/TLazyLoadList.php
@@ -0,0 +1,87 @@
+<?php
+
+class TLazyLoadList implements IInterceptor
+{
+ private $_param;
+ private $_target;
+ private $_propertyName='';
+ private $_sqlMap;
+ private $_statementName='';
+ private $_loaded=false;
+ private $_innerList;
+
+ protected function __construct($mappedStatement, $param, $target, $propertyName)
+ {
+ $this->_param = $param;
+ $this->_target = $target;
+ $this->_statementName = $mappedStatement->getID();
+ $this->_sqlMap = $mappedStatement->getSqlMap();
+ $this->_propertyName = $propertyName;
+ }
+
+ public static function newInstance($mappedStatement, $param, $target, $propertyName)
+ {
+ $handler = new self($mappedStatement, $param, $target, $propertyName);
+ $statement = $mappedStatement->getStatement();
+ $list = $statement->createInstanceOfListClass();
+ if(!is_object($list))
+ throw new TSqlMapExecutionException('sqlmap_invalid_lazyload_list',
+ $statement->getID());
+ return new TObjectProxy($handler, $list);
+ }
+
+ public function intercept($method, $arguments)
+ {
+ return call_user_func_array(array($this->_innerList, $method), $arguments);
+ }
+
+ protected function fetchListData()
+ {
+
+ if($this->_loaded == false)
+ {
+ $this->_innerList = $this->_sqlMap->queryForList(
+ $this->_statementName, $this->_param);
+ $this->_loaded = true;
+ //replace the target property with real list
+ TPropertyAccess::set($this->_target,
+ $this->_propertyName, $this->_innerList);
+ }
+ }
+
+ public function hasMethod($method)
+ {
+ $this->fetchListData();
+ if(is_object($this->_innerList))
+ return in_array($method, get_class_methods($this->_innerList));
+ return false;
+ }
+}
+
+interface IInterceptor
+{
+ public function intercept($method, $params);
+ public function hasMethod($method);
+}
+
+class TObjectProxy
+{
+ private $_object;
+ private $_handler;
+
+ public function __construct(IInterceptor $handler, $object)
+ {
+ $this->_handler = $handler;
+ $this->_object = $object;
+ }
+
+ public function __call($method,$params)
+ {
+ if($this->_handler->hasMethod($method))
+ return $this->_handler->intercept($method, $params);
+ else
+ return call_user_func_array(array($this->_object, $method), $params);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/DataMapper/TPropertyAccess.php b/framework/DataAccess/SQLMap/DataMapper/TPropertyAccess.php
new file mode 100644
index 00000000..8680601e
--- /dev/null
+++ b/framework/DataAccess/SQLMap/DataMapper/TPropertyAccess.php
@@ -0,0 +1,91 @@
+<?php
+
+class TPropertyAccess
+{
+ private $_obj;
+ private $_performance=false;
+
+ public function __construct($obj,$performance=false)
+ {
+ $this->_obj = $obj;
+ $this->_performance=$performance;
+ }
+
+ public function __get($name)
+ {
+ return self::get($this->_obj,$name,$this->_performance);
+ }
+
+ public function __set($name,$value)
+ {
+ self::set($this->_obj,$name,$value,$this->_performance);
+ }
+
+ /**
+ * Evaluates the data value at the specified field.
+ * - If the data is an array, then the field is treated as an array index
+ * and the corresponding element value is returned;
+ * - If the data is a TMap or TList object, then the field is treated as a key
+ * into the map or list, and the corresponding value is returned.
+ * - If the data is an object, the field is treated as a property or subproperty
+ * defined with getter methods. For example, if the object has a method called
+ * getMyValue(), then field 'MyValue' will retrive the result of this method call.
+ * If getMyValue() returns an object which contains a method getMySubValue(),
+ * then field 'MyValue.MySubValue' will return that method call result.
+ * @param mixed data containing the field value, can be an array, TMap, TList or object.
+ * @param mixed field value
+ * @return mixed value at the specified field
+ * @throw TInvalidDataValueException if field or data is invalid
+ */
+ public static function get($object,$path)
+ {
+ if(!is_array($object) && !is_object($object))
+ return $object;
+ $properties = explode('.', $path);
+ foreach($properties as $prop)
+ {
+ if(is_array($object) || $object instanceof ArrayAccess)
+ {
+ if(isset($object[$prop]))
+ $object = $object[$prop];
+ else
+ throw new TInvalidPropertyException('sqlmap_invalid_property',$path);
+ }
+ else if(is_object($object))
+ {
+ $getter = 'get'.$prop;
+ if(is_callable(array($object,$getter)))
+ $object = $object->{$getter}();
+ else if(in_array($prop, array_keys(get_object_vars($object))))
+ $object = $object->{$prop};
+ else
+ throw new TInvalidPropertyException('sqlmap_invalid_property',$path);
+ }
+ else
+ throw new TInvalidPropertyException('sqlmap_invalid_property',$path);
+ }
+ return $object;
+ }
+
+
+ public static function set($object, $path, $value)
+ {
+ $properties = explode('.', $path);
+ $prop = array_pop($properties);
+ if(count($properties) > 0)
+ $object = self::get($object, implode('.',$properties));
+ if(is_object($object))
+ {
+ $setter = 'set'.$prop;
+ if(is_callable(array($object, $setter)))
+ $object->{$setter}($value);
+ else
+ $object->{$prop} = $value;
+ }
+ else
+ throw new TInvalidPropertyException('sqlmap_invalid_property_type',$path);
+ }
+
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/DataMapper/TSqlMapCache.php b/framework/DataAccess/SQLMap/DataMapper/TSqlMapCache.php
new file mode 100644
index 00000000..8571d46d
--- /dev/null
+++ b/framework/DataAccess/SQLMap/DataMapper/TSqlMapCache.php
@@ -0,0 +1,165 @@
+<?php
+/**
+ * TSqlMapCache class file contains FIFO and LRU cache implementations.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $Date: $
+ * @package System.DataAccess.SQLMap
+ */
+
+interface ISqLMapCache
+{
+ public function remove($key);
+
+ public function flush();
+
+ public function get($key);
+
+ public function set($key, $value);
+
+ public function configure($properties);
+}
+
+/**
+ * Allow different implementation of caching strategy. See <tt>TSqlMapFifoCache</tt>
+ * for a first-in-first-out implementation. See <tt>TSqlMapLruCache</tt> for
+ * a least-recently-used cache implementation.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: $ $Date: $
+ * @package System.DataAccess.SQLMap
+ * @since 3.0
+ */
+abstract class TSqlMapCache implements ISqlMapCache
+{
+ protected $_keyList;
+ protected $_cache;
+ protected $_cacheSize = 100;
+
+ /**
+ * Create a new cache with limited cache size.
+ * @param integer maxium number of items to cache.
+ */
+ public function __construct($cacheSize=100)
+ {
+ $this->_cache = new TMap;
+ $this->_cacheSize = intval($cacheSize);
+ $this->_keyList = new TList;
+ }
+
+ /**
+ * Configures the Cache Size.
+ * @param array list of properties
+ */
+ public function configure($properties)
+ {
+ if(isset($properties['size']))
+ $this->_cacheSize = intval($properties['size']);
+ }
+
+ /**
+ * @return object the object removed if exists, null otherwise.
+ */
+ public function remove($key)
+ {
+ $object = $this->get($key);
+ $this->_cache->remove($key);
+ $this->_keyList->remove($key);
+ return $object;
+ }
+
+ /**
+ * Clears the cache.
+ */
+ public function flush()
+ {
+ $this->_keyList->clear();
+ $this->_cache->clear();
+ }
+
+}
+
+/**
+ * First-in-First-out cache implementation, removes
+ * object that was first added when the cache is full.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: $ $Date: $
+ * @package System.DataAccess.SQLMap
+ * @since 3.0
+ */
+class TSqlMapFifoCache extends TSqlMapCache
+{
+ /**
+ * @return mixed Gets a cached object with the specified key.
+ */
+ public function get($key)
+ {
+ return $this->_cache->itemAt($key);
+ }
+
+ /**
+ * Adds an item with the specified key and value into cached data.
+ * @param string cache key
+ * @param mixed value to cache.
+ */
+ public function set($key, $value)
+ {
+ $this->_cache->add($key, $value);
+ $this->_keyList->add($key);
+ if($this->_keyList->getCount() > $this->_cacheSize)
+ {
+ $oldestKey = $this->_keyList->removeAt(0);
+ $this->_cache->remove($oldestKey);
+ }
+ }
+}
+
+/**
+ * Least recently used cache implementation, removes
+ * object that was accessed last when the cache is full.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: $ $Date: $
+ * @package System.DataAccess.SQLMap
+ * @since 3.0
+ */
+class TSqlMapLruCache extends TSqlMapCache
+{
+ /**
+ * @return mixed Gets a cached object with the specified key.
+ */
+ public function get($key)
+ {
+ if($this->_keyList->contains($key))
+ {
+ $this->_keyList->remove($key);
+ $this->_keyList->add($key);
+ return $this->_cache->itemAt($key);
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Adds an item with the specified key and value into cached data.
+ * @param string cache key
+ * @param mixed value to cache.
+ */
+ public function set($key, $value)
+ {
+ $this->_cache->add($key, $value);
+ $this->_keyList->add($key);
+ if($this->_keyList->getCount() > $this->_cacheSize)
+ {
+ $oldestKey = $this->_keyList->removeAt(0);
+ $this->_cache->remove($oldestKey);
+ }
+ }
+}
+
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/DataMapper/TSqlMapPagedList.php b/framework/DataAccess/SQLMap/DataMapper/TSqlMapPagedList.php
new file mode 100644
index 00000000..cded4b32
--- /dev/null
+++ b/framework/DataAccess/SQLMap/DataMapper/TSqlMapPagedList.php
@@ -0,0 +1,156 @@
+<?php
+
+/**
+ * TSQLMapPagedList
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: $ $Date: $
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TSqlMapPagedList extends TPagedList
+{
+ private $_statement;
+ private $_parameter;
+ private $_prevPageList;
+ private $_nextPageList;
+ private $_delegate=null;
+
+ public function __construct(IMappedStatement $statement,
+ $parameter, $pageSize, $delegate=null)
+ {
+ parent::__construct();
+ parent::setCustomPaging(true);
+ $this->initialize($statement,$parameter, $pageSize);
+ $this->_delegate=$delegate;
+ }
+
+ protected function initialize($statement, $parameter, $pageSize)
+ {
+ $this->_statement = $statement;
+ $this->_parameter = $parameter;
+ $this->setPageSize($pageSize);
+ $this->attachEventHandler('OnFetchData', array($this, 'fetchDataFromStatement'));
+ $this->gotoPage(0);
+ }
+
+ public function setCustomPaging($value)
+ {
+ throw new TDataMapperException('sqlmap_must_enable_custom_paging');
+ }
+
+ protected function fetchDataFromStatement($sender, $param)
+ {
+ $limit = $this->getOffsetAndLimit($param);
+ $connection = $this->_statement->getSqlMap()->openConnection();
+ $data = $this->_statement->executeQueryForList($connection,
+ $this->_parameter, null, $limit[0], $limit[1], $this->_delegate);
+ $this->populateData($param, $data);
+ }
+
+ public function nextPage()
+ {
+ if($this->getIsNextPageAvailable())
+ return parent::nextPage();
+ else
+ return false;
+ }
+
+ public function previousPage()
+ {
+ if($this->getIsPreviousPageAvailable())
+ return parent::previousPage();
+ else
+ return false;
+ }
+
+ protected function populateData($param, $data)
+ {
+ $total = $data instanceof TList ? $data->getCount() : count($data);
+ $pageSize = $this->getPageSize();
+ if($total < 1)
+ {
+ $param->setData($data);
+ $this->_prevPageList = null;
+ $this->_nextPageList = null;
+ return;
+ }
+
+ if($param->getNewPageIndex() < 1)
+ {
+ $this->_prevPageList = null;
+ if($total <= $pageSize)
+ {
+ $param->setData($data);
+ $this->_nextPageList = null;
+ }
+ else
+ {
+ $param->setData($this->sublist($data, 0, $pageSize));
+ $this->_nextPageList = $this->sublist($data, $pageSize,$total);
+ }
+ }
+ else
+ {
+ if($total <= $pageSize)
+ {
+ $this->_prevPageList = $this->sublist($data, 0, $total);
+ $param->setData(array());
+ $this->_nextPageList = null;
+ }
+ else if($total <= $pageSize*2)
+ {
+ $this->_prevPageList = $this->sublist($data, 0, $pageSize);
+ $param->setData($this->sublist($data, $pageSize, $total));
+ $this->_nextPageList = null;
+ }
+ else
+ {
+ $this->_prevPageList = $this->sublist($data, 0, $pageSize);
+ $param->setData($this->sublist($data, $pageSize, $pageSize*2));
+ $this->_nextPageList = $this->sublist($data, $pageSize*2, $total);
+ }
+ }
+ }
+
+ protected function sublist($data, $from, $to)
+ {
+ $array = array();
+ for($i = $from; $i<$to; $i++)
+ $array[] = $data[$i];
+ return $array;
+ }
+
+ protected function getOffsetAndLimit($param)
+ {
+ $index = $param->getNewPageIndex();
+ $pageSize = $this->getPageSize();
+ if($index < 1)
+ return array($index, $pageSize*2);
+ else
+ return array(($index-1)*$pageSize, $pageSize*3);
+ }
+
+ public function getIsNextPageAvailable()
+ {
+ return !is_null($this->_nextPageList);
+ }
+
+ public function getIsPreviousPageAvailable()
+ {
+ return !is_null($this->_prevPageList);
+ }
+
+ public function getIsLastPage()
+ {
+ return is_null($this->_nextPageList)
+ || $this->_nextPageList->getCount() < 1;
+ }
+
+ public function getIsMiddlePage()
+ {
+ return !($this->getIsFirstPage() || $this->getIsLastPage());
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/DataMapper/TTypeHandlerFactory.php b/framework/DataAccess/SQLMap/DataMapper/TTypeHandlerFactory.php
new file mode 100644
index 00000000..fcadea28
--- /dev/null
+++ b/framework/DataAccess/SQLMap/DataMapper/TTypeHandlerFactory.php
@@ -0,0 +1,134 @@
+<?php
+
+class TTypeHandlerFactory
+{
+ private $_typeHandlerMap;
+
+ const NullDbType = '__NULL__';
+
+ public function __construct()
+ {
+ $this->_typeHandlerMap = new TMap;
+ }
+
+ public function getTypeHandler($type, $dbType=null)
+ {
+ $dbTypeHandlerMap = $this->_typeHandlerMap[$type];
+ $handler = null;
+ if(!is_null($dbTypeHandlerMap))
+ {
+ if(is_null($dbType))
+ $handler = $dbTypeHandlerMap[self::NullDbType];
+ else
+ {
+ $handler = $dbTypeHandlerMap[$dbType];
+ if(is_null($handler))
+ $handler = $dbTypeHandlerMap[self::NullDbType];
+ }
+ }
+ return $handler;
+ }
+
+ public function register($type, $handler, $dbType=null)
+ {
+ $map = $this->_typeHandlerMap[$type];
+ if(is_null($map))
+ {
+ $map = new TMap;
+ $this->_typeHandlerMap->add($type, $map);
+ }
+ if(is_null($dbType))
+ $map->add(self::NullDbType, $handler);
+ else
+ $map->add($dbType, $handler);
+ }
+
+ public static function createInstanceOf($type)
+ {
+ if(strlen($type) > 0)
+ {
+ switch(strtolower($type))
+ {
+ case 'string': return '';
+ case 'array': return array();
+ case 'float': case 'double': case 'decimal': return 0.0;
+ case 'integer': case 'int': return 0;
+ case 'bool': case 'boolean': return false;
+ }
+
+ if(class_exists($type, false)) //NO auto loading
+ return new $type;
+ else
+ throw new TDataMapperException('sqlmap_unable_to_find_class', $type);
+ }
+ return null;
+ }
+
+ public static function convertToType($type, $value)
+ {
+ switch(strtolower($type))
+ {
+ case 'integer': case 'int':
+ $type = 'integer'; break;
+ case 'float': case 'double': case 'decimal':
+ $type = 'float'; break;
+ case 'boolean': case 'bool':
+ $type = 'boolean'; break;
+ case 'string' :
+ $type = 'string'; break;
+ default:
+ return $value;
+ }
+ settype($value, $type);
+ return $value;
+ }
+}
+
+/**
+ * A simple interface for implementing custom type handlers.
+ *
+ * Using this interface, you can implement a type handler that
+ * will perform customized processing before parameters are set
+ * on and after values are retrieved from the database.
+ * Using a custom type handler you can extend
+ * the framework to handle types that are not supported, or
+ * handle supported types in a different way. For example,
+ * you might use a custom type handler to implement proprietary
+ * BLOB support (e.g. Oracle), or you might use it to handle
+ * booleans using "Y" and "N" instead of the more typical 0/1.
+ */
+interface ITypeHandlerCallback
+{
+ /**
+ * Performs processing on a value before it is used to set
+ * the parameter of a IDbCommand.
+ * @param object The interface for setting the value.
+ * @param object The value to be set.
+ */
+ public function getParameter($object);
+
+
+ /**
+ * Performs processing on a value before after it has been retrieved
+ * from a database
+ * @param object The interface for getting the value.
+ * @return mixed The processed value.
+ */
+ public function getResult($string);
+
+
+ /**
+ * Casts the string representation of a value into a type recognized by
+ * this type handler. This method is used to translate nullValue values
+ * into types that can be appropriately compared. If your custom type handler
+ * cannot support nullValues, or if there is no reasonable string representation
+ * for this type (e.g. File type), you can simply return the String representation
+ * as it was passed in. It is not recommended to return null, unless null was passed
+ * in.
+ * @param string nullValue.
+ * @return mixed
+ */
+ public function createNewInstance();
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/DataMapper/messages.txt b/framework/DataAccess/SQLMap/DataMapper/messages.txt
new file mode 100644
index 00000000..79c80ad5
--- /dev/null
+++ b/framework/DataAccess/SQLMap/DataMapper/messages.txt
@@ -0,0 +1,61 @@
+component_property_undefined = Component property '{0}.{1}' is not defined.
+component_property_readonly = Component property '{0}.{1}' is read-only.
+component_event_undefined = Component event '{0}.{1}' is not defined.
+component_eventhandler_invalid = Component event '{0}.{1}' is attached with an invalid event handler.
+component_expression_invalid = Component '{0}' is evaluating an invalid expression '{1}' : {2}.
+component_statements_invalid = Component '{0}' is evaluating invalid PHP statements '{1}' : {2}.
+
+propertyvalue_enumvalue_invalid = Value '{0}' is a not valid enumeration value ({1}).
+
+list_index_invalid = Index '{0}' is out of range.
+list_item_inexistent = The item cannot be found in the list.
+list_data_not_iterable = Data must be either an array or an object implementing Traversable interface.
+list_readonly = {0} is read-only.
+
+map_addition_disallowed = The new item cannot be added to the map.
+map_item_unremovable = The item cannot be removed from the map.
+map_data_not_iterable = Data must be either an array or an object implementing Traversable interface.
+map_readonly = {0} is read-only.
+
+sqlmap_contains_no_statement = Unable to find SQLMap statement '{0}'.
+sqlmap_already_contains_statement = Duplicate SQLMap statement found, '{0}' already exists.
+sqlmap_contains_no_result_map = Unable to find SQLMap result map '{0}'.
+sqlmap_already_contains_result_map = Duplicate SQLMap result map found, '{0}' already exists.
+sqlmap_contains_no_parameter_map = Unable to find SQLMap parameter map '{0}'.
+sqlmap_already_contains_parameter_map = Duplicate SQLMap parameter map found, '{0}' already exists.
+sqlmap_connection_already_exists = SqlMap could not invoke OpenConnection(). A connection is already started. Call CloseConnection first.
+sqlmap_unable_to_close_null_connection = SqlMap could not invoke CloseConnection(). No connection was started. Call OpenConnection() first.
+sqlmap_undefined_attribute = {0} attribute '{1}' is not defined for {2} in file {3}.
+sqlmap_unable_find_provider_class = Unable to find a database provider in SQLMap configuration file {0}.
+sqlmap_unable_to_find_parent_parameter_map = Unable to find parent parameter map extension '{0}' in file {1}.
+sqlmap_unable_to_find_parent_sql = Unable to find parent sql statement extension '{0}' in file {1}.
+sqlmap_unable_to_find_result_mapping = Unable to resolve SQLMap result mapping '{0}' in Result Map '{2}' using configuration file {1}.
+sqlmap_unable_to_find_parent_result_map = Unable to find parent SQLMap result map '{0}' in file {1}.
+sqlmap_undefined_property_inline_map = Invalid attribute '{0}' for inline parameter in statement '{1}' in file {2}.
+sqlmap_index_must_be_string_or_int = Invalid index '{0}', must be an integes or string to get a SQLMap parameter map property.
+sqlmap_undefined_input_property = Undefined array index '{0}' in retrieving property in SQLMap parameter map '{1}'.
+sqlmap_unable_to_find_class = Unable to find result class '{0}' in TResultMap::createInstanceOfResult().
+sqlmap_can_not_instantiate = Type handler '{0}' can not create new objects.
+sqlmap_cannot_execute_query_for_map = SQLMap statement class {0} can not query for map.
+sqlmap_cannot_execute_update = SQLMap statement class {0} can not execute update query.
+sqlmap_cannot_execute_insert = SQLMap statement class {0} can not execute insert.
+sqlmap_cannot_execute_query_for_list = SQLMap statement class {0} can not query for list.
+sqlmap_cannot_execute_query_for_object = SQLMap statement class {0} can not query for object
+sqlmap_execution_error_no_record = No record set found in executing statement '{0}': '{1}'.
+sqlmap_unable_to_create_new_instance = Unable to create a new instance of '{0}' using type hander '{1}' for SQLMap statement with ID '{2}'.
+sqlmap_invalid_property = Invalid property getter path '{0}'.
+sqlmap_invalid_property_type = Invalid object type, must be 'Object', unable to set property in path '{0}'.
+sqlmap_unable_to_get_property_for_parameter = Unable to find property '{1}' in object '{2}' for parameter map '{0}' while executing statement '{4}': '{3}'.
+sqlmap_error_in_parameter_from_handler = For parameter map '{0}', error in getting parameter from type handler '{2}' with value '{1}': '{3}'.
+sqlmap_error_in_result_property_from_handler = For result map '{0}', error in getting result from type handler '{2}', with value '{1}': '{3}'.=======
+sqlmap_unable_to_find_implemenation = Unable to find SQLMap cache implementation named '{0}'.
+sqlmap_cache_model_already_exists = This SQLMap already contains cache model '{0}'.
+sqlmap_unable_to_find_cache_model = Unable to find cache model '{0}' in this SQLMap.
+sqlmap_unable_to_find_db_config = Unable to find database connection settings &lt;provider&gt; and &lt;datasource&gt; in configuration file '{0}'.
+sqlmap_unable_to_find_config = Unable to find SQLMap configuration file '{0}'.
+sqlmap_unable_to_find_groupby = Unable to find data in result set with column '{0}' in result map with ID '{1}'.
+sqlmap_invalid_lazyload_list = Invalid type to lazy load, must specify a valid ListClass in statement '{0}'.
+sqlmap_unable_to_find_resource = 'Unable to find SQLMap configuration file '{0}'.
+sqlmap_query_execution_error = Error in executing SQLMap statement '{0}' : '{1}'.
+sqlmap_undefined_discriminator = The discriminator is null, but somehow a subMap was reached in ResultMap '{0}' in file '{1}'.
+sqlmap_invalid_delegate = Invalid callback row delegate '{1}' in mapped statement '{0}'. \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Statements/IMappedStatement.php b/framework/DataAccess/SQLMap/Statements/IMappedStatement.php
new file mode 100644
index 00000000..6a4d76db
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Statements/IMappedStatement.php
@@ -0,0 +1,71 @@
+<?php
+
+interface IMappedStatement
+{
+ /**
+ * @return string Name used to identify the MappedStatement amongst the others.
+ */
+ public function getID();
+
+ /**
+ * @return TSqlMapStatement The SQL statment used by this TMappedStatement.
+ */
+ public function getStatement();
+
+ /**
+ * @return TSqlMap The TSqlMap used by this TMappedStatement
+ */
+ public function getSqlMap();
+
+ /**
+ * Executes the SQL and retuns all rows selected in a map that is keyed on
+ * the property named in the <tt>$keyProperty</tt> parameter. The value at
+ * each key will be the value of the property specified in the
+ * <tt>$valueProperty</tt> parameter. If <tt>$valueProperty</tt> is
+ * <tt>null</tt>, the entire result object will be entered.
+ * @param IDbConnection database connection to execute the query
+ * @param mixed The object used to set the parameters in the SQL.
+ * @param string The property of the result object to be used as the key.
+ * @param string The property of the result object to be used as the value (or null)
+ * @return TMap A map of object containing the rows keyed by <tt>$keyProperty</tt>.
+ */
+ public function executeQueryForMap($connection, $parameter,
+ $keyProperty, $valueProperty=null);
+
+
+ /**
+ * Execute an update statement. Also used for delete statement. Return the
+ * number of row effected.
+ * @param IDbConnection database connection to execute the query
+ * @param mixed The object used to set the parameters in the SQL.
+ * @return integer The number of row effected.
+ */
+ public function executeUpdate($connection, $parameter);
+
+
+ /**
+ * Executes the SQL and retuns a subset of the rows selected.
+ * @param IDbConnection database connection to execute the query
+ * @param mixed The object used to set the parameters in the SQL.
+ * @param TList A list to populate the result with.
+ * @param integer The number of rows to skip over.
+ * @param integer The maximum number of rows to return.
+ * @return TList A TList of result objects.
+ */
+ public function executeQueryForList($connection,
+ $parameter, $result, $skip=-1, $max=-1);
+
+
+ /**
+ * Executes an SQL statement that returns a single row as an object
+ * of the type of the <tt>$result</tt> passed in as a parameter.
+ * @param IDbConnection database connection to execute the query
+ * @param mixed The object used to set the parameters in the SQL.
+ * @param object The result object.
+ * @return object result.
+ */
+ public function executeQueryForObject($connection,
+ $parameter, $result);
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Statements/TCachingStatement.php b/framework/DataAccess/SQLMap/Statements/TCachingStatement.php
new file mode 100644
index 00000000..8e4e2a3d
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Statements/TCachingStatement.php
@@ -0,0 +1,102 @@
+<?php
+
+/**
+ *
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: $ $Date: $
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TCachingStatement implements IMappedStatement
+{
+ private $_mappedStatement;
+
+ public function __construct(TMappedStatement $statement)
+ {
+ $this->_mappedStatement = $statement;
+ }
+
+ public function getID()
+ {
+ return $this->_mappedStatement->getID();
+ }
+
+ public function getStatement()
+ {
+ return $this->_mappedStatement->getStatement();
+ }
+
+ public function getSqlMap()
+ {
+ return $this->_mappedStatement->getSqlMap();
+ }
+
+ public function executeQueryForMap($connection, $parameter,
+ $keyProperty, $valueProperty=null, $delegate=null)
+ {
+ $sql = $this->createCommand($connection, $parameter);
+ $key = $this->getCacheKey(array($sql, $keyProperty, $valueProperty));
+ $map = $this->getStatement()->getCache()->get($key);
+ if(is_null($map))
+ {
+ $map = $this->_mappedStatement->runQueryForMap(
+ $connection, $parameter, $sql, $keyProperty, $valueProperty, $delegate);
+ $this->getStatement()->getCache()->set($key, $map);
+ }
+ return $map;
+ }
+
+ public function executeUpdate($connection, $parameter)
+ {
+ return $this->_mappedStatement->executeUpdate($connection, $parameter);
+ }
+
+ public function executeInsert($connection, $parameter)
+ {
+ return $this->executeInsert($connection, $parameter);
+ }
+
+ public function executeQueryForList($connection, $parameter,
+ $result, $skip=-1, $max=-1, $delegate=null)
+ {
+ $sql = $this->createCommand($connection, $parameter);
+ $key = $this->getCacheKey(array($sql, $skip, $max));
+ $list = $this->getStatement()->getCache()->get($key);
+ if(is_null($list))
+ {
+ $list = $this->_mappedStatement->runQueryForList(
+ $connection, $parameter, $sql, $result, $skip, $max, $delegate);
+ $this->getStatement()->getCache()->set($key, $list);
+ }
+ return $list;
+ }
+
+ public function executeQueryForObject($connection, $parameter, $result)
+ {
+ $sql = $this->createCommand($connection, $parameter);
+ $key = $this->getCacheKey($sql);
+ $object = $this->getStatement()->getCache()->get($key);
+ if(is_null($object))
+ {
+ $object = $this->_mappedStatement->runQueryForObject(
+ $connection, $sql, $result);
+ $this->getStatement()->getCache()->set($key, $object);
+ }
+ return $object;
+ }
+
+ protected function getCacheKey($object)
+ {
+ $cacheKey = new TSqlMapCacheKey($object);
+ return $cacheKey->getHash();
+ }
+
+ protected function createCommand($connection, $parameter)
+ {
+ return $this->_mappedStatement->getCommand()->create(
+ $connection, $this->getStatement(), $parameter);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Statements/TDeleteMappedStatement.php b/framework/DataAccess/SQLMap/Statements/TDeleteMappedStatement.php
new file mode 100644
index 00000000..9a1c8fae
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Statements/TDeleteMappedStatement.php
@@ -0,0 +1,7 @@
+<?php
+
+class TDeleteMappedStatement extends TUpdateMappedStatement
+{
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Statements/TInsertMappedStatement.php b/framework/DataAccess/SQLMap/Statements/TInsertMappedStatement.php
new file mode 100644
index 00000000..7a444c89
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Statements/TInsertMappedStatement.php
@@ -0,0 +1,32 @@
+<?php
+
+class TInsertMappedStatement extends TMappedStatement
+{
+ public function executeQueryForMap($connection, $parameter,
+ $keyProperty, $valueProperty=null)
+ {
+ throw new TSqlMapExecutionException(
+ 'sqlmap_cannot_execute_query_for_map', get_class($this));
+ }
+
+ public function executeUpdate($connection, $parameter)
+ {
+ throw new TSqlMapExecutionException(
+ 'sqlmap_cannot_execute_update', get_class($this));
+ }
+
+ public function executeQueryForList($connection, $parameter, $result,
+ $skip=-1, $max=-1)
+ {
+ throw new TSqlMapExecutionException(
+ 'sqlmap_cannot_execute_query_for_list', get_class($this));
+ }
+
+ public function executeQueryForObject($connection, $parameter, $result)
+ {
+ throw new TSqlMapExecutionException(
+ 'sqlmap_cannot_execute_query_for_object', get_class($this));
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Statements/TMappedStatement.php b/framework/DataAccess/SQLMap/Statements/TMappedStatement.php
new file mode 100644
index 00000000..483a315a
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Statements/TMappedStatement.php
@@ -0,0 +1,988 @@
+<?php
+/**
+ * TMappedStatement and related classes.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $Date: $
+ * @package System.DataAccess.SQLMap.Statements
+ */
+
+/**
+ * TMappedStatement class executes SQL mapped statements. Mapped Statements can
+ * hold any SQL statement and use Parameter Maps and Result Maps for input and output.
+ *
+ * This class is usualy instantiated during SQLMap configuration by TSqlDomBuilder.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: $ $Date: $
+ * @package System.DataAccess.SQLMap.Statements
+ * @since 3.0
+ */
+class TMappedStatement extends TComponent implements IMappedStatement
+{
+ /**
+ * @var TSqlMapStatement current SQL statement.
+ */
+ private $_statement;
+
+ /**
+ * @var TPreparedCommand SQL command prepareer
+ */
+ private $_command;
+
+ /**
+ * @var TSqlMapper sqlmap used by this mapper.
+ */
+ private $_sqlMap;
+
+ /**
+ * @var TPostSelectBinding[] post select statement queue.
+ */
+ private $_selectQueque=array();
+
+ /**
+ * @var boolean true when data is mapped to a particular row.
+ */
+ private $_IsRowDataFound = false;
+
+ /**
+ * @var array group by result data cache.
+ */
+ private $_groupBy=array();
+
+ /**
+ * @var Post select is to query for list.
+ */
+ const QUERY_FOR_LIST = 0;
+
+ /**
+ * @var Post select is to query for list.
+ */
+ const QUERY_FOR_ARRAY = 1;
+
+ /**
+ * @var Post select is to query for object.
+ */
+ const QUERY_FOR_OBJECT = 2;
+
+ /**
+ * @return string Name used to identify the TMappedStatement amongst the others.
+ * This the name of the SQL statement by default.
+ */
+ public function getID()
+ {
+ return $this->_statement->ID;
+ }
+
+ /**
+ * @return TSqlMapStatement The SQL statment used by this MappedStatement
+ */
+ public function getStatement()
+ {
+ return $this->_statement;
+ }
+
+ /**
+ * @return TSqlMapper The SqlMap used by this MappedStatement
+ */
+ public function getSqlMap()
+ {
+ return $this->_sqlMap;
+ }
+
+ /**
+ * @return TPreparedCommand command to prepare SQL statements.
+ */
+ public function getCommand()
+ {
+ return $this->_command;
+ }
+
+ /**
+ * @return TResultMapGroupBy[] list of results obtained from group by result maps.
+ */
+ protected function getGroupByResults()
+ {
+ return $this->_groupBy;
+ }
+
+ /**
+ * Empty the group by results cache.
+ */
+ protected function clearGroupByResults()
+ {
+ $this->_groupBy = array();
+ }
+
+ /**
+ * Creates a new mapped statement.
+ * @param TSqlMapper an sqlmap.
+ * @param TSqlMapStatement An SQL statement.
+ */
+ public function __construct(TSqlMapper $sqlMap, TSqlMapStatement $statement)
+ {
+ $this->_sqlMap = $sqlMap;
+ $this->_statement = $statement;
+ $this->_command = new TPreparedCommand();
+ }
+
+ /**
+ * Execute SQL Query.
+ * @param IDbConnection database connection
+ * @param array SQL statement and parameters.
+ * @return mixed record set if applicable.
+ * @throws TSqlMapExecutionException if execution error or false record set.
+ * @throws TSqlMapQueryExecutionException if any execution error
+ */
+ protected function executeSQLQuery($connection, $sql)
+ {
+ try
+ {
+ if(!($recordSet = $connection->execute($sql['sql'],$sql['parameters'])))
+ {
+ throw new TSqlMapExecutionException(
+ 'sqlmap_execution_error_no_record', $this->getID(),
+ $connection->ErrorMsg());
+ }
+ return $recordSet;
+ }
+ catch (Exception $e)
+ {
+ throw new TSqlMapQueryExecutionException($this->getStatement(), $e);
+ }
+ }
+
+ /**
+ * Execute SQL Query with limits.
+ * @param IDbConnection database connection
+ * @param array SQL statement and parameters.
+ * @return mixed record set if applicable.
+ * @throws TSqlMapExecutionException if execution error or false record set.
+ * @throws TSqlMapQueryExecutionException if any execution error
+ */
+ protected function executeSQLQueryLimit($connection, $sql, $max, $skip)
+ {
+ try
+ {
+ $recordSet = $connection->selectLimit($sql['sql'],$max,$skip,$sql['parameters']);
+ if(!$recordSet)
+ {
+ throw new TSqlMapExecutionException(
+ 'sqlmap_execution_error_query_for_list',
+ $connection->ErrorMsg());
+ }
+ return $recordSet;
+ }
+ catch (Exception $e)
+ {
+ throw new TSqlMapQueryExecutionException($this->getStatement(), $e);
+ }
+ }
+
+ /**
+ * Executes the SQL and retuns a List of result objects.
+ * @param IDbConnection database connection
+ * @param mixed The object used to set the parameters in the SQL.
+ * @param object result collection object.
+ * @param integer The number of rows to skip over.
+ * @param integer The maximum number of rows to return.
+ * @return array a list of result objects
+ * @param callback row delegate handler
+ * @see executeQueryForList()
+ */
+ public function executeQueryForList($connection, $parameter, $result, $skip=-1, $max=-1, $delegate=null)
+ {
+ $sql = $this->_command->create($connection, $this->_statement, $parameter);
+ return $this->runQueryForList($connection, $parameter, $sql, $result, $skip, $max, $delegate);
+ }
+
+ /**
+ * Executes the SQL and retuns a List of result objects.
+ *
+ * This method should only be called by internal developers, consider using
+ * <tt>executeQueryForList()</tt> first.
+ *
+ * @param IDbConnection database connection
+ * @param mixed The object used to set the parameters in the SQL.
+ * @param array SQL string and subsititution parameters.
+ * @param object result collection object.
+ * @param integer The number of rows to skip over.
+ * @param integer The maximum number of rows to return.
+ * @param callback row delegate handler
+ * @return array a list of result objects
+ * @see executeQueryForList()
+ */
+ public function runQueryForList($connection, $parameter, $sql, $result, $skip=-1, $max=-1, $delegate=null)
+ {
+ $list = $result instanceof ArrayAccess ? $result :
+ $this->_statement->createInstanceOfListClass();
+ $recordSet = $this->executeSQLQueryLimit($connection, $sql, $max, $skip);
+
+ if(!is_null($delegate))
+ {
+ while($row = $recordSet->fetchRow())
+ {
+ $obj = $this->applyResultMap($row);
+ $param = new TResultSetListItemParameter($obj, $parameter, $list);
+ $this->raiseRowDelegate($delegate, $param);
+ }
+ }
+ else
+ {
+ while($row = $recordSet->fetchRow())
+ {
+ $obj = $this->applyResultMap($row);
+ if(!is_null($obj))
+ $list[] = $obj;
+ }
+ }
+
+ //get the groupings
+ foreach($this->getGroupbyResults() as $group)
+ $list[] = $group->updateProperties();
+ $this->clearGroupByResults();
+
+ $this->executePostSelect($connection);
+ $this->onExecuteQuery($sql);
+ return $list;
+ }
+
+ /**
+ * Executes the SQL and retuns all rows selected in a map that is keyed on
+ * the property named in the keyProperty parameter. The value at each key
+ * will be the value of the property specified in the valueProperty parameter.
+ * If valueProperty is null, the entire result object will be entered.
+ * @param IDbConnection database connection
+ * @param mixed The object used to set the parameters in the SQL.
+ * @param string The property of the result object to be used as the key.
+ * @param string The property of the result object to be used as the value (or null).
+ * @param callback row delegate handler
+ * @return array An array of object containing the rows keyed by keyProperty.
+ */
+ public function executeQueryForMap($connection, $parameter, $keyProperty, $valueProperty=null, $delegate=null)
+ {
+ $sql = $this->_command->create($connection, $this->_statement, $parameter);
+ return $this->runQueryForMap($connection, $parameter, $sql, $keyProperty, $valueProperty, $delegate);
+ }
+
+ /**
+ * Executes the SQL and retuns all rows selected in a map that is keyed on
+ * the property named in the keyProperty parameter. The value at each key
+ * will be the value of the property specified in the valueProperty parameter.
+ * If valueProperty is null, the entire result object will be entered.
+ *
+ * This method should only be called by internal developers, consider using
+ * <tt>executeQueryForMap()</tt> first.
+ *
+ * @param IDbConnection database connection
+ * @param mixed The object used to set the parameters in the SQL.
+ * @param array SQL string and subsititution parameters.
+ * @param string The property of the result object to be used as the key.
+ * @param string The property of the result object to be used as the value (or null).
+ * @param callback row delegate, a callback function
+ * @return array An array of object containing the rows keyed by keyProperty.
+ * @see executeQueryForMap()
+ */
+ public function runQueryForMap($connection, $parameter, $sql, $keyProperty, $valueProperty=null, $delegate=null)
+ {
+ $map = array();
+ $recordSet = $this->executeSQLQuery($connection, $sql);
+ if(!is_null($delegate))
+ {
+ while($row = $recordSet->fetchRow())
+ {
+ $obj = $this->applyResultMap($row);
+ $key = TPropertyAccess::get($obj, $keyProperty);
+ $value = is_null($valueProperty) ? $obj :
+ TPropertyAccess::get($obj, $valueProperty);
+ $param = new TResultSetMapItemParameter($key, $value, $parameter, $map);
+ $this->raiseRowDelegate($delegate, $param);
+ }
+ }
+ else
+ {
+ while($row = $recordSet->fetchRow())
+ {
+ $obj = $this->applyResultMap($row);
+ $key = TPropertyAccess::get($obj, $keyProperty);
+ $map[$key] = is_null($valueProperty) ? $obj :
+ TPropertyAccess::get($obj, $valueProperty);
+ }
+ }
+ $this->onExecuteQuery($sql);
+ return $map;
+ }
+
+ /**
+ * Raises delegate handler.
+ * This method is invoked for each new list item. It is the responsibility
+ * of the handler to add the item to the list.
+ * @param object event parameter
+ */
+ protected function raiseRowDelegate($handler, $param)
+ {
+ if(is_string($handler))
+ {
+ call_user_func($handler,$this,$param);
+ }
+ else if(is_callable($handler,true))
+ {
+ // an array: 0 - object, 1 - method name/path
+ list($object,$method)=$handler;
+ if(is_string($object)) // static method call
+ call_user_func($handler,$this,$param);
+ else
+ {
+ if(($pos=strrpos($method,'.'))!==false)
+ {
+ $object=$this->getSubProperty(substr($method,0,$pos));
+ $method=substr($method,$pos+1);
+ }
+ $object->$method($this,$param);
+ }
+ }
+ else
+ throw new TInvalidDataValueException('sqlmap_invalid_delegate', $this->getID(), $handler);
+ }
+
+ /**
+ * Executes an SQL statement that returns a single row as an object of the
+ * type of the <tt>$result</tt> passed in as a parameter.
+ * @param IDbConnection database connection
+ * @param mixed The parameter data (object, arrary, primitive) used to set the parameters in the SQL
+ * @param mixed The result object.
+ * @return ${return}
+ */
+ public function executeQueryForObject($connection, $parameter, $result)
+ {
+ $sql = $this->_command->create($connection, $this->_statement, $parameter);
+ return $this->runQueryForObject($connection, $sql, $result);
+ }
+
+ /**
+ * Executes an SQL statement that returns a single row as an object of the
+ * type of the <tt>$result</tt> passed in as a parameter.
+ *
+ * This method should only be called by internal developers, consider using
+ * <tt>executeQueryForObject()</tt> first.
+ *
+ * @param IDbConnection database connection
+ * @param array SQL string and subsititution parameters.
+ * @param object The result object.
+ * @return object the object.
+ * @see executeQueryForObject()
+ */
+ public function runQueryForObject($connection, $sql, $result)
+ {
+ $recordSet = $this->executeSQLQuery($connection, $sql);
+ $object = $this->applyResultMap($recordSet->fetchRow(), $result);
+
+ //get group by result
+ foreach($this->getGroupbyResults() as $group)
+ $object = $group->updateProperties();
+ $this->clearGroupByResults();
+
+ $this->executePostSelect($connection);
+ $this->onExecuteQuery($sql);
+ return $object;
+ }
+
+ /**
+ * Execute an insert statement. Fill the parameter object with the ouput
+ * parameters if any, also could return the insert generated key.
+ * @param IDbConnection database connection
+ * @param mixed The parameter object used to fill the statement.
+ * @return string the insert generated key.
+ */
+ public function executeInsert($connection, $parameter)
+ {
+ $generatedKey = $this->getPreGeneratedSelectKey($connection, $parameter);
+
+ $sql = $this->_command->create($connection, $this->_statement, $parameter);
+
+ $this->executeSQLQuery($connection, $sql);
+
+ if(is_null($generatedKey))
+ $generatedKey = $this->getPostGeneratedSelectKey($connection, $parameter);
+
+ $this->executePostSelect($connection);
+ $this->onExecuteQuery($sql);
+ return $generatedKey;
+ }
+
+ /**
+ * Gets the insert generated ID before executing an insert statement.
+ * @param IDbConnection database connection
+ * @param mixed insert statement parameter.
+ * @return string new insert ID if pre-select key statement was executed, null otherwise.
+ */
+ protected function getPreGeneratedSelectKey($connection, $parameter)
+ {
+ if($this->_statement instanceof TSqlMapInsert)
+ {
+ $selectKey = $this->_statement->getSelectKey();
+ if(!is_null($selectKey) && !$selectKey->getIsAfter())
+ return $this->executeSelectKey($connection, $parameter, $selectKey);
+ }
+ }
+
+ /**
+ * Gets the inserted row ID after executing an insert statement.
+ * @param IDbConnection database connection
+ * @param mixed insert statement parameter.
+ * @return string last insert ID, null otherwise.
+ */
+ protected function getPostGeneratedSelectKey($connection, $parameter)
+ {
+ if($this->_statement instanceof TSqlMapInsert)
+ {
+ $selectKey = $this->_statement->getSelectKey();
+ if(!is_null($selectKey) && $selectKey->getIsAfter())
+ return $this->executeSelectKey($connection, $parameter, $selectKey);
+ }
+ }
+
+ /**
+ * Execute the select key statement, used to obtain last insert ID.
+ * @param IDbConnection database connection
+ * @param mixed insert statement parameter
+ * @param TSqlMapSelectKey select key statement
+ * @return string last insert ID.
+ */
+ protected function executeSelectKey($connection, $parameter, $selectKey)
+ {
+ $mappedStatement = $this->sqlMap->getMappedStatement($selectKey->getID());
+ $generatedKey = $mappedStatement->executeQueryForObject(
+ $connection, $parameter, null);
+ if(strlen($prop = $selectKey->getProperty()) > 0)
+ TPropertyAccess::set($parameter, $prop, $generatedKey);
+ return $generatedKey;
+ }
+
+ /**
+ * Execute an update statement. Also used for delete statement.
+ * Return the number of rows effected.
+ * @param IDbConnection database connection
+ * @param mixed The object used to set the parameters in the SQL.
+ * @return integer The number of rows effected.
+ */
+ public function executeUpdate($connection, $parameter)
+ {
+ $sql = $this->_command->create($connection, $this->_statement, $parameter);
+ $this->executeSQLQuery($connection, $sql);
+ $this->executePostSelect($connection);
+ $this->onExecuteQuery($sql);
+ return $connection->Affected_Rows();
+ }
+
+ /**
+ * Process 'select' result properties
+ * @param IDbConnection database connection
+ */
+ protected function executePostSelect($connection)
+ {
+
+ while(count($this->_selectQueque))
+ {
+ $postSelect = array_shift($this->_selectQueque);
+ $method = $postSelect->getMethod();
+ $statement = $postSelect->getStatement();
+ $property = $postSelect->getResultProperty()->getProperty();
+ $keys = $postSelect->getKeys();
+ $resultObject = $postSelect->getResultObject();
+
+ if($method == self::QUERY_FOR_LIST || $method == self::QUERY_FOR_ARRAY)
+ {
+ $values = $statement->executeQueryForList($connection, $keys, null);
+
+ if($method == self::QUERY_FOR_ARRAY)
+ $values = $values->toArray();
+ TPropertyAccess::set($resultObject, $property, $values);
+ }
+ else if($method == self::QUERY_FOR_OBJECT)
+ {
+ $value = $statement->executeQueryForObject($connection, $keys, null);
+ TPropertyAccess::set($resultObject, $property, $value);
+ }
+ }
+ }
+
+ /**
+ * Raise the execute query event.
+ * @param array prepared SQL statement and subsititution parameters
+ */
+ public function onExecuteQuery($sql)
+ {
+ $this->raiseEvent('OnExecuteQuery', $this, $sql);
+ }
+
+ /**
+ * Apply result mapping.
+ * @param array a result set row retrieved from the database
+ * @param object the result object, will create if necessary.
+ * @return object the result filled with data, null if not filled.
+ */
+ protected function applyResultMap($row, $resultObject=null)
+ {
+ if($row === false) return null;
+
+ $resultMapName = $this->_statement->getResultMap();
+ $resultClass = $this->_statement->getResultClass();
+
+ if($this->_sqlMap->getResultMaps()->contains($resultMapName))
+ return $this->fillResultMap($resultMapName, $row, $resultObject);
+ else if(strlen($resultClass) > 0)
+ return $this->fillResultClass($resultClass, $row, $resultObject);
+ else
+ return $this->fillDefaultResultMap(null, $row, $resultObject);
+ }
+
+ /**
+ * Fill the result using ResultClass, will creates new result object if required.
+ * @param string result object class name
+ * @param array a result set row retrieved from the database
+ * @param object the result object, will create if necessary.
+ * @return object result object filled with data
+ */
+ protected function fillResultClass($resultClass, $row, $resultObject)
+ {
+ if(is_null($resultObject))
+ $resultObject = $this->_statement->createInstanceOfResultClass();
+
+ if($resultObject instanceOf ArrayAccess)
+ return $this->fillResultArrayList($row, $resultObject);
+ else if(is_object($resultObject))
+ return $this->fillResultObjectProperty($row, $resultObject);
+ else
+ return $this->fillDefaultResultMap(null, $row, $resultObject);
+ }
+
+ /**
+ * Apply the result to a TList or an array.
+ * @param array a result set row retrieved from the database
+ * @param object result object, array or list
+ * @return object result filled with data.
+ */
+ protected function fillResultArrayList($row, $resultObject)
+ {
+ if($resultObject instanceof TList)
+ foreach($row as $v)
+ $resultObject[] = $v;
+ else
+ foreach($row as $k => $v)
+ $resultObject[$k] = $v;
+ return $resultObject;
+ }
+
+ /**
+ * Apply the result to an object.
+ * @param array a result set row retrieved from the database
+ * @param object result object, array or list
+ * @return object result filled with data.
+ */
+ protected function fillResultObjectProperty($row, $resultObject)
+ {
+ $index = 0;
+ foreach($row as $k=>$v)
+ {
+ $property = new TResultProperty;
+ $property->initialize($this->_sqlMap);
+ if(is_string($k) && strlen($k) > 0)
+ $property->setColumn($k);
+ $property->setColumnIndex(++$index);
+ $type = gettype(TPropertyAccess::get($resultObject,$k));
+ $property->setType($type);
+ $value = $property->getDatabaseValue($row);
+ TPropertyAccess::set($resultObject, $k,$value);
+ }
+ return $resultObject;
+ }
+
+ /**
+ * Fills the result object according to result mappings.
+ * @param string result map name.
+ * @param array a result set row retrieved from the database
+ * @param object result object to fill, will create new instances if required.
+ * @return object result object filled with data.
+ */
+ protected function fillResultMap($resultMapName, $row, $resultObject)
+ {
+ $resultMap = $this->_sqlMap->getResultMap($resultMapName);
+ $resultMap = $resultMap->resolveSubMap($row);
+
+ if(is_null($resultObject))
+ $resultObject = $resultMap->createInstanceOfResult();
+
+ if(is_object($resultObject))
+ {
+ if(strlen($resultMap->getGroupBy()) > 0)
+ return $this->addResultMapGroupBy($resultMap, $row, $resultObject);
+ else
+ foreach($resultMap->getColumns() as $property)
+ $this->setObjectProperty($resultMap, $property, $row, $resultObject);
+ }
+ else
+ {
+ $resultObject = $this->fillDefaultResultMap($resultMap, $row, $resultObject);
+ }
+ return $resultObject;
+ }
+
+ /**
+ * ResultMap with GroupBy property. Save results temporarily, retrieve it later using
+ * <tt>TMappedStatement::getGroupByResults()</tt> and <tt>TResultMapGroupBy::updateProperties()</tt>
+ * @param TResultMap result mapping details.
+ * @param array a result set row retrieved from the database
+ * @param object the result object
+ * @return null, always returns null, use getGroupByResults() to obtain the result object list.
+ * @see getGroupByResults()
+ * @see runQueryForList()
+ */
+ protected function addResultMapGroupBy($resultMap, $row, $resultObject)
+ {
+ $group = $this->getResultMapGroupKey($resultMap, $row, $resultObject);
+ foreach($resultMap->getColumns() as $property)
+ {
+ $this->setObjectProperty($resultMap, $property, $row, $resultObject);
+ if(strlen($property->getResultMapping()) > 0)
+ {
+ $key = $property->getProperty();
+ $value = TPropertyAccess::get($resultObject, $key);
+ $this->_groupBy[$group]->addValue($key, $value);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the result 'group by' groupping key for each row.
+ * @param TResultMap result mapping details.
+ * @param array a result set row retrieved from the database
+ * @param object the result object
+ * @return string groupping key.
+ * @throws TSqlMapExecutionException if unable to find grouping key.
+ */
+ protected function getResultMapGroupKey($resultMap, $row, $resultObject)
+ {
+ $groupBy = $resultMap->getGroupBy();
+ if(isset($row[$groupBy]))
+ {
+ $group = $row[$groupBy];
+ if(!isset($this->_groupBy[$group]))
+ $this->_groupBy[$group] = new TResultMapGroupBy($group, $resultObject);
+ return $group;
+ }
+ else
+ {
+ throw new TSqlMapExecutionException('sqlmap_unable_to_find_groupby',
+ $groupBy, $resultMap->getID());
+ }
+ }
+
+ /**
+ * Fill the result map using default settings. If <tt>$resultMap</tt> is null
+ * the result object returned will be guessed from <tt>$resultObject</tt>.
+ * @param TResultMap result mapping details.
+ * @param array a result set row retrieved from the database
+ * @param object the result object
+ * @return mixed the result object filled with data.
+ */
+ protected function fillDefaultResultMap($resultMap, $row, $resultObject)
+ {
+ if(is_null($resultObject))
+ $resultObject='';
+
+ if(!is_null($resultMap))
+ $result = $this->fillArrayResultMap($resultMap, $row, $resultObject);
+ else
+ $result = $row;
+
+ //if scalar result types
+ if(count($result) == 1 && ($type = gettype($resultObject))!= 'array')
+ return $this->getScalarResult($result, $type);
+ else
+ return $result;
+ }
+
+ /**
+ * Retrieve the result map as an array.
+ * @param TResultMap result mapping details.
+ * @param array a result set row retrieved from the database
+ * @param object the result object
+ * @return array array list of result objects.
+ */
+ protected function fillArrayResultMap($resultMap, $row, $resultObject)
+ {
+ $result = array();
+ foreach($resultMap->getColumns() as $column)
+ {
+ if(is_null($column->getType())
+ && !is_null($resultObject) && !is_object($resultObject))
+ $column->setType(gettype($resultObject));
+ $result[$column->getProperty()] = $column->getDatabaseValue($row);
+ }
+ return $result;
+ }
+
+ /**
+ * Converts the first array value to scalar value of given type.
+ * @param array list of results
+ * @param string scalar type.
+ * @return mixed scalar value.
+ */
+ protected function getScalarResult($result, $type)
+ {
+ $scalar = array_shift($result);
+ settype($scalar, $type);
+ return $scalar;
+ }
+
+ /**
+ * Set a property of the result object with appropriate value.
+ * @param TResultMap result mapping details.
+ * @param TResultProperty the result property to fill.
+ * @param array a result set row retrieved from the database
+ * @param object the result object
+ */
+ protected function setObjectProperty($resultMap, $property, $row, $resultObject)
+ {
+ $select = $property->getSelect();
+ $key = $property->getProperty();
+ $nested = $property->getNestedResultMap();
+
+ if(strlen($select) == 0 && is_null($nested))
+ {
+ $value = $property->getDatabaseValue($row);
+ TPropertyAccess::set($resultObject, $key, $value);
+ $this->_IsRowDataFound = $this->_IsRowDataFound || ($value != null);
+ }
+ else if(!is_null($nested))
+ {
+ $obj = $nested->createInstanceOfResult();
+ if($this->fillPropertyWithResultMap($nested, $row, $obj) == false)
+ $obj = null;
+ TPropertyAccess::set($resultObject, $key, $obj);
+ }
+ else //'select' ResultProperty
+ {
+ $this->enquequePostSelect($select, $resultMap, $property, $row, $resultObject);
+ }
+ }
+
+ /**
+ * Add nested result property to post select queue.
+ * @param string post select statement ID
+ * @param TResultMap current result mapping details.
+ * @param TResultProperty current result property.
+ * @param array a result set row retrieved from the database
+ * @param object the result object
+ */
+ protected function enquequePostSelect($select, $resultMap, $property, $row, $resultObject)
+ {
+ $statement = $this->_sqlMap->getMappedStatement($select);
+ $key = $this->getPostSelectKeys($resultMap, $property, $row);
+ $postSelect = new TPostSelectBinding;
+ $postSelect->setStatement($statement);
+ $postSelect->setResultObject($resultObject);
+ $postSelect->setResultProperty($property);
+ $postSelect->setKeys($key);
+
+ if($property->isListType($resultObject))
+ {
+ $values = null;
+ if($property->getLazyLoad())
+ {
+ $values = TLazyLoadList::newInstance($statement, $key,
+ $resultObject, $property->getProperty());
+ TPropertyAccess::set($resultObject, $property->getProperty(), $values);
+ }
+ else
+ $postSelect->setMethod(self::QUERY_FOR_LIST);
+ }
+ else if($property->isArrayType($resultObject))
+ $postSelect->setMethod(self::QUERY_FOR_ARRAY);
+ else
+ $postSelect->setMethod(self::QUERY_FOR_OBJECT);
+
+ if(!$property->getLazyLoad())
+ array_push($this->_selectQueque, $postSelect);
+ }
+
+ /**
+ * Finds in the post select property the SQL statement primary selection keys.
+ * @param TResultMap result mapping details
+ * @param TResultProperty result property
+ * @param array current row data.
+ * @return array list of primary key values.
+ */
+ protected function getPostSelectKeys($resultMap, $property,$row)
+ {
+ $value = $property->getColumn();
+ if(is_int(strpos($value.',',0)) || is_int(strpos($value, '=',0)))
+ {
+ $keys = array();
+ foreach(explode(',', $value) as $entry)
+ {
+ $pair =explode('=',$entry);
+ $keys[trim($pair[0])] = $row[trim($pair[1])];
+ }
+ return $keys;
+ }
+ else
+ {
+ return $property->getOrdinalValue($row);
+ }
+ }
+
+ /**
+ * Fills the property with result mapping results.
+ * @param TResultMap nested result mapping details.
+ * @param array a result set row retrieved from the database
+ * @param object the result object
+ * @return boolean true if the data was found, false otherwise.
+ */
+ protected function fillPropertyWithResultMap($resultMap, $row, $resultObject)
+ {
+ $dataFound = false;
+ foreach($resultMap->getColumns() as $property)
+ {
+ $this->_IsRowDataFound = false;
+ $this->setObjectProperty($resultMap, $property, $row, $resultObject);
+ $dataFound = $dataFound || $this->_IsRowDataFound;
+ }
+ $this->_IsRowDataFound = $dataFound;
+ return $dataFound;
+ }
+}
+
+class TPostSelectBinding
+{
+ private $_statement=null;
+ private $_property=null;
+ private $_resultObject=null;
+ private $_keys=null;
+ private $_method=TMappedStatement::QUERY_FOR_LIST;
+
+ public function getStatement(){ return $this->_statement; }
+ public function setStatement($value){ $this->_statement = $value; }
+
+ public function getResultProperty(){ return $this->_property; }
+ public function setResultProperty($value){ $this->_property = $value; }
+
+ public function getResultObject(){ return $this->_resultObject; }
+ public function setResultObject($value){ $this->_resultObject = $value; }
+
+ public function getKeys(){ return $this->_keys; }
+ public function setKeys($value){ $this->_keys = $value; }
+
+ public function getMethod(){ return $this->_method; }
+ public function setMethod($value){ $this->_method = $value; }
+}
+
+class TResultMapGroupBy
+{
+ private $_ID='';
+ private $_object='';
+ private $_values = array();
+
+ public function __construct($id, $object)
+ {
+ $this->setID($id);
+ $this->setObject($object);
+ }
+
+ public function getID(){ return $this->_ID; }
+ public function setID($value){ $this->_ID = $value; }
+
+ public function getObject(){ return $this->_object; }
+ public function setObject($value){ $this->_object = $value; }
+
+ public function addValue($property, $value)
+ {
+ $this->_values[$property][] = $value;
+ }
+
+ public function getProperties()
+ {
+ return array_keys($this->_values);
+ }
+
+ public function updateProperties()
+ {
+ foreach($this->_values as $property => $value)
+ {
+ TPropertyAccess::set($this->getObject(), $property, $value);
+ }
+ return $this->getObject();
+ }
+}
+
+class TResultSetListItemParameter extends TComponent
+{
+ private $_resultObject;
+ private $_parameterObject;
+ private $_list;
+
+ public function __construct($result, $parameter, &$list)
+ {
+ $this->_resultObject = $result;
+ $this->_parameterObject = $parameter;
+ $this->_list = &$list;
+ }
+
+ public function getResult()
+ {
+ return $this->_resultObject;
+ }
+
+ public function getParameter()
+ {
+ return $this->_parameterObject;
+ }
+
+ public function &getList()
+ {
+ return $this->_list;
+ }
+}
+
+class TResultSetMapItemParameter extends TComponent
+{
+ private $_key;
+ private $_value;
+ private $_parameterObject;
+ private $_map;
+
+ public function __construct($key, $value, $parameter, &$map)
+ {
+ $this->_key = $key;
+ $this->_value = $value;
+ $this->_parameterObject = $parameter;
+ $this->_map = &$map;
+ }
+
+ public function getKey()
+ {
+ return $this->_key;
+ }
+
+ public function getValue()
+ {
+ return $this->_value;
+ }
+
+ public function getParameter()
+ {
+ return $this->_parameterObject;
+ }
+
+ public function &getMap()
+ {
+ return $this->_map;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Statements/TPreparedCommand.php b/framework/DataAccess/SQLMap/Statements/TPreparedCommand.php
new file mode 100644
index 00000000..1c0e5ad7
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Statements/TPreparedCommand.php
@@ -0,0 +1,60 @@
+<?php
+
+class TPreparedCommand
+{
+
+ public function create($connection, $statement, $parameterObject)
+ {
+ $prepared = $statement->getSQL()->getPreparedStatement();
+ $parameters = $this->applyParameterMap($connection,
+ $prepared, $statement, $parameterObject);
+ return array('sql'=>$prepared->getPreparedSql(),
+ 'parameters'=>$parameters);
+ }
+
+ protected function applyParameterMap($connection,
+ $prepared, $statement, $parameterObject)
+ {
+ $properties = $prepared->getParameterNames();
+ $parameters = $prepared->getParameterValues();
+ $values = array();
+ for($i = 0, $k=$properties->getCount(); $i<$k; $i++)
+ {
+ $property = $statement->parameterMap()->getProperty($i);
+ $values[] = $statement->parameterMap()->getParameter(
+ $property, $parameterObject, $statement);
+ }
+ return count($values) > 0 ? $values : false;
+ }
+
+/* protected function applyParameterClass($connection, $statement, $parameter)
+ {
+ $type=$statement->getParameterClass();
+ if(strlen($type) < 1) return;
+ $prepared = $statement->getSql()->getPreparedStatement();
+ $names = $prepared->getParameterNames();
+ $values = $prepared->getParameterValues();
+ switch (strtolower($type))
+ {
+ case 'integer':
+ case 'int':
+ $values[$names[0]] = $connection->quote(intval($parameter));
+ break;
+ case 'array':
+ foreach($names as $name)
+ {
+ $key = substr(substr($name,0,-1),1);
+ if(isset($parameter[$key]))
+ $values->add($name,$connection->quote($parameter[$key]));
+ else
+ throw new TDataMapperException('unable_to_find_parameter', $key);
+ }
+ break;
+ default:
+ var_dump("todo for other parameter classes");
+ }
+ }
+*/
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Statements/TPreparedStatement.php b/framework/DataAccess/SQLMap/Statements/TPreparedStatement.php
new file mode 100644
index 00000000..e534f532
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Statements/TPreparedStatement.php
@@ -0,0 +1,26 @@
+<?php
+
+class TPreparedStatement extends TComponent
+{
+ private $_sqlString='';
+ private $_parameterNames;
+ private $_parameterValues;
+
+ public function __construct()
+ {
+ $this->_parameterNames=new TList;
+ $this->_parameterValues=new TMap;
+ }
+
+ public function getPreparedSql(){ return $this->_sqlString; }
+ public function setPreparedSql($value){ $this->_sqlString = $value; }
+
+ public function getParameterNames(){ return $this->_parameterNames; }
+ public function setParameterNames($value){ $this->_parameterNames = $value; }
+
+ public function getParameterValues(){ return $this->_parameterValues; }
+ public function setParameterValues($value){ $this->_parameterValues = $value; }
+
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Statements/TPreparedStatementFactory.php b/framework/DataAccess/SQLMap/Statements/TPreparedStatementFactory.php
new file mode 100644
index 00000000..41059934
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Statements/TPreparedStatementFactory.php
@@ -0,0 +1,47 @@
+<?php
+
+class TPreparedStatementFactory
+{
+ private $_statement;
+ private $_preparedStatement;
+ private $_parameterPrefix = 'param';
+ private $_commandText;
+
+ public function __construct($statement, $sqlString)
+ {
+ $this->_statement = $statement;
+ $this->_commandText = $sqlString;
+ // $this->_statement = new TPreparedStatement();
+// $this->_statement->setSqlString($sqlString);
+ }
+
+ public function prepare()
+ {
+ //$this->createParametersFromTextCommand();
+ //return $this->_statement;
+ $this->_preparedStatement = new TPreparedStatement();
+ $this->_preparedStatement->setPreparedSql($this->_commandText);
+ if(!is_null($this->_statement->parameterMap()))
+ {
+ $this->createParametersForTextCommand();
+ //$this->evaluateParameterMap();
+ }
+ //var_dump($this->_preparedStatement);
+ return $this->_preparedStatement;
+ }
+
+ protected function createParametersForTextCommand()
+ {
+ /*$matches = array();
+ $string = $this->_statement->getSqlString();
+ preg_match_all('/#([a-zA-Z0-9._]+)#/', $string, $matches);
+ $this->_statement->getParameterNames()->copyFrom($matches[0]);*/
+ //var_dump($this->_statement);
+ foreach($this->_statement->ParameterMap()->getProperties() as $prop)
+ {
+ $this->_preparedStatement->getParameterNames()->add($prop->getProperty());
+ }
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Statements/TSelectMappedStatement.php b/framework/DataAccess/SQLMap/Statements/TSelectMappedStatement.php
new file mode 100644
index 00000000..1171e28f
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Statements/TSelectMappedStatement.php
@@ -0,0 +1,19 @@
+<?php
+
+class TSelectMappedStatement extends TMappedStatement
+{
+ public function executeInsert($connection, $parameter)
+ {
+ throw new TSqlMapExecutionException(
+ 'sqlmap_cannot_execute_insert', get_class($this));
+ }
+
+ public function executeUpdate($connection, $parameter)
+ {
+ throw new TSqlMapExecutionException(
+ 'sqlmap_cannot_execute_update', get_class($this));
+ }
+
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Statements/TStaticSql.php b/framework/DataAccess/SQLMap/Statements/TStaticSql.php
new file mode 100644
index 00000000..bf6e4a18
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Statements/TStaticSql.php
@@ -0,0 +1,19 @@
+<?php
+
+class TStaticSql extends TComponent
+{
+ private $_preparedStatement;
+
+ public function buildPreparedStatement($statement, $sqlString)
+ {
+ $factory = new TPreparedStatementFactory($statement, $sqlString);
+ $this->_preparedStatement = $factory->prepare();
+ }
+
+ public function getPreparedStatement()
+ {
+ return $this->_preparedStatement;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/Statements/TUpdateMappedStatement.php b/framework/DataAccess/SQLMap/Statements/TUpdateMappedStatement.php
new file mode 100644
index 00000000..cf16ee52
--- /dev/null
+++ b/framework/DataAccess/SQLMap/Statements/TUpdateMappedStatement.php
@@ -0,0 +1,32 @@
+<?php
+
+class TUpdateMappedStatement extends TMappedStatement
+{
+ public function executeInsert($connection, $parameter)
+ {
+ throw new TSqlMapExecutionException(
+ 'sqlmap_cannot_execute_insert', get_class($this));
+ }
+
+ public function executeQueryForMap($connection, $parameter, $keyProperty,
+ $valueProperty=null)
+ {
+ throw new TSqlMapExecutionException(
+ 'sqlmap_cannot_execute_query_for_map', get_class($this));
+ }
+
+ public function executeQueryForList($connection, $parameter, $result,
+ $skip=-1, $max=-1)
+ {
+ throw new TSqlMapExecutionException(
+ 'sqlmap_cannot_execute_query_for_list', get_class($this));
+ }
+
+ public function executeQueryForObject($connection, $parameter, $result)
+ {
+ throw new TSqlMapExecutionException(
+ 'sqlmap_cannot_execute_query_for_object', get_class($this));
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/TMapper.php b/framework/DataAccess/SQLMap/TMapper.php
new file mode 100644
index 00000000..4427c012
--- /dev/null
+++ b/framework/DataAccess/SQLMap/TMapper.php
@@ -0,0 +1,60 @@
+<?php
+
+require_once(dirname(__FILE__).'/TSqlMapClient.php');
+
+/**
+ * A singleton class to access the default SqlMapper.
+ *
+ * Usage: Call configure() once, then use instance() to obtain a TSqlMapper
+ * instance.
+ * <code>
+ * TMapper::configure($configFile);
+ * $object = TMapper::instance()->queryForObject('statementName');
+ * </code>
+ *
+ * If your configuration file is named 'sqlmap.config' you may skip the
+ * configure() call.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: $ $Date: $
+ * @package System.DataAccess.SQLMap
+ * @since 3.0
+ */
+class TMapper
+{
+ /**
+ * Data mapper singleton
+ * @var TSqlMapper
+ */
+ private static $_mapper;
+
+ /**
+ * Configure the data mapper singleton instance.
+ * @param string configuration file
+ * @param boolean true to load configuration from cache.
+ * @return TSqlMapper data mapper instance.
+ */
+ public static function configure($configFile,$loadCachedConfig=false)
+ {
+ if(is_null(self::$_mapper))
+ {
+ $sqlmap = new TSQLMapClient;
+ self::$_mapper = $sqlmap->configure($configFile,$loadCachedConfig);
+ }
+ return self::$_mapper;
+ }
+
+ /**
+ * Gets the data mapper singleton instance. Default configuration file is
+ * 'sqlmap.config'.
+ * @return TSqlMapper singleton instance.
+ */
+ public static function instance()
+ {
+ if(is_null(self::$_mapper))
+ self::configure('sqlmap.xml');
+ return self::$_mapper;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/TSqlMapClient.php b/framework/DataAccess/SQLMap/TSqlMapClient.php
new file mode 100644
index 00000000..7662d83e
--- /dev/null
+++ b/framework/DataAccess/SQLMap/TSqlMapClient.php
@@ -0,0 +1,81 @@
+<?php
+
+require_once(dirname(__FILE__).'/TSqlMapper.php');
+
+/**
+ * A DataMapper client class that can load a cached SqlMapper. Give the configuration
+ * file, it looks for a .cache file containing serialized TSqlMapClient instance to
+ * load. Usage:
+ *
+ * <code>
+ * $client = new TSqlMapClient;
+ * $sqlmap = $client->configure($configFile, true); //load from cache.
+ * $products = $sqlMap->queryForList('statementName');
+ * </code>
+ *
+ * To save the TSqlMapper instance to cache for later usage, call
+ * cacheConfiguration().
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: $ $Date: $
+ * @package System.DataAccess.SQLMap
+ * @since 3.0
+ */
+class TSqlMapClient
+{
+ private $_mapper;
+ private $_cache;
+
+ public function configure($configFile, $loadFromCache=false)
+ {
+ if(is_null($this->_mapper))
+ $this->initMapper($configFile, $loadFromCache);
+ return $this->_mapper;
+ }
+
+ public function getInstance()
+ {
+ return $this->_mapper;
+ }
+
+ public function cacheConfiguration()
+ {
+ if(!is_null($this->_mapper) && $this->_cache !== false)
+ {
+ if(!is_file($this->_cache))
+ {
+ var_dump('saving cache to file', $this->_cache);
+ file_put_contents($this->_cache,serialize($this->_mapper));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected function initMapper($file=null,$loadFromCache=false)
+ {
+ $this->_cache = $this->getCacheFile($file);
+ if($loadFromCache && $this->_cache !== false && is_file($this->_cache))
+ {
+ var_dump('loading from cache: '.$this->_cache);
+ $this->_mapper = unserialize(file_get_contents($this->_cache));
+ }
+ else
+ {
+// var_dump('build from *.xml');
+ $builder = new TDomSqlMapBuilder();
+ $this->_mapper = $builder->configure($file);
+ }
+ }
+
+ protected function getCacheFile($file)
+ {
+ $path = realpath($file);
+ if($path !== false)
+ return substr($path,0, strrpos($path,'.')).'.cache';
+ else
+ return false;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/TSqlMapper.php b/framework/DataAccess/SQLMap/TSqlMapper.php
new file mode 100644
index 00000000..602b83ea
--- /dev/null
+++ b/framework/DataAccess/SQLMap/TSqlMapper.php
@@ -0,0 +1,543 @@
+<?php
+
+Prado::using('System.DataAccess.SQLMap.DataMapper.*');
+Prado::using('System.DataAccess.SQLMap.Configuration.*');
+Prado::using('System.DataAccess.SQLMap.Statements.*');
+Prado::using('System.DataAccess.SQLMap.DataMapper.TTypeHandlerFactory');
+Prado::using('System.DataAccess.SQLMap.DataMapper.TSqlMapCache');
+Prado::using('System.DataAccess.SQLMap.DataMapper.TDataMapperException');
+Prado::using('System.DataAccess.TAdodbProvider');
+
+/**
+ * DataMapper client, a facade to provide access the rest of the DataMapper
+ * framework. It provides three core functions:
+ *
+ * # execute an update query (including insert and delete).
+ * # execute a select query for a single object
+ * # execute a select query for a list of objects
+ *
+ * Do not create this class explicitly, use TDomSqlMapBuilder to obtain
+ * an instance by parsing through the xml configurations. Example:
+ * <code>
+ * $builder = new TDomSqlMapBuilder();
+ * $mapper = $builder->configure($configFile);
+ * </code>
+ *
+ * Otherwise use convient classes TMapper or TSqlMap to obtain singleton
+ * instances.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: $ $Date: $
+ * @package System.DataAccess.SQLMap
+ * @since 3.0
+ */
+class TSqlMapper extends TComponent
+{
+ private $_connection;
+ private $_mappedStatements;
+ private $_provider;
+ private $_resultMaps;
+ private $_parameterMaps;
+ private $_typeHandlerFactory;
+ private $_cacheModelsEnabled = false;
+ private $_cacheMaps;
+
+ /**
+ * Create a new SqlMap.
+ * @param TTypeHandlerFactory
+ */
+ public function __construct($typeHandlerFactory=null)
+ {
+ $this->_mappedStatements = new TMap;
+ $this->_resultMaps = new TMap;
+ $this->_parameterMaps = new TMap;
+ $this->_typeHandlerFactory = $typeHandlerFactory;
+ $this->_cacheMaps = new TMap;
+ }
+
+ /**
+ * Cleanup work before serializing.
+ * This is a PHP defined magic method.
+ * @return array the names of instance-variables to serialize.
+ */
+ public function __sleep()
+ {
+ if(!is_null($this->_connection) && !$this->_connection->getIsClosed())
+ $this->closeConnection();
+ $this->_connection = null;
+ return array_keys(get_object_vars($this));
+ }
+
+ /**
+ * This method will be automatically called when unserialization happens.
+ * This is a PHP defined magic method.
+ */
+ public function __wake()
+ {
+
+ }
+
+ /**
+ * Set the falg to tell us if cache models were enabled or not.
+ * This should only be called during configuration parsing.
+ * It does not disable the cache after the configuration phase.
+ * @param boolean enables cache.
+ */
+ public function setCacheModelsEnabled($value)
+ {
+ $this->_cacheModelsEnabled = $value;
+ }
+
+ /**
+ * @return boolean true if cache models were enabled when this SqlMap was
+ * built.
+ */
+ public function getIsCacheModelsEnabled()
+ {
+ return $this->_cacheModelsEnabled;
+ }
+
+ /**
+ * @return TTypeHandlerFactory The TypeHandlerFactory
+ */
+ public function getTypeHandlerFactory()
+ {
+ return $this->_typeHandlerFactory;
+ }
+
+ /**
+ * @return TMap mapped statements collection.
+ */
+ public function getStatements()
+ {
+ return $this->_mappedStatements;
+ }
+
+ /**
+ * @return TMap result maps collection.
+ */
+ public function getResultMaps()
+ {
+ return $this->_resultMaps;
+ }
+
+ /**
+ * Adds a named cache.
+ * @param TSqlMapCacheModel the cache to add.
+ * @throws TSqlMapConfigurationException
+ */
+ public function addCache(TSqlMapCacheModel $cacheModel)
+ {
+ if($this->_cacheMaps->contains($cacheModel->getID()))
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_cache_model_already_exists', $cacheModel->getID());
+ else
+ $this->_cacheMaps->add($cacheModel->getID(), $cacheModel);
+ }
+
+ /**
+ * Gets a cache by name
+ * @param string the name of the cache to get.
+ * @return TSqlMapCacheModel the cache object.
+ * @throws TSqlMapConfigurationException
+ */
+ public function getCache($name)
+ {
+ if(!$this->_cacheMaps->contains($name))
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_unable_to_find_cache_model', $name);
+ return $this->_cacheMaps[$name];
+ }
+
+ /**
+ * Flushes all cached objects that belong to this SqlMap
+ */
+ public function flushCaches()
+ {
+ foreach($this->_cacheMaps as $cache)
+ $cache->flush();
+ }
+
+ /**
+ * @return TMap parameter maps collection.
+ */
+ public function getParameterMaps()
+ {
+ return $this->_parameterMaps;
+ }
+
+ /**
+ * Gets a MappedStatement by name.
+ * @param string The name of the statement.
+ * @return IMappedStatement The MappedStatement
+ * @throws TSqlMapUndefinedException
+ */
+ public function getMappedStatement($name)
+ {
+ if($this->_mappedStatements->contains($name) == false)
+ throw new TSqlMapUndefinedException(
+ 'sqlmap_contains_no_statement', $name);
+ return $this->_mappedStatements[$name];
+ }
+
+ /**
+ * Adds a (named) MappedStatement.
+ * @param string The key name
+ * @param IMappedStatement The statement to add
+ * @throws TSqlMapDuplicateException
+ */
+ public function addMappedStatement(IMappedStatement $statement)
+ {
+ $key = $statement->getID();
+ if($this->_mappedStatements->contains($key) == true)
+ throw new TSqlMapDuplicateException(
+ 'sqlmap_already_contains_statement', $key);
+ $this->_mappedStatements->add($key, $statement);
+ }
+
+ /**
+ * Gets a named result map
+ * @param string result name.
+ * @return TResultMap the result map.
+ * @throws TSqlMapUndefinedException
+ */
+ public function getResultMap($name)
+ {
+ if($this->_resultMaps->contains($name) == false)
+ throw new TSqlMapUndefinedException(
+ 'sqlmap_contains_no_result_map', $name);
+ return $this->_resultMaps[$name];
+ }
+
+ /**
+ * @param TResultMap add a new result map to this SQLMap
+ * @throws TSqlMapDuplicateException
+ */
+ public function addResultMap(TResultMap $result)
+ {
+ $key = $result->getID();
+ if($this->_resultMaps->contains($key) == true)
+ throw new TSqlMapDuplicateException(
+ 'sqlmap_already_contains_result_map', $key);
+ $this->_resultMaps->add($key, $result);
+ }
+
+ /**
+ * @param string parameter map ID name.
+ * @return TParameterMap the parameter with given ID.
+ * @throws TSqlMapUndefinedException
+ */
+ public function getParameterMap($name)
+ {
+ if($this->_parameterMaps->contains($name) == false)
+ throw new TSqlMapUndefinedException(
+ 'sqlmap_contains_no_parameter_map', $name);
+ return $this->_parameterMaps[$name];
+ }
+
+ /**
+ * @param TParameterMap add a new parameter map to this SQLMap.
+ * @throws TSqlMapDuplicateException
+ */
+ public function addParameterMap(TParameterMap $parameter)
+ {
+ $key = $parameter->getID();
+ if($this->_parameterMaps->contains($key) == true)
+ throw new TSqlMapDuplicateException(
+ 'sqlmap_already_contains_parameter_map', $key);
+ $this->_parameterMaps->add($key, $parameter);
+ }
+
+ /**
+ * @param TDatabaseProvider changes the database provider.
+ */
+ public function setDataProvider($provider)
+ {
+ $this->_provider = $provider;
+ }
+
+ /**
+ * @return TDatabaseProvider database provider.
+ */
+ public function getDataProvider()
+ {
+ return $this->_provider;
+ }
+
+ /**
+ * Get the current connection, opens the connection if necessary.
+ * @return TDbConnection database connection.
+ */
+ protected function getConnection()
+ {
+ if(is_null($this->_connection))
+ $this->_connection = $this->getDataProvider()->getConnection();
+ $this->_connection->open();
+ return $this->_connection;
+ }
+
+ /**
+ * Open a connection, on the specified connection string if provided.
+ * @param string The connection DSN string
+ * @return TDbConnection database connection.
+ */
+ public function openConnection($connectionString=null)
+ {
+ if(!is_null($connectionString))
+ {
+ if(!is_null($this->_connection))
+ throw new TSqlMapConnectionException(
+ 'sqlmap_connection_already_exists');
+ $this->getDataProvider()->setConnectionString($connectionString);
+ }
+ return $this->getConnection();
+ }
+
+ /**
+ * Close the current database connection.
+ */
+ public function closeConnection()
+ {
+ if(is_null($this->_connection))
+ throw new TSqlMapConnectionException(
+ 'sqlmap_unable_to_close_null_connection');
+ $this->_connection->close();
+ }
+
+ /**
+ * Executes a Sql SELECT statement that returns that returns data
+ * to populate a single object instance.
+ *
+ * The parameter object is generally used to supply the input
+ * data for the WHERE clause parameter(s) of the SELECT statement.
+ *
+ * @param string The name of the sql statement to execute.
+ * @param mixed The object used to set the parameters in the SQL.
+ * @param mixed An object of the type to be returned.
+ * @return object A single result object populated with the result set data.
+ */
+ public function queryForObject($statementName, $parameter=null, $result=null)
+ {
+ $statement = $this->getMappedStatement($statementName);
+ $connection = $this->getConnection();
+ return $statement->executeQueryForObject($connection,
+ $parameter, $result);
+ }
+
+ /**
+ * Executes a Sql SELECT statement that returns data to populate a number
+ * of result objects.
+ *
+ * The parameter object is generally used to supply the input
+ * data for the WHERE clause parameter(s) of the SELECT statement.
+ *
+ * @param string The name of the sql statement to execute.
+ * @param mixed The object used to set the parameters in the SQL.
+ * @param TList An Ilist object used to hold the objects,
+ * pass in null if want to return a list instead.
+ * @param int The number of rows to skip over.
+ * @param int The maximum number of rows to return.
+ * @return TList A List of result objects.
+ */
+ public function queryForList($statementName, $parameter=null,
+ $result=null, $skip=-1, $max=-1)
+ {
+ $statement = $this->getMappedStatement($statementName);
+ $connection = $this->getConnection();
+ return $statement->executeQueryForList($connection,
+ $parameter, $result, $skip, $max);
+ }
+
+ /**
+ * Runs a query for list with a custom object that gets a chance to deal
+ * with each row as it is processed.
+ *
+ * Example: $sqlmap->queryWithRowDelegate('getAccounts', array($this, 'rowHandler'));
+ *
+ * @param string The name of the sql statement to execute.
+ * @param callback Row delegate handler, a valid callback required.
+ * @param mixed The object used to set the parameters in the SQL.
+ * @param TList An Ilist object used to hold the objects,
+ * pass in null if want to return a list instead.
+ * @param int The number of rows to skip over.
+ * @param int The maximum number of rows to return.
+ * @return TList A List of result objects.
+ */
+ public function queryWithRowDelegate($statementName, $delegate, $parameter=null,
+ $result=null, $skip=-1, $max=-1)
+ {
+ $statement = $this->getMappedStatement($statementName);
+ $connection = $this->getConnection();
+ return $statement->executeQueryForList($connection,
+ $parameter, $result, $skip, $max, $delegate);
+ }
+
+ /**
+ * Executes the SQL and retuns a subset of the results in a dynamic
+ * TPagedList that can be used to automatically scroll through results
+ * from a database table.
+ * @param string The name of the sql statement to execute.
+ * @param mixed The object used to set the parameters in the SQL.
+ * @param integer The maximum number of objects to store in each page.
+ * @return TPagedList A PaginatedList of beans containing the rows.
+ */
+ public function queryForPagedList($statementName, $parameter=null, $pageSize=10)
+ {
+ $statement = $this->getMappedStatement($statementName);
+ return new TSqlMapPagedList($statement, $parameter, $pageSize);
+ }
+
+ /**
+ * Executes the SQL and retuns a subset of the results in a dynamic
+ * TPagedList that can be used to automatically scroll through results
+ * from a database table.
+ *
+ * Runs paged list query with row delegate
+ * Example: $sqlmap->queryForPagedListWithRowDelegate('getAccounts', array($this, 'rowHandler'));
+ *
+ * @param string The name of the sql statement to execute.
+ * @param callback Row delegate handler, a valid callback required.
+ * @param mixed The object used to set the parameters in the SQL.
+ * @param integer The maximum number of objects to store in each page.
+ * @return TPagedList A PaginatedList of beans containing the rows.
+ */
+ public function queryForPagedListWithRowDelegate($statementName,
+ $delegate, $parameter=null, $pageSize=10)
+ {
+ $statement = $this->getMappedStatement($statementName);
+ return new TSqlMapPagedList($statement, $parameter, $pageSize, $delegate);
+ }
+
+
+ /**
+ * Executes the SQL and retuns all rows selected in a map that is keyed on
+ * the property named in the keyProperty parameter. The value at each key
+ * will be the value of the property specified in the valueProperty
+ * parameter. If valueProperty is null, the entire result object will be
+ * entered.
+ * @param string The name of the sql statement to execute.
+ * @param mixed The object used to set the parameters in the SQL.
+ * @param string The property of the result object to be used as the key.
+ * @param string The property of the result object to be used as the value.
+ * @return TMap Array object containing the rows keyed by keyProperty.
+ */
+ public function queryForMap($statementName, $parameter=null,
+ $keyProperty=null, $valueProperty=null)
+ {
+ $statement = $this->getMappedStatement($statementName);
+ $connection = $this->getConnection();
+ return $statement->executeQueryForMap($connection,
+ $parameter, $keyProperty, $valueProperty);
+ }
+
+ /**
+ * Runs a query with a custom object that gets a chance to deal
+ * with each row as it is processed.
+ *
+ * Example: $sqlmap->queryForMapWithRowDelegate('getAccounts', array($this, 'rowHandler'));
+ *
+ * @param string The name of the sql statement to execute.
+ * @param callback Row delegate handler, a valid callback required.
+ * @param mixed The object used to set the parameters in the SQL.
+ * @param string The property of the result object to be used as the key.
+ * @param string The property of the result object to be used as the value.
+ * @return TMap Array object containing the rows keyed by keyProperty.
+ */
+ public function queryForMapWithRowDelegate($statementName,
+ $delegate, $parameter=null, $keyProperty=null, $valueProperty=null)
+ {
+ $statement = $this->getMappedStatement($statementName);
+ $connection = $this->getConnection();
+ return $statement->executeQueryForMap($connection,
+ $parameter, $keyProperty, $valueProperty, $delegate);
+ }
+
+ /**
+ * Executes a Sql INSERT statement.
+ *
+ * Insert is a bit different from other update methods, as it provides
+ * facilities for returning the primary key of the newly inserted row
+ * (rather than the effected rows),
+ *
+ * The parameter object is generally used to supply the input data for the
+ * INSERT values.
+ *
+ * @param string The name of the statement to execute.
+ * @param string The parameter object.
+ * @return mixed The primary key of the newly inserted row.
+ * This might be automatically generated by the RDBMS,
+ * or selected from a sequence table or other source.
+ */
+ public function insert($statementName, $parameter=null)
+ {
+ $statement = $this->getMappedStatement($statementName);
+ $connection = $this->getConnection();
+ $generatedKey = $statement->executeInsert($connection, $parameter);
+ return $generatedKey;
+ }
+
+ /**
+ * Executes a Sql UPDATE statement.
+ *
+ * Update can also be used for any other update statement type, such as
+ * inserts and deletes. Update returns the number of rows effected.
+ *
+ * The parameter object is generally used to supply the input data for the
+ * UPDATE values as well as the WHERE clause parameter(s).
+ *
+ * @param string The name of the statement to execute.
+ * @param mixed The parameter object.
+ * @return integer The number of rows effected.
+ */
+ public function update($statementName, $parameter=null)
+ {
+ $statement = $this->getMappedStatement($statementName);
+ $connection = $this->getConnection();
+ return $statement->executeUpdate($connection, $parameter);
+ }
+
+ /**
+ * Executes a Sql DELETE statement. Delete returns the number of rows effected.
+ * @param string The name of the statement to execute.
+ * @param mixed The parameter object.
+ * @return integer The number of rows effected.
+ */
+ public function delete($statementName, $parameter=null)
+ {
+ return $this->update($statementName, $parameter);
+ }
+
+
+ /**
+ * Begins a database transaction on the currect session.
+ * Some databases will always return false if transaction support is not
+ * available
+ * @return boolean true if successful, false otherwise.
+ */
+ public function beginTransaction()
+ {
+ return $this->getConnection()->beginTransaction();
+ }
+
+ /**
+ * End a transaction successfully. If the database does not support
+ * transactions, will return true also as data is always committed.
+ * @return boolean true if successful, false otherwise.
+ */
+ public function commitTransaction()
+ {
+ return $this->getConnection()->commit();
+ }
+
+ /**
+ * End a transaction, rollback all changes. If the database does not
+ * support transactions, will return false as data is never rollbacked.
+ * @return boolean true if successful, false otherwise.
+ */
+ public function rollbackTransaction()
+ {
+ return $this->getConnection()->rollback();
+ }
+}
+
+?> \ No newline at end of file