pk = array(); $this->fields = array(); $this->sTable = $sTable; } function addPKInt($sField, $nDefault, $bNullable, $nInsertFunction=RE_INSERT_NOTHING) { $this->pk[$sField] = array('type' => RE_TYPE_INT, 'default' => $nDefault, 'nullable' => $bNullable, 'value' => $nDefault, 'insertfunction' => $nInsertFunction); if (($nInsertFunction & RE_INSERT_AUTOINCREMENT) == RE_INSERT_AUTOINCREMENT) $this->sAutoIncrementField = $sField; } function addPKFloat($sField, $nDefault, $bNullable, $nInsertFunction=RE_INSERT_NOTHING) { $this->pk[$sField] = array('type' => RE_TYPE_FLOAT, 'default' => $nDefault, 'nullable' => $bNullable, 'value' => $nDefault, 'insertfunction' => $nInsertFunction); } function addPKDouble($sField, $nDefault, $bNullable, $nInsertFunction=RE_INSERT_NOTHING) { $this->pk[$sField] = array('type' => RE_TYPE_DOUBLE, 'default' => $nDefault, 'nullable' => $bNullable, 'value' => $nDefault, 'insertfunction' => $nInsertFunction); } function addPKString($sField, $sDefault, $bNullable, $nInsertFunction=RE_INSERT_NOTHING) { if (($nInsertFunction & RE_INSERT_AUTOUUID) == RE_INSERT_AUTOUUID) die('rowEditor: RE_INSERT_AUTOUUID not supported for primary key fields'); $this->pk[$sField] = array('type' => RE_TYPE_STRING, 'default' => $sDefault, 'nullable' => $bNullable, 'value' => $sDefault, 'insertfunction' => $nInsertFunction); } function addPKBoolean($sField, $bDefault, $bNullable, $nInsertFunction=RE_INSERT_NOTHING) { $this->pk[$sField] = array('type' => RE_TYPE_BOOLEAN, 'default' => $bDefault, 'nullable' => $bNullable, 'value' => $bDefault, 'insertfunction' => $nInsertFunction); } function addPKDate($sField, $dDefault, $bNullable, $nInsertFunction=RE_INSERT_NOTHING) { $this->pk[$sField] = array('type' => RE_TYPE_DATE, 'default' => $dDefault, 'nullable' => $bNullable, 'value' => $dDefault, 'insertfunction' => $nInsertFunction); } function addInt($sField, $nDefault, $bNullable, $nInsertFunction=RE_INSERT_NOTHING) { $this->fields[$sField] = array('type' => RE_TYPE_INT, 'default' => $nDefault, 'nullable' => $bNullable, 'value' => $nDefault, 'changed => false', 'insertfunction' => $nInsertFunction); } function addFloat($sField, $nDefault, $bNullable, $nInsertFunction=RE_INSERT_NOTHING) { $this->fields[$sField] = array('type' => RE_TYPE_FLOAT, 'default' => $nDefault, 'nullable' => $bNullable, 'value' => $nDefault, 'changed => false', 'insertfunction' => $nInsertFunction); } function addDouble($sField, $nDefault, $bNullable, $nInsertFunction=RE_INSERT_NOTHING) { $this->fields[$sField] = array('type' => RE_TYPE_DOUBLE, 'default' => $nDefault, 'nullable' => $bNullable, 'value' => $nDefault, 'changed => false', 'insertfunction' => $nInsertFunction); } function addString($sField, $sDefault, $bNullable, $nInsertFunction=RE_INSERT_NOTHING) { $this->fields[$sField] = array('type' => RE_TYPE_STRING, 'default' => $sDefault, 'nullable' => $bNullable, 'value' => $sDefault, 'changed => false', 'insertfunction' => $nInsertFunction); } function addBoolean($sField, $bDefault, $bNullable, $nInsertFunction=RE_INSERT_NOTHING) { $this->fields[$sField] = array('type' => RE_TYPE_BOOLEAN, 'default' => $bDefault, 'nullable' => $bNullable, 'value' => $bDefault, 'changed => false', 'insertfunction' => $nInsertFunction); } function addDate($sField, $dDefault, $bNullable, $nInsertFunction=RE_INSERT_NOTHING) { $this->fields[$sField] = array('type' => RE_TYPE_DATE, 'default' => $dDefault, 'nullable' => $bNullable, 'value' => $dDefault, 'changed => false', 'insertfunction' => $nInsertFunction); } function removePK($sField) { unset($this->pk[$sField]); } function removeField($sField) { unset($this->fields[$sField]); } /* PKValues may be an string, indized or ordered array */ function load($PKValues) { $this->pSetPK($PKValues); $this->bLoaded = true; $this->bAddNew = false; $this->bExist = false; $rs = sql($this->pBuildSelect()); if (!$r = sql_fetch_assoc($rs)) { $this->bExist = false; return false; } // assign values foreach ($this->fields AS $k => $field) { $this->fields[$k]['value'] = $this->pFormatValue($this->fields[$k]['type'], $r[$k]); $this->fields[$k]['changed'] = false; } $this->bExist = true; return true; } function addNew($PKValues) { $this->pSetPK($PKValues); $this->bLoaded = true; $this->bExist = false; $this->bAddNew = true; } function exist() { return $this->bExist; } function pSetPK($PKValues) { $this->pResetValues(); foreach ($this->pk AS $k => $field) { $this->pk[$k]['value'] = $field['default']; } if (is_array($PKValues)) { foreach ($PKValues AS $k => $v) { $pkKey = $this->pGetPKKey($k); $this->pk[$pkKey]['value'] = $this->pFormatValue($this->pk[$pkKey]['type'], $v); } } else { $pkKey = $this->pGetPKKey(0); $this->pk[$pkKey]['value'] = $this->pFormatValue($this->pk[$pkKey]['type'], $PKValues); } } function pGetPKKey($index) { if (isset($this->pk[$index])) return $index; $i = 0; foreach ($this->pk AS $k => $v) { if ($i == $index) return $k; $i++; } } function pResetValues() { foreach ($this->fields AS $k => $field) { $this->fields[$k]['value'] = $field['default']; $this->fields[$k]['changed'] = false; } } function pFormatValue($type, $value) { if ($value === null) return null; if ($type == RE_TYPE_INT) $value = (int)$value+0; else if ($type == RE_TYPE_FLOAT) $value = $value+0; else if ($type == RE_TYPE_DOUBLE) $value = $value+0; else if ($type == RE_TYPE_BOOLEAN) $value = (($value+0) != 0); else if ($type == RE_TYPE_DATE) { if (!is_numeric($value)) $value = strtotime($value); } return $value; } function pFormatValueSql($type, $value) { if ($type == RE_TYPE_INT) $value = (int)$value+0; else if ($type == RE_TYPE_FLOAT) $value = $value+0; else if ($type == RE_TYPE_DOUBLE) $value = $value+0; else if ($type == RE_TYPE_BOOLEAN) $value = (($value+0) != 0) ? 1 : 0; else if ($type == RE_TYPE_DATE) { if (!is_numeric($value)) $value = strtotime($value); $value = strftime(DB_DATE_FORMAT, $value); } return $value; } function pBuildSelect() { $fselect = array(); $sql = 'SELECT '; foreach ($this->fields AS $k => $field) { $fselect[] = '`' . sql_escape($k) . '`'; } $sql .= join(', ', $fselect); $sql .= ' FROM `' . sql_escape($this->sTable) . '`'; $sql .= ' WHERE ' . $this->pBuildPK(); return $sql; } function pBuildPK() { $fwhere = array(); foreach ($this->pk AS $k => $field) { if ($field['value'] === null) $fwhere[] = 'ISNULL(`' . sql_escape($k) . '`)'; else $fwhere[] = '`' . sql_escape($k) . '`=\'' . sql_escape($field['value']) . '\''; } return join(' AND ', $fwhere); } function getValue($sField) { if (isset($this->pk[$sField])) return $this->pk[$sField]['value']; return $this->fields[$sField]['value']; } function getDefault($sField) { return $this->fields[$sField]['default']; } function getChanged($sField) { return $this->fields[$sField]['changed']; } function getAnyChanged() { foreach ($this->fields AS $field) if ($field['changed'] == true) return true; } function setValue($sField, $sValue) { if ($this->bLoaded == false || ($this->bAddNew == false && $this->bExist == false)) return false; $sFormatedValue = $this->pFormatValue($this->fields[$sField]['type'], $sValue); if ($this->fields[$sField]['type'] == RE_TYPE_FLOAT) // Direct float comparison is deprecated and can result in last-digit errors. // Floats in OC database are only used for reasonably large numbers like coordinates, // waylengths and time estimates, so using a fixed epsilon threshold is safe: $changed = (abs($sFormatedValue - $this->fields[$sField]['value']) >= 1e-12); else $changed = ($sFormatedValue != $this->fields[$sField]['value']); if ($changed) { $this->fields[$sField]['value'] = $sFormatedValue; $this->fields[$sField]['changed'] = true; } return true; } function save() { if ($this->bLoaded == false || ($this->bAddNew == false && $this->bExist == false)) return false; if ($this->bAddNew == true) { // INSERT $sql = $this->pBuildInsert(); if ($sql != '') { sql($sql); if (sql_affected_rows() == 0) return false; } else return true; if ($this->sAutoIncrementField != null) { $nInsertId = sql_insert_id(); $this->pk[$this->sAutoIncrementField]['value'] = $nInsertId; if (isset($this->fields[$this->sAutoIncrementField])) $this->fields[$this->sAutoIncrementField]['value'] = $nInsertId; } /* reload the record to get the actual stored values * (inserted values maybe truncated by mysql or trigger could modify values) */ $pkv = array(); foreach ($this->pk AS $k => $v) { $pkv[$k] = $this->pk[$k]['value']; } $this->load($pkv); return true; } else { // UPDATE $sql = $this->pBuildUpdate(); if ($sql != '') { $rs = sql($sql); if (sql_affected_rows($rs) == 0) return false; } else return true; foreach ($this->fields AS $k => $field) { $this->fields[$k]['changed'] = false; } return true; } } function reload() { $pkv = array(); foreach ($this->pk AS $k => $v) { $pkv[$k] = $this->pk[$k]['value']; } $this->load($pkv); } function pBuildInsert() { $sql = 'INSERT IGNORE INTO `' . sql_escape($this->sTable) . '` ('; $sFields = array(); $sValues = array(); foreach ($this->pk AS $k => $field) { if (isset($this->fields[$k])) continue; if ($this->sAutoIncrementField == $k) continue; if (($field['insertfunction'] & RE_INSERT_IGNORE) == RE_INSERT_IGNORE) continue; $sFields[] = '`' . sql_escape($k) . '`'; if ((($field['insertfunction'] & RE_INSERT_OVERWRITE) == RE_INSERT_OVERWRITE) || (($field['changed'] == false) && ($field['insertfunction'] != RE_INSERT_NOTHING))) { if (($field['insertfunction'] & RE_INSERT_NOW) == RE_INSERT_NOW) $sValues[] = 'NOW()'; else $sValues[] = 'NULL'; } else { if ($field['value'] === null) $sValues[] = 'NULL'; else $sValues[] = '\'' . sql_escape($this->pFormatValueSql($field['type'], $field['value'])) . '\''; } } foreach ($this->fields AS $k => $field) { if (($field['insertfunction'] & RE_INSERT_IGNORE) == RE_INSERT_IGNORE) continue; $sFields[] = '`' . sql_escape($k) . '`'; if ((($field['insertfunction'] & RE_INSERT_OVERWRITE) == RE_INSERT_OVERWRITE) || (($field['changed'] == false) && ($field['insertfunction'] != RE_INSERT_NOTHING))) { if (($field['insertfunction'] & RE_INSERT_NOW) == RE_INSERT_NOW) $sValues[] = 'NOW()'; else $sValues[] = 'NULL'; } else { if ($field['value'] === null) $sValues[] = 'NULL'; else $sValues[] = '\'' . sql_escape($this->pFormatValueSql($field['type'], $field['value'])) . '\''; } } $sql .= join(', ', $sFields); $sql .= ') VALUES ('; $sql .= join(', ', $sValues); $sql .= ')'; return $sql; } function pBuildUpdate() { $sql = 'UPDATE IGNORE `' . sql_escape($this->sTable) . '` SET '; $sSet = ''; foreach ($this->fields AS $k => $field) { if ($field['changed'] == true) { if ($sSet != '') $sSet .= ', '; if ($field['value'] === null) $sSet .= '`' . sql_escape($k) . '`=NULL'; else $sSet .= '`' . sql_escape($k) . '`=\'' . sql_escape($this->pFormatValueSql($field['type'], $field['value'])) . '\''; } } if ($sSet == '') return ''; $sql .= $sSet; $sql .= ' WHERE '; $sql .= $this->pBuildPK(); return $sql; } function saveField($field) { if ($this->bLoaded == false || $this->bExist == false || $this->bAddNew == true) return false; if ($this->fields[$field]['changed'] == false) return true; if ($this->fields[$field]['value'] === null) $sSet = '`' . sql_escape($field) . '`=NULL'; else $sSet = '`' . sql_escape($field) . '`=\'' . sql_escape($this->pFormatValueSql($this->fields[$field]['type'], $this->fields[$field]['value'])) . '\''; $sql = 'UPDATE `' . sql_escape($this->sTable) . '` SET ' . $sSet; $sql .= ' WHERE '; $sql .= $this->pBuildPK(); sql($sql); if (sql_affected_rows() == 0) return false; $this->fields[$field]['changed'] = false; return true; } } ?>