2017-03-01 127 views
3

我有一个名为EventPage的页面,我通过模型管理员进行管理。还使用目录管理器:https://github.com/littlegiant/silverstripe-catalogmanager如何生成自定义CSV导出?

问题是我需要能够导出所有过期的事件(和所有的字段)。我有一个'EndDate' => 'Date',字段EventPage

所以我只想在我的CSV导出中显示EventDages,其中EndDate是GreaterThanOrEqual到今天的日期,例如Expired。

以下内容会生成一个CSV导出按钮,但目前它会导出所有字段,因为我想对其进行过滤,因此我们只显示过期的事件。

我该如何解决这个问题?

<?php 

class EventAdmin extends CatalogPageAdmin { 

    public $showImportForm = false; 

    private static $managed_models = array(
     'EventPage', 
     'EventCategory', 
     'EventSubmission', 
    ); 

    private static $url_segment = 'events'; 

    private static $menu_title = 'Events'; 


    public function getEditForm($id = null, $fields = null) { 

     $form = parent::getEditForm($id, $fields); 

     $gridFieldName = 'EventPage'; 
     $gridField = $form->Fields()->fieldByName($gridFieldName); 

     if ($gridField) { 
      $gridField->getConfig()->addComponent(new GridFieldExportButton()); 
     } 

     return $form; 
    } 


} 
+0

所以你想两件事情? CSV导出仅包含您想要的字段,并且只在Gridfield上显示一定数量的“EventPages”?我回答了第一个问题,但让我知道如果我理解正确... –

回答

0

你看过GridFieldExportButton这个类吗? 构造

/** 
* @param string $targetFragment The HTML fragment to write the button into 
* @param array $exportColumns The columns to include in the export 
*/ 
public function __construct($targetFragment = "after", $exportColumns = null) { 
    $this->targetFragment = $targetFragment; 
    $this->exportColumns = $exportColumns; 
} 

所以,你应该能够通过$exportColumns作为参数。

在你的代码

这将是

 if ($gridField) { 
     $gridField->getConfig()->addComponent(new GridFieldExportButton("after", ["field1", "field2"])); 
    } 

或者 - 更好的解决方案

你可以EventPage定义汇总字段这样

private static $summary_fields = ["FIeld1", "Field2"]; 

然后确保你的同花和它应该使用它作为字段。

+0

嘿,不是什么即时通讯之后,所以我想导出所有的领域,但只有过期的事件。所以我需要一种方法来添加一些逻辑,说'如果EndDate:GreaterThanOrEqual比今天的日期'生成一个列表,所以我们最终只是过期的事件,而不是所有的事件。希望有道理:) – ifusion

+0

您必须在导出之前过滤ModelAdmin中的列表。请参阅http://stackoverflow.com/a/42450800/4137738作为开始。您需要覆盖您的ModelAdmin的'getList()'方法。 – wmk

+0

你能结合你的答案到一个吗? –

1

这本来是两个答案...

要限制领域

你有没有看看GridFieldExportButton类? 构造

/** 
* @param string $targetFragment The HTML fragment to write the button into 
* @param array $exportColumns The columns to include in the export 
*/ 
public function __construct($targetFragment = "after", $exportColumns = null) { 
    $this->targetFragment = $targetFragment; 
    $this->exportColumns = $exportColumns; 
} 

所以,你应该能够通过$exportColumns作为参数。

在你的代码

这将是

 if ($gridField) { 
     $gridField->getConfig()->addComponent(new GridFieldExportButton("after", ["field1", "field2"])); 
    } 

或者 - 更好的解决方案

你可以EventPage定义汇总字段这样

private static $summary_fields = ["FIeld1", "Field2"]; 

然后确保你的同花和它应该使用它作为字段。

要过滤的CSV出口

因此,在这种情况下,哪个项目,我觉得你应该创建一个扩展GridFieldExportButton一个新的类(也许叫EventPageCSVExportButton或东西),并覆盖您想要的方法。在你的情况下,它可能是generateExportFileData(),只需在循环中检查并排除你不想要的数据。

然后在你的EventAdmin中使用这个新类。

3

我们可以创建一个自定义导出按钮,以在导出项目之前过滤项目列表。

首先我们创建一个GridFieldExportExpiredEventsButton,它延伸GridFieldExportButton。这是当前SilverStripe 3.5 generateExportFileData函数的完整副本,但在$items列表中添加了filterByCallback以筛选具有EndDate < date('Y-m-d')的项目。

class GridFieldExportExpiredEventsButton extends GridFieldExportButton { 

    public function getHTMLFragments($gridField) { 
     $button = new GridField_FormAction(
      $gridField, 
      'export', 
      'Export expired events', 
      'export', 
      null 
     ); 
     $button->setAttribute('data-icon', 'download-csv'); 
     $button->addExtraClass('no-ajax action_export'); 
     $button->setForm($gridField->getForm()); 
     return array(
      $this->targetFragment => '<p class="grid-csv-button">' . $button->Field() . '</p>', 
     ); 
    } 

    public function generateExportFileData($gridField) { 
     $separator = $this->csvSeparator; 
     $csvColumns = $this->getExportColumnsForGridField($gridField); 
     $fileData = ''; 
     $member = Member::currentUser(); 

     if($this->csvHasHeader) { 
      $headers = array(); 

      // determine the CSV headers. If a field is callable (e.g. anonymous function) then use the 
      // source name as the header instead 
      foreach($csvColumns as $columnSource => $columnHeader) { 
       $headers[] = (!is_string($columnHeader) && is_callable($columnHeader)) ? $columnSource : $columnHeader; 
      } 

      $fileData .= "\"" . implode("\"{$separator}\"", array_values($headers)) . "\""; 
      $fileData .= "\n"; 
     } 

     //Remove GridFieldPaginator as we're going to export the entire list. 
     $gridField->getConfig()->removeComponentsByType('GridFieldPaginator'); 

     $items = $gridField->getManipulatedList(); 

     $items = $items->filterByCallback(function($item) { 
      // The following line modifies what items are filtered. Change this to change what items are filtered 
      return $item->EndDate < date('Y-m-d'); 
     }); 

     // @todo should GridFieldComponents change behaviour based on whether others are available in the config? 
     foreach($gridField->getConfig()->getComponents() as $component){ 
      if($component instanceof GridFieldFilterHeader || $component instanceof GridFieldSortableHeader) { 
       $items = $component->getManipulatedData($gridField, $items); 
      } 
     } 

     foreach($items->limit(null) as $item) { 
      if(!$item->hasMethod('canView') || $item->canView($member)) { 
       $columnData = array(); 

       foreach($csvColumns as $columnSource => $columnHeader) { 
        if(!is_string($columnHeader) && is_callable($columnHeader)) { 
         if($item->hasMethod($columnSource)) { 
          $relObj = $item->{$columnSource}(); 
         } else { 
          $relObj = $item->relObject($columnSource); 
         } 

         $value = $columnHeader($relObj); 
        } else { 
         $value = $gridField->getDataFieldValue($item, $columnSource); 

         if($value === null) { 
          $value = $gridField->getDataFieldValue($item, $columnHeader); 
         } 
        } 

        $value = str_replace(array("\r", "\n"), "\n", $value); 
        $columnData[] = '"' . str_replace('"', '""', $value) . '"'; 
       } 

       $fileData .= implode($separator, $columnData); 
       $fileData .= "\n"; 
      } 

      if($item->hasMethod('destroy')) { 
       $item->destroy(); 
      } 
     } 

     return $fileData; 
    } 
} 

我们已经将其过滤出口项目的额外行是:

return $item->EndDate < date('Y-m-d'); 

改变这种改变这种出口的项目清单。我已将此设置为仅返回具有过去的EndDate的项目。根据需要更改此项。

我们再加入这个出口按钮,我们的电网领域在我们的事件模型管理:

class EventAdmin extends CatalogPageAdmin { 

    private static $managed_models = array(
     'EventPage' 
    ); 

    public function getEditForm($id = null, $fields = null) { 
     $form = parent::getEditForm($id); 
     if ($this->modelClass == 'EventPage') { 
      $gridField = $form->Fields()->fieldByName($this->modelClass); 
      $gridField->getConfig()->removeComponentsByType('GridFieldExportButton'); 
      $gridField->getConfig()->addComponent(new GridFieldExportExpiredEventsButton('buttons-before-left')); 
     } 

     return $form; 
    } 
} 
+0

看起来非常有希望,有几个问题,首先它给出了这个错误:'[Recoverable Error]传递给GridFieldConfig :: removeComponent()的参数1必须实现接口GridFieldComponent,null给定' - 我注释掉了这一行:'$ gridField - > getConfig() - > removeComponent($ gridField-> getConfig() - > getComponentByType('GridFieldExportButton'));' - 当点击“导出过期事件”按钮时,它会摆脱错误,然后只导出3项因为它应该出口大约30个货物atm。感谢您的帮助:) – ifusion

+0

我修改了'removeComponent'这一行,希望它对您有用。我还注意到修改项目列表的代码行。修改此行以满足您的需求。在我的示例代码中,我将此行设置为'return $ item-> EndDate 3dgoo

+0

谢谢你,它现在的工作没有得到那个错误,但它仍然只返回CSV内的结果,它应该返回更多。你在'filterByCallback'内的代码应该像你说的那样工作。 Somethings不完全正确,如果我运行一个MySQL查询,如:'SELECT * FROM EventPage WHERE EndDate ifusion