Record.php

Go to the documentation of this file.
00001 <?php 00002 00003 /* 00004 * $Id: Record.php,v 1.2 2004/05/22 13:37:20 micha Exp $ 00005 * 00006 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00007 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00008 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00009 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00010 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00011 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00012 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00013 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00014 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00015 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00016 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00017 * 00018 * This software consists of voluntary contributions made by many individuals 00019 * and is licensed under the LGPL. For more information please see 00020 * <http://creole.phpdb.org>. 00021 * 00022 * This product includes software based on the Village framework, 00023 * http://share.whichever.com/index.php?SCREEN=village. 00024 */ 00025 00026 include_once 'creole/CreoleTypes.php'; 00027 00039 class Record 00040 { 00041 // saveType constants 00042 function ZOMBIE() { return -1; } 00043 function UNKNOWN() { return 0; } 00044 function INSERT() { return 1; } 00045 function UPDATE() { return 2; } 00046 function DELETE() { return 3; } 00047 function BEFOREINSERT() { return 4; } 00048 function AFTERINSERT() { return 5; } 00049 function BEFOREUPDATE() { return 6; } 00050 function AFTERUPDATE() { return 7; } 00051 function BEFOREDELETE() { return 8; } 00052 function AFTERDELETE() { return 9; } 00053 00055 var $values = array(); 00056 00058 var $dirtyCols = array(); 00059 00061 var $ds; 00062 00064 var $saveType = 0; 00065 00076 function Record(/*DataSet*/ &$ds, $addRecord = false) 00077 { 00078 /* checks for type DataSet */ 00079 $this->setParentDataSet($ds); 00080 00081 if (! $addRecord) { 00082 $rs =& $this->ds->resultSet(); 00083 if (Creole::isError($rs)) { 00084 $this =& $rs; 00085 } 00086 else { 00087 $this->createValues($rs); 00088 } 00089 } 00090 } 00091 00096 function initializeRecord() 00097 { 00098 $this->values = array(); 00099 $this->dirtyCols = array(); 00100 $this->setSaveType(UNKNOWN); 00101 } 00102 00109 function createValues(/*ResultSet*/ &$rs) 00110 { 00111 Creole::typeHint($rs, 'ResultSet', 'DataSet', 'createValues'); 00112 $this->values =& $rs->getRow(); 00113 } 00114 00121 function save() 00122 { 00123 $returnValue = false; 00124 00125 if (is_a($this->ds, 'QueryDataSet')) { 00126 return new DataSetException(0, "You cannot save a QueryDataSet. Please use a TableDataSet instead."); 00127 } 00128 00129 if (! $this->needsToBeSaved()) { 00130 return $returnValue; 00131 } 00132 00133 switch($this->saveType) 00134 { 00135 case INSERT: 00136 $returnValue = $this->doInsert(); 00137 break; 00138 case UPDATE: 00139 $returnValue = $this->doUpdate(); 00140 break; 00141 case DELETE: 00142 $returnValue = $this->doDelete(); 00143 break; 00144 default: 00145 return new DataSetException("Invalid or no-action saveType for Record."); 00146 } 00147 00148 if (Creole::isError($returnValue)) { 00149 return $returnValue; 00150 } 00151 00152 return (boolean) $returnValue; 00153 } 00154 00161 function doDelete() 00162 { 00163 $conn =& $this->ds->connection(); 00164 $table =& $this->ds->tableInfo(); 00165 $sql =& $this->getDeleteSql(); 00166 00167 if (Creole::isError($sql)) { 00168 return $sql; 00169 } 00170 00171 $stmt =& $conn->prepareStatement($sql); 00172 $kd =& $this->ds->keydef(); 00173 $ps = 1; 00174 00175 for ($i = 1, $kdsize = $kd->size(); $i <= $kdsize; $i++) { 00176 $col =& $kd->getAttrib($i); 00177 $colInfo =& $table->getColumn($col); 00178 $val =& $this->getValue($col); 00179 00180 if (Creole::isError($val)) { return $val; } 00181 else if (Creole::isError($colInfo)) { return $colIinfo; } 00182 00183 $setter = 'set' . CreoleTypes::getAffix($colInfo->getType()); 00184 $stmt->$setter($ps++, $val); 00185 } 00186 00187 $ret = $stmt->executeUpdate(); 00188 00189 if (Creole::isError($ret)) { 00190 $stmt->close(); 00191 return $ret; 00192 } 00193 00194 // note that the actual removal of the Record objects 00195 // from the DataSet is done by the TDS::save() method. 00196 $this->setSaveType(ZOMBIE); 00197 00198 $stmt->close(); 00199 00200 if ($ret > 1) { 00201 return new SQLException(0, "There were " . $ret . " rows deleted with this records key value."); 00202 } 00203 00204 return $ret; 00205 } 00206 00214 function doUpdate() 00215 { 00216 $conn =& $this->ds->connection(); 00217 $table =& $this->ds->tableInfo(); 00218 $sql =& $this->getUpdateSql(); 00219 00220 if (Creole::isError($sql)) { 00221 return $sql; 00222 } 00223 00224 $stmt =& $conn->prepareStatement($sql); 00225 $ps = 1; 00226 00227 foreach($this->dirtyColumns() as $col) { 00228 $colInfo =& $table->getColumn($col); 00229 $value =& $this->getValue($col); 00230 00231 if (Creole::isError($value)) { return $value; } 00232 else if (Creole::isError($colInfo)) { return $colInfo; } 00233 00234 $setter = 'set' . CreoleTypes::getAffix($colInfo->getType()); 00235 $stmt->$setter($ps++, $value); 00236 } 00237 00238 $kd =& $this->ds->keydef(); 00239 00240 for ($i = 1, $kdsize = $kd->size(); $i <= $kdsize; $i++) { 00241 $attrib = $kd->getAttrib($i); 00242 $colInfo =& $table->getColumn($attrib); 00243 $value =& $this->getValue($attrib); 00244 00245 if (Creole::isError($value)) { return $value; } 00246 else if (Creole::isError($colInfo)) { return $colInfo; } 00247 00248 $setter = 'set' . CreoleTypes::getAffix($colInfo->getType()); 00249 $stmt->$setter($ps++, $value); 00250 } 00251 00252 $ret = $stmt->executeUpdate(); 00253 00254 if (Creole::isError($ret)) { 00255 $stmt->close(); 00256 return $ret; 00257 } 00258 00259 if ($this->ds->refreshOnSave()) { 00260 if (($e = $this->refresh()) !== true) { 00261 $stmt->close(); 00262 return $e; 00263 } 00264 } else { 00265 // Marks all of the values clean since they have now been saved 00266 $this->markRecordClean(); 00267 } 00268 00269 $this->setSaveType(AFTERUPDATE); 00270 00271 if ($ret > 1) { 00272 return new SQLException (0, "There were " . $ret . " rows updated with this records key value."); 00273 } 00274 00275 return $ret; 00276 } 00277 00284 function doInsert() 00285 { 00286 /* getInsertSql does not throw anything */ 00287 $stmt =& $conn->prepareStatement($this->getInsertSql()); 00288 $ps = 1; 00289 00290 foreach($this->dirtyColumns() as $col) { 00291 $colInfo =& $table->getColumn($col); 00292 $value =& $this->getValue($col); 00293 00294 if (Creole::isError($value)) { return $value; } 00295 else if (Creole::isError($colInfo)) { return $colInfo; } 00296 00297 $setter = 'set' . CreoleTypes::getAffix($colInfo->getType()); 00298 $stmt->$setter($ps++, $value); 00299 } 00300 00301 $ret = $stmt->executeUpdate(); 00302 00303 if (Creole::isError($ret)) { 00304 $stmt->close(); 00305 return $ret; 00306 } 00307 00308 if ($this->ds->refreshOnSave()) { 00309 $e = $this->refresh(); 00310 if (Creole::isError($e)) { 00311 $stmt->close(); 00312 return $e; 00313 } 00314 } else { 00315 // Marks all of the values clean since they have now been saved 00316 $this->markRecordClean(); 00317 } 00318 00319 $this->setSaveType(AFTERINSERT); 00320 00321 if ($ret > 1) { 00322 $stmt->close(); 00323 // a little late again... 00324 return new SQLException (0, "There were " . $ret . " rows inserted with this records key value."); 00325 } 00326 00327 return $ret; 00328 } 00329 00336 function getUpdateSql() 00337 { 00338 $kd =& $this->ds->keydef(); 00339 00340 if ($kd === null || $kd->size() === 0) { 00341 return new DataSetException(0, "You must specify KeyDef attributes for this TableDataSet in order to create a Record for update."); 00342 } 00343 elseif ($this->recordIsClean()) { 00344 return new DataSetException (0, "You must Record->setValue() on a column before doing an update."); 00345 } 00346 00347 $set_sql = ""; 00348 $where_sql = ""; 00349 00350 $comma = false; 00351 00352 foreach($this->dirtyColumns() as $col) { 00353 if (!$comma) { 00354 $set_sql .= $col . " = ?"; 00355 $comma = true; 00356 } else { 00357 $set_sql .= ", " . $col . " = ?"; 00358 } 00359 } 00360 00361 $comma = false; 00362 for ($i = 1, $kdsize = $kd->size(); $i <= $kdsize; $i++) { 00363 $attrib = $kd->getAttrib($i); 00364 if (! $this->valueIsClean ($attrib)) { 00365 return new DataSetException (0, "The value for column '" . $attrib . "' is a key value and cannot be updated."); 00366 } 00367 if (!$comma) { 00368 $where_sql .= $attrib . " = ?"; 00369 $comma = true; 00370 } else { 00371 $where_sql .= " AND " . $attrib . " = ?"; 00372 } 00373 } 00374 00375 return "UPDATE " . $this->ds->tableName() . " SET " . $set_sql . " WHERE " . $where_sql; 00376 } 00377 00378 00385 function getDeleteSql() 00386 { 00387 $kd =& $this->ds->keydef(); 00388 00389 if ($kd === null || $kd->size() === 0) { 00390 return new DataSetException(0, "You must specify KeyDef attributes for this TableDataSet in order to delete a Record."); 00391 } 00392 00393 $where_sql = ""; 00394 $comma = false; 00395 for ($i = 1, $kdsize = $kd->size(); $i <= $kdsize; $i++) { 00396 if (!$comma) { 00397 $where_sql .= $kd->getAttrib($i) . " = ?"; 00398 $comma = true; 00399 } else { 00400 $where_sql .= " AND " . $kd->getAttrib($i) . " = ?"; 00401 } 00402 } 00403 00404 return "DELETE FROM " . $this->ds->tableName() . " WHERE " . $where_sql; 00405 } 00406 00413 function getInsertSql() 00414 { 00415 $fields_sql = ""; 00416 $values_sql = ""; 00417 $comma = false; 00418 00419 foreach($this->dirtyColumns() as $col) { 00420 if (!$comma) { 00421 $fields_sql .= $col; 00422 $values_sql .= "?"; 00423 $comma = true; 00424 } else { 00425 $fields_sql .= ", " . $col; 00426 $values_sql .= ", ?"; 00427 } 00428 } 00429 00430 return "INSERT INTO " . $this->ds->tableName() . " ( " . $fields_sql . " ) VALUES ( " . $values_sql . " )"; 00431 } 00432 00439 function & getValue($col) 00440 { 00441 if (!isset($this->values[$col])) { 00442 return new DataSetException(0, "Undefined column in Record: " . $col); 00443 } 00444 return $this->values[$col]; 00445 } 00446 00451 function columns() 00452 { 00453 return array_keys($this->values); 00454 } 00455 00464 function dirtyColumns() 00465 { 00466 return array_keys($this->dirtyCols); 00467 } 00468 00473 function size() 00474 { 00475 return count($this->values); 00476 } 00477 00482 function toBeSavedWithInsert() 00483 { 00484 return ($this->saveType === INSERT); 00485 } 00486 00491 function toBeSavedWithUpdate() 00492 { 00493 return ($this->saveType === UPDATE); 00494 } 00495 00500 function toBeSavedWithDelete() 00501 { 00502 return ($this->saveType === DELETE); 00503 } 00504 00509 function markRecordClean() 00510 { 00511 $this->dirtyCols = array(); 00512 } 00513 00518 function markForInsert() 00519 { 00520 if (is_a($this->ds, 'QueryDataSet')) { 00521 return new DataSetException (0, "You cannot mark a record in a QueryDataSet for insert"); 00522 } 00523 $this->setSaveType(INSERT); 00524 return true; 00525 } 00526 00532 function markForUpdate() 00533 { 00534 if (is_a($this->ds, 'QueryDataSet')) { 00535 return new DataSetException (0, "You cannot mark a record in a QueryDataSet for update"); 00536 } 00537 $this->setSaveType(UPDATE); 00538 return true; 00539 } 00540 00545 function markToBeDeleted() 00546 { 00547 if (is_a($this->ds, 'QueryDataSet')) { 00548 return new DataSetException (0, "You cannot mark a record in a QueryDataSet for deletion"); 00549 } 00550 $this->setSaveType(DELETE); 00551 return true; 00552 } 00553 00564 function unmarkToBeDeleted() 00565 { 00566 if ($this->saveType === ZOMBIE) { 00567 return new DataSetException (0, "This record has already been deleted!"); 00568 } 00569 $this->setSaveType(UNKNOWN); 00570 return true; 00571 } 00572 00578 function markValueClean($col) 00579 { 00580 unset($this->dirtyCols[$col]); 00581 } 00582 00588 function markValueDirty($col) 00589 { 00590 $this->dirtyCols[$col] = true; 00591 } 00592 00598 function setSaveType($type) 00599 { 00600 $this->saveType = $type; 00601 } 00602 00607 function getSaveType() 00608 { 00609 return $this->saveType; 00610 } 00611 00616 function & setValue ($col, &$value) 00617 { 00618 $this->values[$col] =& $value; 00619 $this->markValueDirty($col); 00620 return $this; 00621 } 00622 00629 function isAZombie() 00630 { 00631 return ($this->saveType === ZOMBIE); 00632 } 00633 00638 function needsToBeSaved() 00639 { 00640 return (!$this->isAZombie() || !$this->recordIsClean() || $this->toBeSavedWithUpdate() || 00641 $this->toBeSavedWithDelete() || $this->toBeSavedWithInsert()); 00642 } 00643 00648 function valueIsClean($column) 00649 { 00650 if (!isset($this->values[$column])) { 00651 return new DataSetException(0, "Undefined column: ".$column); 00652 } 00653 return !isset($this->dirtyCols[$column]); 00654 } 00655 00660 function recordIsClean() 00661 { 00662 return empty($this->dirtyCols); 00663 } 00664 00672 function refresh() 00673 { 00674 $conn =& $this->ds->connection(); 00675 00676 if ($this->toBeSavedWithDelete()) { 00677 return; 00678 } elseif ($this->toBeSavedWithInsert()) { 00679 return new DataSetException(0, "There is no way to refresh a record which has been created with addRecord()."); 00680 } elseif (is_a($this->ds, 'QueryDataSet')) { 00681 return new DataSetException(0, "You can only perform a refresh on Records created with a TableDataSet."); 00682 } 00683 00684 $sql =& $this->getRefreshSql(); 00685 if (Creole::isError($sql)) { 00686 return $sql; 00687 } 00688 00689 $stmt &= $conn->prepareStatement (); 00690 $kd =& $this->ds->keydef(); 00691 $ps = 1; 00692 00693 for ($i = 1, $kdsize = $kd->size(); $i <= $kdsize; $i++) 00694 { 00695 $colInfo =& $table->getColumn($col); 00696 $val =& $this->getValue($kd->getAttrib($i)); 00697 00698 if (Creole::isError($val)) { return $val; } 00699 else if (Creole::isError($colInfo)) { return $colInfo; } 00700 00701 if ($val == null) { 00702 return new DataSetException(0, "You cannot execute an update with a null value for a KeyDef."); 00703 } 00704 00705 $setter = 'set' . CreoleTypes::getAffix($colInfo->getType()); 00706 $stmt->$setter($ps++, $val); 00707 } 00708 00709 $rs = $stmt->executeQuery(); 00710 00711 if (Creole::isError($rs)) { 00712 $stmt->close(); 00713 return $rs; 00714 } 00715 00716 if (($e = $rs->next()) !== true) { 00717 $stmt->close(); 00718 $rs->close(); 00719 return $e; 00720 } 00721 00722 $this->initializeRecord(); 00723 $this->createValues($rs); 00724 return true; 00725 } 00726 00734 function & getRefreshSql() 00735 { 00736 $kd =& $this->ds->keydef(); 00737 00738 if ($kd === null || $kd->size() === 0) { 00739 return new DataSetException(0, "You can only perform a getRefreshQueryString on a TableDataSet that was created with a KeyDef."); 00740 } elseif (is_a($this->ds, 'QueryDataSet')) { 00741 return new DataSetException(0, "You can only perform a getRefreshQueryString on Records created with a TableDataSet."); 00742 } 00743 00744 $sql1 = ""; 00745 $sql2 = ""; 00746 $comma = false; 00747 00748 foreach($this->columns() as $col) { 00749 if (!$comma) { 00750 $attribs_sql .= $col; 00751 $comma = true; 00752 } else { 00753 $attribs_sql .= ", " . $col; 00754 } 00755 } 00756 00757 $comma = false; 00758 00759 for ($i = 1, $kdsize = $kd->size(); $i <= $kdsize; $i++) { 00760 $attrib = $kd->getAttrib($i); 00761 00762 if (!$this->valueIsClean($attrib)) { 00763 return new DataSetException (0, 00764 "You cannot do a refresh from the database if the value " . 00765 "for a KeyDef column has been changed with a Record.setValue()."); 00766 } 00767 00768 if (!$comma) { 00769 $where_sql .= $attrib . " = ?"; 00770 $comma = true; 00771 } else { 00772 $where_sql .= " AND " . $attrib . " = ?"; 00773 } 00774 } 00775 00776 return "SELECT " . $attribs_sql . " FROM " . $this->ds->tableName() . " WHERE " . $where_sql; 00777 } 00778 00784 function & dataset() 00785 { 00786 return $this->ds; 00787 } 00788 00793 function setParentDataSet(/*DataSet*/ &$ds) 00794 { 00795 Creole::typeHint($ds, 'DataSet', 'Record', 'setParentDataSet'); 00796 $this->ds =& $ds; 00797 } 00798 00803 function __toString() 00804 { 00805 $sb = "{"; 00806 foreach($this->columns() as $col) { 00807 $sb .= "'" . $this->getValue($col) . "',"; 00808 } 00809 $sb = substr($sb, 0, -1); 00810 $sb .= "}"; 00811 return $sb; 00812 } 00813 00814 }

This file is part of the Creole[php4] library.


Copyright © 2004 Hans Lellelid  
Creole[php4] CVS