helenclarko
helenclarko

Reputation: 269

Export products table via CSV in CMS

Ive been trying to extend ProductCatalogAdmin, because thats the ModelAdmin that holds the Products I want to export. The code below works fine when added to core code (Which I don't want to do), but fails to do anything when added as an Extension.

PHP

<?php

class ProductCatalogAdminExtension extends DataExtension {

    public function getExportFields() {
            return array(
                'ID' => 'ID',
                'InternalItemID' => 'InternalItemID',
                'Model' => 'Model',
                'Content' => 'Content',
                'CostPrice' => 'CostPrice',
                'BasePrice' => 'BasePrice',
                'Weight' => 'Weight',
                'Height' => 'Height',
                'Width' => 'Width',
                'Depth' => 'Depth',
                'Featured' => 'Featured',
                'AllowPurchase' => 'AllowPurchase',
                'Popularity' => 'Popularity',
                'PromoActive' => 'PromoActive',
                'PromoDisplay' => 'PromoDisplay',
                'PromoType' => 'PromoType',
                'PromoAmount' => 'PromoAmount',
                'PromoPercent' => 'PromoPercent',
                'PromoStartDate' => 'PromoStartDate',
                'PromoEndDate' => 'PromoEndDate',
                'Image.URL' => 'Image',
                'WholesalePrice' => 'WholesalePrice',
                'ParentID' => 'ParentID',
                'ProductCategory.ID' => 'AdditionalCategories'
            );
    }

}

YML

---
Name: mysite
After:
  - 'framework/*'
  - 'cms/*'
---
# YAML configuration for SilverStripe
# See http://doc.silverstripe.org/framework/en/topics/configuration
# Caution: Indentation through two spaces, not tabs
SSViewer:
  theme: 'simple'
SiteConfig:
  extensions:
    - SiteConfigExtension
ProductCatalogAdmin:
  extensions:
    - ProductCatalogAdminExtension

I've been told, ModelAdmin's getExportFields() doesn't have an extend() call, so I'll have to use inheritance rather than an Extension. However doing it under inheritance for ModelAdmin seems to do nothing also. Interestingly I get no error messages, it doesn't really fail.

Upvotes: 2

Views: 336

Answers (2)

bummzack
bummzack

Reputation: 5875

You could subclass the ProductCatalogAdmin and use Injector, as pointed out by wmk, but you can also use an Extension instead. This works for any ModelAdmin setup:

<?php
class CustomExportExtension extends Extension
{
    private $exportFields = [
        'ID' => 'ID',
        'Reference' => 'Order Number',
        // … all your other fields
    ];

    public function updateEditForm($form) {
        // Get the gridfield for the model we want, in this case 'Product'
        if ($gridField = $form->Fields()->fieldByName('Product')) {
            // Get the export button instance from the GridField config
            if ($exportButton = $gridField->getConfig()->getComponentByType(GridFieldExportButton::class)) {
                // Apply custom export columns to the export button
                $exportButton->setExportColumns($this->exportFields);
            }
        }
    }
}

Then just apply the extension to ProductCatalogAdmin, as you did via YML:

ProductCatalogAdmin:
  extensions:
    - CustomExportExtension

You could also rewrite the Extension to be more flexible and re-usable for any ModelAdmin, by making the exportFields part of the DataObject config the extension is being attached to. But for a single use-case like yours the above works just fine.

A reusable approach

Here's a slightly modified Version of the above extension that can be used to configure the export fields on any ModelAdmin, without having to create multiple Extensions.

<?php
class CustomExportExtension extends Extension
{
    private $modelClass = null;

    public function updateEditForm($form)
    {
        // Get the gridfield for the current model
        if ($gridField = $form->Fields()->fieldByName($this->modelClass)) {
            // Get the export button instance from the gridfield config
            if ($exportButton = $gridField->getConfig()->getComponentByType(GridFieldExportButton::class)) {
                // Look for custom exportFields config
                $exportFields = Config::inst()->get($this->modelClass, 'exportFields');
                // If custom exportFields aren't set, fall back to summaryfields
                if (!$exportFields || !is_array($exportFields)) {
                    $exportFields = $this->owner->getExportFields();
                }
                $exportButton->setExportColumns($exportFields);
            }
        }
    }

    public function onBeforeInit() {
        // Grab the current model-class from the controller
        $this->modelClass = $this->owner->getRequest()->param('ModelClass');
    }
}

This extension looks for a config setting exportFields on the model that should be exported. If none is given, the default summary_fields are being used.

Here's how you could apply that extension to different ModelAdmins:

# In your YML File
ProductCatalogAdmin:
  extensions:
    - CustomExportExtension

Product:
  exportFields:
    ID: ID
    Model: Model
    # More fields to export

OrdersAdmin:
  extensions:
    - CustomExportExtension

Order:
  exportFields:
    ID: ID
    Reference: 'Order Number'
    # More fields to export

Upvotes: 1

wmk
wmk

Reputation: 4626

yes, you need to subclass ProductCatalogAdmin in this case and tell SilverStripe to use your subclass instead.

class MyProductCatalogAdmin extends ProductCatalogAdmin

    public function getExportFields() {
        //your stuff here
    }
}

And in your config.yml you write:

Injector:
  ProductCatalogAdmin:
    class: MyProductCatalogAdmin

Now when anywhere ProductCatalogAdmin::create() is called, your subclass will be returned by the Injector. It won't work with new ProductCatalogAdmin()

See also Injector Docs

Upvotes: 0

Related Questions