diff --git a/core/manifest/ClassLoader.php b/core/manifest/ClassLoader.php index b79c3b55d..70b13636d 100644 --- a/core/manifest/ClassLoader.php +++ b/core/manifest/ClassLoader.php @@ -14,7 +14,7 @@ class SS_ClassLoader { private static $instance; /** - * @var SS_ClassManifest[] + * @var array Map of 'instance' (SS_ClassManifest) and other options. */ protected $manifests = array(); @@ -32,7 +32,7 @@ class SS_ClassLoader { * @return SS_ClassManifest */ public function getManifest() { - return $this->manifests[count($this->manifests) - 1]; + return $this->manifests[count($this->manifests) - 1]['instance']; } /** @@ -47,16 +47,23 @@ class SS_ClassLoader { * also include any module configuration files at the same time. * * @param SS_ClassManifest $manifest + * @param Boolean Marks the manifest as exclusive. If set to FALSE, will + * look for classes in earlier manifests as well. */ - public function pushManifest(SS_ClassManifest $manifest) { - $this->manifests[] = $manifest; + public function pushManifest(SS_ClassManifest $manifest, $exclusive = true) { + $this->manifests[] = array('exclusive' => $exclusive, 'instance' => $manifest); + + foreach ($manifest->getConfigs() as $config) { + require_once $config; + } } /** * @return SS_ClassManifest */ public function popManifest() { - return array_pop($this->manifests); + $manifest = array_pop($this->manifests); + return $manifest['instance']; } public function registerAutoloader() { @@ -68,11 +75,28 @@ class SS_ClassLoader { * manifest. * * @param string $class + * @return String */ public function loadClass($class) { - if ($path = $this->getManifest()->getItemPath($class)) { + if ($path = $this->getItemPath($class)) { require_once $path; } + return $path; + } + + /** + * Returns the path for a class or interface in the currently active manifest, + * or any previous ones if later manifests aren't set to "exclusive". + * + * @return String + */ + public function getItemPath($class) { + foreach(array_reverse($this->manifests) as $manifest) { + $manifestInst = $manifest['instance']; + if ($path = $manifestInst->getItemPath($class)) return $path; + if($manifest['exclusive']) break; + } + return false; } /** @@ -82,7 +106,7 @@ class SS_ClassLoader { * @return bool */ public function classExists($class) { - return class_exists($class, false) || $this->getManifest()->getItemPath($class); + return class_exists($class, false) || $this->getItemPath($class); } } diff --git a/tests/core/manifest/ClassLoaderTest.php b/tests/core/manifest/ClassLoaderTest.php new file mode 100644 index 000000000..53f67eb3e --- /dev/null +++ b/tests/core/manifest/ClassLoaderTest.php @@ -0,0 +1,71 @@ +baseManifest1 = dirname(__FILE__) . '/fixtures/classmanifest'; + $this->baseManifest2 = dirname(__FILE__) . '/fixtures/classmanifest_other'; + $this->testManifest1 = new SS_ClassManifest($this->baseManifest1, false, true, false); + $this->testManifest2 = new SS_ClassManifest($this->baseManifest2, false, true, false); + } + + function testExclusive() { + $loader = new SS_ClassLoader(); + + $loader->pushManifest($this->testManifest1); + $this->assertTrue((bool)$loader->getItemPath('ClassA')); + $this->assertFalse((bool)$loader->getItemPath('OtherClassA')); + + $loader->pushManifest($this->testManifest2); + $this->assertFalse((bool)$loader->getItemPath('ClassA')); + $this->assertTrue((bool)$loader->getItemPath('OtherClassA')); + + $loader->popManifest(); + $loader->pushManifest($this->testManifest2, false); + $this->assertTrue((bool)$loader->getItemPath('ClassA')); + $this->assertTrue((bool)$loader->getItemPath('OtherClassA')); + } + + function testGetItemPath() { + $ds = DIRECTORY_SEPARATOR; + $loader = new SS_ClassLoader(); + + $loader->pushManifest($this->testManifest1); + $this->assertEquals( + $this->baseManifest1 . $ds . 'module' . $ds . 'classes' . $ds . 'ClassA.php', + $loader->getItemPath('ClassA') + ); + $this->assertEquals( + false, + $loader->getItemPath('UnknownClass') + ); + $this->assertEquals( + false, + $loader->getItemPath('OtherClassA') + ); + + $loader->pushManifest($this->testManifest2); + $this->assertEquals( + false, + $loader->getItemPath('ClassA') + ); + $this->assertEquals( + false, + $loader->getItemPath('UnknownClass') + ); + $this->assertEquals( + $this->baseManifest2 . $ds . 'module' . $ds . 'classes' . $ds . 'OtherClassA.php', + $loader->getItemPath('OtherClassA') + ); + } +} \ No newline at end of file diff --git a/tests/core/manifest/fixtures/classmanifest_other/module/_config.php b/tests/core/manifest/fixtures/classmanifest_other/module/_config.php new file mode 100644 index 000000000..e69de29bb diff --git a/tests/core/manifest/fixtures/classmanifest_other/module/classes/OtherClassA.php b/tests/core/manifest/fixtures/classmanifest_other/module/classes/OtherClassA.php new file mode 100644 index 000000000..4dac42e8b --- /dev/null +++ b/tests/core/manifest/fixtures/classmanifest_other/module/classes/OtherClassA.php @@ -0,0 +1,5 @@ +