How to customize Silverstripe 3.0 ModelAdmin - php

I'd like to do a number of small customizations on the ModelAdmin.
I'd like to change the text on the 'Add' button to one that is different from the original DataModel.
I have a has_many relationship. I'd like to hide the ability to 'link to existing' so that one cannot search for other 'skills' as per below.
I have the following in the Model:
public function getCMSFields() {
...
$characterSkillsField = new GridField(
'CharacterSkills',
'Character Skills',
$this->CharacterSkills(),
GridFieldConfig_RelationEditor::create()
);
$fields->addFieldToTab('Root.CharacterSkills', $characterSkillsField);
...
}
ANSWER to #2:
// Add the relation editor.
$config = GridFieldConfig_RelationEditor::create();
// Remove the ability to search and link to other skills.
$config->removeComponentsByType('GridFieldAddExistingAutocompleter');
$characterSkillsField = new GridField(
'CharacterSkills',
'Character Skills',
$this->CharacterSkills(),
$config
);

regarding #1:
add the following to the model class that's managed by the GridField (e.g. 'CharacterSkill') :
private static $singular_name = 'foo';
private static $plural_name = 'bar';
don't forget flushing the cache afterwards (add '?flush=All' to the url).
the preceding will set the button name to 'Add foo', but it's also possible to set your very own button title, using the following:
$config = GridFieldConfig_RelationEditor::create();
$addButton = $config->getComponentByType('GridFieldAddNewButton');
$addButton->setButtonName('my button name');

Related

SilverStripe 4.0.0 GridFieldConfig_RelationEditor: adding relations to an object on creation time doesn't work

I have two different data objects (StockExchangeShare and NewsArticle) which are linked with a many_many relation.
In NewsArticle.php:
private static $many_many = [
'Shares' => StockExchangeShare::class
];
In StockExchangeShare.php:
private static $belongs_many_many = [
'NewsArticles' => NewsArticle::class
];
When adding a new news article, the user should be able to link some existing stock exchange shares to the new article. This should be done using a GridField with the config 'GridFieldConfig_RelationEditor'.
Currently, this only works after a news article has already been created. I can't add shares via the grid field to a new (not saved) article. This is the error message:
E_RECOVERABLE_ERROR: Argument 1 passed to SilverStripe\ORM\DataList::subtract() must be an instance of SilverStripe\ORM\DataList, instance of SilverStripe\ORM\UnsavedRelationList given, called in /vendor/silverstripe/framework/src/Forms/GridField/GridFieldAddExistingAutocompleter.php on line 247
Here's the code I used to create the grid field:
$gridFieldConfig = GridFieldConfig_RelationEditor::create();
$gridFieldConfig->removeComponentsByType(GridFieldAddNewButton::class);
$gridFieldConfig->getComponentByType(GridFieldAddExistingAutocompleter::class)->setSearchFields(array('name', 'tickerSymbol', 'isin', 'wpknr'));
$gridFieldConfig->getComponentByType(GridFieldAddExistingAutocompleter::class)->setResultsFormat('$name | $isin');
$fields->addFieldsToTab('Root.Main', [
GridField::create(
'Shares',
'Shares',
$this->Shares(),
$gridFieldConfig
),
]);
Is this a problem with SilverStripe or did I do something wrong?
This is the same behaviour in SilverStripe 3 too. Normally what I've done is to check if the record is saved before you display the GridField, otherwise add a message saying it'll be available when you've saved it.
public function updateCMSFields(FieldList $fields)
{
if (!$this->owner->isInDB()) {
$fields->addFieldToTab('Root.Main', LiteralField::create('Please note: you can modify relations when this item has been saved.'));
return;
}
// add your GridField now
}

SilverStripe change field label from parent class

Within SiteConfig there is a TextField Site title. I'm trying to change the label of this textfield $titleField through a SiteConfig extension in class SiteConfigExtension extends DataExtension.
Here is the code from siteconfig/code/model/ where it's created:
$fields = new FieldList(
new TabSet("Root",
$tabMain = new Tab('Main',
$titleField = new TextField("Title", _t('SiteConfig.SITETITLE', "Site title")),
....
Q: What's the easiest way to replace the SiteTitle label without having to remove the field in the SiteConfig extension and re-add it again with the desired label?
You could make use of the implemented _t() function. Put following in your mysite/lang/{LANG_CODE}.yml file:
{LANG_CODE}:
SiteConfig:
SITETITLE: 'My new title'
Replace {LANG_CODE} with the admin language(s) being used (eg sv for Swedish, or en for English). Keeping your strings separated from the code comes with many benefits. Remember to run ?flush after updating YAML files.
https://docs.silverstripe.org/en/3.4/developer_guides/i18n/
Updating the title from SiteConfigExtension uses updateCMSFields...
class SiteConfigExtension extends DataExtension {
public function updateCMSFields(FieldList $fields) {
if ($titleField = $fields->dataFieldByName('Title'))
$titleField->setTitle('my title');
}
}

SilverStripe Fluent field icons

In the back-end, the SilverStripe Fluent module adds a green flag icon to indicate the field is translatable (as seen next to PageName, URL Segment and Content).
This is a userfriendly detail and I would expect it work for custom added CMS Fields which are made translatable. For example, I've added a custom field named Introduction and made it translatable using: private static $translate = array( 'Introduction' ); But there is no green icon next to it. Can this be added?
It was necessary to add $this->beforeUpdateCMSFields(function($fields) { ... } BEFORE $fields = parent::getCMSFields(); and put all translatable fields in there like so:
function getCMSFields() {
//This needs to be added for Fluent to apply css
$this->beforeUpdateCMSFields(function($fields) {
//Translatable field
$fields->addFieldToTab("Root.Main", new TextAreaField('Introduction','Introduction'), 'Content');
});
$fields = parent::getCMSFields();
//Non-translatable field
$fields->addFieldToTab("Root.Main", $uploadField = new UploadField('Slideshow', 'Slideshow Images'), 'Content');
return $fields;
}

Seed Silverstripe database

Is it possible to "seed" a database like you can in rails? I want to use a seed in combination with an imageobject manager so that I can get records by title.
Based on your comment left on Ingo's answer, you want to add a requireDefaultRecords() method to your page class.
The below is from a recent project and ensures there is a particular user group, but you can do the same with any type of DataObject (e.g. Page).
public function requireDefaultRecords() {
// Make sure there is a readers security group
$group = Group::get('Group')->filter('Code', 'readers')
if ( !$group->exists() ) {
$group = Group::create(array('Title' => 'Readers'));
$group->write();
}
}
This function is run on all DataObject classes when you do a build.
You can set the default values of your page $db variables by setting the $defaults array.
class Page extends SiteTree {
public static $db = array(
'Title' => 'Text',
'Description' => 'Text'
);
public static $defaults = array(
'Title' => 'Default Title',
'Description' => 'Default Description'
);
...
}
Not quite sure what you mean by "seed" in this context. There's a "data-generator" module which writes random data with educated guesses on the ORM column types.

Silverstripe page relation in different languages

I have created a Link DataObject to automatically let users create a reference to a different page in the Frontend. I use two languages in the frontend, German and English. In the popup I create a dropdown to select the pages
public function getCMSFields_forPopup()
{
return new FieldSet(
new TextField('Titel'),
new TextField('URL', 'Externer Link'),
new SimpleTreeDropdownField('PageLinkID', 'Interner Link', 'SiteTree')
);
}
But I only get the German pages in the dropdown. Tried to change the admin language to English but no change. The database seems to only return the German pages...
Any clue?
Edit: I did some more digging and found out how to do this. You need to call "disable_locale_filter" before you get your SiteTree objects:
Translatable::disable_locale_filter();
Then call "enable_locale_filter" once you've retrieved them:
Translatable::enable_locale_filter();
These are other approaches which I'll leave here as I think they are still useful...
I believe you may have to do this using Translatable::get_by_locale() - I assume you only want people to be able to select a page to link to within their language??
Perhaps something like this?
public function getCMSFields_forPopup()
{
$member = Member::currentUser();
if($member && $member->Locale) {
$pagesByLocale = Translatable::get_by_locale('SiteTree', $member->Locale);
$pagesByLocale = $pagesByLocale->map('ID', 'Title', '(Select one)', true);
return new FieldSet(
new TextField('Title'),
new TextField('URL', 'Externer Link'),
new DropdownField('PageLinkID', 'Interner Link', $pagesByLocale);
);
} else {
// Handle non-member
}
}
Edit: see comments below but another option is to use the Translatable::get_current_locale() function to find all pages in the Site Tree for that locale... if the user is viewing an english page then the locale should be set to english etc...
public function getCMSFields_forPopup()
{
$pagesByLocale = Translatable::get_by_locale('SiteTree', Translatable::get_current_locale());
$pagesByLocale = $pagesByLocale->map('ID', 'Title', '(Select one)', true);
return new FieldSet(
new TextField('Title'),
new TextField('URL', 'Externer Link'),
new DropdownField('PageLinkID', 'Interner Link', $pagesByLocale);
);
}
You can also get the locale from the current page e.g.
$this->Locale; // From within the model
$this->dataRecord->Locale; // from within the controller
Director::get_current_page()->Locale; // If you're outside the context of the page altogether i.e. code inside your DataObject.

Categories