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. * Returns the manifest of all classes which are present in the database.
* @param string $class Class name to check enum values for ClassName field * @param string $class Class name to check enum values for ClassName field
*/ */
static function getValidSubClasses($class = 'SiteTree') { static function getValidSubClasses($class = 'SiteTree', $includeUnbacked = false) {
return DB::getConn()->enumValuesForField($class, 'ClassName'); $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) { public static function database_fields($class) {
if(get_parent_class($class) == 'DataObject') { 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 ( return array_merge (
array ( array (
'ClassName' => "Enum('" . implode(', ', ClassInfo::subclassesFor($class)) . "')", 'ClassName' => "Enum('" . implode(', ', array_unique(array_merge($existing, ClassInfo::subclassesFor($class)))) . "')",
'Created' => 'SS_Datetime', 'Created' => 'SS_Datetime',
'LastEdited' => 'SS_Datetime' 'LastEdited' => 'SS_Datetime'
), ),
@ -443,6 +446,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. * Set the ClassName attribute. {@link $class} is also updated.
@ -985,17 +999,34 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
$firstWrite = false; $firstWrite = false;
$this->brokenOnWrite = true; $this->brokenOnWrite = true;
$isNewRecord = false; $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(); $valid = $this->validate();
if(!$valid->valid()) { if (!$valid->valid()) {
// Used by DODs to clean up after themselves, eg, Versioned $writeException = new ValidationException(
$this->extend('onAfterSkippedWrite'); $valid,
throw new ValidationException($valid, "Validation error writing a $this->class object: " . $valid->message() . ". Object not written.", E_USER_WARNING); "Validation error writing a $this->class object: " . $valid->message() . ". Object not written.",
return false; E_USER_WARNING
);
} }
} }
if($writeException) {
// Used by DODs to clean up after themselves, eg, Versioned
$this->extend('onAfterSkippedWrite');
throw $writeException;
return false;
}
$this->onBeforeWrite(); $this->onBeforeWrite();
if($this->brokenOnWrite) { if($this->brokenOnWrite) {
user_error("$this->class has a broken onBeforeWrite() function. Make sure that you call parent::onBeforeWrite().", E_USER_ERROR); user_error("$this->class has a broken onBeforeWrite() function. Make sure that you call parent::onBeforeWrite().", E_USER_ERROR);

View File

@ -143,7 +143,7 @@ abstract class SS_Database {
* Returns true if the given table exists in the database * Returns true if the given table exists in the database
*/ */
abstract function hasTable($tableName); abstract function hasTable($tableName);
/** /**
* Returns the enum values available on the given field * Returns the enum values available on the given field
*/ */
@ -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. * Generate the given field on the table, modifying whatever already exists as necessary.
* @param string $table The table name. * @param string $table The table name.

View File

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