summaryrefslogtreecommitdiff
path: root/framework/Data/ActiveRecord
diff options
context:
space:
mode:
Diffstat (limited to 'framework/Data/ActiveRecord')
-rw-r--r--framework/Data/ActiveRecord/TActiveRecord.php83
-rw-r--r--framework/Data/ActiveRecord/TActiveRecordCriteria.php22
-rw-r--r--framework/Data/ActiveRecord/TActiveRecordGateway.php149
-rw-r--r--framework/Data/ActiveRecord/TActiveRecordManager.php66
4 files changed, 127 insertions, 193 deletions
diff --git a/framework/Data/ActiveRecord/TActiveRecord.php b/framework/Data/ActiveRecord/TActiveRecord.php
index 0400661d..1ea06a60 100644
--- a/framework/Data/ActiveRecord/TActiveRecord.php
+++ b/framework/Data/ActiveRecord/TActiveRecord.php
@@ -17,7 +17,10 @@ Prado::using('System.Data.ActiveRecord.TActiveRecordCriteria');
* Base class for active records.
*
* An active record creates an object that wraps a row in a database table
- * or view, encapsulates the database access, and adds domain logic on that data.
+ * or view, encapsulates the database access, and adds domain logic on that data.
+ *
+ * Active record objects are stateful, this is main difference between the
+ * TActiveRecord implementation and the TTableGateway implementation.
*
* The essence of an Active Record is an object model of the
* domain (e.g. products, items) that incorporates both behavior and
@@ -140,7 +143,11 @@ abstract class TActiveRecord extends TComponent
}
/**
- * Returns the instance of a active record finder for a particular class.
+ * Returns the instance of a active record finder for a particular class.
+ * The finder objects are static instances for each ActiveRecord class.
+ * This means that event handlers bound to these finder instances are class wide.
+ * Create a new instance of the ActiveRecord class if you wish to bound the
+ * event handlers to object instance.
* @param string active record class name.
* @return TActiveRecord active record finder instance.
* @throws TActiveRecordException if class name equals 'TActiveRecord'.
@@ -168,6 +175,14 @@ abstract class TActiveRecord extends TComponent
public function getRecordManager()
{
return TActiveRecordManager::getInstance();
+ }
+
+ /**
+ * @return TActiveRecordGateway record table gateway.
+ */
+ public function getRecordGateway()
+ {
+ return $this->getRecordManager()->getRecordGateway();
}
/**
@@ -266,15 +281,20 @@ abstract class TActiveRecord extends TComponent
//try the cache (the cache object must be clean)
if(!is_null($obj = $registry->getCachedInstance($data)))
- return $obj;
+ return $obj;
+
+ $gateway = $this->getRecordManager()->getRecordGateway();
//create and populate the object
$obj = Prado::createComponent($type);
- foreach($data as $name => $value)
- $obj->{$name} = $value;
+ $tableInfo = $gateway->getRecordTableInfo($obj);
+ foreach($tableInfo->getColumns()->getKeys() as $name)
+ {
+ if(isset($data[$name]))
+ $obj->{$name} = $data[$name];
+ }
- $gateway = $this->getRecordManager()->getRecordGateway();
- $obj->_readOnly = $gateway->getRecordTableInfo($this)->getIsView();
+ $obj->_readOnly = $tableInfo->getIsView();
//cache it
return $registry->addCachedInstance($data,$obj);
@@ -484,21 +504,38 @@ abstract class TActiveRecord extends TComponent
else
throw new TActiveRecordException('ar_invalid_criteria');
}
+
+ /**
+ * Raised when a command is prepared and parameter binding is completed.
+ * The parameter object is TDataGatewayEventParameter of which the
+ * {@link TDataGatewayEventParameter::getCommand Command} property can be
+ * inspected to obtain the sql query to be executed.
+ *
+ * Note well that the finder objects obtained from ActiveRecord::finder()
+ * method are static objects. This means that the event handlers are
+ * bound to a static finder object and not to each distinct active record object.
+ * @param TDataGatewayEventParameter
+ */
+ public function onCreateCommand($param)
+ {
+ $this->raiseEvent('OnCreateCommand', $this, $param);
+ }
+
+ /**
+ * Raised when a command is executed and the result from the database was returned.
+ * The parameter object is TDataGatewayResultEventParameter of which the
+ * {@link TDataGatewayEventParameter::getResult Result} property contains
+ * the data return from the database. The data returned can be changed
+ * by setting the {@link TDataGatewayEventParameter::setResult Result} property.
+ *
+ * Note well that the finder objects obtained from ActiveRecord::finder()
+ * method are static objects. This means that the event handlers are
+ * bound to a static finder object and not to each distinct active record object.
+ * @param TDataGatewayResultEventParameter
+ */
+ public function onExecuteCommand($param)
+ {
+ $this->raiseEvent('OnExecuteCommand', $this, $param);
+ }
}
-
-/**
- * TActiveRecordEventParameter class.
- *
- * @author Wei Zhuo <weizho[at]gmail[dot]com>
- * @version $Id$
- * @package System.Data.ActiveRecord
- * @since 3.1
- */
-class TActiveRecordEventParameter extends TEventParameter
-{
-
-}
-
-
-
?>
diff --git a/framework/Data/ActiveRecord/TActiveRecordCriteria.php b/framework/Data/ActiveRecord/TActiveRecordCriteria.php
index cc4da7c8..8328b4a6 100644
--- a/framework/Data/ActiveRecord/TActiveRecordCriteria.php
+++ b/framework/Data/ActiveRecord/TActiveRecordCriteria.php
@@ -34,29 +34,7 @@ Prado::using('System.Data.DataGateway.TSqlCriteria');
*/
class TActiveRecordCriteria extends TSqlCriteria
{
- /**
- * This method is invoked before the object is deleted from the database.
- * The method raises 'OnDelete' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TActiveRecordEventParameter event parameter to be passed to the event handlers
- */
- public function onDelete($param)
- {
- $this->raiseEvent('OnDelete', $this, $param);
- }
- /**
- * This method is invoked before any select query is executed on the database.
- * The method raises 'OnSelect' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TActiveRecordEventParameter event parameter to be passed to the event handlers
- */
- public function onSelect($param)
- {
- $this->raiseEvent('OnSelect', $this, $param);
- }
}
?> \ No newline at end of file
diff --git a/framework/Data/ActiveRecord/TActiveRecordGateway.php b/framework/Data/ActiveRecord/TActiveRecordGateway.php
index 9c480ad0..c3239c5c 100644
--- a/framework/Data/ActiveRecord/TActiveRecordGateway.php
+++ b/framework/Data/ActiveRecord/TActiveRecordGateway.php
@@ -1,6 +1,6 @@
<?php
/**
- * TActiveRecordGateway, TActiveRecordStatementType, TActiveRecordGatewayEventParameter classes file.
+ * TActiveRecordGateway, TActiveRecordStatementType, TActiveRecordEventParameter classes file.
*
* @author Wei Zhuo <weizhuo[at]gmail[dot]com>
* @link http://www.pradosoft.com/
@@ -25,6 +25,8 @@ class TActiveRecordGateway extends TComponent
private $_tables=array(); //table cache
private $_meta=array(); //meta data cache.
private $_commandBuilders=array();
+ private $_currentRecord;
+
/**
* Constant name for specifying optional table name in TActiveRecord.
*/
@@ -99,7 +101,7 @@ class TActiveRecordGateway extends TComponent
if(!isset($this->_meta[$connStr]))
{
Prado::using('System.Data.Common.TDbMetaData');
- $this->_meta[$connStr] = TDbMetaData::getMetaData($connection);
+ $this->_meta[$connStr] = TDbMetaData::getInstance($connection);
}
$tableInfo = $this->_meta[$connStr]->getTableInfo($tableName);
}
@@ -123,14 +125,53 @@ class TActiveRecordGateway extends TComponent
{
$builder = $tableInfo->createCommandBuilder($record->getDbConnection());
Prado::using('System.Data.DataGateway.TDataGatewayCommand');
- $this->_commandBuilders[$connStr] = new TDataGatewayCommand($builder);
+ $command = new TDataGatewayCommand($builder);
+ $command->OnCreateCommand[] = array($this, 'onCreateCommand');
+ $command->OnExecuteCommand[] = array($this, 'onExecuteCommand');
+ $this->_commandBuilders[$connStr] = $command;
+
}
$this->_commandBuilders[$connStr]->getBuilder()->setTableInfo($tableInfo);
-
+ $this->_currentRecord=$record;
return $this->_commandBuilders[$connStr];
}
/**
+ * Raised when a command is prepared and parameter binding is completed.
+ * The parameter object is TDataGatewayEventParameter of which the
+ * {@link TDataGatewayEventParameter::getCommand Command} property can be
+ * inspected to obtain the sql query to be executed.
+ * This method also raises the OnCreateCommand event on the ActiveRecord
+ * object calling this gateway.
+ * @param TDataGatewayCommand originator $sender
+ * @param TDataGatewayEventParameter
+ */
+ public function onCreateCommand($sender, $param)
+ {
+ $this->raiseEvent('OnCreateCommand', $this, $param);
+ if($this->_currentRecord!==null)
+ $this->_currentRecord->onCreateCommand($param);
+ }
+
+ /**
+ * Raised when a command is executed and the result from the database was returned.
+ * The parameter object is TDataGatewayResultEventParameter of which the
+ * {@link TDataGatewayEventParameter::getResult Result} property contains
+ * the data return from the database. The data returned can be changed
+ * by setting the {@link TDataGatewayEventParameter::setResult Result} property.
+ * This method also raises the OnCreateCommand event on the ActiveRecord
+ * object calling this gateway.
+ * @param TDataGatewayCommand originator $sender
+ * @param TDataGatewayResultEventParameter
+ */
+ public function onExecuteCommand($sender, $param)
+ {
+ $this->raiseEvent('OnExecuteCommand', $this, $param);
+ if($this->_currentRecord!==null)
+ $this->_currentRecord->onExecuteCommand($param);
+ }
+
+ /**
* Returns record data matching the given primary key(s). If the table uses
* composite key, specify the name value pairs as an array.
* @param TActiveRecord active record instance.
@@ -139,7 +180,8 @@ class TActiveRecordGateway extends TComponent
*/
public function findRecordByPK(TActiveRecord $record,$keys)
{
- return $this->getCommand($record)->findByPk($keys);
+ $command = $this->getCommand($record);
+ return $command->findByPk($keys);
}
/**
@@ -164,10 +206,8 @@ class TActiveRecordGateway extends TComponent
*/
public function findRecordsByCriteria(TActiveRecord $record, $criteria, $iterator=false)
{
- if($iterator)
- return $this->getCommand($record)->findAll($criteria);
- else
- return $this->getCommand($record)->find($criteria);
+ $command = $this->getCommand($record);
+ return $iterator ? $command->findAll($criteria) : $command->find($criteria);
}
/**
@@ -205,6 +245,10 @@ class TActiveRecordGateway extends TComponent
return $result;
}
+ /**
+ * Sets the last insert ID to the corresponding property of the record if available.
+ * @param TActiveRecord record for insertion
+ */
protected function updatePostInsert($record)
{
$command = $this->getCommand($record);
@@ -324,91 +368,16 @@ class TActiveRecordGateway extends TComponent
* @param string command type
* @param TDbCommand sql command to be executed.
* @param TActiveRecord active record
- * @param mixed data for the command.
+ * @param TActiveRecordCriteria data for the command.
*/
- protected function raiseCommandEvent($type,$command,$record=null,$data=null)
+ protected function raiseCommandEvent($event,$command,$record,$criteria)
{
- $param = new TActiveRecordGatewayEventParameter($type,$command,$record,$data);
+ if(!($criteria instanceof TSqlCriteria))
+ $criteria = new TActiveRecordCriteria(null,$criteria);
+ $param = new TActiveRecordEventParameter($command,$record,$criteria);
$manager = $record->getRecordManager();
- $event = 'on'.$type;
- if($data instanceof TActiveRecordCriteria)
- $data->{$event}($param);
$manager->{$event}($param);
- }
-}
-
-/**
- * Command statement types.
- *
- * @author Wei Zhuo <weizho[at]gmail[dot]com>
- * @version $Id$
- * @package System.Data.ActiveRecord
- * @since 3.1
- */
-class TActiveRecordStatementType
-{
- const Insert='Insert';
- const Update='Update';
- const Delete='Delete';
- const Select='Select';
-}
-
-/**
- * Active Record command event parameter.
- *
- * @author Wei Zhuo <weizho[at]gmail[dot]com>
- * @version $Id$
- * @package System.Data.ActiveRecord
- * @since 3.1
- */
-class TActiveRecordGatewayEventParameter extends TActiveRecordEventParameter
-{
- private $_type;
- private $_command;
- private $_record;
- private $_data;
-
- /**
- * New gateway command event parameter.
- */
- public function __construct($type,$command,$record=null,$data=null)
- {
- $this->_type=$type;
- $this->_command=$command;
- $this->_data=$data;
- $this->_record=$record;
- }
-
- /**
- * @return string TActiveRecordStateType
- */
- public function getType()
- {
- return $this->_type;
- }
-
- /**
- * @return TDbCommand command to be executed.
- */
- public function getCommand()
- {
- return $this->_command;
- }
-
- /**
- * @return TActiveRecord active record.
- */
- public function getRecord()
- {
- return $this->_record;
- }
-
- /**
- * @return mixed command data.
- */
- public function getData()
- {
- return $this->_data;
+ $record->{$event}($param);
}
}
diff --git a/framework/Data/ActiveRecord/TActiveRecordManager.php b/framework/Data/ActiveRecord/TActiveRecordManager.php
index 5e463d2d..ab6fe88d 100644
--- a/framework/Data/ActiveRecord/TActiveRecordManager.php
+++ b/framework/Data/ActiveRecord/TActiveRecordManager.php
@@ -20,20 +20,16 @@ Prado::using('System.Data.ActiveRecord.TActiveRecordStateRegistry');
* TActiveRecordManager provides the default DB connection, default object state
* registry, default active record gateway, and table meta data inspector.
*
- * You can provide a different registry by overriding the {@link createObjectStateRegistry()} method.
- * Similarly, override {@link createRecordGateway()} for default gateway and override
- * {@link createMetaDataInspector() }for meta data inspector.
- *
* The default connection can be set as follows:
* <code>
* TActiveRecordManager::getInstance()->setDbConnection($conn);
* </code>
* All new active record created after setting the
- * {@link DbConnection setDbConnection()} will use that connection.
+ * {@link DbConnection setDbConnection()} will use that connection unless
+ * the custom ActiveRecord class overrides the ActiveRecord::getDbConnection().
*
- * The {@link onInsert()}, {@link onUpdate()},
- * {@link onDelete()} and {@link onSelect()} events are raised
- * <b>before</b> their respective command are executed.
+ * Set the {@link setCache Cache} property to an ICache object to allow
+ * the active record gateway to cache the table meta data information.
*
* @author Wei Zhuo <weizho[at]gmail[dot]com>
* @version $Id$
@@ -84,10 +80,12 @@ class TActiveRecordManager extends TComponent
/**
* @return TActiveRecordManager static instance of record manager.
*/
- public static function getInstance()
+ public static function getInstance($self=null)
{
static $instance;
- if($instance===null)
+ if($self!==null)
+ $instance=$self;
+ else if($instance===null)
$instance = new self;
return $instance;
}
@@ -127,54 +125,6 @@ class TActiveRecordManager extends TComponent
{
return new TActiveRecordGateway($this);
}
-
- /**
- * This method is invoked before the object is inserted into the database.
- * The method raises 'OnInsert' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TActiveRecordEventParameter event parameter to be passed to the event handlers
- */
- public function onInsert($param)
- {
- $this->raiseEvent('OnInsert', $this, $param);
- }
-
- /**
- * This method is invoked before the object is deleted from the database.
- * The method raises 'OnDelete' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TActiveRecordEventParameter event parameter to be passed to the event handlers
- */
- public function onDelete($param)
- {
- $this->raiseEvent('OnDelete', $this, $param);
- }
-
- /**
- * This method is invoked before the object data is updated in the database.
- * The method raises 'OnUpdate' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TActiveRecordEventParameter event parameter to be passed to the event handlers
- */
- public function onUpdate($param)
- {
- $this->raiseEvent('OnUpdate', $this, $param);
- }
-
- /**
- * This method is invoked before any select query is executed on the database.
- * The method raises 'OnSelect' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TActiveRecordEventParameter event parameter to be passed to the event handlers
- */
- public function onSelect($param)
- {
- $this->raiseEvent('OnSelect', $this, $param);
- }
}