public function testMySQLCreateTableOptions()
 {
     if (!DB::get_conn() instanceof MySQLDatabase) {
         $this->markTestSkipped('MySQL only');
     }
     $ret = DB::query(sprintf('SHOW TABLE STATUS WHERE "Name" = \'%s\'', 'DatabaseTest_MyObject'))->first();
     $this->assertEquals($ret['Engine'], 'InnoDB', "MySQLDatabase tables can be changed to InnoDB through DataObject::\$create_table_options");
 }
 /**
  * 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;
 }
 public function testSavingUnchecked()
 {
     /* Create a new test data record */
     $article = new CheckboxFieldTest_Article();
     /* Create a field, with no value */
     $field = new CheckboxField('IsChecked', 'Checked');
     /* Save the field into our Article object */
     $field->saveInto($article);
     /* Write the record to the test database */
     $article->write();
     /* Check that IsChecked column contains a 0 */
     $this->assertEquals(DB::query("SELECT \"IsChecked\" FROM \"CheckboxFieldTest_Article\"")->value(), 0, 'We have a 0 set in the database, because the field saved into as a 0');
     /* Delete the record we tested */
     $article->delete();
 }
 /**
  * Remove invalid records from tables - that is, records that don't have
  * corresponding records in their parent class tables.
  */
 public function cleanup()
 {
     $allClasses = get_declared_classes();
     foreach ($allClasses as $class) {
         if (get_parent_class($class) == 'SilverStripe\\ORM\\DataObject') {
             $baseClasses[] = $class;
         }
     }
     foreach ($baseClasses as $baseClass) {
         // Get data classes
         $subclasses = ClassInfo::subclassesFor($baseClass);
         unset($subclasses[0]);
         foreach ($subclasses as $k => $subclass) {
             if (DataObject::has_own_table($subclass)) {
                 unset($subclasses[$k]);
             }
         }
         if ($subclasses) {
             $records = DB::query("SELECT * FROM \"{$baseClass}\"");
             foreach ($subclasses as $subclass) {
                 $recordExists[$subclass] = DB::query("SELECT \"ID\" FROM \"{$subclass}\"")->keyedColumn();
             }
             foreach ($records as $record) {
                 foreach ($subclasses as $subclass) {
                     $id = $record['ID'];
                     if ($record['ClassName'] != $subclass && !is_subclass_of($record['ClassName'], $subclass) && isset($recordExists[$subclass][$id])) {
                         $sql = "DELETE FROM \"{$subclass}\" WHERE \"ID\" = {$record['ID']}";
                         echo "<li>{$sql}";
                         DB::query($sql);
                     }
                 }
             }
         }
     }
 }
 /**
  * Get a list of all available permission codes, both defined through the
  * {@link PermissionProvider} interface, and all not explicitly defined codes existing
  * as a {@link Permission} database record. By default, the results are
  * grouped as denoted by {@link Permission_Group}.
  *
  * @param bool $grouped Group results into an array of permission groups.
  * @return array Returns an array of all available permission codes. The
  *  array indicies are the permission codes as used in
  *  {@link Permission::check()}. The value is a description
  *  suitable for using in an interface.
  */
 public static function get_codes($grouped = true)
 {
     $classes = ClassInfo::implementorsOf('SilverStripe\\Security\\PermissionProvider');
     $allCodes = array();
     $adminCategory = _t('Permission.AdminGroup', 'Administrator');
     $allCodes[$adminCategory]['ADMIN'] = array('name' => _t('Permission.FULLADMINRIGHTS', 'Full administrative rights'), 'help' => _t('Permission.FULLADMINRIGHTS_HELP', 'Implies and overrules all other assigned permissions.'), 'sort' => 100000);
     if ($classes) {
         foreach ($classes as $class) {
             $SNG = singleton($class);
             if ($SNG instanceof TestOnly) {
                 continue;
             }
             $someCodes = $SNG->providePermissions();
             if ($someCodes) {
                 foreach ($someCodes as $k => $v) {
                     if (is_array($v)) {
                         // There must be a category and name key.
                         if (!isset($v['category'])) {
                             user_error("The permission {$k} must have a category key", E_USER_WARNING);
                         }
                         if (!isset($v['name'])) {
                             user_error("The permission {$k} must have a name key", E_USER_WARNING);
                         }
                         if (!isset($allCodes[$v['category']])) {
                             $allCodes[$v['category']] = array();
                         }
                         $allCodes[$v['category']][$k] = array('name' => $v['name'], 'help' => isset($v['help']) ? $v['help'] : null, 'sort' => isset($v['sort']) ? $v['sort'] : 0);
                     } else {
                         $allCodes['Other'][$k] = array('name' => $v, 'help' => null, 'sort' => 0);
                     }
                 }
             }
         }
     }
     $flatCodeArray = array();
     foreach ($allCodes as $category) {
         foreach ($category as $code => $permission) {
             $flatCodeArray[] = $code;
         }
     }
     $otherPerms = DB::query("SELECT DISTINCT \"Code\" From \"Permission\" WHERE \"Code\" != ''")->column();
     if ($otherPerms) {
         foreach ($otherPerms as $otherPerm) {
             if (!in_array($otherPerm, $flatCodeArray)) {
                 $allCodes['Other'][$otherPerm] = array('name' => $otherPerm, 'help' => null, 'sort' => 0);
             }
         }
     }
     // Don't let people hijack ADMIN rights
     if (!Permission::check("ADMIN")) {
         unset($allCodes['ADMIN']);
     }
     ksort($allCodes);
     $returnCodes = array();
     foreach ($allCodes as $category => $permissions) {
         if ($grouped) {
             uasort($permissions, array(__CLASS__, 'sort_permissions'));
             $returnCodes[$category] = $permissions;
         } else {
             $returnCodes = array_merge($returnCodes, $permissions);
         }
     }
     return $returnCodes;
 }
 /**
  * Remove invalid records from tables - that is, records that don't have
  * corresponding records in their parent class tables.
  */
 public function cleanup()
 {
     $baseClasses = [];
     foreach (ClassInfo::subclassesFor(DataObject::class) as $class) {
         if (get_parent_class($class) == DataObject::class) {
             $baseClasses[] = $class;
         }
     }
     $schema = DataObject::getSchema();
     foreach ($baseClasses as $baseClass) {
         // Get data classes
         $baseTable = $schema->baseDataTable($baseClass);
         $subclasses = ClassInfo::subclassesFor($baseClass);
         unset($subclasses[0]);
         foreach ($subclasses as $k => $subclass) {
             if (!DataObject::getSchema()->classHasTable($subclass)) {
                 unset($subclasses[$k]);
             }
         }
         if ($subclasses) {
             $records = DB::query("SELECT * FROM \"{$baseTable}\"");
             foreach ($subclasses as $subclass) {
                 $subclassTable = $schema->tableName($subclass);
                 $recordExists[$subclass] = DB::query("SELECT \"ID\" FROM \"{$subclassTable}\"")->keyedColumn();
             }
             foreach ($records as $record) {
                 foreach ($subclasses as $subclass) {
                     $subclassTable = $schema->tableName($subclass);
                     $id = $record['ID'];
                     if ($record['ClassName'] != $subclass && !is_subclass_of($record['ClassName'], $subclass) && isset($recordExists[$subclass][$id])) {
                         $sql = "DELETE FROM \"{$subclassTable}\" WHERE \"ID\" = ?";
                         echo "<li>{$sql} [{$id}]</li>";
                         DB::prepared_query($sql, [$id]);
                     }
                 }
             }
         }
     }
 }
 public function testWriteToDataObject()
 {
     $obj = new MoneyTest_DataObject();
     $m = new DBMoney();
     $m->setValue(array('Currency' => 'EUR', 'Amount' => 1.23));
     $obj->MyMoney = $m;
     $obj->write();
     $this->assertEquals('EUR', DB::query(sprintf('SELECT "MyMoneyCurrency" FROM "MoneyTest_DataObject" WHERE "ID" = %d', $obj->ID))->value());
     $this->assertEquals('1.23', DB::query(sprintf('SELECT "MyMoneyAmount" FROM "MoneyTest_DataObject" WHERE "ID" = %d', $obj->ID))->value());
 }
 public function testSavingIntoTextField()
 {
     $field = new CheckboxSetField('Content', 'Content', array('Test' => 'Test', 'Another' => 'Another', 'Something' => 'Something'));
     $article = new CheckboxSetFieldTest_Article();
     $field->setValue(array('Test' => 'Test', 'Another' => 'Another'));
     $field->saveInto($article);
     $article->write();
     $dbValue = DB::query(sprintf('SELECT "Content" FROM "CheckboxSetFieldTest_Article" WHERE "ID" = %s', $article->ID))->value();
     // JSON encoded values
     $this->assertEquals('["Test","Another"]', $dbValue);
 }
 public function testDeleteFromStage()
 {
     $page1 = $this->objFromFixture('VersionedTest_DataObject', 'page1');
     $pageID = $page1->ID;
     $page1->Content = 'orig';
     $page1->write();
     $page1->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
     $this->assertEquals(1, DB::query('SELECT COUNT(*) FROM "VersionedTest_DataObject" WHERE "ID" = ' . $pageID)->value());
     $this->assertEquals(1, DB::query('SELECT COUNT(*) FROM "VersionedTest_DataObject_Live" WHERE "ID" = ' . $pageID)->value());
     $page1->deleteFromStage('Live');
     // Confirm that deleteFromStage() doesn't manipulate the original record
     $this->assertEquals($pageID, $page1->ID);
     $this->assertEquals(1, DB::query('SELECT COUNT(*) FROM "VersionedTest_DataObject" WHERE "ID" = ' . $pageID)->value());
     $this->assertEquals(0, DB::query('SELECT COUNT(*) FROM "VersionedTest_DataObject_Live" WHERE "ID" = ' . $pageID)->value());
     $page1->delete();
     $this->assertEquals(0, $page1->ID);
     $this->assertEquals(0, DB::query('SELECT COUNT(*) FROM "VersionedTest_DataObject" WHERE "ID" = ' . $pageID)->value());
     $this->assertEquals(0, DB::query('SELECT COUNT(*) FROM "VersionedTest_DataObject_Live" WHERE "ID" = ' . $pageID)->value());
 }
 /**
  * Test that passwords validate against NZ e-government guidelines
  *  - don't allow the use of the last 6 passwords
  *  - require at least 3 of lowercase, uppercase, digits and punctuation
  *  - at least 7 characters long
  */
 public function testValidatePassword()
 {
     $member = $this->objFromFixture('SilverStripe\\Security\\Member', 'test');
     $this->assertNotNull($member);
     Member::set_password_validator(new MemberTest_PasswordValidator());
     // BAD PASSWORDS
     $valid = $member->changePassword('shorty');
     $this->assertFalse($valid->valid());
     $this->assertContains("TOO_SHORT", $valid->codeList());
     $valid = $member->changePassword('longone');
     $this->assertNotContains("TOO_SHORT", $valid->codeList());
     $this->assertContains("LOW_CHARACTER_STRENGTH", $valid->codeList());
     $this->assertFalse($valid->valid());
     $valid = $member->changePassword('w1thNumb3rs');
     $this->assertNotContains("LOW_CHARACTER_STRENGTH", $valid->codeList());
     $this->assertTrue($valid->valid());
     // Clear out the MemberPassword table to ensure that the system functions properly in that situation
     DB::query("DELETE FROM \"MemberPassword\"");
     // GOOD PASSWORDS
     $valid = $member->changePassword('withSym###Ls');
     $this->assertNotContains("LOW_CHARACTER_STRENGTH", $valid->codeList());
     $this->assertTrue($valid->valid());
     $valid = $member->changePassword('withSym###Ls2');
     $this->assertTrue($valid->valid());
     $valid = $member->changePassword('withSym###Ls3');
     $this->assertTrue($valid->valid());
     $valid = $member->changePassword('withSym###Ls4');
     $this->assertTrue($valid->valid());
     $valid = $member->changePassword('withSym###Ls5');
     $this->assertTrue($valid->valid());
     $valid = $member->changePassword('withSym###Ls6');
     $this->assertTrue($valid->valid());
     $valid = $member->changePassword('withSym###Ls7');
     $this->assertTrue($valid->valid());
     // CAN'T USE PASSWORDS 2-7, but I can use pasword 1
     $valid = $member->changePassword('withSym###Ls2');
     $this->assertFalse($valid->valid());
     $this->assertContains("PREVIOUS_PASSWORD", $valid->codeList());
     $valid = $member->changePassword('withSym###Ls5');
     $this->assertFalse($valid->valid());
     $this->assertContains("PREVIOUS_PASSWORD", $valid->codeList());
     $valid = $member->changePassword('withSym###Ls7');
     $this->assertFalse($valid->valid());
     $this->assertContains("PREVIOUS_PASSWORD", $valid->codeList());
     $valid = $member->changePassword('withSym###Ls');
     $this->assertTrue($valid->valid());
     // HAVING DONE THAT, PASSWORD 2 is now available from the list
     $valid = $member->changePassword('withSym###Ls2');
     $this->assertTrue($valid->valid());
     $valid = $member->changePassword('withSym###Ls3');
     $this->assertTrue($valid->valid());
     $valid = $member->changePassword('withSym###Ls4');
     $this->assertTrue($valid->valid());
     Member::set_password_validator(null);
 }
 public function testForceInsert()
 {
     /* If you set an ID on an object and pass forceInsert = true, then the object should be correctly created */
     $conn = DB::get_conn();
     if (method_exists($conn, 'allowPrimaryKeyEditing')) {
         $conn->allowPrimaryKeyEditing('DataObjectTest_Team', true);
     }
     $obj = new DataObjectTest_SubTeam();
     $obj->ID = 1001;
     $obj->Title = 'asdfasdf';
     $obj->SubclassDatabaseField = 'asdfasdf';
     $obj->write(false, true);
     if (method_exists($conn, 'allowPrimaryKeyEditing')) {
         $conn->allowPrimaryKeyEditing('DataObjectTest_Team', false);
     }
     $this->assertEquals("DataObjectTest_SubTeam", DB::query("SELECT \"ClassName\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = {$obj->ID}")->value());
     /* Check that it actually saves to the database with the correct ID */
     $this->assertEquals("1001", DB::query("SELECT \"ID\" FROM \"DataObjectTest_SubTeam\" WHERE \"SubclassDatabaseField\" = 'asdfasdf'")->value());
     $this->assertEquals("1001", DB::query("SELECT \"ID\" FROM \"DataObjectTest_Team\" WHERE \"Title\" = 'asdfasdf'")->value());
 }
 public function testLazyLoadedFieldsDoNotReferenceVersionsTable()
 {
     // Save another record, sanity check that we're getting the right one
     $obj2 = new VersionedTest_Subclass();
     $obj2->Name = "test2";
     $obj2->ExtraField = "foo2";
     $obj2->write();
     $obj1 = new VersionedLazySub_DataObject();
     $obj1->PageName = "old-value";
     $obj1->ExtraField = "old-value";
     $obj1ID = $obj1->write();
     $obj1->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
     $obj1 = VersionedLazySub_DataObject::get()->byID($obj1ID);
     $this->assertEquals('old-value', $obj1->PageName, "Correct value on base table when fetching base class");
     $this->assertEquals('old-value', $obj1->ExtraField, "Correct value on sub table when fetching base class");
     $obj1 = VersionedLazy_DataObject::get()->byID($obj1ID);
     $this->assertEquals('old-value', $obj1->PageName, "Correct value on base table when fetching sub class");
     $this->assertEquals('old-value', $obj1->ExtraField, "Correct value on sub table when fetching sub class");
     // Force inconsistent state to test behaviour (shouldn't select from *_versions)
     DB::query(sprintf("UPDATE \"VersionedLazy_DataObject_versions\" SET \"PageName\" = 'versioned-value' " . "WHERE \"RecordID\" = %d", $obj1ID));
     DB::query(sprintf("UPDATE \"VersionedLazySub_DataObject_versions\" SET \"ExtraField\" = 'versioned-value' " . "WHERE \"RecordID\" = %d", $obj1ID));
     $obj1 = VersionedLazySub_DataObject::get()->byID($obj1ID);
     $this->assertEquals('old-value', $obj1->PageName, "Correct value on base table when fetching base class");
     $this->assertEquals('old-value', $obj1->ExtraField, "Correct value on sub table when fetching base class");
     $obj1 = VersionedLazy_DataObject::get()->byID($obj1ID);
     $this->assertEquals('old-value', $obj1->PageName, "Correct value on base table when fetching sub class");
     $this->assertEquals('old-value', $obj1->ExtraField, "Correct value on sub table when fetching sub class");
     // Update live table only to test behaviour (shouldn't select from *_versions or stage)
     DB::query(sprintf('UPDATE "VersionedLazy_DataObject_Live" SET "PageName" = \'live-value\' WHERE "ID" = %d', $obj1ID));
     DB::query(sprintf('UPDATE "VersionedLazySub_DataObject_Live" SET "ExtraField" = \'live-value\' WHERE "ID" = %d', $obj1ID));
     Versioned::set_stage(Versioned::LIVE);
     $obj1 = VersionedLazy_DataObject::get()->byID($obj1ID);
     $this->assertEquals('live-value', $obj1->PageName, "Correct value from base table when fetching base class on live stage");
     $this->assertEquals('live-value', $obj1->ExtraField, "Correct value from sub table when fetching base class on live stage");
 }
 public function testComparisonClauseTextCaseSensitive()
 {
     DB::query("INSERT INTO \"DataQueryTest_F\" (\"MyString\") VALUES ('HelloWorld')");
     $query = new DataQuery('DataQueryTest_F');
     $query->where(DB::get_conn()->comparisonClause('"MyString"', 'HelloWorld', false, false, true));
     $this->assertGreaterThan(0, $query->count(), "Couldn't find MyString");
     $query2 = new DataQuery('DataQueryTest_F');
     $query2->where(DB::get_conn()->comparisonClause('"MyString"', 'helloworld', false, false, true));
     $this->assertEquals(0, $query2->count(), "Found mystring. Shouldn't be able too.");
     $this->resetDBSchema(true);
 }