after looking at the documentation for the built-in CSV importing, it's still not clear to me how to add a custom CsvBulkUploader to ModelAdmin. I see how you can easily add the default uploader and how you can create a custom controller for importing but it's not clear to me how you would add this to a ModelAdmin. I've spent the morning looking through Stack Overflow and the SilverStripe community forums, but haven't been able to find anything yet. Any direction would be greatly appreciated!
I figured it out.
You can add the CSV Bulk Loader to your ModelAdmin by declaring it in $model_importers:
<?php
class PlayerAdmin extends ModelAdmin {
private static $managed_models = array(
'Player'
);
private static $model_importers = array(
'Player' => 'CsvBulkLoader',
);
private static $url_segment = 'players';
}
?>
And as indicated in the CSV Import documentation, you can extend the CsvBulkLoader class. For example:
<?php
class PlayerCsvBulkLoader extends CsvBulkLoader {
public $columnMap = array(
'Number' => 'PlayerNumber',
...
);
public $duplicateChecks = array(
'Number' => 'PlayerNumber'
);
public $relationCallbacks = array(
'Team.Title' => array(
'relationname' => 'Team',
'callback' => 'getTeamByTitle'
)
);
public static function getTeamByTitle(&$obj, $val, $record) {
return FootballTeam::get()->filter('Title', $val)->First();
}
}
?>
In the documentation what wasn't made explicit was that you pull in the new extended Bulk Loader by simply adding it to $model_importers in your ModelAdmin. So now instead of using CsvBulkLoader, you'll be using PlayerCsvBulkLoader. The snippet up top would be revised thusly:
<?php
class PlayerAdmin extends ModelAdmin {
private static $managed_models = array(
'Player'
);
private static $model_importers = array(
'Player' => 'PlayerCsvBulkLoader',
);
private static $url_segment = 'players';
}
?>
Fairly simple. I had tried this approach early on, but had misspelled the name of the subclass!
UPDATE: Just added this to SilverStripe's documentation
Related
I'm trying to use a GridField component for the first time.
I've added an 'Add' button using GridFieldConfig_RecordEditor as followings:
class AdvertisersPage extends Page
{
//...
public function getCMSFields()
{
$fields = parent::getCMSFields();
$advertiserAccounts = AdvertiserAccount::get();
$fields->addFieldToTab('Root.Advertisers',
$gridField = new GridField(
'Advertisers',
'All advertisers',
$this->Advertisers(),
GridFieldConfig_RecordEditor::create()
)
);
return $fields;
}
}
But the button doesn't do anything besides changing the URL in the browser from
admin/pages/edit/show/7
to
admin/pages/edit/EditForm/7/field/Advertisers/item/new
Here is the related DataObject class:
class AdvertiserAccount extends DataObject
{
//...
private static $has_one = [
'AdvertisersPage' => AdvertisersPage::class,
];
public function getCMSFields()
{
$fields = FieldList::create(
TextField::create('contactNumber'),
TextField::create('nickname')
);
return $fields;
}
}
I need your advice on what should I look at to fix the issue.
It is an extremely strange bug.
I've made some experiments and renamed the related classes. I found that the problem only appears when first GridField constructor parameter name is one of the followings: 'Adv', 'Advert', 'Advertise', 'Advertiser' and 'Advertisers'. In the project, I haven't got any classes with such names. Full-text search through all the project's files hasn't gave any results.
So, I've solved the problem just by renaming the parameter, but what was that?
I've created a module that overrides an AdminProductController.php and make a new bulk_action.
<?php
class AdminProductsController extends AdminProductsControllerCore
{
public function __construct()
{
parent::__construct();
$this->bulk_actions['setprice'] = array(
'text' => $this->l('Set a price for selected'),
'icon' => 'icon-price',
);
}
}
Now I need to translate the action text and distribute that translation with module.
The problem is that I don't see the original text inside modules translation instead it is visible in back-office translations.
So, is there any way to add this string to module translations not to back-office translations?
You can do it by creating an instance of a module you want the translation to be in.
class AdminProductsController extends AdminProductsControllerCore
{
public function __construct()
{
parent::__construct();
$module = Module::getInstanceByName('modulename');
$this->bulk_actions['setprice'] = array(
'text' => $module->l('Set a price for selected'),
'icon' => 'icon-price',
);
}
}
The main problem description I've found here: How to get translation from other module in PrestaShop?
This is because translations controller scans for $this->l((.*)) inside module folder using regex and adds the translatable strings to a file
So we should in module do something like this:
class MyModule extends Module
{
public static $l = null;
public function __construct()
{
parent::__construct();
$this::$l = $this->l('Set a price for selected');
}
}
Than in controller we can do what was suggested by #TheDrot:
class AdminProductsController extends AdminProductsControllerCore
{
public function __construct()
{
parent::__construct();
$module = Module::getInstanceByName('modulename');
$this->bulk_actions['setprice'] = array(
'text' => $module->l('Set a price for selected'),
'icon' => 'icon-price',
);
}
}
Try using the following code in place of $this->l('Set a price for selected')
Translate::getModuleTranslation(YOUR_MODULE_NAME, 'Set a price for selected', FILE_NAME);
I've been trying to make an extension to add some function to the CMS. As it's a setting for the CMS I've added it to the settings tab. While I can take values and save them I needed an action on the page to synchronise a system and I can't get my action to be called, here is my code.
private static $db = array(
'Path' => 'Varchar(50)',
);
private static $allowed_actions = array (
'update',
);
public function updateCMSFields(FieldList $fields)
{
$fields->addFieldsToTab('Root.Importer', array(
ImporterPathField::create('Path', 'Path')->setDescription('Path to area'),
FormAction::create('update', 'Synchronise')
));
}
public function update() {
SS_Log::add_writer(new SS_LogEmailWriter('test#example.com'), SS_Log::ERR);
}
It doesn't get called. If I need to add the function to the left nav rather than part of the settings I'm ok with that too but I also tried that with even less success. Is it possible to get the action called on button press?
You need to place the $allowed_actions and the update method in an extension for CMSSettingsController. Also you should probably put the FormAction into the CMSActions list.
Here's how I would do this:
SiteConfigExtension.php
class SiteConfigExtension extends DataExtension
{
private static $db = array(
'Path' => 'Varchar(50)',
);
public function updateCMSFields(FieldList $fields)
{
$fields->addFieldsToTab('Root.Importer', array(
ImporterPathField::create('Path', 'Path')->setDescription('Path to area')
));
}
public function updateCMSActions(FieldList $actions)
{
$actions->push(
FormAction::create('update', 'Synchronise')
);
}
}
CMSSettingsControllerExtension.php
class CMSSettingsControllerExtension extends DataExtension
{
private static $allowed_actions = array (
'update',
);
public function update() {
SS_Log::add_writer(new SS_LogEmailWriter('test#example.com'), SS_Log::ERR);
}
}
I'm wanting to extend an existing Silverstripe module (Swipestripe) where Attribute has_many Options.
The following code successfully extends Option so a Cost is added to each Option.
class OptionCost extends DataExtension {
private static $db = array(
'Cost' => 'Decimal(19,4)'
);
public function getCMSFields() {
$fields = parent::getCMSFields();
$fields->addFieldToTab('Root.Main', new PriceField('Cost'));
return $fields;
}
}
However when viewing the options via the parent Attribute the Cost is not display. This is controlled via the $summary_fields static but I can't work how to add Cost as a new summary field.
I've tried adding the following code to OptionCost, and to an extension of Attribute - but neither method worked.
private static $summary_fields = array(
'Cost' => 'Cost'
);
What is the correct approach to add Cost to the summary_fields table?
Thank you in advance for any advice.
In Silverstripe 3.1 adding fields to $summary_fields in the extension is the correct way to do this.
The following code worked for me:
class OptionCost extends DataExtension {
private static $db = array(
'Cost' => 'Decimal(19,4)'
);
private static $summary_fields = array(
'Cost'
);
public function getCMSFields() {
$fields = parent::getCMSFields();
$fields->addFieldToTab('Root.Main', new PriceField('Cost'));
return $fields;
}
}
Declare the extension in your config or in a config yaml file.
config.yml
...
Attribute:
extensions:
- OptionCost
...
Run a dev/build?flush=all.
Also make sure you call ?flush=all on your admin page.
I am trying to create a tree of pages using PHP Active Record and I seem to be having trouble getting it setup to work correctly.
Here is the code I am using for the Page class:
class Page extends ActiveRecord\Model {
static $belongs_to = array(array('parent_page', 'class_name' => 'Page'));
static $has_many = array(
array('pages')
);
public static function get_top_level_pages() {
return Page::all(array('conditions' => 'parent_page_id = 0'));
}
}
My database table called Pages has the following columns inside:
id
parent_page_id
type
title
meta_title
content
Does anyone know what I am doing wrong here?
I am not sure if this is the "most correct" way to link a class to itself, but it seems to work for me.
First I changed the parent_page_id in the table to just be page_id and I made the class come together by using the following class:
class Page extends ActiveRecord\Model {
static $has_many = array(
array('pages')
);
static $belongs_to = array(array('page', 'class_name' => 'Page'));
public static function get_top_level_pages() {
return Page::all(array('conditions' => 'page_id = 0'));
}
public function get_parent() {
return $this->page;
}
public function get_children() {
return $this->pages;
}
}
I created the get_parent() and get_children() functions because ->page and ->pages did not make sense to me and the functions help clear that up.
I am open to a better or "more correct" solution.
JP
I was also struggling with this (annoying issue).
You where missing the foreign_key (this will simply point to your column name).
I've modified your code and pasted it here below:
class Page extends ActiveRecord\Model {
//make sure that you define the 'foreign_key'
static $belongs_to = array(
array('parent_page', 'class_name' => 'Page', 'foreign_key' => 'parent_page_id')
);
static $has_many = array(
array('pages')
);
public static function get_top_level_pages() {
return Page::all(array('conditions' => 'parent_page_id = 0'));
}
}
$parent_page = Page::find(20)->parent_page; // this works fine