phpsilverstripesilvershop

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.


Solution

  • 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