How to add extra summary_field in Silverstripe when extending an object? - php

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.

Related

In Silverstripe 4, a standard "Add" button of a GridField does nothing

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?

Adding Custom CsvBulkUploader to ModelAdmin in Silverstripe

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

PrestaShop: Translating overrided controller

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);

Adding a form action to a config page

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);
}
}

Self-referential Relationships in PHP Active Record

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

Categories