Lento "Aggiungi un altro oggetto" con campi a valore illimitato


8

In Drupal 7, quando hai un nodo con un campo che ha valori illimitati (diciamo, campo immagine), il tempo di risposta "aggiungi un altro elemento" diventa molto lento dopo aver aggiunto 10-20 elementi. Come combatti questo problema? Hai mai riscontrato questo problema?

Ho creato un progetto, in cui l'utente può aggiungere fino a 100 valori di un campo immagine che in teoria ha un'impostazione di valori illimitata. Ma, dopo aver aggiunto una dozzina di immagini, ogni nuovo clic su "Aggiungi un altro elemento" diventa più lento del precedente. So che questo accade a causa del fatto che Drupal ricostruisce questo campo e tutti i suoi valori dopo ogni richiesta ajax, quindi più valori hai aggiunto più lavoro deve fare Drupal su ogni richiesta "ajax", ma in realtà non lo è cosa abbastanza bella.

Ci sono approcci su come cambiare / scavalcare un simile comportamento?

Risposte:


3

basandomi sulla risposta di Charlie, ho scoperto che ci vuole circa la stessa quantità di tempo per ricaricare il blocco se stai aggiungendo 1 o 100 elementi, quindi ecco un trucco per aggiungere un elenco selezionato di numeri nel modulo accanto a 'aggiungi di piu 'in modo da poter scegliere quanti ne stai aggiungendo. Ciò consente di risparmiare molto tempo ed è ancora flessibile. Potrebbe essere inserito in un piccolo modulo

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

Ho anche pubblicato il suggerimento su Drupal.org all'indirizzo https://drupal.org/node/1394184#comment-8252701 dove l'operazione aveva un problema simile.


Ho adattato il codice sopra per un campo personalizzato con cardinalità illimitata e ha funzionato bene per me. L'unica modifica che ho apportato alla logica principale è stata sottrarre 1 da $ numbtoadd prima di usarlo. Penso che ciò sia dovuto al fatto che items_count è sottorappresentato poiché è basato su zero?
Dave Bruns,

2

È un ritorno alla natura dell'API del modulo e al modo in cui rende l'intero $forme $form_statedisponibile nuovamente sul server. Questa è una cosa interessante per molte ragioni, anche se concordo sul fatto che può essere abbastanza fastidioso dal punto di vista delle prestazioni. Alcune statistiche su un server Ubuntu 12.04 che esegue Apache2 con PHP-FPM:

  • Ho aggiunto 30 elementi in un campo file, aggiungendo e caricando 1 alla volta, e il tempo totale per il caricamento + risposta del server + inserimento javascript del nuovo elemento è passato da 414 millisecondi, aumentando su ogni caricamento successivo da 0-20 millisecondi, che termina a 800 millisecondi per il viaggio numero 30.

  • Ho fatto clic su "Aggiungi un altro elemento" per un campo di testo illimitato 100 volte e il tempo totale è passato da 337 millisecondi a 1,3 secondi. Se la mia forma fosse più complessa, questi numeri aumenterebbero solo.

In $form_state['fields']['your_field_name']['und']esiste una proprietà chiamata items_count. Viene utilizzato per calcolare il numero di widget di campo che devono essere visualizzati per un determinato campo. Ti consiglierei di usare hook_field_attach_form()per modificare $form_state prima che il widget del campo sia costruito e impostare la items_countproprietà del campo su un numero maggiore, dandoti così il numero di campi che ti occorrono immediatamente. L'utente sarà comunque in grado di aggiungere più elementi. Spetta a te trovare un modo migliore per nascondere gli elementi in più dal rendere il modulo lungo 10 pagine; forse un div con overflow: scroll;potrebbe funzionare. Comunque, questo potrebbe essere un punto di partenza per trovare qualcosa che permetta al tuo flusso di lavoro di andare più veloce:

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

Modifica: nel codice di esempio manca un po 'di logica per garantire che venga eseguito solo per il modulo appropriato e che non ti consenta di "aggiungere un altro elemento". Lo revisionerò quando avrò un esempio di lavoro migliore a livello locale.


Ciao Charlie, ho pensato anche al trucco che hai descritto, ma le cose peggiorano quando l'utente vuole riordinare i campi (nel mio caso, è un requisito vitale). Quando provi a riordinare uno dei 100 campi tramite drag'n'drop, il browser si blocca per sempre ...
Timur Kamanin,

Si blocca solo su riordino di campi file o campi di testo? Sembra strano, dal momento che draggable.js non dovrebbe inviare nulla al server, ma solo ascoltare le modifiche delle righe e quindi aggiornare i campi di input nascosti. Inoltre, quale browser e versione stai vivendo? Penso che tutto ciò che scopriamo qui potrebbe essere utile a molti altri utenti.
Charlie Schliesser,

Sì, se hai un caso di utilizzo riproducibile di draggable.js sospeso che richiede un problema di base.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.