带有无限值字段的慢速“添加其他项目”


8

在Drupal 7中,当节点的字段值不受限制(例如,图像字段)时,添加10至20个项目后,“添加另一个项目”的响应时间将变得非常缓慢。您如何解决这个问题?您遇到过这个问题吗?

我创建了一个项目,在此项目中,用户最多可以添加100个值的图像字段,理论上,该字段具有无限值设置。但是,在添加了十二个图像之后,每次单击“添加其他项目”都会比以前慢。我知道发生这种情况的原因是,在每个ajax请求之后,Drupal都会重建该字段及其所有值,因此,添加的值越多,Drupal在每个“ ajax”请求上要做的工作就越多,但是实际上,这不是很棒的事情。

是否有任何方法可以改变/替代这种行为?

Answers:


3

根据查理(Charlie)的答案,我发现如果要添加1或100个项目,则重新加载块所需的时间大约相同,因此,这是一个技巧,可以在“添加”旁边的表格中添加数字选择列表更多”,因此您可以选择要添加的数量。这样可以节省大量时间,并且仍然很灵活。可以包装到一个小模块中

<?php
/**
* Implements hook_field_attach_form()
*/
function village_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode){
  $options = array('language' => field_valid_language($langcode));
  // Merge default options.
  $default_options = array(
    'default' => FALSE,
    'deleted' => FALSE,
    'language' => NULL,
  );
  $options += $default_options;
  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
  $instances = _field_invoke_get_instances($entity_type, $bundle, $options);
  // Iterate through the instances.
  $return = array();
  foreach ($instances as $instance) {
    // field_info_field() is not available for deleted fields, so use
    // field_info_field_by_id().
    $field = field_info_field_by_id($instance['field_id']);
    $field_name = $field['field_name'];
    //If we are looking at our field type and specific widget type, and we are multiple entries
    if($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED){
      //Check just in case the button is here, and add another #submit function
      if(isset($form[$field['field_name']]['und']['add_more'])){
        // add a simple select list, this defaults to numb 3
        $form[$field['field_name']]['add_more_number'] = array(
          '#type' => 'select',
          '#title' => t('Add more no.'),
          '#options' => drupal_map_assoc(range(0, 50)),
          '#default_value' => 2,
        );
        $form[$field['field_name']]['und']['add_more']['#submit'][] = 'village_field_add_more_submit';
        $form[$field['field_name']]['und']['add_more']['#value'] = 'Add more rows';
      }
    }
  }
}
function village_field_add_more_submit($form, &$form_state){
  $button = $form_state['triggering_element'];
  // Go one level up in the form, to the widgets container.
  $element = drupal_array_get_nested_value($form, array_slice($button['#array_parents'], 0, -1));
  $field_name = $element['#field_name'];
  $langcode = $element['#language'];
  $parents = $element['#field_parents'];
  // Alter the number of widgets to show. items_count = 0 means 1.
  $field_state = field_form_get_state($parents, $field_name, $langcode, $form_state);
  //get the number from the select
  $numbtoadd = $form[$field_name]['add_more_number']['#value'];
  if($numbtoadd){
    $field_state['items_count'] += $numbtoadd;
    field_form_set_state($parents, $field_name, $langcode, $form_state, $field_state);
    $form_state['rebuild'] = TRUE;
  }
}
?>

我还在https://drupal.org/node/1394184#comment-8252701上的Drupal.org上发布了该建议, 其中操作存在类似问题。


我将上面的代码改编为具有无限基数的自定义字段,它对我来说很好用。我对核心逻辑所做的唯一更改是在使用$ numbtoadd之前减去了1。我认为这是因为items_count的表示量不足,因为它是从零开始的?
Dave Bruns 2014年

2

这是一个从形式API的性质反吹,以及它如何使得整个$form$form_state服务器上可用了。尽管有很多原因,但这是一件很酷的事情,尽管我同意从性能角度来看这可能会很烦人。在运行带有PHP-FPM的Apache2的Ubuntu 12.04服务器上的一些统计信息:

  • 我在文件字段中添加了30个项目,一次添加和上传了1个,并且上载+服务器响应+ javascript插入新元素的总时间为414毫秒,每次连续上载的时间从0到20毫秒,结束于旅行次数30的800毫秒。

  • 我单击“添加另一个项目”以无限制地输入文本框100次,总时间从337毫秒增加到1.3秒。如果我的表格比较复杂,这些数字只会增加。

$form_state['fields']['your_field_name']['und']存在所谓的财产items_count。这用于计算应为给定字段显示的字段小部件的数量。我建议您构造字段的窗口小部件之前先hook_field_attach_form()进行更改,$form_state 然后将字段的items_count属性设置为更大的数量,这样就可以立即为您提供所需的字段数量。用户仍然可以添加更多项目。您可能需要找到一种更好的方法来隐藏多余的项目,以免表格长10页;也许一个div overflow: scroll;可以工作。无论如何,这可能是您寻找可以使工作流程加快速度的起点:

function mymodule_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
  $form_state['field']['field_my_field'][$langcode]['items_count'] = 100;
}

编辑:示例代码缺少某些逻辑来确保它仅以适当的形式运行,并且不允许您“添加其他项”。当我在本地有一个更好的工作示例时,我将对此进行修改。


你好,查理,我也想过你描述的技巧,但是当用户想要对字段重新排序时,情况变得更糟(在我的情况下,这是至关重要的要求)。当您尝试通过
拖放

它也仅挂在重新排序文件字段或文本字段上吗?这似乎很奇怪,因为draggable.js不应将任何内容发送回服务器,而只是侦听行更改,然后更新隐藏的输入字段。另外,您遇到了什么浏览器和版本问题?我认为我们在这里发现的任何内容可能对许多其他用户有用。
Charlie Schliesser 2012年

是的,如果您有一个可重用的draggable.js挂起用例,这需要一个核心问题。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.