From caa348ceabba58447bf8deddb8c6316ff3dc88ce Mon Sep 17 00:00:00 2001
From: wei <>
Date: Fri, 28 Jul 2006 00:02:13 +0000
Subject: Fixed nested GroupBy resultMap
---
demos/time-tracker/protected/App_Code/UserDao.php | 4 +-
.../protected/pages/TimeTracker/Login.php | 16 ++
.../SQLMap/Configuration/TDomSqlMapBuilder.php | 6 +-
.../SQLMap/DataMapper/TPropertyAccess.php | 8 +-
.../SQLMap/Statements/TMappedStatement.php | 268 +++++++++++----------
framework/DataAccess/TEzpdo.php | 9 +-
tests/unit/SQLMap/PropertyAccessTest.php | 1 -
tests/unit/SQLMap/sqlite/tests.db | Bin 32768 -> 32768 bytes
8 files changed, 181 insertions(+), 131 deletions(-)
diff --git a/demos/time-tracker/protected/App_Code/UserDao.php b/demos/time-tracker/protected/App_Code/UserDao.php
index 6f31090d..a0a80f7e 100644
--- a/demos/time-tracker/protected/App_Code/UserDao.php
+++ b/demos/time-tracker/protected/App_Code/UserDao.php
@@ -30,7 +30,9 @@ class UserDao extends BaseDao
public function getUserByName($username)
{
$sqlmap = $this->getConnection();
- return $sqlmap->queryForObject('GetUserByName', $username);
+ $user = $sqlmap->queryForObject('GetUserByName', $username);
+ var_dump($user);
+ return $user;
}
/**
diff --git a/demos/time-tracker/protected/pages/TimeTracker/Login.php b/demos/time-tracker/protected/pages/TimeTracker/Login.php
index aa12e716..d8c5182f 100644
--- a/demos/time-tracker/protected/pages/TimeTracker/Login.php
+++ b/demos/time-tracker/protected/pages/TimeTracker/Login.php
@@ -1,4 +1,7 @@
Application->Modules['ezpdo']->getConnection();
+ //$cats = $ezpdo->find('from TimeEntryCategory');
+ $category = $ezpdo->create('TimeEntryCategory');
+ //$category->Name = "Category 1";
+ //$category->Abbreviation = "CAT1";
+ var_dump($category);
+ //$ezpdo->commit($category);
+ }
+
/**
* Validates the username and password.
* @param TControl custom validator that created the event.
diff --git a/framework/DataAccess/SQLMap/Configuration/TDomSqlMapBuilder.php b/framework/DataAccess/SQLMap/Configuration/TDomSqlMapBuilder.php
index 0d1172b0..e43e362d 100644
--- a/framework/DataAccess/SQLMap/Configuration/TDomSqlMapBuilder.php
+++ b/framework/DataAccess/SQLMap/Configuration/TDomSqlMapBuilder.php
@@ -48,11 +48,11 @@ class TDomSqlMapBuilder
public function build(SimpleXMLElement $document)
{
$this->_document = $document;
- $this->initialize($document);
+ $this->initializeSQLMap($document);
return $this->_sqlMapper;
}
- protected function initialize($document)
+ protected function initializeSQLMap($document)
{
$this->_sqlMapper = new TSqlMapper(new TTypeHandlerFactory);
@@ -81,6 +81,7 @@ class TDomSqlMapBuilder
foreach($document->xpath('//sqlMap') as $sqlmap)
$this->loadSqlMappingFiles($sqlmap);
+ $this->resolveResultMapping();
if($this->_sqlMapper->getIsCacheModelsEnabled())
$this->attachCacheModel();
@@ -216,7 +217,6 @@ class TDomSqlMapBuilder
$resource = $this->getResourceFromPath((string)$node['resource']);
$sqlmap = $this->getConfigAsXmlDocument($resource);
$this->configureSqlMap($sqlmap,$resource);
- $this->resolveResultMapping();
}
protected function getResourceFromPath($resource)
diff --git a/framework/DataAccess/SQLMap/DataMapper/TPropertyAccess.php b/framework/DataAccess/SQLMap/DataMapper/TPropertyAccess.php
index dbd4d6e7..e4177be0 100644
--- a/framework/DataAccess/SQLMap/DataMapper/TPropertyAccess.php
+++ b/framework/DataAccess/SQLMap/DataMapper/TPropertyAccess.php
@@ -96,12 +96,16 @@ class TPropertyAccess
return true;
}
- public static function set(&$object, $path, $value)
+ public static function set(&$originalObject, $path, $value)
{
$properties = explode('.', $path);
$prop = array_pop($properties);
if(count($properties) > 0)
- $object = self::get($object, implode('.',$properties));
+ $object = self::get($originalObject, implode('.',$properties));
+ else
+ $object = &$originalObject;
+
+ //var_dump($object);
if(is_array($object) || $object instanceof ArrayAccess)
{
$object[$prop] = $value;
diff --git a/framework/DataAccess/SQLMap/Statements/TMappedStatement.php b/framework/DataAccess/SQLMap/Statements/TMappedStatement.php
index 5c111c22..dfe7aa9a 100644
--- a/framework/DataAccess/SQLMap/Statements/TMappedStatement.php
+++ b/framework/DataAccess/SQLMap/Statements/TMappedStatement.php
@@ -49,7 +49,7 @@ class TMappedStatement extends TComponent implements IMappedStatement
private $_IsRowDataFound = false;
/**
- * @var TSQLMapGroupByTree group by result data cache.
+ * @var TSQLMapObjectCollectionTree group by object collection tree
*/
private $_groupBy;
@@ -101,20 +101,12 @@ class TMappedStatement extends TComponent implements IMappedStatement
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()
+ protected function initialGroupByResults()
{
- $this->_groupBy = new TSQLMapGroupByTree();
+ $this->_groupBy = new TSQLMapObjectCollectionTree();
}
/**
@@ -127,7 +119,7 @@ class TMappedStatement extends TComponent implements IMappedStatement
$this->_sqlMap = $sqlMap;
$this->_statement = $statement;
$this->_command = new TPreparedCommand();
- $this->clearGroupByResults();
+ $this->initialGroupByResults();
}
/**
@@ -236,18 +228,15 @@ class TMappedStatement extends TComponent implements IMappedStatement
$list[] = $this->applyResultMap($row);
}
-// var_dump($list);
- //var_dump($this->_groupBy);
- //get the groupings
- /*foreach($this->getGroupbyResults() as $group)
- $list[] = $group->updateProperties();
- $this->clearGroupByResults();
-*/
if(!$this->_groupBy->isEmpty())
+ {
$list = $this->_groupBy->collect();
+ $this->initialGroupByResults();
+ }
$this->executePostSelect($connection);
$this->onExecuteQuery($sql);
+
return $list;
}
@@ -385,10 +374,13 @@ class TMappedStatement extends TComponent implements IMappedStatement
while($row = $recordSet->fetchRow())
$object = $this->applyResultMap($row, $result);
-// foreach($this->getGroupbyResults() as $group)
- // $object = $group->updateProperties();
-
- $this->clearGroupByResults();
+ //var_dump($this->_groupBy);
+ if(!$this->_groupBy->isEmpty())
+ {
+ $list = $this->_groupBy->collect();
+ $this->initialGroupByResults();
+ $object = $list[0];
+ }
$this->executePostSelect($connection);
$this->onExecuteQuery($sql);
@@ -637,80 +629,66 @@ class TMappedStatement extends TComponent implements IMappedStatement
}
/**
- * ResultMap with GroupBy property. Save results temporarily, retrieve it later using
- * TMappedStatement::getGroupByResults() and TResultMapGroupBy::updateProperties()
+ * ResultMap with GroupBy property. Save object collection graph in a tree
+ * and collect the result later.
* @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()
+ * @return object result object.
*/
protected function addResultMapGroupBy($resultMap, $row, $parent, &$resultObject)
{
- $group = $this->getResultMapGroupKey($resultMap, $row, $resultObject);
+ $group = $this->getResultMapGroupKey($resultMap, $row);
if(empty($parent))
{
- $root= new TResultMapGroupBy(null, $resultObject);
- $this->_groupBy->add('root#'.$group, $group, $root);
+ $rootObject = array('object'=>$resultObject, 'property' => null);
+ $this->_groupBy->add(null, $group, $rootObject);
}
foreach($resultMap->getColumns() as $property)
{
- $scalar = $this->setObjectProperty($resultMap, $property, $row, $resultObject);
- $key = $property->getProperty();
- if(strlen($nested = $property->getResultMapping()) > 0)
+ //set properties.
+ $this->setObjectProperty($resultMap, $property, $row, $resultObject);
+ $nested = $property->getResultMapping();
+
+ //nested property
+ if($this->_sqlMap->getResultMaps()->contains($nested))
{
- if($this->_sqlMap->getResultMaps()->contains($nested))
- $value = $this->fillResultMap($nested, $row, $group);
- else
- $value = $this->extractGroupByValue($property, $resultObject);
-
- $groupby = new TResultMapGroupBy($key, $value);
- $this->_groupBy->add($parent, $group, $groupby);
+ $nestedMap = $this->_sqlMap->getResultMap($nested);
+ $groupKey = $this->getResultMapGroupKey($nestedMap, $row);
+
+ //add the node reference first
+ if(empty($parent))
+ $this->_groupBy->add($group, $groupKey, '');
+
+ //get the nested result mapping value
+ $value = $this->fillResultMap($nested, $row, $groupKey);
+
+ //add it to the object tree graph
+ $groupObject = array('object'=>$value, 'property' => $property->getProperty());
+ if(empty($parent))
+ $this->_groupBy->add($group, $groupKey, $groupObject);
+ else
+ $this->_groupBy->add($parent, $groupKey, $groupObject);
}
}
return $resultObject;
}
- /**
- * Extract value from the object for later adding to a GroupBy collection.
- * @param TResultProperty result property
- * @param mixed result object
- * @return mixed collection element
- */
- protected function extractGroupByValue($property, $resultObject)
- {
- $key = $property->getProperty();
- $value = TPropertyAccess::get($resultObject, $key);
- $type = strtolower($property->getType());
- if(($type == 'array' || $type == 'map') && is_array($value) && count($value) == 1)
- return $value[0];
- else
- return $value;
- }
-
/**
* 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)
+ protected function getResultMapGroupKey($resultMap, $row)
{
$groupBy = $resultMap->getGroupBy();
if(isset($row[$groupBy]))
- {
- return $resultMap->getID().':'.$row[$groupBy];
- }
+ return $resultMap->getID().$row[$groupBy];
else
- {
- throw new TSqlMapExecutionException('sqlmap_unable_to_find_groupby',
- $groupBy, $resultMap->getID());
- }
+ return $resultMap->getID().crc32(serialize($row));
}
/**
@@ -783,8 +761,11 @@ class TMappedStatement extends TComponent implements IMappedStatement
$select = $property->getSelect();
$key = $property->getProperty();
$nested = $property->getNestedResultMap();
-
- if(strlen($select) == 0 && is_null($nested))
+ if($key === '')
+ {
+ $resultObject = $property->getDatabaseValue($row);
+ }
+ else if(strlen($select) == 0 && is_null($nested))
{
$value = $property->getDatabaseValue($row);
@@ -927,45 +908,55 @@ class TPostSelectBinding
public function setMethod($value){ $this->_method = $value; }
}
-class TResultMapGroupBy
-{
- private $_object='';
- private $_property='';
-
- public function __construct($property, $object)
- {
- $this->_property = $property;
- $this->_object = $object;
- }
-
- public function getObject()
- {
- return $this->_object;
- }
-
- public function getProperty()
- {
- return $this->_property;
- }
-}
-
-class TSQLMapGroupByTree
+/**
+ * TSQLMapObjectCollectionTree class.
+ *
+ * Maps object collection graphs as trees. Nodes in the collection can
+ * be {@link add} using parent relationships. The object collections can be
+ * build using the {@link collect} method.
+ *
+ * @author Wei Zhuo
+ * @version $Revision: $ $27/07/2006: $
+ * @package System.DataAccess.SQLMap.Statements
+ * @since 3.1
+ */
+class TSQLMapObjectCollectionTree
{
+ /**
+ * @var array object graph as tree
+ */
private $_tree = array();
-
+ /**
+ * @var array tree node values
+ */
private $_entries = array();
-
+ /**
+ * @var array resulting object collection
+ */
private $_list = array();
+ /**
+ * @return boolean true if the graph is empty
+ */
public function isEmpty()
{
return count($this->_entries) == 0;
}
+ /**
+ * Add a new node to the object tree graph.
+ * @param string parent node id
+ * @param string new node id
+ * @param mixed node value
+ */
public function add($parent, $node, $object='')
{
- if(isset($this->_entries[$parent]) && isset($this->_entries[$node]))
+ if(isset($this->_entries[$parent]) && !is_null($this->_entries[$parent])
+ && isset($this->_entries[$node]) && !is_null($this->_entries[$node]))
+ {
+ $this->_entries[$node] = $object;
return;
+ }
$this->_entries[$node] = $object;
if(empty($parent))
{
@@ -982,6 +973,13 @@ class TSQLMapGroupByTree
}
}
+ /**
+ * Find the parent node and add the new node as its child.
+ * @param array list of nodes to check
+ * @param string parent node id
+ * @param string new node id
+ * @return boolean true if parent node is found.
+ */
protected function addNode(&$childs, $parent, $node)
{
$found = false;
@@ -1003,64 +1001,90 @@ class TSQLMapGroupByTree
return $found;
}
+ /**
+ * @return array object collection
+ */
public function collect()
{
while(count($this->_tree) > 0)
- $this->findAndCollectChilds(null, $this->_tree);
- return $this->getList();
+ $this->collectChildren(null, $this->_tree);
+ return $this->getCollection();
}
- protected function isChild(&$nodes)
+ /**
+ * @param array list of nodes to check
+ * @return boolean true if all nodes are leaf nodes, false otherwise
+ */
+ protected function hasChildren(&$nodes)
{
- $isChild = true;
+ $hasChildren = false;
foreach($nodes as $node)
- {
if(count($node) != 0)
- {
- $isChild = false;
- break;
- }
- }
- return $isChild;
+ return true;
+ return $hasChildren;
}
- protected function findAndCollectChilds($parent, &$nodes)
+ /**
+ * Visit all the child nodes and collect them by removing.
+ * @param string parent node id
+ * @param array list of child nodes.
+ */
+ protected function collectChildren($parent, &$nodes)
{
- $isChild = $this->isChild($nodes);
- reset($nodes);
-
+ $noChildren = !$this->hasChildren($nodes);
$childs = array();
- for($i = 0, $k = count($nodes); $i < $k; $i++)
+ for(reset($nodes); $key = key($nodes);)
{
- $key = key($nodes);
next($nodes);
- if($isChild)
+ if($noChildren)
{
$childs[] = $key;
unset($nodes[$key]);
}
else
- $this->findAndCollectChilds($key, $nodes[$key]);
+ $this->collectChildren($key, $nodes[$key]);
}
if(count($childs) > 0)
$this->onChildNodesVisited($parent, $childs);
}
+ /**
+ * Set the object properties for all the child nodes visited.
+ * @param string parent node id
+ * @param array list of child nodes visited.
+ */
protected function onChildNodesVisited($parent, $nodes)
{
- if(empty($parent))
+ if(empty($parent) || empty($this->_entries[$parent]))
return;
- $parentObject = $this->_entries[$parent]->getObject();
+
+ $parentObject = $this->_entries[$parent]['object'];
+ $property = $this->_entries[$nodes[0]]['property'];
+
+ $list = TPropertyAccess::get($parentObject, $property);
+
foreach($nodes as $node)
- {
- $property= $this->_entries[$node]->getProperty();
- $parentObject->{$property}[] = $this->_entries[$node]->getObject();
+ {
+ if($list instanceof TList)
+ $parentObject->{$property}[] = $this->_entries[$node]['object'];
+ else if(is_array($list))
+ $list[] = $this->_entries[$node]['object'];
+ else
+ throw TSqlMapExecutionException(
+ 'sqlmap_property_must_be_list');
}
- if($this->_entries[$parent]->getProperty() === null)
+
+ if(is_array($list))
+ TPropertyAccess::set($parentObject, $property, $list);
+
+ if($this->_entries[$parent]['property'] === null)
$this->_list[] = $parentObject;
}
- public function getList()
+ /**
+ * @return array object collection.
+ */
+ protected function getCollection()
{
return $this->_list;
}
diff --git a/framework/DataAccess/TEzpdo.php b/framework/DataAccess/TEzpdo.php
index de9d53fe..56065959 100644
--- a/framework/DataAccess/TEzpdo.php
+++ b/framework/DataAccess/TEzpdo.php
@@ -47,9 +47,14 @@ class TEzpdo extends TDatabaseProvider
if($this->getApplication()->getMode() != TApplication::STATE_PERFORMANCE)
{
if(!is_dir($path))
- throw new TConfigurationException('ezpdo_compile_dir_not_found', $path);
+ {
+ if(@mkdir($path)===false)
+ throw new TConfigurationException('ezpdo_compile_dir_not_found' . $path);
+ }
$this->_options['auto_compile'] = false;
}
+ if(!is_dir($path))
+ throw new TConfigurationException('ezpdo_missing_compile_dir', $path);
}
/**
@@ -68,7 +73,7 @@ class TEzpdo extends TDatabaseProvider
if(strlen($dsn = $this->getConnectionString()) > 0)
$options['default_dsn'] = $dsn;
else
- $options['default_dsn'] = $this->buildDsn();
+ $options['default_dsn'] = $this->buildConnectionString();
return array_merge($this->_options, $options);
}
diff --git a/tests/unit/SQLMap/PropertyAccessTest.php b/tests/unit/SQLMap/PropertyAccessTest.php
index 96b942dc..04bb8c17 100644
--- a/tests/unit/SQLMap/PropertyAccessTest.php
+++ b/tests/unit/SQLMap/PropertyAccessTest.php
@@ -7,7 +7,6 @@ require_once(dirname(__FILE__).'/BaseTest.php');
*/
class PropertyAccessTest extends BaseTest
{
-
function testGetPublicProperty()
{
$account = new AccountBis();
diff --git a/tests/unit/SQLMap/sqlite/tests.db b/tests/unit/SQLMap/sqlite/tests.db
index 380ef8fa..fa66b2cc 100644
Binary files a/tests/unit/SQLMap/sqlite/tests.db and b/tests/unit/SQLMap/sqlite/tests.db differ
--
cgit v1.2.3