diff options
Diffstat (limited to 'framework/Data/SqlMap/Configuration')
10 files changed, 2758 insertions, 2758 deletions
diff --git a/framework/Data/SqlMap/Configuration/TDiscriminator.php b/framework/Data/SqlMap/Configuration/TDiscriminator.php index cbc05612..f0c9187b 100644 --- a/framework/Data/SqlMap/Configuration/TDiscriminator.php +++ b/framework/Data/SqlMap/Configuration/TDiscriminator.php @@ -1,232 +1,232 @@ -<?php
-/**
- * TDiscriminator and TSubMap classes file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TDiscriminator and TSubMap classes file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @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>
- * @version $Id$
- * @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>
- * @version $Id$
- * @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;
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @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> + * @version $Id$ + * @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> + * @version $Id$ + * @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/framework/Data/SqlMap/Configuration/TInlineParameterMapParser.php b/framework/Data/SqlMap/Configuration/TInlineParameterMapParser.php index b78a235c..914d7eb7 100644 --- a/framework/Data/SqlMap/Configuration/TInlineParameterMapParser.php +++ b/framework/Data/SqlMap/Configuration/TInlineParameterMapParser.php @@ -1,79 +1,79 @@ -<?php
-/**
- * TInlineParameterMapParser class file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TInlineParameterMapParser class file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @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>
- * @version $Id$
- * @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;
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @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> + * @version $Id$ + * @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/framework/Data/SqlMap/Configuration/TParameterMap.php b/framework/Data/SqlMap/Configuration/TParameterMap.php index d7cc5eb6..ee740fdb 100644 --- a/framework/Data/SqlMap/Configuration/TParameterMap.php +++ b/framework/Data/SqlMap/Configuration/TParameterMap.php @@ -1,210 +1,210 @@ -<?php
-/**
- * TParameterMap class file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @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>
- * @version $Id$
- * @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;
- }
-}
+<?php +/** + * TParameterMap class file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @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> + * @version $Id$ + * @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/framework/Data/SqlMap/Configuration/TParameterProperty.php b/framework/Data/SqlMap/Configuration/TParameterProperty.php index d941ca18..a79af7f2 100644 --- a/framework/Data/SqlMap/Configuration/TParameterProperty.php +++ b/framework/Data/SqlMap/Configuration/TParameterProperty.php @@ -1,150 +1,150 @@ -<?php
-/**
- * TParameterPropert class file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TParameterPropert class file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @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>
- * @version $Id$
- * @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);
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @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> + * @version $Id$ + * @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/framework/Data/SqlMap/Configuration/TResultMap.php b/framework/Data/SqlMap/Configuration/TResultMap.php index e05c4c47..77b5f0b2 100644 --- a/framework/Data/SqlMap/Configuration/TResultMap.php +++ b/framework/Data/SqlMap/Configuration/TResultMap.php @@ -1,200 +1,200 @@ -<?php
-/**
- * TResultMap class file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @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>
- * @version $Id$
- * @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;
- }
-}
-
+<?php +/** + * TResultMap class file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @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> + * @version $Id$ + * @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/framework/Data/SqlMap/Configuration/TResultProperty.php b/framework/Data/SqlMap/Configuration/TResultProperty.php index 0a016350..8447d400 100644 --- a/framework/Data/SqlMap/Configuration/TResultProperty.php +++ b/framework/Data/SqlMap/Configuration/TResultProperty.php @@ -1,344 +1,344 @@ -<?php
-/**
- * TResultProperty class file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @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>
- * @version $Id$
- * @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);
- }
-}
-
+<?php +/** + * TResultProperty class file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @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> + * @version $Id$ + * @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/framework/Data/SqlMap/Configuration/TSimpleDynamicParser.php b/framework/Data/SqlMap/Configuration/TSimpleDynamicParser.php index 1ceba9eb..a70e6b3f 100644 --- a/framework/Data/SqlMap/Configuration/TSimpleDynamicParser.php +++ b/framework/Data/SqlMap/Configuration/TSimpleDynamicParser.php @@ -1,45 +1,45 @@ -<?php
-/**
- * TSimpleDynamicParser class file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TSimpleDynamicParser class file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @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>
- * @version $Id$
- * @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);
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @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> + * @version $Id$ + * @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/framework/Data/SqlMap/Configuration/TSqlMapCacheModel.php b/framework/Data/SqlMap/Configuration/TSqlMapCacheModel.php index 4b985e51..0dc5d821 100644 --- a/framework/Data/SqlMap/Configuration/TSqlMapCacheModel.php +++ b/framework/Data/SqlMap/Configuration/TSqlMapCacheModel.php @@ -1,246 +1,246 @@ -<?php
-/**
- * TSqlMapCacheModel, TSqlMapCacheTypes and TSqlMapCacheKey classes file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @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>
- * @version $Id$
- * @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>
- * @version $Id$
- * @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>
- * @version $Id$
- * @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;
- }
-}
-
+<?php +/** + * TSqlMapCacheModel, TSqlMapCacheTypes and TSqlMapCacheKey classes file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @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> + * @version $Id$ + * @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> + * @version $Id$ + * @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> + * @version $Id$ + * @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/framework/Data/SqlMap/Configuration/TSqlMapStatement.php b/framework/Data/SqlMap/Configuration/TSqlMapStatement.php index 1d90d4b1..8f2ca5cc 100644 --- a/framework/Data/SqlMap/Configuration/TSqlMapStatement.php +++ b/framework/Data/SqlMap/Configuration/TSqlMapStatement.php @@ -1,451 +1,451 @@ -<?php
-/**
- * TSqlMapStatement, TSqlMapInsert, TSqlMapUpdate, TSqlMapDelete,
- * TSqlMapSelect and TSqlMapSelectKey classes file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @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>
- * @version $Id$
- * @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>
- * @version $Id$
- * @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>
- * @version $Id$
- * @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>
- * @version $Id$
- * @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>
- * @version $Id$
- * @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>
- * @version $Id$
- * @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';
- }
-}
-
+<?php +/** + * TSqlMapStatement, TSqlMapInsert, TSqlMapUpdate, TSqlMapDelete, + * TSqlMapSelect and TSqlMapSelectKey classes file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @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> + * @version $Id$ + * @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> + * @version $Id$ + * @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> + * @version $Id$ + * @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> + * @version $Id$ + * @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> + * @version $Id$ + * @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> + * @version $Id$ + * @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/framework/Data/SqlMap/Configuration/TSqlMapXmlConfiguration.php b/framework/Data/SqlMap/Configuration/TSqlMapXmlConfiguration.php index a60827fe..988d00db 100644 --- a/framework/Data/SqlMap/Configuration/TSqlMapXmlConfiguration.php +++ b/framework/Data/SqlMap/Configuration/TSqlMapXmlConfiguration.php @@ -1,805 +1,805 @@ -<?php
-/**
- * TSqlMapXmlConfigBuilder, TSqlMapXmlConfiguration, TSqlMapXmlMappingConfiguration classes file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Data.SqlMap.Configuration
- */
-
-Prado::using('System.Data.SqlMap.Configuration.TSqlMapStatement');
-
-/**
- * TSqlMapXmlConfig class file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @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>
- * @version $Id$
- * @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>
- * @version $Id$
- * @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);
- }
- }
- }
-}
-
+<?php +/** + * TSqlMapXmlConfigBuilder, TSqlMapXmlConfiguration, TSqlMapXmlMappingConfiguration classes file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Data.SqlMap.Configuration + */ + +Prado::using('System.Data.SqlMap.Configuration.TSqlMapStatement'); + +/** + * TSqlMapXmlConfig class file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @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> + * @version $Id$ + * @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> + * @version $Id$ + * @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); + } + } + } +} + |