diff --git a/.upgrade.yml b/.upgrade.yml index 59cccbf43..a2d4baa0e 100644 --- a/.upgrade.yml +++ b/.upgrade.yml @@ -1100,6 +1100,32 @@ warnings: 'SilverStripe\Control\Email\Email->setTemplate()': message: 'Renamed to setHTMLTemplate()' replacement: 'setHTMLTemplate' + 'SilverStripe\Control\Email\Email->replyTo()': + message: 'Renamed to setReplyTo()' + replacement: 'setReplyTo' + 'SilverStripe\Control\Email\Email->attachFile()': + message: 'Renamed to addAttachment()' + replacement: 'addAttachment' + 'SilverStripe\Control\Email\Email->Subject()': + message: 'Renamed to getSubject()' + replacement: 'getSubject' + 'SilverStripe\Control\Email\Email->Body()': + message: 'Renamed to getBody()' + replacement: 'getBody' + 'SilverStripe\Control\Email\Email->From()': + message: 'Renamed to getFrom()' + replacement: 'getFrom' + 'SilverStripe\Control\Email\Email->To()': + message: 'Renamed to getTo()' + replacement: 'getTo' + 'SilverStripe\Control\Email\Email->Cc()': + message: 'Renamed to getCc()' + replacement: 'getCc' + 'SilverStripe\Control\Email\Email->Bcc()': + message: 'Renamed to getBcc()' + replacement: 'getBcc' + 'SilverStripe\Control\Email\Email->addCustomHeader()': + message: 'addCustomHeader() is removed' 'SilverStripe\i18n\i18n::get_language_name()': message: 'moved to SilverStripe\i18n\Data\Locales::languageName()' replacement: 'getData()->languageName' diff --git a/src/Dev/CsvBulkLoader.php b/src/Dev/CsvBulkLoader.php index be6ea4c9c..3b95fa2fd 100644 --- a/src/Dev/CsvBulkLoader.php +++ b/src/Dev/CsvBulkLoader.php @@ -76,6 +76,7 @@ class CsvBulkLoader extends BulkLoader $filepath = Director::getAbsFile($filepath); $csvReader = Reader::createFromPath($filepath, 'r'); $csvReader->setDelimiter($this->delimiter); + $csvReader->stripBom(true); $tabExtractor = function ($row, $rowOffset, $iterator) { foreach ($row as &$item) { diff --git a/src/Forms/GridField/GridFieldDataColumns.php b/src/Forms/GridField/GridFieldDataColumns.php index b908dcf4b..fc68a70f3 100644 --- a/src/Forms/GridField/GridFieldDataColumns.php +++ b/src/Forms/GridField/GridFieldDataColumns.php @@ -154,7 +154,7 @@ class GridFieldDataColumns implements GridField_ColumnProvider { // Find the data column for the given named column $columns = $this->getDisplayFields($gridField); - $columnInfo = $columns[$columnName]; + $columnInfo = array_key_exists($columnName, $columns) ? $columns[$columnName] : null; // Allow callbacks if (is_array($columnInfo) && isset($columnInfo['callback'])) { diff --git a/src/Forms/GridField/GridFieldDetailForm_ItemRequest.php b/src/Forms/GridField/GridFieldDetailForm_ItemRequest.php index 63a55f343..1b7896b1a 100644 --- a/src/Forms/GridField/GridFieldDetailForm_ItemRequest.php +++ b/src/Forms/GridField/GridFieldDetailForm_ItemRequest.php @@ -349,17 +349,26 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler */ protected function getFormActions() { - $actions = FieldList::create(); $manager = $this->getStateManager(); + + $actions = FieldList::create(); + $majorActions = CompositeField::create()->setName('MajorActions'); + $majorActions->setFieldHolderTemplate(get_class($majorActions) . '_holder_buttongroup'); + $actions->push($majorActions); + if ($this->record->ID !== 0) { // existing record if ($this->record->canEdit()) { - $actions->push(FormAction::create('doSave', _t('SilverStripe\\Forms\\GridField\\GridFieldDetailForm.Save', 'Save')) + $noChangesClasses = 'btn-outline-primary font-icon-tick'; + $majorActions->push(FormAction::create('doSave', _t('SilverStripe\\Forms\\GridField\\GridFieldDetailForm.Save', 'Save')) + ->addExtraClass($noChangesClasses) + ->setAttribute('data-btn-alternate-add', 'btn-primary font-icon-save') + ->setAttribute('data-btn-alternate-remove', $noChangesClasses) ->setUseButtonTag(true) - ->addExtraClass('btn-primary font-icon-save')); + ->setAttribute('data-text-alternate', _t('SilverStripe\\CMS\\Controllers\\CMSMain.SAVEDRAFT', 'Save'))); } if ($this->record->canDelete()) { - $actions->push(FormAction::create('doDelete', _t('SilverStripe\\Forms\\GridField\\GridFieldDetailForm.Delete', 'Delete')) + $actions->insertAfter('MajorActions', FormAction::create('doDelete', _t('SilverStripe\\Forms\\GridField\\GridFieldDetailForm.Delete', 'Delete')) ->setUseButtonTag(true) ->addExtraClass('btn-outline-danger btn-hide-outline font-icon-trash-bin action--delete')); } @@ -371,7 +380,7 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler $actions->push($this->getRightGroupField()); } else { // adding new record //Change the Save label to 'Create' - $actions->push(FormAction::create('doSave', _t('SilverStripe\\Forms\\GridField\\GridFieldDetailForm.Create', 'Create')) + $majorActions->push(FormAction::create('doSave', _t('SilverStripe\\Forms\\GridField\\GridFieldDetailForm.Create', 'Create')) ->setUseButtonTag(true) ->addExtraClass('btn-primary font-icon-plus-thin')); @@ -385,7 +394,7 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler $oneLevelUp->Link, // url _t('SilverStripe\\Forms\\GridField\\GridFieldDetailForm.CancelBtn', 'Cancel') // label ); - $actions->push(new LiteralField('cancelbutton', $text)); + $actions->insertAfter('MajorActions', new LiteralField('cancelbutton', $text)); } } diff --git a/src/Security/Group.php b/src/Security/Group.php index 403f92819..eb72fbfe3 100755 --- a/src/Security/Group.php +++ b/src/Security/Group.php @@ -83,15 +83,6 @@ class Group extends DataObject private static $table_name = "Group"; - public function populateDefaults() - { - parent::populateDefaults(); - - if (!$this->Title) { - $this->Title = _t(__CLASS__ . '.NEWGROUP', "New Group"); - } - } - public function getAllChildren() { $doSet = new ArrayList(); @@ -105,6 +96,16 @@ class Group extends DataObject return $doSet; } + + private function getDecodedBreadcrumbs() + { + $list = Group::get()->exclude('ID', $this->ID); + $groups = ArrayList::create(); + foreach ($list as $group) { + $groups->push(['ID' => $group->ID, 'Title' => $group->getBreadcrumbs(' » ')]); + } + return $groups; + } /** * Caution: Only call on instances, not through a singleton. @@ -125,7 +126,7 @@ class Group extends DataObject $parentidfield = DropdownField::create( 'ParentID', $this->fieldLabel('Parent'), - Group::get()->exclude('ID', $this->ID)->map('ID', 'Breadcrumbs') + $this->getDecodedBreadcrumbs() )->setEmptyString(' '), new TextareaField('Description', $this->fieldLabel('Description')) ), diff --git a/tests/php/Dev/CsvBulkLoaderTest.php b/tests/php/Dev/CsvBulkLoaderTest.php index 8885e58a9..f00f15f32 100644 --- a/tests/php/Dev/CsvBulkLoaderTest.php +++ b/tests/php/Dev/CsvBulkLoaderTest.php @@ -2,6 +2,7 @@ namespace SilverStripe\Dev\Tests; +use League\Csv\Writer; use SilverStripe\Dev\Tests\CsvBulkLoaderTest\CustomLoader; use SilverStripe\Dev\Tests\CsvBulkLoaderTest\Player; use SilverStripe\Dev\Tests\CsvBulkLoaderTest\PlayerContract; @@ -300,6 +301,20 @@ class CsvBulkLoaderTest extends SapphireTest $this->assertEquals($player->FirstName, "John. He's a good guy. "); } + public function testLoadWithByteOrderMark() + { + $loader = new CsvBulkLoader(Player::class); + $loader->load($this->csvPath . 'PlayersWithHeaderAndBOM.csv'); + + $players = Player::get(); + + $this->assertCount(3, $players); + $this->assertListContains([ + ['FirstName' => 'Jamie', 'Birthday' => '1882-01-31'], + ['FirstName' => 'Järg', 'Birthday' => '1982-06-30'], + ['FirstName' => 'Jacob', 'Birthday' => '2000-04-30'], + ], $players); + } protected function getLineCount(&$file) { diff --git a/tests/php/Dev/CsvBulkLoaderTest/csv/PlayersWithHeaderAndBOM.csv b/tests/php/Dev/CsvBulkLoaderTest/csv/PlayersWithHeaderAndBOM.csv new file mode 100644 index 000000000..93a871931 --- /dev/null +++ b/tests/php/Dev/CsvBulkLoaderTest/csv/PlayersWithHeaderAndBOM.csv @@ -0,0 +1,4 @@ +FirstName,Biography,Birthday,IsRegistered +Jamie,"Pretty old\, with an escaped comma",1882-01-31,1 +Järg,"Unicode FTW",1982-06-30,1 +Jacob," Likes leading tabs in his biography",2000-04-30,0