/**
  * Reset all global caches associated with DataObject.
  */
 public static function reset()
 {
     // @todo Decouple these
     DBClassName::clear_classname_cache();
     ClassInfo::reset_db_cache();
     static::getSchema()->reset();
     self::$_cache_get_one = array();
     self::$_cache_field_labels = array();
 }
 /**
  * Reset the testing database's schema.
  * @param bool $includeExtraDataObjects If true, the extraDataObjects tables will also be included
  */
 public function resetDBSchema($includeExtraDataObjects = false)
 {
     if (self::using_temp_db()) {
         DataObject::reset();
         // clear singletons, they're caching old extension info which is used in DatabaseAdmin->doBuild()
         Injector::inst()->unregisterAllObjects();
         $dataClasses = ClassInfo::subclassesFor('SilverStripe\\ORM\\DataObject');
         array_shift($dataClasses);
         DB::quiet();
         $schema = DB::get_schema();
         $extraDataObjects = $includeExtraDataObjects ? $this->extraDataObjects : null;
         $schema->schemaUpdate(function () use($dataClasses, $extraDataObjects) {
             foreach ($dataClasses as $dataClass) {
                 // Check if class exists before trying to instantiate - this sidesteps any manifest weirdness
                 if (class_exists($dataClass)) {
                     $SNG = singleton($dataClass);
                     if (!$SNG instanceof TestOnly) {
                         $SNG->requireTable();
                     }
                 }
             }
             // If we have additional dataobjects which need schema, do so here:
             if ($extraDataObjects) {
                 foreach ($extraDataObjects as $dataClass) {
                     $SNG = singleton($dataClass);
                     if (singleton($dataClass) instanceof DataObject) {
                         $SNG->requireTable();
                     }
                 }
             }
         });
         ClassInfo::reset_db_cache();
         singleton('SilverStripe\\ORM\\DataObject')->flushCache();
     }
 }
 /**
  * Updates the database schema, creating tables & fields as necessary.
  *
  * @param boolean $quiet Don't show messages
  * @param boolean $populate Populate the database, as well as setting up its schema
  * @param bool $testMode
  */
 public function doBuild($quiet = false, $populate = true, $testMode = false)
 {
     if ($quiet) {
         DB::quiet();
     } else {
         $conn = DB::get_conn();
         // Assumes database class is like "MySQLDatabase" or "MSSQLDatabase" (suffixed with "Database")
         $dbType = substr(get_class($conn), 0, -8);
         $dbVersion = $conn->getVersion();
         $databaseName = method_exists($conn, 'currentDatabase') ? $conn->getSelectedDatabase() : "";
         if (Director::is_cli()) {
             echo sprintf("\n\nBuilding database %s using %s %s\n\n", $databaseName, $dbType, $dbVersion);
         } else {
             echo sprintf("<h2>Building database %s using %s %s</h2>", $databaseName, $dbType, $dbVersion);
         }
     }
     // Set up the initial database
     if (!DB::is_active()) {
         if (!$quiet) {
             echo '<p><b>Creating database</b></p>';
         }
         // Load parameters from existing configuration
         global $databaseConfig;
         if (empty($databaseConfig) && empty($_REQUEST['db'])) {
             user_error("No database configuration available", E_USER_ERROR);
         }
         $parameters = !empty($databaseConfig) ? $databaseConfig : $_REQUEST['db'];
         // Check database name is given
         if (empty($parameters['database'])) {
             user_error("No database name given; please give a value for \$databaseConfig['database']", E_USER_ERROR);
         }
         $database = $parameters['database'];
         // Establish connection and create database in two steps
         unset($parameters['database']);
         DB::connect($parameters);
         DB::create_database($database);
     }
     // Build the database.  Most of the hard work is handled by DataObject
     $dataClasses = ClassInfo::subclassesFor('SilverStripe\\ORM\\DataObject');
     array_shift($dataClasses);
     if (!$quiet) {
         if (Director::is_cli()) {
             echo "\nCREATING DATABASE TABLES\n\n";
         } else {
             echo "\n<p><b>Creating database tables</b></p>\n\n";
         }
     }
     // Initiate schema update
     $dbSchema = DB::get_schema();
     $dbSchema->schemaUpdate(function () use($dataClasses, $testMode, $quiet) {
         foreach ($dataClasses as $dataClass) {
             // Check if class exists before trying to instantiate - this sidesteps any manifest weirdness
             if (!class_exists($dataClass)) {
                 continue;
             }
             // Check if this class should be excluded as per testing conventions
             $SNG = singleton($dataClass);
             if (!$testMode && $SNG instanceof TestOnly) {
                 continue;
             }
             // Log data
             if (!$quiet) {
                 if (Director::is_cli()) {
                     echo " * {$dataClass}\n";
                 } else {
                     echo "<li>{$dataClass}</li>\n";
                 }
             }
             // Instruct the class to apply its schema to the database
             $SNG->requireTable();
         }
     });
     ClassInfo::reset_db_cache();
     if ($populate) {
         if (!$quiet) {
             if (Director::is_cli()) {
                 echo "\nCREATING DATABASE RECORDS\n\n";
             } else {
                 echo "\n<p><b>Creating database records</b></p>\n\n";
             }
         }
         foreach ($dataClasses as $dataClass) {
             // Check if class exists before trying to instantiate - this sidesteps any manifest weirdness
             // Test_ indicates that it's the data class is part of testing system
             if (strpos($dataClass, 'Test_') === false && class_exists($dataClass)) {
                 if (!$quiet) {
                     if (Director::is_cli()) {
                         echo " * {$dataClass}\n";
                     } else {
                         echo "<li>{$dataClass}</li>\n";
                     }
                 }
                 singleton($dataClass)->requireDefaultRecords();
             }
         }
         // Remap obsolete class names
         $schema = DataObject::getSchema();
         foreach ($this->config()->classname_value_remapping as $oldClassName => $newClassName) {
             $baseDataClass = $schema->baseDataClass($newClassName);
             $badRecordCount = DataObject::get($baseDataClass)->filter(["ClassName" => $oldClassName])->count();
             if ($badRecordCount > 0) {
                 if (Director::is_cli()) {
                     echo " * Correcting {$badRecordCount} obsolete classname values for {$newClassName}\n";
                 } else {
                     echo "<li>Correcting {$badRecordCount} obsolete classname values for {$newClassName}</li>\n";
                 }
                 $table = $schema->baseDataTable($baseDataClass);
                 DB::prepared_query("UPDATE \"{$table}\" SET \"ClassName\" = ? WHERE \"ClassName\" = ?", [$newClassName, $oldClassName]);
             }
         }
     }
     touch(TEMP_FOLDER . '/database-last-generated-' . str_replace(array('\\', '/', ':'), '.', Director::baseFolder()));
     if (isset($_REQUEST['from_installer'])) {
         echo "OK";
     }
     if (!$quiet) {
         echo Director::is_cli() ? "\n Database build completed!\n\n" : "<p>Database build completed!</p>";
     }
     ClassInfo::reset_db_cache();
 }
 /**
  * @covers SilverStripe\Core\ClassInfo::dataClassesFor()
  */
 public function testDataClassesFor()
 {
     $expect = array('ClassInfoTest_BaseDataClass' => 'ClassInfoTest_BaseDataClass', 'ClassInfoTest_HasFields' => 'ClassInfoTest_HasFields', 'ClassInfoTest_WithRelation' => 'ClassInfoTest_WithRelation', 'ClassInfoTest_WithCustomTable' => 'ClassInfoTest_WithCustomTable');
     $classes = array('ClassInfoTest_BaseDataClass', 'ClassInfoTest_NoFields', 'ClassInfoTest_HasFields');
     ClassInfo::reset_db_cache();
     $this->assertEquals($expect, ClassInfo::dataClassesFor($classes[0]));
     ClassInfo::reset_db_cache();
     $this->assertEquals($expect, ClassInfo::dataClassesFor(strtoupper($classes[0])));
     ClassInfo::reset_db_cache();
     $this->assertEquals($expect, ClassInfo::dataClassesFor($classes[1]));
     $expect = array('ClassInfoTest_BaseDataClass' => 'ClassInfoTest_BaseDataClass', 'ClassInfoTest_HasFields' => 'ClassInfoTest_HasFields');
     ClassInfo::reset_db_cache();
     $this->assertEquals($expect, ClassInfo::dataClassesFor($classes[2]));
     ClassInfo::reset_db_cache();
     $this->assertEquals($expect, ClassInfo::dataClassesFor(strtolower($classes[2])));
 }