public function testGetItemPath()
 {
     $loader = new ClassLoader();
     $loader->pushManifest($this->testManifest1);
     $this->assertEquals(realpath($this->baseManifest1 . '/module/classes/ClassA.php'), realpath($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(realpath($this->baseManifest2 . '/module/classes/OtherClassA.php'), realpath($loader->getItemPath('OtherClassA')));
 }
 function executeInSubprocess($includeStderr = false)
 {
     // Get the path to the ErrorControlChain class
     $erroControlClass = 'SilverStripe\\Core\\Startup\\ErrorControlChain';
     $classpath = ClassLoader::instance()->getItemPath($erroControlClass);
     $suppression = $this->suppression ? 'true' : 'false';
     // Start building a PHP file that will execute the chain
     $src = '<' . "?php\nrequire_once '{$classpath}';\n\n\$chain = new {$erroControlClass}();\n\n\$chain->setSuppression({$suppression});\n\n\$chain\n";
     // For each step, use reflection to pull out the call, stick in the the PHP source we're building
     foreach ($this->steps as $step) {
         $func = new ReflectionFunction($step['callback']);
         $source = file($func->getFileName());
         $start_line = $func->getStartLine() - 1;
         $end_line = $func->getEndLine();
         $length = $end_line - $start_line;
         $src .= implode("", array_slice($source, $start_line, $length)) . "\n";
     }
     // Finally add a line to execute the chain
     $src .= "->execute();";
     // Now stick it in a temporary file & run it
     $codepath = TEMP_FOLDER . '/ErrorControlChainTest_' . sha1($src) . '.php';
     if ($includeStderr) {
         $null = '&1';
     } else {
         $null = is_writeable('/dev/null') ? '/dev/null' : 'NUL';
     }
     file_put_contents($codepath, $src);
     exec("php {$codepath} 2>{$null}", $stdout, $errcode);
     unlink($codepath);
     return array(implode("\n", $stdout), $errcode);
 }
 public function tearDown()
 {
     parent::tearDown();
     ClassLoader::instance()->popManifest();
 }
 /**
  * Updates the database schema, creating tables & fields as necessary.
  */
 public function build()
 {
     // The default time limit of 30 seconds is normally not enough
     increase_time_limit_to(600);
     // Get all our classes
     ClassLoader::instance()->getManifest()->regenerate();
     $url = $this->getReturnURL();
     if ($url) {
         echo "<p>Setting up the database; you will be returned to your site shortly....</p>";
         $this->doBuild(true);
         echo "<p>Done!</p>";
         $this->redirect($url);
     } else {
         $quiet = $this->request->requestVar('quiet') !== null;
         $fromInstaller = $this->request->requestVar('from_installer') !== null;
         $populate = $this->request->requestVar('dont_populate') === null;
         $this->doBuild($quiet || $fromInstaller, $populate);
     }
 }
 /**
  * Pushes a class and template manifest instance that include tests onto the
  * top of the loader stacks.
  */
 public static function use_test_manifest()
 {
     $flush = true;
     if (isset($_GET['flush']) && $_GET['flush'] === '0') {
         $flush = false;
     }
     $classManifest = new ClassManifest(BASE_PATH, true, $flush);
     ClassLoader::instance()->pushManifest($classManifest, false);
     SapphireTest::set_test_class_manifest($classManifest);
     ThemeResourceLoader::instance()->addSet('$default', new ThemeManifest(BASE_PATH, project(), true, $flush));
     Config::inst()->pushConfigStaticManifest(new ConfigStaticManifest(BASE_PATH, true, $flush));
     // Invalidate classname spec since the test manifest will now pull out new subclasses for each internal class
     // (e.g. Member will now have various subclasses of DataObjects that implement TestOnly)
     DataObject::reset();
 }
gc_enable();
// Initialise the dependency injector as soon as possible, as it is
// subsequently used by some of the following code
$injector = new Injector(array('locator' => 'SilverStripe\\Core\\Injector\\SilverStripeServiceConfigurationLocator'));
Injector::set_inst($injector);
///////////////////////////////////////////////////////////////////////////////
// MANIFEST
// Regenerate the manifest if ?flush is set, or if the database is being built.
// The coupling is a hack, but it removes an annoying bug where new classes
// referenced in _config.php files can be referenced during the build process.
$requestURL = isset($_REQUEST['url']) ? trim($_REQUEST['url'], '/') : false;
$flush = isset($_GET['flush']) || $requestURL === trim(BASE_URL . '/dev/build', '/');
global $manifest;
$manifest = new ClassManifest(BASE_PATH, false, $flush);
// Register SilverStripe's class map autoload
$loader = ClassLoader::instance();
$loader->registerAutoloader();
$loader->pushManifest($manifest);
// Now that the class manifest is up, load the static configuration
$configManifest = new ConfigStaticManifest();
Config::inst()->pushConfigStaticManifest($configManifest);
// And then the yaml configuration
$configManifest = new ConfigManifest(BASE_PATH, false, $flush);
Config::inst()->pushConfigYamlManifest($configManifest);
// Load template manifest
SilverStripe\View\ThemeResourceLoader::instance()->addSet('$default', new SilverStripe\View\ThemeManifest(BASE_PATH, project(), false, $flush));
// If in live mode, ensure deprecation, strict and notices are not reported
if (Director::isLive()) {
    error_reporting(E_ALL & ~(E_DEPRECATED | E_STRICT | E_NOTICE));
}
///////////////////////////////////////////////////////////////////////////////
 /**
  * Returns all classes contained in a certain folder.
  *
  * @todo Doesn't return additional classes that only begin
  *  with the filename, and have additional naming separated through underscores.
  *
  * @param string $folderPath Relative or absolute folder path
  * @return array Array of class names
  */
 public static function classes_for_folder($folderPath)
 {
     $absFolderPath = Director::getAbsFile($folderPath);
     $matchedClasses = array();
     $manifest = ClassLoader::instance()->getManifest()->getClasses();
     foreach ($manifest as $class => $compareFilePath) {
         if (stripos($compareFilePath, $absFolderPath) === 0) {
             $matchedClasses[] = $class;
         }
     }
     return $matchedClasses;
 }
 /**
  * Test ability for textcollector to detect modules
  */
 public function testModuleDetection()
 {
     ClassLoader::instance()->pushManifest($this->manifest);
     $collector = new i18nTextCollectorTest_Collector();
     $modules = $collector->getModules_Test($this->alternateBasePath);
     $this->assertEquals(array('i18nnonstandardmodule', 'i18nothermodule', 'i18ntestmodule', 'themes/testtheme1', 'themes/testtheme2'), $modules);
     $this->assertEquals('i18ntestmodule', $collector->findModuleForClass_Test('i18nTestNamespacedClass'));
     $this->assertEquals('i18ntestmodule', $collector->findModuleForClass_Test('i18nTest\\i18nTestNamespacedClass'));
     $this->assertEquals('i18ntestmodule', $collector->findModuleForClass_Test('i18nTestSubModule'));
 }
 /**
  * Includes all available language files for a certain defined locale.
  *
  * @param string $locale All resources from any module in locale $locale will be loaded
  * @param Boolean $clean Clean old caches?
  */
 public static function include_by_locale($locale, $clean = false)
 {
     if ($clean) {
         self::flush();
     }
     // Get list of module => path pairs, and then just the names
     $modules = ClassLoader::instance()->getManifest()->getModules();
     $moduleNames = array_keys($modules);
     // Remove the "project" module from the list - we'll add it back specially later if needed
     global $project;
     if (($idx = array_search($project, $moduleNames)) !== false) {
         array_splice($moduleNames, $idx, 1);
     }
     // Get the order from the config syste,
     $order = i18n::config()->get('module_priority');
     // Find all modules that don't have their order specified by the config system
     $unspecified = array_diff($moduleNames, $order);
     // If the placeholder "other_modules" exists in the order array, replace it by the unspecified modules
     if (($idx = array_search('other_modules', $order)) !== false) {
         array_splice($order, $idx, 1, $unspecified);
     } else {
         // Otherwise just jam them on the front
         array_splice($order, 0, 0, $unspecified);
     }
     // Put the project module back in at the begining if it wasn't specified by the config system
     if (!in_array($project, $order)) {
         array_unshift($order, $project);
     }
     $sortedModules = array();
     foreach ($order as $module) {
         if (isset($modules[$module])) {
             $sortedModules[$module] = $modules[$module];
         }
     }
     $sortedModules = array_reverse($sortedModules, true);
     // Loop in reverse order, meaning the translator with the highest priority goes first
     $translatorsByPrio = array_reverse(self::get_translators(), true);
     foreach ($translatorsByPrio as $priority => $translators) {
         /** @var Zend_Translate $translator */
         foreach ($translators as $name => $translator) {
             /** @var i18nTranslateAdapterInterface|Zend_Translate_Adapter $adapter */
             $adapter = $translator->getAdapter();
             // Load translations from modules
             foreach ($sortedModules as $module) {
                 $filename = $adapter->getFilenameForLocale($locale);
                 $filepath = "{$module}/lang/" . $filename;
                 if ($filename && !file_exists($filepath)) {
                     continue;
                 }
                 $adapter->addTranslation(array('content' => $filepath, 'locale' => $locale));
             }
             // Load translations from themes
             // TODO Replace with theme listing once implemented in TemplateManifest
             $themesBase = Director::baseFolder() . '/themes';
             if (is_dir($themesBase)) {
                 foreach (scandir($themesBase) as $theme) {
                     if (strpos($theme, Config::inst()->get('SilverStripe\\View\\SSViewer', 'theme')) === 0 && file_exists("{$themesBase}/{$theme}/lang/")) {
                         $filename = $adapter->getFilenameForLocale($locale);
                         $filepath = "{$themesBase}/{$theme}/lang/" . $filename;
                         if ($filename && !file_exists($filepath)) {
                             continue;
                         }
                         $adapter->addTranslation(array('content' => $filepath, 'locale' => $locale));
                     }
                 }
             }
             // Add empty translations to ensure the locales are "registered" with isAvailable(),
             // and the next invocation of include_by_locale() doesn't cause a new reparse.
             $adapter->addTranslation(array('content' => array($locale => $locale), 'locale' => $locale, 'usetranslateadapter' => true));
         }
     }
 }
 /**
  * Given a backtrace, get the module name from the caller two removed (the caller of the method that called
  * #notice)
  *
  * @param array $backtrace A backtrace as returned from debug_backtrace
  * @return string The name of the module the call came from, or null if we can't determine
  */
 protected static function get_calling_module_from_trace($backtrace)
 {
     if (!isset($backtrace[1]['file'])) {
         return null;
     }
     $callingfile = realpath($backtrace[1]['file']);
     $manifest = ClassLoader::instance()->getManifest();
     foreach ($manifest->getModules() as $name => $path) {
         if (strpos($callingfile, realpath($path)) === 0) {
             return $name;
         }
     }
     return null;
 }
 /**
  * Given a partial class name, attempt to determine the best module to assign strings to.
  *
  * @param string $class Either a FQN class name, or a non-qualified class name.
  * @return string Name of module
  */
 protected function findModuleForClass($class)
 {
     if (ClassInfo::exists($class)) {
         return i18n::get_owner_module($class);
     }
     // If we can't find a class, see if it needs to be fully qualified
     if (strpos($class, '\\') !== false) {
         return null;
     }
     // Find FQN that ends with $class
     $classes = preg_grep('/' . preg_quote("\\{$class}", '\\/') . '$/i', ClassLoader::instance()->getManifest()->getClassNames());
     // Find all modules for candidate classes
     $modules = array_unique(array_map(function ($class) {
         return i18n::get_owner_module($class);
     }, $classes));
     if (count($modules) === 1) {
         return reset($modules);
     }
     // Couldn't find it! Exists in none, or multiple modules.
     return null;
 }