web-dev-qa-db-ja.com

無制限の値フィールドを持つ遅い「別のアイテムの追加」

Drupal 7で、無制限の値を持つフィールド(たとえば、画像フィールド)を持つノードがある場合、10〜20のアイテムを追加した後、「別のアイテムの追加」の応答時間が非常に遅くなります。方法あなたはこの問題と戦っていますか?この問題に遭遇したことがありますか?

私はユーザーが最大100の画像フィールドの値を追加できるプロジェクトを作成しました。理論的には無制限の値設定があります。ただし、数十の画像を追加した後、[別のアイテムを追加]をクリックするたびに、以前よりも遅くなります。 Drupalは、各ajaxリクエストの後にこのフィールドとそのすべての値を再構築するので、これが発生することはわかっています。そのため、追加する値が増えるほど、より多くの作業が必要になりますDrupal =はすべての「ajax」リクエストで実行する必要がありますが、実際には、これはそれほど素晴らしいことではありません。

このような動作を変更/オーバーライドする方法についてのアプローチはありますか?

8
Timur Kamanin

チャーリーの答えに基づいて、1アイテムまたは100アイテムを追加する場合、ブロックをリロードするのとほぼ同じ時間がかかることがわかりました。ここで、「add more 'なので、追加する数を選択できます。これは多くの時間を節約し、まだ柔軟性があります。小さなモジュールにラップすることができます

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

また、提案はDrupal.orgの https://drupal.org/node/1394184#comment-8252701 にも投稿しました。

3
jowan sebastian

これは、フォーム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_を変更することをお勧めしますbeforeフィールドのウィジェットが作成され、フィールドの_items_count_プロパティをより大きな数にして、すぐに必要なフィールドの数を得ることができます。ユーザーは引き続きアイテムを追加できます。フォームを10ページにして、余分なアイテムを隠すより良い方法を見つけるのはあなた次第です。おそらく_overflow: scroll;_のdivが機能する可能性があります。とにかく、これは、ワークフローを高速化できるものを見つけるための出発点になる場合があります。

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

編集:サンプルコードには、適切なフォームでのみ実行され、「別のアイテムを追加」できないようにするロジックがありません。ローカルでより良い動作例があるときに、これを修正します。

2