Fix fatal error with abstract/interface classes

Abstract/Interface classes + ClassRegistry::init() should
raise an exception, not cause fatal errors.

Update CakeSchema to swallow and ignore any exceptions coming from
ClassRegistry.

Fixes #2328
This commit is contained in:
mark_story 2011-12-07 20:58:01 -05:00
parent 9b4d830bc3
commit bc8ae11fc1
3 changed files with 50 additions and 4 deletions

View file

@ -247,7 +247,12 @@ class CakeSchema extends Object {
continue;
}
$Object = ClassRegistry::init(array('class' => $model, 'ds' => $connection));
try {
$Object = ClassRegistry::init(array('class' => $model, 'ds' => $connection));
} catch (CakeException $e) {
continue;
}
$db = $Object->getDataSource();
if (is_object($Object) && $Object->useTable !== false) {
$fulltable = $table = $db->fullTableName($Object, false);

View file

@ -123,6 +123,22 @@ class RegisterCategory extends ClassRegisterModel {
public $name = 'RegisterCategory';
}
/**
* Abstract class for testing ClassRegistry.
*/
abstract class ClassRegistryAbstractModel extends ClassRegisterModel {
abstract function doSomething();
}
/**
* Interface for testing ClassRegistry
*/
interface ClassRegistryInterfaceTest {
function doSomething();
}
/**
* ClassRegistryTest class
*
@ -277,4 +293,24 @@ class ClassRegistryTest extends CakeTestCase {
public function testInitStrict() {
$this->assertFalse(ClassRegistry::init('NonExistent', true));
}
/**
* Test that you cannot init() an abstract class. An exception will be raised.
*
* @expectedException CakeException
* @return void
*/
public function testInitAbstractClass() {
ClassRegistry::init('ClassRegistryAbstractModel');
}
/**
* Test that you cannot init() an abstract class. A exception will be raised.
*
* @expectedException CakeException
* @return void
*/
public function testInitInterface() {
ClassRegistry::init('ClassRegistryInterfaceTest');
}
}

View file

@ -88,7 +88,8 @@ class ClassRegistry {
* stored in the registry and returned.
* @param boolean $strict if set to true it will return false if the class was not found instead
* of trying to create an AppModel
* @return object instance of ClassName
* @return object instance of ClassName.
* @throws CakeException when you try to construct an interface or abstract class.
*/
public static function init($class, $strict = false) {
$_this = ClassRegistry::getInstance();
@ -132,8 +133,12 @@ class ClassRegistry {
App::uses($plugin . 'AppModel', $pluginPath . 'Model');
App::uses($class, $pluginPath . 'Model');
if (class_exists($class)) {
$instance = new $class($settings);
if (class_exists($class) || interface_exists($class)) {
$reflection = new ReflectionClass($class);
if ($reflection->isAbstract() || $reflection->isInterface()) {
throw new CakeException(__d('cake_dev', 'Cannot create instance of %s, as it is abstract or is an interface', $class));
}
$instance = $reflection->newInstance($settings);
if ($strict) {
$instance = ($instance instanceof Model) ? $instance : null;
}