public function fire() { $this->info('Used cache location: ' . TEMP_FOLDER); SS_ClassLoader::instance()->getManifest()->regenerate(); $this->info('regenerated manifest!'); ClassInfo::reset_db_cache(); $this->info('resetted db cache!'); }
/** * @covers ClassInfo::dataClassesFor() */ public function testDataClassesFor() { $expect = array('ClassInfoTest_BaseDataClass' => 'ClassInfoTest_BaseDataClass', 'ClassInfoTest_HasFields' => 'ClassInfoTest_HasFields', 'ClassInfoTest_WithRelation' => 'ClassInfoTest_WithRelation'); $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]))); }
/** * Reset the testing database's schema. * @param $includeExtraDataObjects If true, the extraDataObjects tables will also be included */ function resetDBSchema($includeExtraDataObjects = false) { if (self::using_temp_db()) { // clear singletons, they're caching old extension info which is used in DatabaseAdmin->doBuild() global $_SINGLETONS; $_SINGLETONS = array(); $dataClasses = ClassInfo::subclassesFor('DataObject'); array_shift($dataClasses); $conn = DB::getConn(); $conn->beginSchemaUpdate(); DB::quiet(); 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 ($includeExtraDataObjects && $this->extraDataObjects) { foreach ($this->extraDataObjects as $dataClass) { $SNG = singleton($dataClass); if (singleton($dataClass) instanceof DataObject) { $SNG->requireTable(); } } } $conn->endSchemaUpdate(); ClassInfo::reset_db_cache(); singleton('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 */ public function doBuild($quiet = false, $populate = true, $testMode = false) { if ($quiet) { DB::quiet(); } else { $conn = DB::getConn(); // 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->currentDatabase() : ""; 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::isActive()) { if (!$quiet) { echo '<p><b>Creating database</b></p>'; } global $databaseConfig; $parameters = $databaseConfig ? $databaseConfig : $_REQUEST['db']; $connect = DB::getConnect($parameters); $username = $parameters['username']; $password = $parameters['password']; $database = $parameters['database']; if (!$database) { user_error("No database name given; please give a value for \$databaseConfig['database']", E_USER_ERROR); } DB::createDatabase($connect, $username, $password, $database); } // Build the database. Most of the hard work is handled by DataObject $dataClasses = ClassInfo::subclassesFor('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"; } } $conn = DB::getConn(); $conn->beginSchemaUpdate(); 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 ($testMode || !$SNG instanceof TestOnly) { if (!$quiet) { if (Director::is_cli()) { echo " * {$dataClass}\n"; } else { echo "<li>{$dataClass}</li>\n"; } } $SNG->requireTable(); } } } $conn->endSchemaUpdate(); 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(); } } } 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(); }
/** * Reset the testing database's schema. * @param $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('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('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 */ 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('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(); } } } 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(); }
/** * Builds out the SiteTree hierarchy as specified in _fixtures.txt * * @see "silversmith help" * @param The parameters, e.g. from the command line */ public static function build_fixtures($params = array()) { ClassInfo::reset_db_cache(); $fixtures_file = isset($params['file']) ? $params['file'] : self::$project_dir . "/_fixtures.txt"; if (!file_exists($fixtures_file)) { fail("The file {$fixtures_file} doesn't exist."); } $code = file_get_contents($fixtures_file); $architectureData = array(); $lines = explode("\n", $code); if (empty($lines)) { fail("The files {$fixtures_file} is empty."); } $sample = Folder::find_or_make("silversmith-samples"); if (!$sample->hasChildren()) { $answer = ask("This project does not have sample assets installed, which can be useful for content seeding. Do you want to install them now? (y/n)"); if (strtolower(trim($answer)) == "y") { SilverSmith::add_sample_assets(); } } $answer = ask("This process will completely empty and repopulate your site tree. Are you sure you want to continue? (y/n)"); if (strtolower($answer) != "y") { die; } say("Parsing architecture file..."); foreach ($lines as $line) { if (empty($line)) { continue; } $level = 0; $count = 1; $class = "Page"; $title = $line; preg_match('/^[ ]+[^ ]/', $line, $matches); if ($matches) { $level = strlen(substr(reset($matches), 0, -1)); } if (stristr($line, ">")) { list($title, $class) = explode(" > ", $line); $class = SilverSmithUtil::proper_form($class); } preg_match('/\\*[0-9]+/', $title, $m); if ($m) { $match = reset($m); $count = (int) trim(str_replace("*", "", $match)); $title = str_replace($match, "", $title); } $architectureData[] = array('title' => trim($title), 'level' => $level, 'class' => trim($class), 'count' => $count, 'new' => !class_exists($class) || !in_array($class, ClassInfo::getValidSubclasses("SiteTree"))); } // Clean the slate say("Deleting current site tree"); DB::query("DELETE FROM SiteTree"); DB::query("DELETE FROM SiteTree_Live"); DB::query("DELETE FROM SiteTree_versions"); say("Done."); // Update the DB with any new page types $new = array(); say("Checking architecture file for new page types..."); foreach ($architectureData as $arr) { if ($arr['new']) { $new[] = $arr['class']; SilverSmithProject::get_configuration()->addNode($arr['class'], "PageTypes"); SilverSmithProject::get_node($arr['class'])->createFile(); say(success("Created " . $arr['class'])); } } if (!empty($new)) { state("Rebuilding database to support " . sizeof($new) . " new page types..."); $result = self::rebuild_database(); self::rebuild_manifest(); state("Done\n"); } $previousParentIDs = array('0' => '0'); $previousLevel = 0; $seeding = isset($params['seeding-level']) ? $params['seeding-level'] : 1; $total = 0; foreach ($architectureData as $arr) { $parentID = 0; $currentLevel = $arr['level']; $title = $arr['title']; $class = $arr['class']; $count = $arr['count']; $indent = ""; while (strlen($indent) < $currentLevel * 2) { $indent .= " "; } if ($currentLevel > 0) { $parentID = $previousParentIDs[$currentLevel - 2]; } for ($i = 0; $i < $count; $i++) { $p = new $class(); if (strtolower($title) == "_auto_") { $p->Title = SilverSmithUtil::get_lipsum_words(rand(2, 5)); } else { $p->Title = $title; } state($indent . $p->Title, "green", "bold"); state(" [{$class}] created..."); if ($seeding > 0) { state("Seeding..."); $p->Content = SilverSmithUtil::get_default_content($p->obj('Content'), $seeding); } $p->Status = "Published"; $p->ParentID = $parentID; $p->write(); if ($seeding > 1) { SilverSmithUtil::add_default_content($p, $seeding); } $p->write(); $p->publish("Stage", "Live"); state("Done.\n"); $total++; $previousParentIDs[$currentLevel] = $p->ID; } } $errorPages = DataList::create("ErrorPage"); if ($errorPages->count()) { state("Fixing error pages..."); $max = DB::query("SELECT MAX(Sort) FROM SiteTree")->value(); foreach ($errorPages as $e) { $max++; $e->Sort = $max; $e->write(); $e->publish("Stage", "Live"); } "Done\n"; } self::rebuild_manifest(); say(success("Success!")); state("Important", "red"); state(": You must "); state("restart your browser", null, null, "bold"); state(" to clear your session in order to view the architecture changes.\n"); }