1

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

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

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

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

4

1 回答 1

1

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

首先让我们创建自定义网格字段操作。在这里,我们将在会话中保存所有可访问的记录,并将查询字符串添加到 url,以便我们知道要“克隆”哪个对象

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

  // http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript#answer-901144
  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);

就是这样……相当棘手。希望它能解决你的问题。

于 2016-01-28T23:37:06.457 回答