public static function getRevisionRecords($options = array()) { $options = static::prepareOptions($options, array('indexField' => false, 'conditions' => array(), 'order' => false, 'limit' => false, 'offset' => 0)); $query = 'SELECT * FROM `%s` WHERE (%s)'; $params = array(static::getHistoryTable(), count($options['conditions']) ? join(') AND (', static::_mapConditions($options['conditions'])) : 1); if ($options['order']) { $query .= ' ORDER BY ' . join(',', static::_mapFieldOrder($options['order'])); } if ($options['limit']) { $query .= sprintf(' LIMIT %u,%u', $options['offset'], $options['limit']); } if ($options['indexField']) { return DB::table(static::_cn($options['indexField']), $query, $params); } else { return DB::allRecords($query, $params); } }
public function save($deep = true, $createRevision = true) { $wasDirty = false; if ($this->isDirty && $createRevision) { // update creation time / user $this->Created = time(); $this->CreatorID = $_SESSION['User'] ? $_SESSION['User']->ID : null; $wasDirty = true; } // save record as usual $return = parent::save($deep); if ($wasDirty && $createRevision) { // save a copy to history table $recordValues = $this->_prepareRecordValues(); $set = static::_mapValuesToSet($recordValues); DB::nonQuery('INSERT INTO `%s` SET %s', array(static::$historyTable, join(',', $set))); } }
public static function getCreateTable($recordClass, $historyVariant = false) { $queryFields = array(); $indexes = $historyVariant ? array() : $recordClass::$indexes; $fulltextColumns = array(); // history table revisionID field if ($historyVariant) { $queryFields[] = '`RevisionID` int(10) unsigned NOT NULL auto_increment'; $queryFields[] = 'PRIMARY KEY (`RevisionID`)'; } // compile fields $rootClass = !empty($recordClass::$rootClass) ? $recordClass::$rootClass : $recordClass; foreach ($recordClass::getClassFields() as $fieldId => $field) { //Debug::dump($field, "Field: $field[columnName]"); if ($field['columnName'] == 'RevisionID') { continue; } // force notnull=false on non-rootclass fields if ($rootClass && !$rootClass::_fieldExists($fieldId)) { $field['notnull'] = false; } // auto-prepend class type if ($field['columnName'] == 'Class' && $field['type'] == 'enum' && !in_array($rootClass, $field['values']) && empty($rootClass::$subClasses)) { array_unshift($field['values'], $rootClass); } // escape namespaces in field names if ($field['columnName'] == 'Class') { foreach ($field['values'] as $index => $value) { $field['values'][$index] = str_replace('\\', '\\\\', $value); } } $fieldDef = '`' . $field['columnName'] . '`'; $fieldDef .= ' ' . static::getSQLType($field); $fieldDef .= ' ' . ($field['notnull'] ? 'NOT NULL' : 'NULL'); if ($field['autoincrement'] && !$historyVariant) { $fieldDef .= ' auto_increment'; } elseif ($field['type'] == 'timestamp' && $field['default'] == 'CURRENT_TIMESTAMP') { $fieldDef .= ' default CURRENT_TIMESTAMP'; } elseif (empty($field['notnull']) && $field['default'] == null) { $fieldDef .= ' default NULL'; } elseif (isset($field['default'])) { if ($field['type'] == 'boolean') { $fieldDef .= ' default ' . ($field['default'] ? 1 : 0); } else { $fieldDef .= ' default "' . DB::escape($field['default']) . '"'; } } $queryFields[] = $fieldDef; if ($field['primary']) { if ($historyVariant) { $queryFields[] = 'KEY `' . $field['columnName'] . '` (`' . $field['columnName'] . '`)'; } else { $queryFields[] = 'PRIMARY KEY (`' . $field['columnName'] . '`)'; } } if ($field['unique'] && !$historyVariant) { $queryFields[] = 'UNIQUE KEY `' . $field['columnName'] . '` (`' . $field['columnName'] . '`)'; } if ($field['index'] && !$historyVariant) { $queryFields[] = 'KEY `' . $field['columnName'] . '` (`' . $field['columnName'] . '`)'; } if ($field['fulltext'] && !$historyVariant) { $fulltextColumns[] = $field['columnName']; } } // context index if (!$historyVariant && $recordClass::_fieldExists('ContextClass') && $recordClass::_fieldExists('ContextID')) { $queryFields[] = 'KEY `CONTEXT` (`' . $recordClass::getColumnName('ContextClass') . '`,`' . $recordClass::getColumnName('ContextID') . '`)'; } // compile indexes foreach ($indexes as $indexName => $index) { if (is_array($index['fields'])) { $indexFields = $index['fields']; } elseif ($index['fields']) { $indexFields = array($index['fields']); } else { continue; } // translate field names foreach ($index['fields'] as &$indexField) { $indexField = $recordClass::getColumnName($indexField); } if (!empty($index['fulltext'])) { $fulltextColumns = array_unique(array_merge($fulltextColumns, $index['fields'])); continue; } $queryFields[] = sprintf('%s KEY `%s` (`%s`)', !empty($index['unique']) ? 'UNIQUE' : '', $indexName, join('`,`', $index['fields'])); } if (!empty($fulltextColumns)) { $queryFields[] = 'FULLTEXT KEY `FULLTEXT` (`' . join('`,`', $fulltextColumns) . '`)'; } $createSQL = sprintf("--\n-- %s for class %s\n--\n" . "CREATE TABLE IF NOT EXISTS `%s` (\n\t%s\n) ENGINE=MyISAM DEFAULT CHARSET=%s;", $historyVariant ? 'History table' : 'Table', $recordClass, $historyVariant ? $recordClass::$historyTable : $recordClass::$tableName, join("\n\t,", $queryFields), DB::$charset); return $createSQL; }
public static function handleError($query = null, $queryLog = null, $parameters = null) { $Connection = DB::getConnection(); if ($Connection->errorCode() == '42S02' && static::$autoCreateTables) { $CreateTable = SQL::getCreateTable(static::$rootClass); // history versions table if (static::isVersioned()) { $CreateTable .= SQL::getCreateTable(static::$rootClass, true); } $Statement = $Connection->query($CreateTable); // check for errors $ErrorInfo = $Statement->errorInfo(); // handle query error if ($ErrorInfo[0] != '00000') { self::handleError($query, $queryLog, $errorHandler); } // clear buffer (required for the next query to work without running fetchAll first $Statement->closeCursor(); return $Connection->query($query); // now the query should finish with no error } else { return DB::handleError($query, $queryLog, $parameters); } }