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


8

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

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

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

回答:


3

チャーリーの答えに基づいて、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に投稿しました 。


カーディナリティが無制限のカスタムフィールドに上記のコードを適合させたところ、うまく機能しました。コアロジックに加えた唯一の変更は、使用する前に$ numbtoaddから1を引くことでした。これはゼロベースであるため、items_countが過小評価されているためだと思いますか?
Dave Bruns、

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

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


こんにちはチャーリー、私もあなたが説明したトリックについて考えましたが、ユーザーがフィールドを並べ替えようとすると、事態はさらに悪化します(私の場合、それは重要な要件です)。ドラッグアンドドロップで100フィールドの1つを並べ替えようとすると、ブラウザーが永久にハングします...
Timur Kamanin

ファイルフィールドまたはテキストフィールドの並べ替えのみでハングアップしますか?draggable.jsは何もサーバーに送り返すのではなく、行の変更をリッスンし、非表示の入力フィールドを更新するだけなので、これは奇妙に思われます。また、どのブラウザとバージョンで問題が発生していますか?ここで発見したことは、他の多くのユーザーに役立つと思います。
チャーリーシュリーサー

はい、draggable.jsがハングする再現可能なユースケースがある場合、コアの問題が発生します。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.