From 03f362a40a8dd39f8c8b4bf816334922b7b264e4 Mon Sep 17 00:00:00 2001
From: wei <>
Date: Tue, 9 Jan 2007 10:42:06 +0000
Subject: add TActiveRecord::findAllByPks()
---
.../Data/ActiveRecord/Exceptions/messages.txt | 4 +-
framework/Data/ActiveRecord/TActiveRecord.php | 33 +++++++-
.../Data/ActiveRecord/TActiveRecordGateway.php | 15 ++++
framework/Data/ActiveRecord/Vendor/TDbMetaData.php | 92 +++++++++-------------
.../Data/ActiveRecord/Vendor/TDbMetaDataCommon.php | 26 ++++--
5 files changed, 105 insertions(+), 65 deletions(-)
(limited to 'framework/Data')
diff --git a/framework/Data/ActiveRecord/Exceptions/messages.txt b/framework/Data/ActiveRecord/Exceptions/messages.txt
index 92bdb30f..774c0275 100644
--- a/framework/Data/ActiveRecord/Exceptions/messages.txt
+++ b/framework/Data/ActiveRecord/Exceptions/messages.txt
@@ -10,4 +10,6 @@ ar_primary_key_is_scalar = Primary key '{1}' in table '{0}' is NOT a composi
ar_invalid_db_connection = Missing or invalid default database connection for ActiveRecord class '{0}', default connection is set by the DbConnection property of TActiveRecordManager.
ar_mismatch_args_exception = ActiveRecord finder method '{0}' expects {1} parameters but found only {2} parameters instead.
ar_invalid_tablename_property = ActiveRecord tablename property '{0}::${1}' must be static and not null.
-ar_value_must_not_be_null = Property '{0}::${2}' must not be null as defined by column '{2}' in table '{1}'.
\ No newline at end of file
+ar_value_must_not_be_null = Property '{0}::${2}' must not be null as defined by column '{2}' in table '{1}'.
+ar_missing_pk_values = Missing primary key values in forming IN(key1, key2, ...) for table '{0}'.
+ar_pk_value_count_mismatch = Composite key value count mismatch in forming IN( (key1, key2, ..), (key3, key4, ..)) for table '{0}'.
\ No newline at end of file
diff --git a/framework/Data/ActiveRecord/TActiveRecord.php b/framework/Data/ActiveRecord/TActiveRecord.php
index 68d63a23..d3e25dcf 100644
--- a/framework/Data/ActiveRecord/TActiveRecord.php
+++ b/framework/Data/ActiveRecord/TActiveRecord.php
@@ -38,7 +38,7 @@ Prado::using('System.Data.ActiveRecord.TActiveRecordCriteria');
* public $username; //corresponds to the fieldname in the table
* public $email;
*
- * private static final $_tablename='users'; //optional table name.
+ * public static final $_tablename='users'; //optional table name.
*
* //returns active record finder instance
* public static function finder()
@@ -332,13 +332,42 @@ abstract class TActiveRecord extends TComponent
*/
public function findByPk($keys)
{
- if(func_num_args() > 1 && !is_array($keys))
+ if(func_num_args() > 1)
$keys = func_get_args();
$gateway = $this->getRecordManager()->getRecordGateway();
$data = $gateway->findRecordByPK($this,$keys);
return $this->populateObject(get_class($this), $data);
}
+ /**
+ * Find multiple records matching a list of primary or composite keys.
+ *
+ * For scalar primary keys:
+ *
+ * $finder->findAllByPk($key1, $key2, ...);
+ * $finder->findAllByPk(array($key1, $key2, ...));
+ *
+ *
+ * For composite keys:
+ *
+ * $finder->findAllByPk(array($key1, $key2), array($key3, $key4), ...);
+ * $finder->findAllByPk(array(array($key1, $key2), array($key3, $key4), ...));
+ *
+ * @param mixed primary keys
+ * @return array matching ActiveRecords
+ */
+ public function findAllByPks($keys)
+ {
+ if(func_num_args() > 1)
+ $keys = func_get_args();
+ $gateway = $this->getRecordManager()->getRecordGateway();
+ $results = array();
+ $class = get_class($this);
+ foreach($gateway->findRecordsByPks($this,(array)$keys) as $data)
+ $results[] = $this->populateObject($class,$data);
+ return $results;
+ }
+
/**
* Find records using full SQL, returns corresponding record object.
* @param string select SQL
diff --git a/framework/Data/ActiveRecord/TActiveRecordGateway.php b/framework/Data/ActiveRecord/TActiveRecordGateway.php
index 1cb1c79f..7bcd0eb2 100644
--- a/framework/Data/ActiveRecord/TActiveRecordGateway.php
+++ b/framework/Data/ActiveRecord/TActiveRecordGateway.php
@@ -146,6 +146,21 @@ class TActiveRecordGateway extends TComponent
return $meta->postQueryRow($command->queryRow());
}
+ /**
+ * Returns records matching the list of given primary keys.
+ * @param TActiveRecord active record instance.
+ * @param array list of primary name value pairs
+ * @return array matching data.
+ */
+ public function findRecordsByPks(TActiveRecord $record, $keys)
+ {
+ $meta = $this->getMetaData($record);
+ $command = $meta->getFindInPksCommand($record->getDbConnection(), $keys);
+ $this->raiseCommandEvent(TActiveRecordStatementType::Select,$command,$record,$keys);
+ return $meta->postQuery($command->query());
+ }
+
+
/**
* Returns record data matching the given critera. If $iterator is true, it will
* return multiple rows as TDbDataReader otherwise it returns the first row data.
diff --git a/framework/Data/ActiveRecord/Vendor/TDbMetaData.php b/framework/Data/ActiveRecord/Vendor/TDbMetaData.php
index efb7c467..38a82aef 100644
--- a/framework/Data/ActiveRecord/Vendor/TDbMetaData.php
+++ b/framework/Data/ActiveRecord/Vendor/TDbMetaData.php
@@ -136,6 +136,43 @@ abstract class TDbMetaData extends TComponent
return implode(' AND ', $criteria);
}
+ /**
+ * Construct a "pk IN ('key1', 'key2', ...)" criteria.
+ * @param TDbConnection database connection.
+ * @param array values for IN predicate
+ * @param string SQL string for primary keys IN a list.
+ */
+ protected function getCompositeKeysCriteria($conn, $values)
+ {
+ $count = count($this->getPrimaryKeys());
+ if($count===0)
+ throw new TActiveRecordException('ar_no_primary_key_found',$this->getTableName());
+ if(!is_array($values) || count($values) === 0)
+ throw new TActiveRecordException('ar_missing_pk_values', $this->getTableName());
+ if($count>1 && !is_array($values[0]))
+ $values = array($values);
+ if($count > 1 && count($values[0]) !== $count)
+ throw new TActiveRecordException('ar_pk_value_count_mismatch', $this->getTableName());
+
+ $columns = array();
+ foreach($this->getPrimaryKeys() as $key)
+ $columns[] = $this->getColumn($key)->getName();
+ return '('.implode(', ',$columns).') IN '.$this->quoteTuple($conn, $values);
+ }
+
+ /**
+ * @param TDbConnection database connection.
+ * @param array values
+ * @return string quoted recursive tuple values, e.g. "('val1', 'val2')".
+ */
+ protected function quoteTuple($conn, $array)
+ {
+ $data = array();
+ foreach($array as $k=>$v)
+ $data[] = is_array($v) ? $this->quoteTuple($conn, $v) : $conn->quoteString($v);
+ return '('.implode(', ', $data).')';
+ }
+
/**
* Bind a list of variables in the command. The named parameters is taken
* from the values of the $keys parameter. The bind value is taken from the
@@ -308,60 +345,5 @@ x * @param array name value pairs of columns for update.
return implode(', ', $fields);
}
- /**
- * @param TDbConnection database connection
- * @param array primary key values.
- * @return string delete criteria for multiple scalar primary keys.
- */
- protected function getDeleteInPkCriteria($conn, $keys)
- {
- $pk = $this->getPrimaryKeys();
- $column = $this->getColumn($pk[0])->getName();
- $values = array();
- foreach($keys as $key)
- {
- if(is_array($key))
- {
- throw new TActiveRecordException('ar_primary_key_is_scalar',
- $this->getTableName(),$column,'array('.implode(', ',$key).')');
- }
- $values[] = $conn->quoteString($key);
- }
- $pks = implode(', ', $values);
- return "$column IN ($pks)";
- }
-
- /**
- * @param TDbConnection database connection
- * @param array primary key values.
- * @return string delete criteria for multiple composite primary keys.
- */
- protected function getDeleteMultiplePkCriteria($conn,$pks)
- {
- //check for 1 set composite keys
- if(count($pks)>0 && !is_array($pks[0]))
- $pks = array($pks);
- $conditions=array();
- foreach($pks as $keys)
- $conditions[] = $this->getDeleteCompositeKeyCondition($conn,$keys);
- return implode(' OR ', $conditions);
- }
-
- /**
- * @return string delete criteria for 1 composite key.
- */
- protected function getDeleteCompositeKeyCondition($conn,$keys)
- {
- $condition=array();
- $index = 0;
- foreach($this->getPrimarykeys() as $pk)
- {
- $name = $this->getColumn($pk)->getName();
- $value = isset($keys[$pk]) ? $keys[$pk] : $keys[$index];
- $condition[] = "$name = ".$conn->quoteString($value);
- $index++;
- }
- return '('.implode(' AND ', $condition).')';
- }
}
?>
\ No newline at end of file
diff --git a/framework/Data/ActiveRecord/Vendor/TDbMetaDataCommon.php b/framework/Data/ActiveRecord/Vendor/TDbMetaDataCommon.php
index fffdb6fb..7f7dad8b 100644
--- a/framework/Data/ActiveRecord/Vendor/TDbMetaDataCommon.php
+++ b/framework/Data/ActiveRecord/Vendor/TDbMetaDataCommon.php
@@ -40,6 +40,24 @@ abstract class TDbMetaDataCommon extends TDbMetaData
return $command;
}
+ /**
+ * SQL database command for finding records by a list of primary keys.
+ * @param TDbConnection database connection.
+ * @param array list of primary keys to match.
+ * @return TDbCommand find by list of primary keys command.
+ */
+ public function getFindInPksCommand($conn, $keys)
+ {
+ $conn->setActive(true);
+ $columns = $this->getSelectionColumns();
+ $table = $this->getTableName();
+ $criteria = $this->getCompositeKeysCriteria($conn,$keys);
+ $sql = "SELECT {$columns} FROM {$table} WHERE {$criteria}";
+ $command = $conn->createCommand($sql);
+ $command->prepare();
+ return $command;
+ }
+
/**
* SQL database command for finding records using a criteria object.
* @param TDbConnection database connection.
@@ -160,14 +178,8 @@ abstract class TDbMetaDataCommon extends TDbMetaData
public function getDeleteByPkCommand($conn,$keys)
{
$conn->setActive(true);
- $numKeys = count($this->getPrimaryKeys());
$table = $this->getTableName();
- if($numKeys===0)
- throw new TActiveRecordException('ar_no_primary_key_found',$table);
- if($numKeys===1)
- $criteria = $this->getDeleteInPkCriteria($conn,$keys);
- else
- $criteria = $this->getDeleteMultiplePkCriteria($conn,$keys);
+ $criteria = $this->getCompositeKeysCriteria($conn, $keys);
$sql = "DELETE FROM {$table} WHERE {$criteria}";
$command = $conn->createCommand($sql);
$command->prepare();
--
cgit v1.2.3