Browse Source

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
mark_story 14 years ago
parent
commit
bc8ae11fc1

+ 6 - 1
lib/Cake/Model/CakeSchema.php

@@ -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);

+ 36 - 0
lib/Cake/Test/Case/Utility/ClassRegistryTest.php

@@ -124,6 +124,22 @@ class RegisterCategory extends ClassRegisterModel {
 }
 
 /**
+ * Abstract class for testing ClassRegistry.
+ */
+abstract class ClassRegistryAbstractModel extends ClassRegisterModel {
+
+	abstract function doSomething();
+}
+
+/**
+ * Interface for testing ClassRegistry
+ */
+interface ClassRegistryInterfaceTest {
+
+	function doSomething();
+}
+
+/**
  * ClassRegistryTest class
  *
  * @package       Cake.Test.Case.Utility
@@ -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');
+	}
 }

+ 8 - 3
lib/Cake/Utility/ClassRegistry.php

@@ -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;
 					}