Пример #1
0
 public function waitUntilIndexingFinished()
 {
     $schema = DB::get_schema();
     if (method_exists($schema, 'waitUntilIndexingFinished')) {
         $schema->waitUntilIndexingFinished();
     }
 }
 /**
  * Perform migration
  *
  * @param string $base Absolute base path (parent of assets folder). Will default to BASE_PATH
  * @return int Number of files successfully migrated
  */
 public function run($base = null)
 {
     if (empty($base)) {
         $base = BASE_PATH;
     }
     // Check if the File dataobject has a "Filename" field.
     // If not, cannot migrate
     if (!DB::get_schema()->hasField('File', 'Filename')) {
         return 0;
     }
     // Set max time and memory limit
     increase_time_limit_to();
     increase_memory_limit_to();
     // Loop over all files
     $count = 0;
     $filenameMap = $this->getFilenameArray();
     foreach ($this->getFileQuery() as $file) {
         // Get the name of the file to import
         $filename = $filenameMap[$file->ID];
         $success = $this->migrateFile($base, $file, $filename);
         if ($success) {
             $count++;
         }
     }
     return $count;
 }
 /**
  * Returns the manifest of all classes which are present in the database.
  *
  * @param string $class Class name to check enum values for ClassName field
  * @param boolean $includeUnbacked Flag indicating whether or not to include
  * types that don't exist as implemented classes. By default these are excluded.
  * @return array List of subclasses
  */
 public static function getValidSubClasses($class = 'SiteTree', $includeUnbacked = false)
 {
     $classes = DB::get_schema()->enumValuesForField($class, 'ClassName');
     if (!$includeUnbacked) {
         $classes = array_filter($classes, array('ClassInfo', 'exists'));
     }
     return $classes;
 }
 protected function deleteAllTempDbs()
 {
     $prefix = defined('SS_DATABASE_PREFIX') ? SS_DATABASE_PREFIX : 'ss_';
     foreach (DB::get_schema()->databaseList() as $dbName) {
         if (preg_match(sprintf('/^%stmpdb[0-9]+$/', $prefix), $dbName)) {
             DB::get_schema()->dropDatabase($dbName);
             $this->info("Dropped database {$dbName}");
         }
     }
 }
Пример #5
0
 /**
  * Returns the manifest of all classes which are present in the database.
  *
  * @param string $class Class name to check enum values for ClassName field
  * @param boolean $includeUnbacked Flag indicating whether or not to include
  * types that don't exist as implemented classes. By default these are excluded.
  * @return array List of subclasses
  */
 public static function getValidSubClasses($class = 'SiteTree', $includeUnbacked = false)
 {
     if (is_string($class) && !class_exists($class)) {
         return null;
     }
     $class = self::class_name($class);
     $classes = DB::get_schema()->enumValuesForField($class, 'ClassName');
     if (!$includeUnbacked) {
         $classes = array_filter($classes, array('ClassInfo', 'exists'));
     }
     return $classes;
 }
 /**
  * Check that once a schema has been generated, then it doesn't need any more updating
  */
 public function testFieldsDontRerequestChanges()
 {
     // These are MySQL specific :-S
     if (DB::get_conn() instanceof MySQLDatabase) {
         $schema = DB::get_schema();
         $test = $this;
         DB::quiet();
         // Verify that it doesn't need to be recreated
         $schema->schemaUpdate(function () use($test, $schema) {
             $obj = new MySQLDatabaseTest_DO();
             $obj->requireTable();
             $needsUpdating = $schema->doesSchemaNeedUpdating();
             $schema->cancelSchemaUpdate();
             $test->assertFalse($needsUpdating);
         });
     }
 }
 /**
  * Check that updates to a dataobject's indexes are reflected in DDL
  */
 public function testIndexesRerequestChanges()
 {
     $schema = DB::get_schema();
     $test = $this;
     DB::quiet();
     // Table will have been initially created by the $extraDataObjects setting
     // Update the SearchFields index here
     Config::inst()->update('DataObjectSchemaGenerationTest_IndexDO', 'indexes', array('SearchFields' => array('value' => 'Title')));
     // Verify that the above index change triggered a schema update
     $schema->schemaUpdate(function () use($test, $schema) {
         $obj = new DataObjectSchemaGenerationTest_IndexDO();
         $obj->requireTable();
         $needsUpdating = $schema->doesSchemaNeedUpdating();
         $schema->cancelSchemaUpdate();
         $test->assertTrue($needsUpdating);
     });
 }
 /**
  * Migrations for GroupSubsites data.
  */
 public function requireDefaultRecords()
 {
     // Migration for Group.SubsiteID data from when Groups only had a single subsite
     $groupFields = DB::field_list('Group');
     // Detection of SubsiteID field is the trigger for old-style-subsiteID migration
     if (isset($groupFields['SubsiteID'])) {
         // Migrate subsite-specific data
         DB::query('INSERT INTO "Group_Subsites" ("GroupID", "SubsiteID")
             SELECT "ID", "SubsiteID" FROM "Group" WHERE "SubsiteID" > 0');
         // Migrate global-access data
         DB::query('UPDATE "Group" SET "AccessAllSubsites" = 1 WHERE "SubsiteID" = 0');
         // Move the field out of the way so that this migration doesn't get executed again
         DB::get_schema()->renameField('Group', 'SubsiteID', '_obsolete_SubsiteID');
         // No subsite access on anything means that we've just installed the subsites module.
         // Make all previous groups global-access groups
     } elseif (!DB::query('SELECT "Group"."ID" FROM "Group"
         LEFT JOIN "Group_Subsites" ON "Group_Subsites"."GroupID" = "Group"."ID" AND "Group_Subsites"."SubsiteID" > 0
         WHERE "AccessAllSubsites" = 1
         OR "Group_Subsites"."GroupID" IS NOT NULL ')->value()) {
         DB::query('UPDATE "Group" SET "AccessAllSubsites" = 1');
     }
 }
Пример #9
0
 public function testUniqueIndexes()
 {
     $tableExpectations = array('VersionedTest_WithIndexes' => array('value' => true, 'message' => 'Unique indexes are unique in main table'), 'VersionedTest_WithIndexes_versions' => array('value' => false, 'message' => 'Unique indexes are no longer unique in _versions table'), 'VersionedTest_WithIndexes_Live' => array('value' => false, 'message' => 'Unique indexes are no longer unique in _Live table'));
     // Test each table's performance
     foreach ($tableExpectations as $tableName => $expectation) {
         $indexes = DB::get_schema()->indexList($tableName);
         // Check for presence of all unique indexes
         $indexColumns = array_map(function ($index) {
             return $index['value'];
         }, $indexes);
         sort($indexColumns);
         $expectedColumns = array('"UniqA"', '"UniqS"');
         $this->assertEquals(array_values($expectedColumns), array_values(array_intersect($indexColumns, $expectedColumns)), "{$tableName} has both indexes");
         // Check unique -> non-unique conversion
         foreach ($indexes as $indexKey => $indexSpec) {
             if (in_array($indexSpec['value'], $expectedColumns)) {
                 $isUnique = $indexSpec['type'] === 'unique';
                 $this->assertEquals($isUnique, $expectation['value'], $expectation['message']);
             }
         }
     }
 }
Пример #10
0
 public function requireField()
 {
     $spec = DB::get_schema()->IdColumn(false, $this->getAutoIncrement());
     DB::require_field($this->getTable(), $this->getName(), $spec);
 }
 public function requireDefaultRecords()
 {
     parent::requireDefaultRecords();
     if ($this->config()->dont_upgrade_on_build) {
         return;
     }
     // Perform migrations
     DB::query(sprintf('UPDATE "%s" SET "%s" = \'%s\'', 'OrderStatusLog', 'ClassName', 'OrderLog'));
     if (DB::get_schema()->hasField('OrderStatusLog', 'Changes')) {
         $fields = '"' . implode('", "', array_intersect(array_keys(DB::get_schema()->fieldList('OrderLog')), array_keys(DB::get_schema()->fieldList('OrderStatusLog')))) . '"';
         DB::query(sprintf('INSERT INTO "%s" (%s) SELECT %s FROM "%s" ON DUPLICATE KEY UPDATE ID=VALUES(ID)', 'OrderLog', $fields, $fields, 'OrderStatusLog'));
     }
     DB::alteration_message('Migrated order status logs', 'changed');
 }
 /**
  * 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();
 }
Пример #14
0
 public function augmentDatabase()
 {
     $classTable = $this->owner->class;
     $isRootClass = $this->owner->class == ClassInfo::baseDataClass($this->owner->class);
     // Build a list of suffixes whose tables need versioning
     $allSuffixes = array();
     foreach (Versioned::$versionableExtensions as $versionableExtension => $suffixes) {
         if ($this->owner->hasExtension($versionableExtension)) {
             $allSuffixes = array_merge($allSuffixes, (array) $suffixes);
             foreach ((array) $suffixes as $suffix) {
                 $allSuffixes[$suffix] = $versionableExtension;
             }
         }
     }
     // Add the default table with an empty suffix to the list (table name = class name)
     array_push($allSuffixes, '');
     foreach ($allSuffixes as $key => $suffix) {
         // check that this is a valid suffix
         if (!is_int($key)) {
             continue;
         }
         if ($suffix) {
             $table = "{$classTable}_{$suffix}";
         } else {
             $table = $classTable;
         }
         if ($fields = DataObject::database_fields($this->owner->class)) {
             $options = Config::inst()->get($this->owner->class, 'create_table_options', Config::FIRST_SET);
             $indexes = $this->owner->databaseIndexes();
             if ($suffix && ($ext = $this->owner->getExtensionInstance($allSuffixes[$suffix]))) {
                 if (!$ext->isVersionedTable($table)) {
                     continue;
                 }
                 $ext->setOwner($this->owner);
                 $fields = $ext->fieldsInExtraTables($suffix);
                 $ext->clearOwner();
                 $indexes = $fields['indexes'];
                 $fields = $fields['db'];
             }
             // Create tables for other stages
             foreach ($this->stages as $stage) {
                 // Extra tables for _Live, etc.
                 // Change unique indexes to 'index'.  Versioned tables may run into unique indexing difficulties
                 // otherwise.
                 $indexes = $this->uniqueToIndex($indexes);
                 if ($stage != $this->defaultStage) {
                     DB::require_table("{$table}_{$stage}", $fields, $indexes, false, $options);
                 }
                 // Version fields on each root table (including Stage)
                 /*
                 if($isRootClass) {
                 	$stageTable = ($stage == $this->defaultStage) ? $table : "{$table}_$stage";
                 	$parts=Array('datatype'=>'int', 'precision'=>11, 'null'=>'not null', 'default'=>(int)0);
                 	$values=Array('type'=>'int', 'parts'=>$parts);
                 	DB::requireField($stageTable, 'Version', $values);
                 }
                 */
             }
             if ($isRootClass) {
                 // Create table for all versions
                 $versionFields = array_merge(Config::inst()->get('Versioned', 'db_for_versions_table'), (array) $fields);
                 $versionIndexes = array_merge(Config::inst()->get('Versioned', 'indexes_for_versions_table'), (array) $indexes);
             } else {
                 // Create fields for any tables of subclasses
                 $versionFields = array_merge(array("RecordID" => "Int", "Version" => "Int"), (array) $fields);
                 //Unique indexes will not work on versioned tables, so we'll convert them to standard indexes:
                 $indexes = $this->uniqueToIndex($indexes);
                 $versionIndexes = array_merge(array('RecordID_Version' => array('type' => 'unique', 'value' => '"RecordID","Version"'), 'RecordID' => true, 'Version' => true), (array) $indexes);
             }
             if (DB::get_schema()->hasTable("{$table}_versions")) {
                 // Fix data that lacks the uniqueness constraint (since this was added later and
                 // bugs meant that the constraint was validated)
                 $duplications = DB::query("SELECT MIN(\"ID\") AS \"ID\", \"RecordID\", \"Version\"\n\t\t\t\t\t\tFROM \"{$table}_versions\" GROUP BY \"RecordID\", \"Version\"\n\t\t\t\t\t\tHAVING COUNT(*) > 1");
                 foreach ($duplications as $dup) {
                     DB::alteration_message("Removing {$table}_versions duplicate data for " . "{$dup['RecordID']}/{$dup['Version']}", "deleted");
                     DB::prepared_query("DELETE FROM \"{$table}_versions\" WHERE \"RecordID\" = ?\n\t\t\t\t\t\t\tAND \"Version\" = ? AND \"ID\" != ?", array($dup['RecordID'], $dup['Version'], $dup['ID']));
                 }
                 // Remove junk which has no data in parent classes. Only needs to run the following
                 // when versioned data is spread over multiple tables
                 if (!$isRootClass && ($versionedTables = ClassInfo::dataClassesFor($table))) {
                     foreach ($versionedTables as $child) {
                         if ($table == $child) {
                             break;
                         }
                         // only need subclasses
                         $count = DB::query("\n\t\t\t\t\t\t\t\tSELECT COUNT(*) FROM \"{$table}_versions\"\n\t\t\t\t\t\t\t\tLEFT JOIN \"{$child}_versions\"\n\t\t\t\t\t\t\t\t\tON \"{$child}_versions\".\"RecordID\" = \"{$table}_versions\".\"RecordID\"\n\t\t\t\t\t\t\t\t\tAND \"{$child}_versions\".\"Version\" = \"{$table}_versions\".\"Version\"\n\t\t\t\t\t\t\t\tWHERE \"{$child}_versions\".\"ID\" IS NULL\n\t\t\t\t\t\t\t")->value();
                         if ($count > 0) {
                             DB::alteration_message("Removing orphaned versioned records", "deleted");
                             $affectedIDs = DB::query("\n\t\t\t\t\t\t\t\t\tSELECT \"{$table}_versions\".\"ID\" FROM \"{$table}_versions\"\n\t\t\t\t\t\t\t\t\tLEFT JOIN \"{$child}_versions\"\n\t\t\t\t\t\t\t\t\t\tON \"{$child}_versions\".\"RecordID\" = \"{$table}_versions\".\"RecordID\"\n\t\t\t\t\t\t\t\t\t\tAND \"{$child}_versions\".\"Version\" = \"{$table}_versions\".\"Version\"\n\t\t\t\t\t\t\t\t\tWHERE \"{$child}_versions\".\"ID\" IS NULL\n\t\t\t\t\t\t\t\t")->column();
                             if (is_array($affectedIDs)) {
                                 foreach ($affectedIDs as $key => $value) {
                                     DB::prepared_query("DELETE FROM \"{$table}_versions\" WHERE \"ID\" = ?", array($value));
                                 }
                             }
                         }
                     }
                 }
             }
             DB::require_table("{$table}_versions", $versionFields, $versionIndexes, true, $options);
         } else {
             DB::dont_require_table("{$table}_versions");
             foreach ($this->stages as $stage) {
                 if ($stage != $this->defaultStage) {
                     DB::dont_require_table("{$table}_{$stage}");
                 }
             }
         }
     }
 }
Пример #15
0
 public function compositeDatabaseFields()
 {
     // Ensure the table level cache exists
     if (empty(self::$classname_spec_cache[$this->tableName])) {
         self::$classname_spec_cache[$this->tableName] = array();
     }
     // Ensure the field level cache exists
     if (empty(self::$classname_spec_cache[$this->tableName][$this->name])) {
         // Get all class names
         $classNames = ClassInfo::subclassesFor('DataObject');
         unset($classNames['DataObject']);
         $schema = DB::get_schema();
         if ($schema->hasField($this->tableName, "{$this->name}Class")) {
             $existing = DB::query("SELECT DISTINCT \"{$this->name}Class\" FROM \"{$this->tableName}\"")->column();
             $classNames = array_unique(array_merge($classNames, $existing));
         }
         self::$classname_spec_cache[$this->tableName][$this->name] = "Enum(array('" . implode("', '", array_filter($classNames)) . "'))";
     }
     return array('ID' => 'Int', 'Class' => self::$classname_spec_cache[$this->tableName][$this->name]);
 }
Пример #16
0
 public function testHasTable()
 {
     $this->assertTrue(DB::get_schema()->hasTable('DatabaseTest_MyObject'));
     $this->assertFalse(DB::get_schema()->hasTable('asdfasdfasdf'));
 }
Пример #17
0
 /**
  * Add default records to database.
  *
  * This function is called whenever the database is built, after the database tables have all been created. Overload
  * this to add default records when the database is built, but make sure you call parent::requireDefaultRecords().
  */
 public function requireDefaultRecords()
 {
     parent::requireDefaultRecords();
     // default pages
     if ($this->class == 'SiteTree' && $this->config()->create_default_pages) {
         if (!SiteTree::get_by_link(Config::inst()->get('RootURLController', 'default_homepage_link'))) {
             $homepage = new Page();
             $homepage->Title = _t('SiteTree.DEFAULTHOMETITLE', 'Home');
             $homepage->Content = _t('SiteTree.DEFAULTHOMECONTENT', '<p>Welcome to SilverStripe! This is the default homepage. You can edit this page by opening <a href="admin/">the CMS</a>.</p><p>You can now access the <a href="http://docs.silverstripe.org">developer documentation</a>, or begin the <a href="http://www.silverstripe.org/learn/lessons">SilverStripe lessons</a>.</p>');
             $homepage->URLSegment = Config::inst()->get('RootURLController', 'default_homepage_link');
             $homepage->Sort = 1;
             $homepage->write();
             $homepage->publish('Stage', 'Live');
             $homepage->flushCache();
             DB::alteration_message('Home page created', 'created');
         }
         if (DB::query("SELECT COUNT(*) FROM \"SiteTree\"")->value() == 1) {
             $aboutus = new Page();
             $aboutus->Title = _t('SiteTree.DEFAULTABOUTTITLE', 'About Us');
             $aboutus->Content = _t('SiteTree.DEFAULTABOUTCONTENT', '<p>You can fill this page out with your own content, or delete it and create your own pages.<br /></p>');
             $aboutus->Sort = 2;
             $aboutus->write();
             $aboutus->publish('Stage', 'Live');
             $aboutus->flushCache();
             DB::alteration_message('About Us page created', 'created');
             $contactus = new Page();
             $contactus->Title = _t('SiteTree.DEFAULTCONTACTTITLE', 'Contact Us');
             $contactus->Content = _t('SiteTree.DEFAULTCONTACTCONTENT', '<p>You can fill this page out with your own content, or delete it and create your own pages.<br /></p>');
             $contactus->Sort = 3;
             $contactus->write();
             $contactus->publish('Stage', 'Live');
             $contactus->flushCache();
             DB::alteration_message('Contact Us page created', 'created');
         }
     }
     // schema migration
     // @todo Move to migration task once infrastructure is implemented
     if ($this->class == 'SiteTree') {
         $conn = DB::get_schema();
         // only execute command if fields haven't been renamed to _obsolete_<fieldname> already by the task
         if ($conn->hasField('SiteTree', 'Viewers')) {
             $task = new UpgradeSiteTreePermissionSchemaTask();
             $task->run(new SS_HTTPRequest('GET', '/'));
         }
     }
 }
 /**
  * Determines the specification for the ClassName field for the given class
  *
  * @param string $class
  * @param boolean $queryDB Determine if the DB may be queried for additional information
  * @return string Resulting ClassName spec. If $queryDB is true this will include all
  * legacy types that no longer have concrete classes in PHP
  */
 public static function get_classname_spec($class, $queryDB = true)
 {
     // Check cache
     if (!empty(self::$classname_spec_cache[$class])) {
         return self::$classname_spec_cache[$class];
     }
     // Build known class names
     $classNames = ClassInfo::subclassesFor($class);
     // Enhance with existing classes in order to prevent legacy details being lost
     if ($queryDB && DB::get_schema()->hasField($class, 'ClassName')) {
         $existing = DB::query("SELECT DISTINCT \"ClassName\" FROM \"{$class}\"")->column();
         $classNames = array_unique(array_merge($classNames, $existing));
     }
     $spec = "Enum('" . implode(', ', $classNames) . "')";
     // Only cache full information if queried
     if ($queryDB) {
         self::$classname_spec_cache[$class] = $spec;
     }
     return $spec;
 }
Пример #19
0
 public function testDatabaseIsReadyWithInsufficientMemberColumns()
 {
     $old = Security::$force_database_is_ready;
     Security::$force_database_is_ready = null;
     Security::$database_is_ready = false;
     DataObject::clear_classname_spec_cache();
     // Assumption: The database has been built correctly by the test runner,
     // and has all columns present in the ORM
     DB::get_schema()->renameField('Member', 'Email', 'Email_renamed');
     // Email column is now missing, which means we're not ready to do permission checks
     $this->assertFalse(Security::database_is_ready());
     // Rebuild the database (which re-adds the Email column), and try again
     $this->resetDBSchema(true);
     $this->assertTrue(Security::database_is_ready());
     Security::$force_database_is_ready = $old;
 }
Пример #20
0
 /**
  * Get the list of classnames, including obsolete classes.
  *
  * If table or name are not set, or if it is not a valid field on the given table,
  * then only known classnames are returned.
  *
  * Values cached in this method can be cleared via `DBClassName::clear_classname_cache();`
  *
  * @return array
  */
 public function getEnumObsolete()
 {
     // Without a table or field specified, we can only retrieve known classes
     $table = $this->getTable();
     $name = $this->getName();
     if (empty($table) || empty($name)) {
         return $this->getEnum();
     }
     // Ensure the table level cache exists
     if (empty(self::$classname_cache[$table])) {
         self::$classname_cache[$table] = array();
     }
     // Check existing cache
     if (!empty(self::$classname_cache[$table][$name])) {
         return self::$classname_cache[$table][$name];
     }
     // Get all class names
     $classNames = $this->getEnum();
     if (DB::get_schema()->hasField($table, $name)) {
         $existing = DB::query("SELECT DISTINCT \"{$name}\" FROM \"{$table}\"")->column();
         $classNames = array_unique(array_merge($classNames, $existing));
     }
     // Cache and return
     self::$classname_cache[$table][$name] = $classNames;
     return $classNames;
 }
Пример #21
0
 public function requireTable()
 {
     // Migrate permission columns
     if (DB::get_schema()->hasTable('Forum')) {
         $fields = DB::get_schema()->fieldList('Forum');
         if (in_array('ForumPosters', array_keys($fields)) && !in_array('CanPostType', array_keys($fields))) {
             DB::get_schema()->renameField('Forum', 'ForumPosters', 'CanPostType');
             DB::alteration_message('Migrated forum permissions from "ForumPosters" to "CanPostType"', "created");
         }
     }
     parent::requireTable();
 }