summaryrefslogtreecommitdiff
path: root/lib/prado/framework/Data/SqlMap/Configuration
diff options
context:
space:
mode:
Diffstat (limited to 'lib/prado/framework/Data/SqlMap/Configuration')
-rw-r--r--lib/prado/framework/Data/SqlMap/Configuration/TDiscriminator.php229
-rw-r--r--lib/prado/framework/Data/SqlMap/Configuration/TInlineParameterMapParser.php77
-rw-r--r--lib/prado/framework/Data/SqlMap/Configuration/TParameterMap.php208
-rw-r--r--lib/prado/framework/Data/SqlMap/Configuration/TParameterProperty.php148
-rw-r--r--lib/prado/framework/Data/SqlMap/Configuration/TResultMap.php198
-rw-r--r--lib/prado/framework/Data/SqlMap/Configuration/TResultProperty.php342
-rw-r--r--lib/prado/framework/Data/SqlMap/Configuration/TSimpleDynamicParser.php43
-rw-r--r--lib/prado/framework/Data/SqlMap/Configuration/TSqlMapCacheModel.php242
-rw-r--r--lib/prado/framework/Data/SqlMap/Configuration/TSqlMapStatement.php444
-rw-r--r--lib/prado/framework/Data/SqlMap/Configuration/TSqlMapXmlConfiguration.php801
10 files changed, 2732 insertions, 0 deletions
diff --git a/lib/prado/framework/Data/SqlMap/Configuration/TDiscriminator.php b/lib/prado/framework/Data/SqlMap/Configuration/TDiscriminator.php
new file mode 100644
index 0000000..004bcca
--- /dev/null
+++ b/lib/prado/framework/Data/SqlMap/Configuration/TDiscriminator.php
@@ -0,0 +1,229 @@
+<?php
+/**
+ * TDiscriminator and TSubMap classes file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Data.SqlMap.Configuration
+ */
+
+/**
+ * The TDiscriminator corresponds to the <discriminator> tag within a <resultMap>.
+ *
+ * TDiscriminator allows inheritance logic in SqlMap result mappings.
+ * SqlMap compares the data found in the discriminator column to the different
+ * <submap> values using the column value's string equivalence. When the string values
+ * matches a particular <submap>, SqlMap will use the <resultMap> defined by
+ * {@link resultMapping TSubMap::setResultMapping()} property for loading
+ * the object data.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ * @since 3.1
+ */
+class TDiscriminator extends TComponent
+{
+ private $_column;
+ private $_type;
+ private $_typeHandler=null;
+ private $_columnIndex;
+ private $_nullValue;
+ private $_mapping;
+ private $_resultMaps=array();
+ private $_subMaps=array();
+
+ /**
+ * @return string the name of the column in the result set from which the
+ * value will be used to populate the property.
+ */
+ public function getColumn()
+ {
+ return $this->_column;
+ }
+
+ /**
+ * @param string the name of the column in the result set from which the
+ * value will be used to populate the property.
+ */
+ public function setColumn($value)
+ {
+ $this->_column = $value;
+ }
+
+ /**
+ * @param string property type of the parameter to be set.
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * The type attribute is used to explicitly specify the property type of the
+ * parameter to be set. If the attribute type is not set and the framework
+ * cannot otherwise determine the type, the type is assumed from the default
+ * value of the property.
+ * @return string property type of the parameter to be set.
+ */
+ public function setType($value)
+ {
+ $this->_type = $value;
+ }
+
+ /**
+ * @return string custom type handler class name (may use namespace).
+ */
+ public function getTypeHandler()
+ {
+ return $this->_typeHandler;
+ }
+
+ /**
+ * @param string custom type handler class name (may use namespace).
+ */
+ public function setTypeHandler($value)
+ {
+ $this->_typeHandler = $value;
+ }
+
+ /**
+ * @return int index of the column in the ResultSet
+ */
+ public function getColumnIndex()
+ {
+ return $this->_columnIndex;
+ }
+
+ /**
+ * The columnIndex attribute value is the index of the column in the
+ * ResultSet from which the value will be used to populate the object property.
+ * @param int index of the column in the ResultSet
+ */
+ public function setColumnIndex($value)
+ {
+ $this->_columnIndex = TPropertyValue::ensureInteger($value);
+ }
+
+ /**
+ * @return mixed outgoing null value replacement.
+ */
+ public function getNullValue()
+ {
+ return $this->_nullValue;
+ }
+
+ /**
+ * @param mixed outgoing null value replacement.
+ */
+ public function setNullValue($value)
+ {
+ $this->_nullValue = $value;
+ }
+
+ /**
+ * @return TResultProperty result property for the discriminator column.
+ */
+ public function getMapping()
+ {
+ return $this->_mapping;
+ }
+
+ /**
+ * @param TSubMap add new sub mapping.
+ */
+ public function addSubMap($subMap)
+ {
+ $this->_subMaps[] = $subMap;
+ }
+
+ /**
+ * @param string database value
+ * @return TResultMap result mapping.
+ */
+ public function getSubMap($value)
+ {
+ if(isset($this->_resultMaps[$value]))
+ return $this->_resultMaps[$value];
+ }
+
+ /**
+ * Copies the discriminator properties to a new TResultProperty.
+ * @param TResultMap result map holding the discriminator.
+ */
+ public function initMapping($resultMap)
+ {
+ $this->_mapping = new TResultProperty($resultMap);
+ $this->_mapping->setColumn($this->getColumn());
+ $this->_mapping->setColumnIndex($this->getColumnIndex());
+ $this->_mapping->setType($this->getType());
+ $this->_mapping->setTypeHandler($this->getTypeHandler());
+ $this->_mapping->setNullValue($this->getNullValue());
+ }
+
+ /**
+ * Set the result maps for particular sub-mapping values.
+ * @param TSqlMapManager sql map manager instance.
+ */
+ public function initialize($manager)
+ {
+ foreach($this->_subMaps as $subMap)
+ {
+ $this->_resultMaps[$subMap->getValue()] =
+ $manager->getResultMap($subMap->getResultMapping());
+ }
+ }
+}
+
+/**
+ * TSubMap class defines a submapping value and the corresponding <resultMap>
+ *
+ * The {@link Value setValue()} property is used for comparison with the
+ * discriminator column value. When the {@link Value setValue()} matches
+ * that of the discriminator column value, the corresponding {@link ResultMapping setResultMapping}
+ * is used inplace of the current result map.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ * @since 3.1
+ */
+class TSubMap extends TComponent
+{
+ private $_value;
+ private $_resultMapping;
+
+ /**
+ * @return string value for comparison with discriminator column value.
+ */
+ public function getValue()
+ {
+ return $this->_value;
+ }
+
+ /**
+ * @param string value for comparison with discriminator column value.
+ */
+ public function setValue($value)
+ {
+ $this->_value = $value;
+ }
+
+ /**
+ * The result map to use when the Value matches the discriminator column value.
+ * @return string ID of a result map
+ */
+ public function getResultMapping()
+ {
+ return $this->_resultMapping;
+ }
+
+ /**
+ * @param string ID of a result map
+ */
+ public function setResultMapping($value)
+ {
+ $this->_resultMapping = $value;
+ }
+}
+
diff --git a/lib/prado/framework/Data/SqlMap/Configuration/TInlineParameterMapParser.php b/lib/prado/framework/Data/SqlMap/Configuration/TInlineParameterMapParser.php
new file mode 100644
index 0000000..dfe14f8
--- /dev/null
+++ b/lib/prado/framework/Data/SqlMap/Configuration/TInlineParameterMapParser.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * TInlineParameterMapParser class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Data.SqlMap.Configuration
+ */
+
+/**
+ * TInlineParameterMapParser class.
+ *
+ * The inline parameter map syntax lets you embed the property name,
+ * the property type, the column type, and a null value replacement into a
+ * parametrized SQL statement.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ * @since 3.1
+ */
+class TInlineParameterMapParser
+{
+ /**
+ * Regular expression for parsing inline parameter maps.
+ */
+ const PARAMETER_TOKEN_REGEXP = '/#([^#]+)#/';
+
+ /**
+ * Parse the sql text for inline parameters.
+ * @param string sql text
+ * @param array file and node details for exception message.
+ * @return array 'sql' and 'parameters' name value pairs.
+ */
+ public function parse($sqlText, $scope)
+ {
+ $matches = array();
+ $mappings = array();
+ preg_match_all(self::PARAMETER_TOKEN_REGEXP, $sqlText, $matches);
+
+ for($i = 0, $k=count($matches[1]); $i<$k; $i++)
+ {
+ $mappings[] = $this->parseMapping($matches[1][$i], $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#
+ * @param string parameter token
+ * @param array file and node details for exception message.
+ */
+ protected function parseMapping($token, $scope)
+ {
+ $mapping = new TParameterProperty;
+ $properties = explode(',', $token);
+ $mapping->setProperty(trim(array_shift($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['file'], $scope['node'], $token);
+ }
+ }
+ return $mapping;
+ }
+}
+
diff --git a/lib/prado/framework/Data/SqlMap/Configuration/TParameterMap.php b/lib/prado/framework/Data/SqlMap/Configuration/TParameterMap.php
new file mode 100644
index 0000000..d6f90b2
--- /dev/null
+++ b/lib/prado/framework/Data/SqlMap/Configuration/TParameterMap.php
@@ -0,0 +1,208 @@
+<?php
+/**
+ * TParameterMap class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Data.SqlMap.Configuration
+ */
+
+/**
+ * TParameterMap corresponds to the <parameterMap> element.
+ *
+ * TParameterMap holds one or more parameter child elements that map object
+ * properties to placeholders in a SQL statement.
+ *
+ * A TParameterMap defines an ordered list of values that match up with the
+ * placeholders of a parameterized query statement. While the attributes
+ * specified by the map still need to be in the correct order, each parameter
+ * is named. You can populate the underlying class in any order, and the
+ * TParameterMap ensures each value is passed in the correct order.
+ *
+ * Parameter Maps can be provided as an external element and inline.
+ * The <parameterMap> element accepts two attributes: id (required) and extends (optional).
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ * @since 3.1
+ */
+class TParameterMap extends TComponent
+{
+ private $_extend;
+ private $_properties;
+ private $_propertyMap;
+ private $_extendMap;
+ private $_ID;
+
+ /**
+ * Initialize the properties and property map collections.
+ */
+ public function __construct()
+ {
+ $this->_properties = new TList;
+ $this->_propertyMap = new TMap;
+ }
+
+ /**
+ * @return string a unique identifier for the <parameterMap>.
+ */
+ public function getID()
+ {
+ return $this->_ID;
+ }
+
+ /**
+ * @param string a unique identifier for the <parameterMap>.
+ */
+ public function setID($value)
+ {
+ $this->_ID=$value;
+ }
+
+ /**
+ * @return TParameterProperty[] list of properties for the parameter map.
+ */
+ public function getProperties()
+ {
+ return $this->_properties;
+ }
+
+ /**
+ * @return string name of another <parameterMap> upon which to base this TParameterMap.
+ */
+ public function getExtends()
+ {
+ return $this->_extend;
+ }
+
+ /**
+ * @param string name of another <parameterMap> upon which to base this TParameterMap.
+ */
+ public function setExtends($value)
+ {
+ $this->_extend = $value;
+ }
+
+ /**
+ * @param string name of a parameter property.
+ * @return TParameterProperty parameter property.
+ * @throws TSqlMapException if index is not string nor integer.
+ */
+ 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 TSqlMapException('sqlmap_index_must_be_string_or_int', $index);
+ }
+
+ /**
+ * @param TParameterProperty new parameter property
+ */
+ public function addProperty(TParameterProperty $property)
+ {
+ $this->_propertyMap->add($property->getProperty(), $property);
+ $this->_properties->add($property);
+ }
+
+ /**
+ * @param int parameter property index
+ * @param TParameterProperty new parameter property.
+ */
+ public function insertProperty($index, TParameterProperty $property)
+ {
+ $this->_propertyMap->add($property->getProperty(), $property);
+ $this->_properties->insertAt($index, $property);
+ }
+
+ /**
+ * @return array list of property names.
+ */
+ public function getPropertyNames()
+ {
+ return $this->_propertyMap->getKeys();
+ }
+
+ /**
+ * Get the value of a property from the the parameter object.
+ * @param TSqlMapTypeHandlerRegistry type handler registry.
+ * @param TParameterProperty parameter proproperty.
+ * @param mixed parameter object to get the value from.
+ * @return unknown
+ */
+ public function getPropertyValue($registry, $property, $parameterValue)
+ {
+ $value = $this->getObjectValue($parameterValue,$property);
+
+ if(($handler=$this->createTypeHandler($property, $registry))!==null)
+ $value = $handler->getParameter($value);
+
+ $value = $this->nullifyDefaultValue($property,$value);
+
+ if(($type = $property->getType())!==null)
+ $value = $registry->convertToType($type, $value);
+
+ return $value;
+ }
+
+
+ /**
+ * Create type handler from {@link Type setType()} or {@link TypeHandler setTypeHandler}.
+ * @param TParameterProperty parameter property
+ * @param TSqlMapTypeHandlerRegistry type handler registry
+ * @return TSqlMapTypeHandler type handler.
+ */
+ protected function createTypeHandler($property, $registry)
+ {
+ $type=$property->getTypeHandler() ? $property->getTypeHandler() : $property->getType();
+ $handler=$registry->getTypeHandler($type);
+ if($handler===null && $property->getTypeHandler())
+ $handler = Prado::createComponent($type);
+ return $handler;
+ }
+
+
+ /**
+ * @param mixed object to obtain the property from.
+ * @param TParameterProperty parameter property.
+ * @return mixed property value.
+ * @throws TSqlMapException if property access is invalid.
+ */
+ protected function getObjectValue($object,$property)
+ {
+ try
+ {
+ return TPropertyAccess::get($object, $property->getProperty());
+ }
+ catch (TInvalidPropertyException $e)
+ {
+ throw new TSqlMapException(
+ 'sqlmap_unable_to_get_property_for_parameter',
+ $this->getID(),
+ $property->getProperty(),
+ (is_object($object) ? get_class($object) : gettype($object))
+ );
+ }
+ }
+
+ /**
+ * When the actual value matches the {@link NullValue TParameterProperty::setNullValue()},
+ * set the current value to null.
+ * @param TParameterProperty parameter property.
+ * @param mixed current property value
+ * @return mixed null if NullValue matches currrent value.
+ */
+ protected function nullifyDefaultValue($property,$value)
+ {
+ if(($nullValue = $property->getNullValue())!==null)
+ {
+ if($nullValue === $value)
+ $value = null;
+ }
+ return $value;
+ }
+}
diff --git a/lib/prado/framework/Data/SqlMap/Configuration/TParameterProperty.php b/lib/prado/framework/Data/SqlMap/Configuration/TParameterProperty.php
new file mode 100644
index 0000000..f6282e4
--- /dev/null
+++ b/lib/prado/framework/Data/SqlMap/Configuration/TParameterProperty.php
@@ -0,0 +1,148 @@
+<?php
+/**
+ * TParameterPropert class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Data.SqlMap.Configuration
+ */
+
+/**
+ * TParameterProperty corresponds to the <property> tag and defines
+ * one object property for the <parameterMap>
+ *
+ * The {@link NullValue setNullValue()} attribute can be set to any valid
+ * value (based on property type). The {@link NullValue setNullValue()} attribute
+ * is used to specify an inbound null value replacement. What this means is
+ * that when the value is detected in the object property, a NULL will be written
+ * to the database (the opposite behavior of an inbound null value replacement).
+ * This allows you to use a magic null number in your application for types that
+ * do not support null values (such as int, double, float). When these types of
+ * properties contain a matching null value (for example, say, -9999), a NULL
+ * will be written to the database instead of the value.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ * @since 3.1
+ */
+class TParameterProperty extends TComponent
+{
+ private $_typeHandler;
+ private $_type;
+ private $_column;
+ private $_dbType;
+ private $_property;
+ private $_nullValue;
+
+ /**
+ * @return string class name of a custom type handler.
+ */
+ public function getTypeHandler()
+ {
+ return $this->_typeHandler;
+ }
+
+ /**
+ * @param string class name of a custom type handler.
+ */
+ public function setTypeHandler($value)
+ {
+ $this->_typeHandler = $value;
+ }
+
+ /**
+ * @return string type of the parameter's property
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * @param string type of the parameter's property
+ */
+ public function setType($value)
+ {
+ $this->_type = $value;
+ }
+
+ /**
+ * @return string name of a parameter to be used in the SQL statement.
+ */
+ public function getColumn()
+ {
+ return $this->_column;
+ }
+
+ /**
+ * @param string name of a parameter to be used in the SQL statement.
+ */
+ public function setColumn($value)
+ {
+ $this->_column = $value;
+ }
+
+ /**
+ * @return string the database column type of the parameter to be set by this property.
+ */
+ public function getDbType()
+ {
+ return $this->_dbType;
+ }
+
+ /**
+ * @param string the database column type of the parameter to be set by this property.
+ */
+ public function setDbType($value)
+ {
+ $this->_dbType = $value;
+ }
+
+ /**
+ * @return string name of a property of the parameter object.
+ */
+ public function getProperty()
+ {
+ return $this->_property;
+ }
+
+ /**
+ * @param string name of a property of the parameter object.
+ */
+ public function setProperty($value)
+ {
+ $this->_property = $value;
+ }
+
+ /**
+ * @return mixed null value replacement
+ */
+ public function getNullValue()
+ {
+ return $this->_nullValue;
+ }
+
+ /**
+ * The nullValue attribute is used to specify an outgoing null value replacement.
+ * @param mixed null value replacement.
+ */
+ public function setNullValue($value)
+ {
+ $this->_nullValue = $value;
+ }
+
+ public function __sleep()
+ {
+ $exprops = array(); $cn = 'TParameterProperty';
+ if ($this->_typeHandler===null) $exprops[] = "\0$cn\0_typeHandler";
+ if ($this->_type===null) $exprops[] = "\0$cn\0_type";
+ if ($this->_column===null) $exprops[] = "\0$cn\0_column";
+ if ($this->_dbType===null) $exprops[] = "\0$cn\0_dbType";
+ if ($this->_property===null) $exprops[] = "\0$cn\0_property";
+ if ($this->_nullValue===null) $exprops[] = "\0$cn\0_nullValue";
+ return array_diff(parent::__sleep(),$exprops);
+ }
+}
+
diff --git a/lib/prado/framework/Data/SqlMap/Configuration/TResultMap.php b/lib/prado/framework/Data/SqlMap/Configuration/TResultMap.php
new file mode 100644
index 0000000..95e8d34
--- /dev/null
+++ b/lib/prado/framework/Data/SqlMap/Configuration/TResultMap.php
@@ -0,0 +1,198 @@
+<?php
+/**
+ * TResultMap class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Data.SqlMap.Configuration
+ */
+
+/**
+ * TResultMap corresponds to <resultMap> mapping tag.
+ *
+ * A TResultMap lets you control how data is extracted from the result of a
+ * query, and how the columns are mapped to object properties. A TResultMap
+ * can describe the column type, a null value replacement, and complex property
+ * mappings including Collections.
+ *
+ * The <resultMap> can contain any number of property mappings that map object
+ * properties to the columns of a result element. The property mappings are
+ * applied, and the columns are read, in the order that they are defined.
+ * Maintaining the element order ensures consistent results between different
+ * drivers and providers.
+ *
+ * The {@link Class setClass()} property must be a PHP class object or array instance.
+ *
+ * The optional {@link Extends setExtends()} attribute can be set to the ID of
+ * another <resultMap> upon which to base this <resultMap>. All properties of the
+ * "parent" <resultMap> will be included as part of this <resultMap>, and values
+ * from the "parent" <resultMap> are set before any values specified by this <resultMap>.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ * @since 3.1
+ */
+class TResultMap extends TComponent
+{
+ private $_columns;
+ private $_class;
+ private $_extends;
+ private $_groupBy;
+ private $_discriminator;
+ private $_typeHandlers;
+ private $_ID;
+
+ /**
+ * Initialize the columns collection.
+ */
+ public function __construct()
+ {
+ $this->_columns=new TMap;
+ }
+
+ /**
+ * @return string a unique identifier for the <resultMap>.
+ */
+ public function getID()
+ {
+ return $this->_ID;
+ }
+
+ /**
+ * @param string a unique identifier for the <resultMap>.
+ */
+ public function setID($value)
+ {
+ $this->_ID=$value;
+ }
+
+ /**
+ * @return string result class name.
+ */
+ public function getClass()
+ {
+ return $this->_class;
+ }
+
+ /**
+ * @param string result class name.
+ */
+ public function setClass($value)
+ {
+ $this->_class = $value;
+ }
+
+ /**
+ * @return TMap result columns.
+ */
+ public function getColumns()
+ {
+ return $this->_columns;
+ }
+
+ /**
+ * @return string result map extends another result map.
+ */
+ public function getExtends()
+ {
+ return $this->_extends;
+ }
+
+ /**
+ * @param string result map extends another result map.
+ */
+ public function setExtends($value)
+ {
+ $this->_extends = $value;
+ }
+
+ /**
+ * @return string result map groups by.
+ */
+ public function getGroupBy()
+ {
+ return $this->_groupBy;
+ }
+
+ /**
+ * @param string result map group by
+ */
+ public function setGroupBy($value)
+ {
+ $this->_groupBy = $value;
+ }
+
+ /**
+ * @return TDiscriminator result class discriminator.
+ */
+ public function getDiscriminator()
+ {
+ return $this->_discriminator;
+ }
+
+ /**
+ * @param TDiscriminator result class discriminator.
+ */
+ public function setDiscriminator(TDiscriminator $value)
+ {
+ $this->_discriminator = $value;
+ }
+
+ /**
+ * Add a TResultProperty to result mapping.
+ * @param TResultProperty result property.
+ */
+ public function addResultProperty(TResultProperty $property)
+ {
+ $this->_columns[$property->getProperty()] = $property;
+ }
+
+ /**
+ * Create a new instance of the class of this result map.
+ * @param TSqlMapTypeHandlerRegistry type handler registry.
+ * @return mixed new result object.
+ * @throws TSqlMapException
+ */
+ public function createInstanceOfResult($registry)
+ {
+ $handler = $registry->getTypeHandler($this->getClass());
+ try
+ {
+ if($handler!==null)
+ return $handler->createNewInstance();
+ else
+ return $registry->createInstanceOf($this->getClass());
+ }
+ catch (TSqlMapException $e)
+ {
+ throw new TSqlMapException(
+ 'sqlmap_unable_to_create_new_instance',
+ $this->getClass(), get_class($handler), $this->getID());
+ }
+ }
+
+ /**
+ * Result sub-mappings using the discriminiator column.
+ * @param TSqlMapTypeHandlerRegistry type handler registry
+ * @param array row data.
+ * @return TResultMap result sub-map.
+ */
+ public function resolveSubMap($registry,$row)
+ {
+ $subMap = $this;
+ if(($disc = $this->getDiscriminator())!==null)
+ {
+ $value = $disc->getMapping()->getPropertyValue($registry,$row);
+ $subMap = $disc->getSubMap((string)$value);
+
+ if($subMap===null)
+ $subMap = $this;
+ else if($subMap !== $this)
+ $subMap = $subMap->resolveSubMap($registry,$row);
+ }
+ return $subMap;
+ }
+}
+
diff --git a/lib/prado/framework/Data/SqlMap/Configuration/TResultProperty.php b/lib/prado/framework/Data/SqlMap/Configuration/TResultProperty.php
new file mode 100644
index 0000000..87b0677
--- /dev/null
+++ b/lib/prado/framework/Data/SqlMap/Configuration/TResultProperty.php
@@ -0,0 +1,342 @@
+<?php
+/**
+ * TResultProperty class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Data.SqlMap.Configuration
+ */
+
+/**
+ * TResultProperty corresponds a <property> tags inside a <resultMap> tag.
+ *
+ * The {@link NullValue setNullValue()} attribute can be set to any valid
+ * value (based on property type). The {@link NullValue setNullValue()} attribute
+ * is used to specify an outgoing null value replacement. What this means is
+ * that when a null value is detected in the result, the corresponding value of
+ * the {@link NullValue getNullValue()} will be used instead.
+ *
+ * The {@link Select setSelect()} property is used to describe a relationship
+ * between objects and to automatically load complex (i.e. user defined)
+ * property types. The value of the {@link Select setSelect()} property must be
+ * the name of another mapped statement. The value of the database
+ * {@link Column setColumn()} that is defined in the same property element as
+ * this statement attribute will be passed to the related mapped statement as
+ * the parameter. The {@link LazyLoad setLayLoad()} attribute can be specified
+ * with the {@link Select setSelect()} .
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ * @since 3.1
+ */
+class TResultProperty extends TComponent
+{
+ private $_nullValue;
+ private $_propertyName;
+ private $_columnName;
+ private $_columnIndex=-1;
+ private $_nestedResultMapName;
+ private $_nestedResultMap;
+ private $_valueType;
+ private $_typeHandler;
+ private $_isLazyLoad=false;
+ private $_select;
+
+ private $_hostResultMapID='inplicit internal mapping';
+
+ const LIST_TYPE = 0;
+ const ARRAY_TYPE = 1;
+
+ /**
+ * Gets the containing result map ID.
+ * @param TResultMap containing result map.
+ */
+ public function __construct($resultMap=null)
+ {
+ if($resultMap instanceof TResultMap)
+ $this->_hostResultMapID = $resultMap->getID();
+ }
+
+ /**
+ * @return mixed null value replacement.
+ */
+ public function getNullValue()
+ {
+ return $this->_nullValue;
+ }
+
+ /**
+ * @param mixed null value replacement.
+ */
+ public function setNullValue($value)
+ {
+ $this->_nullValue = $value;
+ }
+
+ /**
+ * @return string name of a property of the result object that will be set to.
+ */
+ public function getProperty()
+ {
+ return $this->_propertyName;
+ }
+
+ /**
+ * @param string name of a property of the result object that will be set to.
+ */
+ public function setProperty($value)
+ {
+ $this->_propertyName = $value;
+ }
+
+ /**
+ * @return string name of the column in the result set from which the value
+ * will be used to populate the property.
+ */
+ public function getColumn()
+ {
+ return $this->_columnName;
+ }
+
+ /**
+ * @param string name of the column in the result set from which the value
+ * will be used to populate the property.
+ */
+ public function setColumn($value)
+ {
+ $this->_columnName = $value;
+ }
+
+ /**
+ * @return int index of the column in the ResultSet from which the value will
+ * be used to populate the object property
+ */
+ public function getColumnIndex()
+ {
+ return $this->_columnIndex;
+ }
+
+ /**
+ * @param int index of the column in the ResultSet from which the value will
+ * be used to populate the object property
+ */
+ public function setColumnIndex($value)
+ {
+ $this->_columnIndex = TPropertyValue::ensureInteger($value);
+ }
+
+ /**
+ * @return string ID of another <resultMap> used to fill the property.
+ */
+ public function getResultMapping()
+ {
+ return $this->_nestedResultMapName;
+ }
+
+ /**
+ * @param string ID of another <resultMap> used to fill the property.
+ */
+ public function setResultMapping($value)
+ {
+ $this->_nestedResultMapName = $value;
+ }
+
+ /**
+ * @return TResultMap nested result map.
+ */
+ public function getNestedResultMap()
+ {
+ return $this->_nestedResultMap;
+ }
+
+ /**
+ * @param TResult nested result map.
+ */
+ public function setNestedResultMap($value)
+ {
+ $this->_nestedResultMap = $value;
+ }
+
+ /**
+ * @return string property type of the object property to be set.
+ */
+ public function getType()
+ {
+ return $this->_valueType;
+ }
+
+ /**
+ * @param string property type of the object property to be set.
+ */
+ public function setType($value)
+ {
+ $this->_valueType = $value;
+ }
+
+ /**
+ * @return string custom type handler class name (may use namespace).
+ */
+ public function getTypeHandler()
+ {
+ return $this->_typeHandler;
+ }
+
+ /**
+ * @param string custom type handler class name (may use namespace).
+ */
+ public function setTypeHandler($value)
+ {
+ $this->_typeHandler = $value;
+ }
+
+ /**
+ * @return string name of another mapped statement
+ */
+ public function getSelect()
+ {
+ return $this->_select;
+ }
+
+ /**
+ * The select property is used to describe a relationship between objects
+ * and to automatically load complex (i.e. user defined) property types.
+ * @param string name of another mapped statement.
+ */
+ public function setSelect($value)
+ {
+ $this->_select = $value;
+ }
+
+ /**
+ * @return boolean indicate whether or not the select statement's results should be lazy loaded
+ */
+ public function getLazyLoad()
+ {
+ return $this->_isLazyLoad;
+ }
+
+ /**
+ * @param boolean indicate whether or not the select statement's results should be lazy loaded
+ */
+ public function setLazyLoad($value)
+ {
+ $this->_isLazyLoad = TPropertyValue::ensureBoolean($value,false);
+ }
+
+ /**
+ * Gets the value for the current property, converts to applicable type if necessary.
+ * @param TSqlMapTypeHandlerRegistry type handler registry
+ * @param array result row
+ * @return mixed property value.
+ */
+ public function getPropertyValue($registry,$row)
+ {
+ $value = null;
+ $index = $this->getColumnIndex();
+ $name = $this->getColumn();
+ if($index > 0 && isset($row[$index]))
+ $value = $this->getTypedValue($registry,$row[$index]);
+ else if(isset($row[$name]))
+ $value = $this->getTypedValue($registry,$row[$name]);
+ if(($value===null) && ($this->getNullValue()!==null))
+ $value = $this->getTypedValue($registry,$this->getNullValue());
+ return $value;
+ }
+
+ /**
+ * @param TSqlMapTypeHandlerRegistry type handler registry
+ * @param mixed raw property value
+ * @return mixed property value casted to specific type.
+ */
+ protected function getTypedValue($registry,$value)
+ {
+ if(($handler = $this->createTypeHandler($registry))!==null)
+ return $handler->getResult($value);
+ else
+ return $registry->convertToType($this->getType(), $value);
+ }
+
+ /**
+ * Create type handler from {@link Type setType()} or {@link TypeHandler setTypeHandler}.
+ * @param TSqlMapTypeHandlerRegistry type handler registry
+ * @return TSqlMapTypeHandler type handler.
+ */
+ protected function createTypeHandler($registry)
+ {
+ $type=$this->getTypeHandler() ? $this->getTypeHandler() : $this->getType();
+ $handler=$registry->getTypeHandler($type);
+ if($handler===null && $this->getTypeHandler())
+ $handler = Prado::createComponent($type);
+ return $handler;
+ }
+
+ /**
+ * Determines if the type is an instance of ArrayAccess, TList or an array.
+ * @return int TResultProperty::LIST_TYPE or TResultProperty::ARRAY_TYPE
+ */
+ protected function getPropertyValueType()
+ {
+ if(class_exists($type = $this->getType(), false)) //NO force autoloading
+ {
+ if($type==='TList')
+ return self::LIST_TYPE;
+ $class = new ReflectionClass($type);
+ if($class->isSubclassOf('TList'))
+ return self::LIST_TYPE;
+ if($class->implementsInterface('ArrayAccess'))
+ return self::ARRAY_TYPE;
+ }
+ if(strtolower($type) == 'array')
+ return self::ARRAY_TYPE;
+ }
+
+ /**
+ * Returns true if the result property {@link Type getType()} is of TList type
+ * or that the actual result object is an instance of TList.
+ * @param object result object
+ * @return boolean true if the result object is an instance of TList
+ */
+ public function instanceOfListType($target)
+ {
+ if($this->getType()===null)
+ return TPropertyAccess::get($target,$this->getProperty()) instanceof TList;
+ return $this->getPropertyValueType() == self::LIST_TYPE;
+ }
+
+ /**
+ * Returns true if the result property {@link Type getType()} is of ArrayAccess
+ * or that the actual result object is an array or implements ArrayAccess
+ * @param object result object
+ * @return boolean true if the result object is an instance of ArrayAccess or is an array.
+ */
+ public function instanceOfArrayType($target)
+ {
+ if($this->getType()===null)
+ {
+ $prop = TPropertyAccess::get($target,$this->getProperty());
+ if(is_object($prop))
+ return $prop instanceof ArrayAccess;
+ return is_array($prop);
+ }
+ return $this->getPropertyValueType() == self::ARRAY_TYPE;
+ }
+
+ public function __sleep()
+ {
+ $exprops = array(); $cn = 'TResultProperty';
+ if ($this->_nullValue===null) $exprops[] = "\0$cn\0_nullValue";
+ if ($this->_propertyName===null) $exprops[] = "\0$cn\0_propertyNama";
+ if ($this->_columnName===null) $exprops[] = "\0$cn\0_columnName";
+ if ($this->_columnIndex==-1) $exprops[] = "\0$cn\0_columnIndex";
+ if ($this->_nestedResultMapName===null) $exprops[] = "\0$cn\0_nestedResultMapName";
+ if ($this->_nestedResultMap===null) $exprops[] = "\0$cn\0_nestedResultMap";
+ if ($this->_valueType===null) $exprops[] = "\0$cn\0_valueType";
+ if ($this->_typeHandler===null) $exprops[] = "\0$cn\0_typeHandler";
+ if ($this->_isLazyLoad===false) $exprops[] = "\0$cn\0_isLazyLoad";
+ if ($this->_select===null) $exprops[] = "\0$cn\0_select";
+ return array_diff(parent::__sleep(),$exprops);
+ }
+}
+
diff --git a/lib/prado/framework/Data/SqlMap/Configuration/TSimpleDynamicParser.php b/lib/prado/framework/Data/SqlMap/Configuration/TSimpleDynamicParser.php
new file mode 100644
index 0000000..41b706a
--- /dev/null
+++ b/lib/prado/framework/Data/SqlMap/Configuration/TSimpleDynamicParser.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * TSimpleDynamicParser class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Data.SqlMap.Configuration
+ */
+
+/**
+ * TSimpleDynamicParser finds place holders $name$ in the sql text and replaces
+ * it with a TSimpleDynamicParser::DYNAMIC_TOKEN.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ * @since 3.1
+ */
+class TSimpleDynamicParser
+{
+ const PARAMETER_TOKEN_REGEXP = '/\$([^\$]+)\$/';
+ const DYNAMIC_TOKEN = '`!`';
+
+ /**
+ * Parse the sql text for dynamic place holders of the form $name$.
+ * @param string Sql text.
+ * @return array name value pairs 'sql' and 'parameters'.
+ */
+ public function parse($sqlText)
+ {
+ $matches = array();
+ $mappings = array();
+ preg_match_all(self::PARAMETER_TOKEN_REGEXP, $sqlText, $matches);
+ for($i = 0, $k=count($matches[1]); $i<$k; $i++)
+ {
+ $mappings[] = $matches[1][$i];
+ $sqlText = str_replace($matches[0][$i], self::DYNAMIC_TOKEN, $sqlText);
+ }
+ return array('sql'=>$sqlText, 'parameters'=>$mappings);
+ }
+}
+
diff --git a/lib/prado/framework/Data/SqlMap/Configuration/TSqlMapCacheModel.php b/lib/prado/framework/Data/SqlMap/Configuration/TSqlMapCacheModel.php
new file mode 100644
index 0000000..8a1e344
--- /dev/null
+++ b/lib/prado/framework/Data/SqlMap/Configuration/TSqlMapCacheModel.php
@@ -0,0 +1,242 @@
+<?php
+/**
+ * TSqlMapCacheModel, TSqlMapCacheTypes and TSqlMapCacheKey classes file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Data.SqlMap.Configuration
+ */
+
+/**
+ * TSqlMapCacheModel corresponds to the <cacheModel> sql mapping configuration tag.
+ *
+ * The results from a query Mapped Statement can be cached simply by specifying
+ * the {@link CacheModel TSqlMapStatement::setCacheModel()} property in <statement> tag.
+ * A cache model is a configured cache that is defined within the sql map
+ * configuration file. Cache models are configured using the <cacheModel> element.
+ *
+ * The cache model uses a pluggable framework for supporting different types of
+ * caches. The choice of cache is specified by the {@link Implementation setImplementation()}
+ * property. The class name specified must be one of {@link TSqlMapCacheTypes}.
+ *
+ * The cache implementations, LRU and FIFO cache below do not persist across
+ * requests. That is, once the request is complete, all cache data is lost.
+ * These caches are useful queries that results in the same repeated data during
+ * the current request.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ * @since 3.1
+ */
+class TSqlMapCacheModel extends TComponent
+{
+ private $_cache;
+ private $_hits = 0;
+ private $_requests = 0;
+ private $_id;
+ private $_implementation=TSqlMapCacheTypes::Basic;
+ private $_properties = array();
+ private $_flushInterval = 0;
+
+ private static $_cacheTypes = array();
+
+ public static function registerCacheType($type, $className)
+ {
+ self::$_cacheTypes[$type] = $className;
+ }
+
+ /**
+ * @return string unique cache model identifier.
+ */
+ public function getID()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * @param string unique cache model identifier.
+ */
+ public function setID($value)
+ {
+ $this->_id = $value;
+ }
+
+ /**
+ * @return string cache implements of TSqlMapCacheTypes, either 'Basic', 'LRU' or 'FIFO'.
+ */
+ public function getImplementation()
+ {
+ return $this->_implementation;
+ }
+
+ /**
+ * @param string cache implements of TSqlMapCacheTypes, either 'Basic', 'LRU' or 'FIFO'.
+ */
+ public function setImplementation($value)
+ {
+ if (isset(self::$_cacheTypes[$value]))
+ $this->_implementation = $value;
+ else
+ $this->_implementation = TPropertyValue::ensureEnum($value,'TSqlMapCacheTypes');
+ }
+
+ /**
+ * @param integer the number of seconds in which the cached value will expire. 0 means never expire.
+ */
+ public function setFlushInterval($value)
+ {
+ $this->_flushInterval=TPropertyValue::ensureInteger($value);
+ }
+
+ /**
+ * @return integer cache duration.
+ */
+ public function getFlushInterval()
+ {
+ return $this->_flushInterval;
+ }
+
+ /**
+ * Initialize the cache implementation, sets the actual cache contain if supplied.
+ * @param ISqLMapCache cache implementation instance.
+ */
+ public function initialize($cache=null)
+ {
+ if($cache===null)
+ $this->_cache= Prado::createComponent($this->getImplementationClass(), $this);
+ else
+ $this->_cache=$cache;
+ }
+
+ /**
+ * @return string cache implementation class name.
+ */
+ public function getImplementationClass()
+ {
+ $implementation = $this->_implementation;
+ if (isset(self::$_cacheTypes[$implementation])) return self::$_cacheTypes[$implementation];
+
+ switch(TPropertyValue::ensureEnum($implementation,'TSqlMapCacheTypes'))
+ {
+ case TSqlMapCacheTypes::FIFO: return 'TSqlMapFifoCache';
+ case TSqlMapCacheTypes::LRU : return 'TSqlMapLruCache';
+ case TSqlMapCacheTypes::Basic : return 'TSqlMapApplicationCache';
+ }
+ }
+
+ /**
+ * Register a mapped statement that will trigger a cache flush.
+ * @param TMappedStatement mapped statement that may flush the cache.
+ */
+ public function registerTriggerStatement($mappedStatement)
+ {
+ $mappedStatement->attachEventHandler('OnExecuteQuery',array($this, 'flush'));
+ }
+
+ /**
+ * Clears the cache.
+ */
+ public function flush()
+ {
+ $this->_cache->flush();
+ }
+
+ /**
+ * @param TSqlMapCacheKey|string cache key
+ * @return mixed cached value.
+ */
+ public function get($key)
+ {
+ if($key instanceof TSqlMapCacheKey)
+ $key = $key->getHash();
+
+ //if flush ?
+ $value = $this->_cache->get($key);
+ $this->_requests++;
+ if($value!==null)
+ $this->_hits++;
+ return $value;
+ }
+
+ /**
+ * @param TSqlMapCacheKey|string cache key
+ * @param mixed value to be cached.
+ */
+ public function set($key, $value)
+ {
+ if($key instanceof TSqlMapCacheKey)
+ $key = $key->getHash();
+
+ if($value!==null)
+ $this->_cache->set($key, $value, $this->_flushInterval);
+ }
+
+ /**
+ * @return float cache hit ratio.
+ */
+ public function getHitRatio()
+ {
+ if($this->_requests != 0)
+ return $this->_hits / $this->_requests;
+ else
+ return 0;
+ }
+}
+
+/**
+ * TSqlMapCacheTypes enumerable class.
+ *
+ * Implemented cache are 'Basic', 'FIFO' and 'LRU'.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ * @since 3.1
+ */
+class TSqlMapCacheTypes extends TEnumerable
+{
+ const Basic='Basic';
+ const FIFO='FIFO';
+ const LRU='LRU';
+}
+
+/**
+ * TSqlMapCacheKey class.
+ *
+ * Provides a hash of the object to be cached.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ * @since 3.1
+ */
+class TSqlMapCacheKey
+{
+ private $_key;
+
+ /**
+ * @param mixed object to be cached.
+ */
+ public function __construct($object)
+ {
+ $this->_key = $this->generateKey(serialize($object));
+ }
+
+ /**
+ * @param string serialized object
+ * @return string crc32 hash of the serialized object.
+ */
+ protected function generateKey($string)
+ {
+ return sprintf('%x',crc32($string));
+ }
+
+ /**
+ * @return string object hash.
+ */
+ public function getHash()
+ {
+ return $this->_key;
+ }
+}
+
diff --git a/lib/prado/framework/Data/SqlMap/Configuration/TSqlMapStatement.php b/lib/prado/framework/Data/SqlMap/Configuration/TSqlMapStatement.php
new file mode 100644
index 0000000..abb21c7
--- /dev/null
+++ b/lib/prado/framework/Data/SqlMap/Configuration/TSqlMapStatement.php
@@ -0,0 +1,444 @@
+<?php
+/**
+ * TSqlMapStatement, TSqlMapInsert, TSqlMapUpdate, TSqlMapDelete,
+ * TSqlMapSelect and TSqlMapSelectKey classes file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Data.SqlMap.Configuration
+ */
+
+/**
+ * TSqlMapStatement class corresponds to <statement> element.
+ *
+ * Mapped Statements can hold any SQL statement and can use Parameter Maps
+ * and Result Maps for input and output.
+ *
+ * The <statement> element is a general "catch all" element that can be used
+ * for any type of SQL statement. Generally it is a good idea to use one of the
+ * more specific statement-type elements. The more specific elements provided
+ * better error-checking and even more functionality. (For example, the insert
+ * statement can return a database-generated key.)
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ * @since 3.1
+ */
+class TSqlMapStatement extends TComponent
+{
+ private $_parameterMapName;
+ private $_parameterMap;
+ private $_parameterClassName;
+ private $_resultMapName;
+ private $_resultMap;
+ private $_resultClassName;
+ private $_cacheModelName;
+ private $_SQL;
+ private $_listClass;
+ private $_typeHandler;
+ private $_extendStatement;
+ private $_cache;
+ private $_ID;
+
+ /**
+ * @return string name for this statement, unique to each sql map manager.
+ */
+ public function getID()
+ {
+ return $this->_ID;
+ }
+
+ /**
+ * @param string name for this statement, which must be unique for each sql map manager.
+ */
+ public function setID($value)
+ {
+ $this->_ID=$value;
+ }
+
+ /**
+ * @return string name of a parameter map.
+ */
+ public function getParameterMap()
+ {
+ return $this->_parameterMapName;
+ }
+
+ /**
+ * A Parameter Map defines an ordered list of values that match up with
+ * the "?" placeholders of a standard, parameterized query statement.
+ * @param string parameter map name.
+ */
+ public function setParameterMap($value)
+ {
+ $this->_parameterMapName = $value;
+ }
+
+ /**
+ * @return string parameter class name.
+ */
+ public function getParameterClass()
+ {
+ return $this->_parameterClassName;
+ }
+
+ /**
+ * If a {@link ParameterMap setParameterMap()} property is not specified,
+ * you may specify a ParameterClass instead and use inline parameters.
+ * The value of the parameterClass attribute can be any existing PHP class name.
+ * @param string parameter class name.
+ */
+ public function setParameterClass($value)
+ {
+ $this->_parameterClassName = $value;
+ }
+
+ /**
+ * @return string result map name.
+ */
+ public function getResultMap()
+ {
+ return $this->_resultMapName;
+ }
+
+ /**
+ * A Result Map lets you control how data is extracted from the result of a
+ * query, and how the columns are mapped to object properties.
+ * @param string result map name.
+ */
+ public function setResultMap($value)
+ {
+ $this->_resultMapName = $value;
+ }
+
+ /**
+ * @return string result class name.
+ */
+ public function getResultClass()
+ {
+ return $this->_resultClassName;
+ }
+
+ /**
+ * If a {@link ResultMap setResultMap()} is not specified, you may specify a
+ * ResultClass instead. The value of the ResultClass property can be the
+ * name of a PHP class or primitives like integer, string, or array. The
+ * class specified will be automatically mapped to the columns in the
+ * result, based on the result metadata.
+ * @param string result class name.
+ */
+ public function setResultClass($value)
+ {
+ $this->_resultClassName = $value;
+ }
+
+ /**
+ * @return string cache mode name.
+ */
+ public function getCacheModel()
+ {
+ return $this->_cacheModelName;
+ }
+
+ /**
+ * @param string cache mode name.
+ */
+ public function setCacheModel($value)
+ {
+ $this->_cacheModelName = $value;
+ }
+
+ /**
+ * @return TSqlMapCacheModel cache implementation instance for this statement.
+ */
+ public function getCache()
+ {
+ return $this->_cache;
+ }
+
+ /**
+ * @param TSqlMapCacheModel cache implementation instance for this statement.
+ */
+ public function setCache($value)
+ {
+ $this->_cache = $value;
+ }
+
+ /**
+ * @return TStaticSql sql text container.
+ */
+ public function getSqlText()
+ {
+ return $this->_SQL;
+ }
+
+ /**
+ * @param TStaticSql sql text container.
+ */
+ public function setSqlText($value)
+ {
+ $this->_SQL = $value;
+ }
+
+ /**
+ * @return string name of a PHP class that implements ArrayAccess.
+ */
+ public function getListClass()
+ {
+ return $this->_listClass;
+ }
+
+ /**
+ * An ArrayAccess class can be specified to handle the type of objects in the collection.
+ * @param string name of a PHP class that implements ArrayAccess.
+ */
+ public function setListClass($value)
+ {
+ $this->_listClass = $value;
+ }
+
+ /**
+ * @return string another statement element name.
+ */
+ public function getExtends()
+ {
+ return $this->_extendStatement;
+ }
+
+ /**
+ * @param string name of another statement element to extend.
+ */
+ public function setExtends($value)
+ {
+ $this->_extendStatement = $value;
+ }
+
+ /**
+ * @return TResultMap the result map corresponding to the
+ * {@link ResultMap getResultMap()} property.
+ */
+ public function resultMap()
+ {
+ return $this->_resultMap;
+ }
+
+ /**
+ * @return TParameterMap the parameter map corresponding to the
+ * {@link ParameterMap getParameterMap()} property.
+ */
+ public function parameterMap()
+ {
+ return $this->_parameterMap;
+ }
+
+ /**
+ * @param TInlineParameterMap parameter extracted from the sql text.
+ */
+ public function setInlineParameterMap($map)
+ {
+ $this->_parameterMap = $map;
+ }
+
+ /**
+ * @param TSqlMapManager initialize the statement, sets the result and parameter maps.
+ */
+ public function initialize($manager)
+ {
+ if(strlen($this->_resultMapName) > 0)
+ $this->_resultMap = $manager->getResultMap($this->_resultMapName);
+ if(strlen($this->_parameterMapName) > 0)
+ $this->_parameterMap = $manager->getParameterMap($this->_parameterMapName);
+ }
+
+ /**
+ * @param TSqlMapTypeHandlerRegistry type handler registry
+ * @return ArrayAccess new instance of list class.
+ */
+ public function createInstanceOfListClass($registry)
+ {
+ if(strlen($type = $this->getListClass()) > 0)
+ return $this->createInstanceOf($registry,$type);
+ return array();
+ }
+
+ /**
+ * Create a new instance of a given type.
+ * @param TSqlMapTypeHandlerRegistry type handler registry
+ * @param string result class name.
+ * @param array result data.
+ * @return mixed result object.
+ */
+ protected function createInstanceOf($registry,$type,$row=null)
+ {
+ $handler = $registry->getTypeHandler($type);
+ if($handler!==null)
+ return $handler->createNewInstance($row);
+ else
+ return $registry->createInstanceOf($type);
+ }
+
+ /**
+ * Create a new instance of result class.
+ * @param TSqlMapTypeHandlerRegistry type handler registry
+ * @param array result data.
+ * @return mixed result object.
+ */
+ public function createInstanceOfResultClass($registry,$row)
+ {
+ if(strlen($type= $this->getResultClass()) > 0)
+ return $this->createInstanceOf($registry,$type,$row);
+ }
+
+ public function __sleep()
+ {
+ $cn = __CLASS__;
+ $exprops = array("\0$cn\0_resultMap");
+ if (!$this->_parameterMapName) $exprops[] = "\0$cn\0_parameterMapName";
+ if (!$this->_parameterMap) $exprops[] = "\0$cn\0_parameterMap";
+ if (!$this->_parameterClassName) $exprops[] = "\0$cn\0_parameterClassName";
+ if (!$this->_resultMapName) $exprops[] = "\0$cn\0_resultMapName";
+ if (!$this->_resultMap) $exprops[] = "\0$cn\0_resultMap";
+ if (!$this->_resultClassName) $exprops[] = "\0$cn\0_resultClassName";
+ if (!$this->_cacheModelName) $exprops[] = "\0$cn\0_cacheModelName";
+ if (!$this->_SQL) $exprops[] = "\0$cn\0_SQL";
+ if (!$this->_listClass) $exprops[] = "\0$cn\0_listClass";
+ if (!$this->_typeHandler) $exprops[] = "\0$cn\0_typeHandler";
+ if (!$this->_extendStatement) $exprops[] = "\0$cn\0_extendStatement";
+ if (!$this->_cache) $exprops[] = "\0$cn\0_cache";
+
+ return array_diff(parent::__sleep(),$exprops);
+ }
+
+}
+
+/**
+ * TSqlMapSelect class file.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Statements
+ * @since 3.1
+ */
+class TSqlMapSelect extends TSqlMapStatement
+{
+ private $_generate;
+
+ public function getGenerate(){ return $this->_generate; }
+ public function setGenerate($value){ $this->_generate = $value; }
+}
+
+/**
+ * TSqlMapInsert class corresponds to the <insert> element.
+ *
+ * The <insert> element allows <selectKey> child elements that can be used
+ * to generate a key to be used for the insert command.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ * @since 3.1
+ */
+class TSqlMapInsert extends TSqlMapStatement
+{
+ private $_selectKey=null;
+
+ /**
+ * @return TSqlMapSelectKey select key element.
+ */
+ public function getSelectKey()
+ {
+ return $this->_selectKey;
+ }
+
+ /**
+ * @param TSqlMapSelectKey select key.
+ */
+ public function setSelectKey($value)
+ {
+ $this->_selectKey = $value;
+ }
+}
+
+/**
+ * TSqlMapUpdate class corresponds to <update> element.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ * @since 3.1
+ */
+class TSqlMapUpdate extends TSqlMapStatement
+{
+}
+
+/**
+ * TSqlMapDelete class corresponds to the <delete> element.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ * @since 3.1
+ */
+class TSqlMapDelete extends TSqlMapUpdate
+{
+}
+
+/**
+ * TSqlMapSelect corresponds to the <selectKey> element.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ * @since 3.1
+ */
+class TSqlMapSelectKey extends TSqlMapStatement
+{
+ private $_type = 'post';
+ private $_property;
+
+ /**
+ * @return string select generated key type, 'post' or 'pre'.
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * @param string select generated key type, 'post' or 'pre'.
+ */
+ public function setType($value)
+ {
+ $this->_type = strtolower($value) == 'post' ? 'post' : 'pre';
+ }
+
+ /**
+ * @return string property name for the generated key.
+ */
+ public function getProperty()
+ {
+ return $this->_property;
+ }
+
+ /**
+ * @param string property name for the generated key.
+ */
+ public function setProperty($value)
+ {
+ $this->_property = $value;
+ }
+
+ /**
+ * @throws TSqlMapConfigurationException extends is unsupported.
+ */
+ public function setExtends($value)
+ {
+ throw new TSqlMapConfigurationException('sqlmap_can_not_extend_select_key');
+ }
+
+ /**
+ * @return boolean true if key is generated after insert command, false otherwise.
+ */
+ public function getIsAfter()
+ {
+ return $this->_type == 'post';
+ }
+}
+
diff --git a/lib/prado/framework/Data/SqlMap/Configuration/TSqlMapXmlConfiguration.php b/lib/prado/framework/Data/SqlMap/Configuration/TSqlMapXmlConfiguration.php
new file mode 100644
index 0000000..062b65e
--- /dev/null
+++ b/lib/prado/framework/Data/SqlMap/Configuration/TSqlMapXmlConfiguration.php
@@ -0,0 +1,801 @@
+<?php
+/**
+ * TSqlMapXmlConfigBuilder, TSqlMapXmlConfiguration, TSqlMapXmlMappingConfiguration classes file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Data.SqlMap.Configuration
+ */
+
+Prado::using('System.Data.SqlMap.Configuration.TSqlMapStatement');
+
+/**
+ * TSqlMapXmlConfig class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ */
+abstract class TSqlMapXmlConfigBuilder
+{
+ /**
+ * Create an instance of an object give by the attribute named 'class' in the
+ * node and set the properties on the object given by attribute names and values.
+ * @param SimpleXmlNode property node
+ * @return Object new instance of class with class name given by 'class' attribute value.
+ */
+ protected function createObjectFromNode($node)
+ {
+ if(isset($node['class']))
+ {
+ $obj = Prado::createComponent((string)$node['class']);
+ $this->setObjectPropFromNode($obj,$node,array('class'));
+ return $obj;
+ }
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_node_class_undef', $node, $this->getConfigFile());
+ }
+
+ /**
+ * For each attributes (excluding attribute named in $except) set the
+ * property of the $obj given by the name of the attribute with the value
+ * of the attribute.
+ * @param Object object instance
+ * @param SimpleXmlNode property node
+ * @param array exception property name
+ */
+ protected function setObjectPropFromNode($obj,$node,$except=array())
+ {
+ foreach($node->attributes() as $name=>$value)
+ {
+ if(!in_array($name,$except))
+ {
+ if($obj->canSetProperty($name))
+ $obj->{$name} = (string)$value;
+ else
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_invalid_property', $name, get_class($obj),
+ $node, $this->getConfigFile());
+ }
+ }
+ }
+
+ /**
+ * Gets the filename relative to the basefile.
+ * @param string base filename
+ * @param string relative filename
+ * @return string absolute filename.
+ */
+ protected function getAbsoluteFilePath($basefile,$resource)
+ {
+ $basedir = dirname($basefile);
+ $file = realpath($basedir.DIRECTORY_SEPARATOR.$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);
+ }
+
+ /**
+ * Load document using simple xml.
+ * @param string filename.
+ * @return SimpleXmlElement xml document.
+ */
+ protected function loadXmlDocument($filename,TSqlMapXmlConfiguration $config)
+ {
+ if( strpos($filename, '${') !== false)
+ $filename = $config->replaceProperties($filename);
+
+ if(!is_file($filename))
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_unable_to_find_config', $filename);
+ return simplexml_load_string($config->replaceProperties(file_get_contents($filename)));
+ }
+
+ /**
+ * Get element node by ID value (try for attribute name ID as case insensitive).
+ * @param SimpleXmlDocument $document
+ * @param string tag name.
+ * @param string id value.
+ * @return SimpleXmlElement node if found, null otherwise.
+ */
+ protected function getElementByIdValue($document, $tag, $value)
+ {
+ //hack to allow upper case and lower case attribute names.
+ foreach(array('id','ID','Id', 'iD') as $id)
+ {
+ $xpath = "//{$tag}[@{$id}='{$value}']";
+ foreach($document->xpath($xpath) as $node)
+ return $node;
+ }
+ }
+
+ /**
+ * @return string configuration file.
+ */
+ protected abstract function getConfigFile();
+}
+
+/**
+ * TSqlMapXmlConfig class.
+ *
+ * Configures the TSqlMapManager using xml configuration file.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ * @since 3.1
+ */
+class TSqlMapXmlConfiguration extends TSqlMapXmlConfigBuilder
+{
+ /**
+ * @var TSqlMapManager manager
+ */
+ private $_manager;
+ /**
+ * @var string configuration file.
+ */
+ private $_configFile;
+ /**
+ * @var array global properties.
+ */
+ private $_properties=array();
+
+ /**
+ * @param TSqlMapManager manager instance.
+ */
+ public function __construct($manager)
+ {
+ $this->_manager=$manager;
+ }
+
+ public function getManager()
+ {
+ return $this->_manager;
+ }
+
+ protected function getConfigFile()
+ {
+ return $this->_configFile;
+ }
+
+ /**
+ * Configure the TSqlMapManager using the given xml file.
+ * @param string SqlMap configuration xml file.
+ */
+ public function configure($filename=null)
+ {
+ $this->_configFile=$filename;
+ $document = $this->loadXmlDocument($filename,$this);
+
+ foreach($document->xpath('//property') as $property)
+ $this->loadGlobalProperty($property);
+
+ foreach($document->xpath('//typeHandler') as $handler)
+ $this->loadTypeHandler($handler);
+
+ foreach($document->xpath('//connection[last()]') as $conn)
+ $this->loadDatabaseConnection($conn);
+
+ //try to load configuration in the current config file.
+ $mapping = new TSqlMapXmlMappingConfiguration($this);
+ $mapping->configure($filename);
+
+ foreach($document->xpath('//sqlMap') as $sqlmap)
+ $this->loadSqlMappingFiles($sqlmap);
+
+ $this->resolveResultMapping();
+ $this->attachCacheModels();
+ }
+
+ /**
+ * Load global replacement property.
+ * @param SimpleXmlElement property node.
+ */
+ protected function loadGlobalProperty($node)
+ {
+ $this->_properties[(string)$node['name']] = (string)$node['value'];
+ }
+
+ /**
+ * Load the type handler configurations.
+ * @param SimpleXmlElement type handler node
+ */
+ protected function loadTypeHandler($node)
+ {
+ $handler = $this->createObjectFromNode($node);
+ $this->_manager->getTypeHandlers()->registerTypeHandler($handler);
+ }
+
+ /**
+ * Load the database connection tag.
+ * @param SimpleXmlElement connection node.
+ */
+ protected function loadDatabaseConnection($node)
+ {
+ $conn = $this->createObjectFromNode($node);
+ $this->_manager->setDbConnection($conn);
+ }
+
+ /**
+ * Load SqlMap mapping configuration.
+ * @param unknown_type $node
+ */
+ protected function loadSqlMappingFiles($node)
+ {
+ if(strlen($resource = (string)$node['resource']) > 0)
+ {
+ if( strpos($resource, '${') !== false)
+ $resource = $this->replaceProperties($resource);
+
+ $mapping = new TSqlMapXmlMappingConfiguration($this);
+ $filename = $this->getAbsoluteFilePath($this->_configFile, $resource);
+ $mapping->configure($filename);
+ }
+ }
+
+ /**
+ * Resolve nest result mappings.
+ */
+ protected function resolveResultMapping()
+ {
+ $maps = $this->_manager->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($entry->getDiscriminator()!==null)
+ $entry->getDiscriminator()->initialize($this->_manager);
+ }
+ }
+
+ /**
+ * Set the cache for each statement having a cache model property.
+ */
+ protected function attachCacheModels()
+ {
+ foreach($this->_manager->getMappedStatements() as $mappedStatement)
+ {
+ if(strlen($model = $mappedStatement->getStatement()->getCacheModel()) > 0)
+ {
+ $cache = $this->_manager->getCacheModel($model);
+ $mappedStatement->getStatement()->setCache($cache);
+ }
+ }
+ }
+
+ /**
+ * Replace the place holders ${name} in text with properties the
+ * corresponding global property value.
+ * @param string original string.
+ * @return string string with global property replacement.
+ */
+ public function replaceProperties($string)
+ {
+ foreach($this->_properties as $find => $replace)
+ $string = str_replace('${'.$find.'}', $replace, $string);
+ return $string;
+ }
+}
+
+/**
+ * Loads the statements, result maps, parameters maps from xml configuration.
+ *
+ * description
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @package System.Data.SqlMap.Configuration
+ * @since 3.1
+ */
+class TSqlMapXmlMappingConfiguration extends TSqlMapXmlConfigBuilder
+{
+ private $_xmlConfig;
+ private $_configFile;
+ private $_manager;
+
+ private $_document;
+
+ private $_FlushOnExecuteStatements=array();
+
+ /**
+ * Regular expressions for escaping simple/inline parameter symbols
+ */
+ const SIMPLE_MARK='$';
+ const INLINE_SYMBOL='#';
+ const ESCAPED_SIMPLE_MARK_REGEXP='/\$\$/';
+ const ESCAPED_INLINE_SYMBOL_REGEXP='/\#\#/';
+ const SIMPLE_PLACEHOLDER='`!!`';
+ const INLINE_PLACEHOLDER='`!!!`';
+
+ /**
+ * @param TSqlMapXmlConfiguration parent xml configuration.
+ */
+ public function __construct(TSqlMapXmlConfiguration $xmlConfig)
+ {
+ $this->_xmlConfig=$xmlConfig;
+ $this->_manager=$xmlConfig->getManager();
+ }
+
+ protected function getConfigFile()
+ {
+ return $this->_configFile;
+ }
+
+ /**
+ * Configure an XML mapping.
+ * @param string xml mapping filename.
+ */
+ public function configure($filename)
+ {
+ $this->_configFile=$filename;
+ $document = $this->loadXmlDocument($filename,$this->_xmlConfig);
+ $this->_document=$document;
+
+ static $bCacheDependencies;
+ if($bCacheDependencies === null)
+ $bCacheDependencies = Prado::getApplication()->getMode() !== TApplicationMode::Performance;
+
+ if($bCacheDependencies)
+ $this->_manager->getCacheDependencies()
+ ->getDependencies()
+ ->add(new TFileCacheDependency($filename));
+
+ foreach($document->xpath('//resultMap') as $node)
+ $this->loadResultMap($node);
+
+ foreach($document->xpath('//parameterMap') as $node)
+ $this->loadParameterMap($node);
+
+ foreach($document->xpath('//statement') as $node)
+ $this->loadStatementTag($node);
+
+ foreach($document->xpath('//select') as $node)
+ $this->loadSelectTag($node);
+
+ foreach($document->xpath('//insert') as $node)
+ $this->loadInsertTag($node);
+
+ foreach($document->xpath('//update') as $node)
+ $this->loadUpdateTag($node);
+
+ foreach($document->xpath('//delete') as $node)
+ $this->loadDeleteTag($node);
+
+ foreach($document->xpath('//procedure') as $node)
+ $this->loadProcedureTag($node);
+
+ foreach($document->xpath('//cacheModel') as $node)
+ $this->loadCacheModel($node);
+
+ $this->registerCacheTriggers();
+ }
+
+ /**
+ * Load the result maps.
+ * @param SimpleXmlElement result map node.
+ */
+ protected function loadResultMap($node)
+ {
+ $resultMap = $this->createResultMap($node);
+
+ //find extended result map.
+ if(strlen($extendMap = $resultMap->getExtends()) > 0)
+ {
+ if(!$this->_manager->getResultMaps()->contains($extendMap))
+ {
+ $extendNode=$this->getElementByIdValue($this->_document,'resultMap',$extendMap);
+ if($extendNode!==null)
+ $this->loadResultMap($extendNode);
+ }
+
+ if(!$this->_manager->getResultMaps()->contains($extendMap))
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_unable_to_find_parent_result_map', $node, $this->_configFile, $extendMap);
+
+ $superMap = $this->_manager->getResultMap($extendMap);
+ $resultMap->getColumns()->mergeWith($superMap->getColumns());
+ }
+
+ //add the result map
+ if(!$this->_manager->getResultMaps()->contains($resultMap->getID()))
+ $this->_manager->addResultMap($resultMap);
+ }
+
+ /**
+ * Create a new result map and its associated result properties,
+ * disciminiator and sub maps.
+ * @param SimpleXmlElement result map node
+ * @return TResultMap SqlMap result mapping.
+ */
+ protected function createResultMap($node)
+ {
+ $resultMap = new TResultMap();
+ $this->setObjectPropFromNode($resultMap,$node);
+
+ //result nodes
+ foreach($node->result as $result)
+ {
+ $property = new TResultProperty($resultMap);
+ $this->setObjectPropFromNode($property,$result);
+ $resultMap->addResultProperty($property);
+ }
+
+ //create the discriminator
+ $discriminator = null;
+ if(isset($node->discriminator))
+ {
+ $discriminator = new TDiscriminator();
+ $this->setObjectPropFromNode($discriminator, $node->discriminator);
+ $discriminator->initMapping($resultMap);
+ }
+
+ foreach($node->xpath('subMap') as $subMapNode)
+ {
+ if($discriminator===null)
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_undefined_discriminator', $node, $this->_configFile,$subMapNode);
+ $subMap = new TSubMap;
+ $this->setObjectPropFromNode($subMap,$subMapNode);
+ $discriminator->addSubMap($subMap);
+ }
+
+ if($discriminator!==null)
+ $resultMap->setDiscriminator($discriminator);
+
+ return $resultMap;
+ }
+
+ /**
+ * Load parameter map from xml.
+ *
+ * @param SimpleXmlElement parameter map node.
+ */
+ protected function loadParameterMap($node)
+ {
+ $parameterMap = $this->createParameterMap($node);
+
+ if(strlen($extendMap = $parameterMap->getExtends()) > 0)
+ {
+ if(!$this->_manager->getParameterMaps()->contains($extendMap))
+ {
+ $extendNode=$this->getElementByIdValue($this->_document,'parameterMap',$extendMap);
+ if($extendNode!==null)
+ $this->loadParameterMap($extendNode);
+ }
+
+ if(!$this->_manager->getParameterMaps()->contains($extendMap))
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_unable_to_find_parent_parameter_map', $node, $this->_configFile,$extendMap);
+ $superMap = $this->_manager->getParameterMap($extendMap);
+ $index = 0;
+ foreach($superMap->getPropertyNames() as $propertyName)
+ $parameterMap->insertProperty($index++,$superMap->getProperty($propertyName));
+ }
+ $this->_manager->addParameterMap($parameterMap);
+ }
+
+ /**
+ * Create a new parameter map from xml node.
+ * @param SimpleXmlElement parameter map node.
+ * @return TParameterMap new parameter mapping.
+ */
+ protected function createParameterMap($node)
+ {
+ $parameterMap = new TParameterMap();
+ $this->setObjectPropFromNode($parameterMap,$node);
+ foreach($node->parameter as $parameter)
+ {
+ $property = new TParameterProperty();
+ $this->setObjectPropFromNode($property,$parameter);
+ $parameterMap->addProperty($property);
+ }
+ return $parameterMap;
+ }
+
+ /**
+ * Load statement mapping from xml configuration file.
+ * @param SimpleXmlElement statement node.
+ */
+ protected function loadStatementTag($node)
+ {
+ $statement = new TSqlMapStatement();
+ $this->setObjectPropFromNode($statement,$node);
+ $this->processSqlStatement($statement, $node);
+ $mappedStatement = new TMappedStatement($this->_manager, $statement);
+ $this->_manager->addMappedStatement($mappedStatement);
+ }
+
+ /**
+ * Load extended SQL statements if application. Replaces global properties
+ * in the sql text. Extracts inline parameter maps.
+ * @param TSqlMapStatement mapped statement.
+ * @param SimpleXmlElement statement node.
+ */
+ protected function processSqlStatement($statement, $node)
+ {
+ $commandText = (string)$node;
+ if(strlen($extend = $statement->getExtends()) > 0)
+ {
+ $superNode = $this->getElementByIdValue($this->_document,'*',$extend);
+ if($superNode!==null)
+ $commandText = (string)$superNode . $commandText;
+ else
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_unable_to_find_parent_sql', $extend, $this->_configFile,$node);
+ }
+ //$commandText = $this->_xmlConfig->replaceProperties($commandText);
+ $statement->initialize($this->_manager);
+ $this->applyInlineParameterMap($statement, $commandText, $node);
+ }
+
+ /**
+ * Extract inline parameter maps.
+ * @param TSqlMapStatement statement object.
+ * @param string sql text
+ * @param SimpleXmlElement statement node.
+ */
+ protected function applyInlineParameterMap($statement, $sqlStatement, $node)
+ {
+ $scope['file'] = $this->_configFile;
+ $scope['node'] = $node;
+
+ $sqlStatement=preg_replace(self::ESCAPED_INLINE_SYMBOL_REGEXP,self::INLINE_PLACEHOLDER,$sqlStatement);
+ if($statement->parameterMap() === null)
+ {
+ // Build a Parametermap with the inline parameters.
+ // if they exist. Then delete inline infos from sqltext.
+ $parameterParser = new TInlineParameterMapParser;
+ $sqlText = $parameterParser->parse($sqlStatement, $scope);
+ if(count($sqlText['parameters']) > 0)
+ {
+ $map = new TParameterMap();
+ $map->setID($statement->getID().'-InLineParameterMap');
+ $statement->setInlineParameterMap($map);
+ foreach($sqlText['parameters'] as $property)
+ $map->addProperty($property);
+ }
+ $sqlStatement = $sqlText['sql'];
+ }
+ $sqlStatement=preg_replace('/'.self::INLINE_PLACEHOLDER.'/',self::INLINE_SYMBOL,$sqlStatement);
+
+ $this->prepareSql($statement, $sqlStatement, $node);
+ }
+
+ /**
+ * Prepare the sql text (may extend to dynamic sql).
+ * @param TSqlMapStatement mapped statement.
+ * @param string sql text.
+ * @param SimpleXmlElement statement node.
+ * @todo Extend to dynamic sql.
+ */
+ protected function prepareSql($statement,$sqlStatement, $node)
+ {
+ $simpleDynamic = new TSimpleDynamicParser;
+ $sqlStatement=preg_replace(self::ESCAPED_SIMPLE_MARK_REGEXP,self::SIMPLE_PLACEHOLDER,$sqlStatement);
+ $dynamics = $simpleDynamic->parse($sqlStatement);
+ if(count($dynamics['parameters']) > 0)
+ {
+ $sql = new TSimpleDynamicSql($dynamics['parameters']);
+ $sqlStatement = $dynamics['sql'];
+ }
+ else
+ $sql = new TStaticSql();
+ $sqlStatement=preg_replace('/'.self::SIMPLE_PLACEHOLDER.'/',self::SIMPLE_MARK,$sqlStatement);
+ $sql->buildPreparedStatement($statement, $sqlStatement);
+ $statement->setSqlText($sql);
+ }
+
+ /**
+ * Load select statement from xml mapping.
+ * @param SimpleXmlElement select node.
+ */
+ protected function loadSelectTag($node)
+ {
+ $select = new TSqlMapSelect;
+ $this->setObjectPropFromNode($select,$node);
+ $this->processSqlStatement($select,$node);
+ $mappedStatement = new TMappedStatement($this->_manager, $select);
+ if(strlen($select->getCacheModel()) > 0)
+ $mappedStatement = new TCachingStatement($mappedStatement);
+
+ $this->_manager->addMappedStatement($mappedStatement);
+ }
+
+ /**
+ * Load insert statement from xml mapping.
+ * @param SimpleXmlElement insert node.
+ */
+ protected function loadInsertTag($node)
+ {
+ $insert = $this->createInsertStatement($node);
+ $this->processSqlStatement($insert, $node);
+ $mappedStatement = new TInsertMappedStatement($this->_manager, $insert);
+ $this->_manager->addMappedStatement($mappedStatement);
+ }
+
+ /**
+ * Create new insert statement from xml node.
+ * @param SimpleXmlElement insert node.
+ * @return TSqlMapInsert insert statement.
+ */
+ protected function createInsertStatement($node)
+ {
+ $insert = new TSqlMapInsert;
+ $this->setObjectPropFromNode($insert,$node);
+ if(isset($node->selectKey))
+ $this->loadSelectKeyTag($insert,$node->selectKey);
+ return $insert;
+ }
+
+ /**
+ * Load the selectKey statement from xml mapping.
+ * @param SimpleXmlElement selectkey node
+ */
+ protected function loadSelectKeyTag($insert, $node)
+ {
+ $selectKey = new TSqlMapSelectKey;
+ $this->setObjectPropFromNode($selectKey,$node);
+ $selectKey->setID($insert->getID());
+ $selectKey->setID($insert->getID().'.SelectKey');
+ $this->processSqlStatement($selectKey,$node);
+ $insert->setSelectKey($selectKey);
+ $mappedStatement = new TMappedStatement($this->_manager, $selectKey);
+ $this->_manager->addMappedStatement($mappedStatement);
+ }
+
+ /**
+ * Load update statement from xml mapping.
+ * @param SimpleXmlElement update node.
+ */
+ protected function loadUpdateTag($node)
+ {
+ $update = new TSqlMapUpdate;
+ $this->setObjectPropFromNode($update,$node);
+ $this->processSqlStatement($update, $node);
+ $mappedStatement = new TUpdateMappedStatement($this->_manager, $update);
+ $this->_manager->addMappedStatement($mappedStatement);
+ }
+
+ /**
+ * Load delete statement from xml mapping.
+ * @param SimpleXmlElement delete node.
+ */
+ protected function loadDeleteTag($node)
+ {
+ $delete = new TSqlMapDelete;
+ $this->setObjectPropFromNode($delete,$node);
+ $this->processSqlStatement($delete, $node);
+ $mappedStatement = new TDeleteMappedStatement($this->_manager, $delete);
+ $this->_manager->addMappedStatement($mappedStatement);
+ }
+
+ /**
+ * Load procedure statement from xml mapping.
+ * @todo Implement loading procedure
+ * @param SimpleXmlElement procedure node
+ */
+ protected function loadProcedureTag($node)
+ {
+ //var_dump('todo: add load procedure');
+ }
+
+ /**
+ * Load cache models from xml mapping.
+ * @param SimpleXmlElement cache node.
+ */
+ protected function loadCacheModel($node)
+ {
+ $cacheModel = new TSqlMapCacheModel;
+ $properties = array('id','implementation');
+ foreach($node->attributes() as $name=>$value)
+ {
+ if(in_array(strtolower($name), $properties))
+ $cacheModel->{'set'.$name}((string)$value);
+ }
+ $cache = Prado::createComponent($cacheModel->getImplementationClass(), $cacheModel);
+ $this->setObjectPropFromNode($cache,$node,$properties);
+
+ foreach($node->xpath('property') as $propertyNode)
+ {
+ $name = $propertyNode->attributes()->name;
+ if($name===null || $name==='') continue;
+
+ $value = $propertyNode->attributes()->value;
+ if($value===null || $value==='') continue;
+
+ if( !TPropertyAccess::has($cache, $name) ) continue;
+
+ TPropertyAccess::set($cache, $name, $value);
+ }
+
+ $this->loadFlushInterval($cacheModel,$node);
+
+ $cacheModel->initialize($cache);
+ $this->_manager->addCacheModel($cacheModel);
+ foreach($node->xpath('flushOnExecute') as $flush)
+ $this->loadFlushOnCache($cacheModel,$node,$flush);
+ }
+
+ /**
+ * Load the flush interval
+ * @param TSqlMapCacheModel cache model
+ * @param SimpleXmlElement cache node
+ */
+ protected function loadFlushInterval($cacheModel, $node)
+ {
+ $flushInterval = $node->xpath('flushInterval');
+ if($flushInterval === null || count($flushInterval) === 0) return;
+ $duration = 0;
+ foreach($flushInterval[0]->attributes() as $name=>$value)
+ {
+ switch(strToLower($name))
+ {
+ case 'seconds':
+ $duration += (integer)$value;
+ break;
+ case 'minutes':
+ $duration += 60 * (integer)$value;
+ break;
+ case 'hours':
+ $duration += 3600 * (integer)$value;
+ break;
+ case 'days':
+ $duration += 86400 * (integer)$value;
+ break;
+ case 'duration':
+ $duration = (integer)$value;
+ break 2; // switch, foreach
+ }
+ }
+ $cacheModel->setFlushInterval($duration);
+ }
+
+ /**
+ * Load the flush on cache properties.
+ * @param TSqlMapCacheModel cache model
+ * @param SimpleXmlElement parent node.
+ * @param SimpleXmlElement flush node.
+ */
+ protected function loadFlushOnCache($cacheModel,$parent,$node)
+ {
+ $id = $cacheModel->getID();
+ if(!isset($this->_FlushOnExecuteStatements[$id]))
+ $this->_FlushOnExecuteStatements[$id] = array();
+ foreach($node->attributes() as $name=>$value)
+ {
+ if(strtolower($name)==='statement')
+ $this->_FlushOnExecuteStatements[$id][] = (string)$value;
+ }
+ }
+
+ /**
+ * Attach CacheModel to statement and register trigger statements for cache models
+ */
+ protected function registerCacheTriggers()
+ {
+ foreach($this->_FlushOnExecuteStatements as $cacheID => $statementIDs)
+ {
+ $cacheModel = $this->_manager->getCacheModel($cacheID);
+ foreach($statementIDs as $statementID)
+ {
+ $statement = $this->_manager->getMappedStatement($statementID);
+ $cacheModel->registerTriggerStatement($statement);
+ }
+ }
+ }
+}
+