Merge pull request #750 from silverstripe-rebelalliance/open/5971

FIX If ClassName read from DB doesnt exist, dont break
This commit is contained in:
Sam Minnée 2012-08-29 22:48:31 -07:00
commit 57ad36e11d
4 changed files with 57 additions and 12 deletions

View File

@ -58,8 +58,10 @@ class ClassInfo {
* Returns the manifest of all classes which are present in the database.
* @param string $class Class name to check enum values for ClassName field
*/
static function getValidSubClasses($class = 'SiteTree') {
return DB::getConn()->enumValuesForField($class, 'ClassName');
static function getValidSubClasses($class = 'SiteTree', $includeUnbacked = false) {
$classes = DB::getConn()->enumValuesForField($class, 'ClassName');
if (!$includeUnbacked) $classes = array_filter($classes, array('ClassInfo', 'exists'));
return $classes;
}
/**

View File

@ -181,9 +181,12 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
*/
public static function database_fields($class) {
if(get_parent_class($class) == 'DataObject') {
$db = DB::getConn();
$existing = $db->hasField($class, 'ClassName') ? $db->query("SELECT DISTINCT \"ClassName\" FROM \"$class\"")->column() : array();
return array_merge (
array (
'ClassName' => "Enum('" . implode(', ', ClassInfo::subclassesFor($class)) . "')",
'ClassName' => "Enum('" . implode(', ', array_unique(array_merge($existing, ClassInfo::subclassesFor($class)))) . "')",
'Created' => 'SS_Datetime',
'LastEdited' => 'SS_Datetime'
),
@ -444,6 +447,17 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
}
}
function getObsoleteClassName() {
$className = $this->getField("ClassName");
if (!ClassInfo::exists($className)) return $className;
}
function getClassName() {
$className = $this->getField("ClassName");
if (!ClassInfo::exists($className)) return get_class($this);
return $className;
}
/**
* Set the ClassName attribute. {@link $class} is also updated.
* Warning: This will produce an inconsistent record, as the object
@ -986,16 +1000,33 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
$this->brokenOnWrite = true;
$isNewRecord = false;
if(self::get_validation_enabled()) {
$writeException = null;
if ($this->ObsoleteClassName) {
$writeException = new ValidationException(
"Object is of class '{$this->ObsoleteClassName}' which doesn't exist - ".
"you need to change the ClassName before you can write it",
E_USER_WARNING
);
}
else if(self::get_validation_enabled()) {
$valid = $this->validate();
if(!$valid->valid()) {
// Used by DODs to clean up after themselves, eg, Versioned
$this->extend('onAfterSkippedWrite');
throw new ValidationException($valid, "Validation error writing a $this->class object: " . $valid->message() . ". Object not written.", E_USER_WARNING);
return false;
if (!$valid->valid()) {
$writeException = new ValidationException(
$valid,
"Validation error writing a $this->class object: " . $valid->message() . ". Object not written.",
E_USER_WARNING
);
}
}
if($writeException) {
// Used by DODs to clean up after themselves, eg, Versioned
$this->extend('onAfterSkippedWrite');
throw $writeException;
return false;
}
$this->onBeforeWrite();
if($this->brokenOnWrite) {
user_error("$this->class has a broken onBeforeWrite() function. Make sure that you call parent::onBeforeWrite().", E_USER_ERROR);

View File

@ -439,6 +439,18 @@ abstract class SS_Database {
}
}
/**
* Return true if the table exists and already has a the field specified
* @param string $tableName - The table to check
* @param string $fieldName - The field to check
* @return bool - True if the table exists and the field exists on the table
*/
function hasField($tableName, $fieldName) {
if (!$this->hasTable($tableName)) return false;
$fields = $this->fieldList($tableName);
return array_key_exists($fieldName, $fields);
}
/**
* Generate the given field on the table, modifying whatever already exists as necessary.
* @param string $table The table name.

View File

@ -1103,7 +1103,7 @@ class Versioned_Version extends ViewableData {
$record['ID'] = $record['RecordID'];
$className = $record['ClassName'];
$this->object = new $className($record);
$this->object = ClassInfo::exists($className) ? new $className($record) : new DataObject($record);
$this->failover = $this->object;
parent::__construct();