[Solar-svn] Revision 2760
pmjones at solarphp.com
pmjones at solarphp.com
Tue Sep 18 20:54:39 CDT 2007
branch: Solar_Sql_Model_Record
* [DEL] Method load() no longer has unserializing logic; placed in Model insert() and update() methods.
* [CHG] Method load() now sets data keys internally.
* [ADD] Added pre- and post- methods for save, validate, insert, update, and delete.
* [BRK] Instead of returning true/false from save(), throw exceptions when validation fails.
* [CHG] Method validate() now throws exceptions on validation failure. Also, validation logic has been moved into this method from the Model class.
Modified: branches/orm/Solar/Sql/Model/Record.php
===================================================================
--- branches/orm/Solar/Sql/Model/Record.php 2007-09-19 01:45:24 UTC (rev 2759)
+++ branches/orm/Solar/Sql/Model/Record.php 2007-09-19 01:54:39 UTC (rev 2760)
@@ -175,8 +175,6 @@
// use accessor method
$method = $this->_access_methods['set'][$key];
$this->$method($val);
- } elseif ($key == $this->_model->primary_col) {
- // disallow setting of primary keys; do nothing.
} else {
// no accessor method, not a primary key; assign directly.
$this->_data[$key] = $val;
@@ -274,18 +272,6 @@
}
}
- // unseralize columns as-needed
- foreach ($this->_model->serialize_cols as $key) {
- // only unserialize if a non-empty string
- if (! empty($this->_data[$key]) && is_string($this->_data[$key])) {
- $this->_data[$key] = unserialize($this->_data[$key]);
- if (! $this->_data[$key]) {
- // unserializing failed
- $this->_data[$key] = null;
- }
- }
- }
-
// load related data as records and collections
foreach ($this->_model->related as $name => $opts) {
@@ -362,6 +348,15 @@
$this->_access_methods[$type][$var] = $method;
}
}
+
+ // put placeholders for each variable; these will be reset by
+ // the load() and/or __set() methods. need to have this here
+ // because load() uses __set(), and primary keys will be ignored
+ // in that case, leaving the data key unset. at the same time,
+ // we don't want to override values that are already present.
+ if (! isset($this->_data[$var])) {
+ $this->_data[$var] = null;
+ }
}
}
@@ -441,8 +436,21 @@
*
* - How to handle one-to-many?
* - How to handle many-to-many?
- * - Use a transaction so we can roll back on related failures?
+ * - Use a transaction so we can roll back on failures in related records?
*
+ * Hook methods:
+ *
+ * 1. `_preSave()` runs before all save operations.
+ *
+ * 2. `_preInsert()` and `_preUpdate()` run before the insert or update.
+ *
+ * 3. The record is validated, then inserted or updated.
+ *
+ * 4. `_postInsert()` and `_postUpdate()` run after the insert or update.
+ *
+ * 5. `_postSave()` runs after all save operations, but before related
+ * records are saved.
+ *
* @param array $data An associative array of data to merge with existing
* record data.
*
@@ -464,20 +472,19 @@
// only save if we're not clean
if ($this->_status != 'clean') {
+ // pre-save routine
+ $this->_preSave();
+
// insert or update based on primary key value
$primary = $this->_model->primary_col;
if (empty($this->$primary)) {
- // no primary key: insert
- $valid = $this->_model->insertRecord($this);
+ $this->_insert();
} else {
- // primary key exists: update
- $valid = $this->_model->updateRecord($this);
+ $this->_update();
}
- // if not valid, return before saving related
- if (! $valid) {
- return $valid;
- }
+ // post-save routine
+ $this->_postSave();
}
// now save each related, but only if instantiated
@@ -493,11 +500,95 @@
$this->$name->save();
}
}
+ }
+
+ protected function _insert()
+ {
+ // filter the data (sanitize and validate)
+ $this->_preValidate();
+ $this->validate();
+ $this->_postValidate();
- // done!
- return true;
+ // convert to array for the SQL command
+ $data = $this->toArray();
+
+ // attempt to insert the record, and catch SQL exceptions.
+ try {
+ // pre-logic, insert, reload, status, post-logic
+ $this->_preInsert();
+ $result = $this->_model->insert($data);
+ $this->load($result);
+ $this->setStatus('inserted');
+ $this->_postInsert();
+ } catch (Solar_Sql_Adapter_Exception_QueryFailed $e) {
+ // something went wrong at the database
+ $this->setStatus('invalid');
+ $this->setInvalid('*', $e->getInfo('pdo_text'));
+ }
}
+ protected function _update()
+ {
+ // filter the data (sanitize and validate)
+ $this->_preValidate();
+ $this->validate();
+ $this->_postValidate();
+
+ // convert to array for the SQL command
+ $data = $this->toArray();
+
+ // remove primary-key column from the data and build a WHERE clause
+ $primary = $this->_model->primary_col;
+ unset($data[$primary]);
+ $where = array("$primary = ?" => $this->$primary);
+
+ // attempt the update logic
+ try {
+ // pre-logic, insert, reload, status, post-logic
+ $this->_preUpdate();
+ $result = $this->_model->update($data, $where);
+ $this->load($result);
+ $this->setStatus('updated');
+ $this->_postUpdate();
+ } catch (Solar_Sql_Adapter_Exception_QueryFailed $e) {
+ // something went wrong at the database
+ $this->setStatus('invalid');
+ $this->setInvalid('*', $e->getInfo('pdo_text'));
+ }
+ }
+
+ protected function _preSave()
+ {
+ }
+
+ protected function _postSave()
+ {
+ }
+
+ protected function _preInsert()
+ {
+ }
+
+ protected function _postInsert()
+ {
+ }
+
+ protected function _preUpdate()
+ {
+ }
+
+ protected function _postUpdate()
+ {
+ }
+
+ protected function _preValidate()
+ {
+ }
+
+ protected function _postValidate()
+ {
+ }
+
/**
*
* Deletes this record from the database.
@@ -507,7 +598,14 @@
*/
public function delete()
{
- $this->_model->deleteRecord($this);
+ $this->_checkDeleted();
+
+ $primary = $this->_model->primary_col;
+ $where = array("$primary = ?" => $this->$primary);
+
+ $this->_preDelete();
+ $this->_model->delete($where);
+ $this->_postDelete();
}
/**
@@ -685,12 +783,40 @@
*/
public function validate()
{
- $filter = $this->_model->newFilterObject();
+ // create a filter object based on the model's filter class
+ $filter = Solar::factory($this->_model->filter_class);
+
+ // set filters as specified by the model
+ foreach ($this->_model->filters as $key => $list) {
+ $filter->addChainFilters($key, $list);
+ }
+
+ // set which elements are required by the table itself
+ foreach ($this->_model->table_cols as $key => $info) {
+ if ($info['autoinc']) {
+ // autoinc are not required
+ $flag = false;
+ } elseif (in_array($key, $this->_model->sequence_cols)) {
+ // auto-sequence are not required
+ $flag = false;
+ } else {
+ // go with the col info
+ $flag = $info['require'];
+ }
+
+ // set the requirement flag
+ $filter->setChainRequire($key, $flag);
+ }
+
+ // tell the filter to use the model for locale strings
+ $filter->setChainLocaleObject($this->_model);
+
+ // apply filters
$valid = $filter->applyChain($this);
-
if (! $valid) {
$this->_status = 'invalid';
$this->_invalid = $filter->getChainInvalid();
+ throw $this->_exception('ERR_INVALID', array($this->_invalid));
}
return $valid;
More information about the Solar-svn
mailing list