Silverstripe 3.2:如何在 CMS 中制作自定义操作按钮以创建新的数据对象并从另一个数据对象填充它

Silverstripe 3.2: How to make a custom action button in the CMS to create a new Dataobject and populate it from another one

我正在寻找一种创建自定义操作按钮的方法,它允许我使用来自另一个 DataObject 的预填充内容创建一个新的 DataObject。举个简单的例子:当我收到一封电子邮件并单击我的电子邮件客户端中的 "answer" 按钮时,我会收到一个新的 window,其中包含之前电子邮件中的预填充内容。我的按钮正是需要这个功能。此按钮应出现在 GridField 中每个 DataObject 的旁边。

所以我知道如何制作一个按钮并将其添加到我的 GridField (--> https://docs.silverstripe.org/en/3.2/developer_guides/forms/how_tos/create_a_gridfield_actionprovider/) 并且我知道如何转到一个新的 DataObject:

Controller::curr()->redirect($gridField->Link('item/new'));

我还发现 DataObjects 有一个重复的函数:

public function duplicate($doWrite = true) {
        $className = $this->class;
        $clone = new $className( $this->toMap(), false, $this->model );
        $clone->ID = 0;

        $clone->invokeWithExtensions('onBeforeDuplicate', $this, $doWrite);
        if($doWrite) {
            $clone->write();
            $this->duplicateManyManyRelations($this, $clone);
        }
        $clone->invokeWithExtensions('onAfterDuplicate', $this, $doWrite);

        return $clone;
    }

也许它比我想象的要容易,但目前我只是不知道如何重写它以获得我需要的东西。有人可以给我提示吗?

这肯定不是最干净的解决方案,但我认为它应该可以解决问题。

首先让我们创建自定义网格字段操作。在这里,我们将在会话中保存所有可访问的记录,并向 url 添加一个查询字符串,以便我们知道我们想要 "clone"

哪个对象
public function getColumnContent($gridField, $record, $columnName) {
    if(!$record->canEdit()) return;

    $field = GridField_FormAction::create(
        $gridField,
        'clone'.$record->ID,
        'Clone',
        'clone',
        array('RecordID' => $record->ID)
    );

    $values = Session::get('ClonedData');
    $data = $record->data()->toMap();

    if($arr = $values) {
        $arr[$record->ID] = $data;
    } else {
        $arr = array(
            $record->ID => $data
        );
    }

    Session::set('ClonedData', $arr);

    return $field->Field();
}

public function getActions($gridField) {
    return array('clone');
}

public function handleAction(GridField $gridField, $actionName, $arguments, $data) {
    if($actionName == 'clone') {
        $id = $arguments['RecordID'];
        Controller::curr()->redirect($gridField->Link("item/new/?cloneID=$id"));
    }
}

将这个新组件添加到我们的网格字段后,

$gridField->getConfig()->addComponent(new GridFieldCustomAction());

我们需要将数据导入新表格。为此,请将此代码直接添加到您的 getCMSFields 函数的 "return $fields" 上方,以便我们每次打开此类对象时都会执行它。

$values = Session::get('ClonedData');

if($values) {
  Session::clear('ClonedData');
  $json = json_encode($values);
  $fields->push(LiteralField::create('ClonedData', "<div id='cloned-data' style='display:none;'>$json</div>"));
}

最后我们需要将内容带回字段中。我们将用一点点 javascript 来做到这一点,所以首先您需要创建一个新的 script.js 文件并将其包含在 ss 后端(或者只使用现有的)。

(function($) {
  $('#cloned-data').entwine({
    onmatch: function() {
      var data = JSON.parse($(this).text()),
          id = getParameterByName('cloneID');

      if(id && data) {
        var obj = data[id];

        if(obj) {
          $.each(obj, function(i, val) {
            $('[name=' + i + ']').val(val);
          });
        }
      }
    }
  });

  // 
  function getParameterByName(name) {
    name = name.replace(/[\[]/, "\[").replace(/[\]]/, "\]");
    var regex = new RegExp("[\?&]" + name + "=([^&#]*)"),
        results = regex.exec(location.search);
    return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
  }
})(jQuery);

就是这样......非常棘手。希望能解决你的问题。