¿Cómo puedo eliminar elementos de la lista de valores permitidos de un campo de selección que tiene datos para los valores?

16

He creado un tipo de contenido que tiene un campo de opción de lista / selección, y he introducido los pares clave | valor según sea necesario para que funcione la lista de selección.

Se ingresaron datos y se decidió que ciertos términos ya no se aplican y que deberían eliminarse.

Sin embargo, cuando intento eliminar dichos términos, aparece el siguiente error:

Allowed values list: some values are being removed while currently in use.

Obviamente, en la vida de un proyecto, los valores van a cambiar. ¿Cuál es una forma práctica de eliminar elementos una vez que los nodos están asociados con los términos enumerados?

Esto es lo más cercano que pude encontrar:

https://drupal.org/node/1653012

Hace referencia a un complemento d6 y algunos trucos de parches que preferiría no tener que recurrir. Si finalmente tuve que recurrir al uso del parche para eliminar la verificación de validación en ese campo, ¿hay algún daño en dejar esos elementos huérfanos en los nodos con los que estaban asociados?

Actualización, me he encontrado nuevamente con este problema con un cliente gubernamental que, durante los últimos 7 años de tener un sitio de Drupal, ha tenido 50 estados y territorios en una lista selecta. Ahora, la política ha cambiado y los territorios ya no necesitan ser incluidos. Poder eliminar elementos de las listas seleccionadas es importante, y por lo tanto estoy ofreciendo una recompensa.

Estoy buscando una solución segura para poder eliminar elementos de una lista seleccionada. Lo que no sé es si esa solución debería actualizar alguno de los nodos, ya que no estoy seguro de cómo se almacenan los valores de campo en relación con el contenido total de un nodo.

Estoy contento con una solución SQL pura para ejecutar en MySQL; o estoy buscando un módulo.

blue928
fuente
3
Obviamente, en la vida de un proyecto, los valores van a cambiar. Discutiría eso: los valores para una lista de selección estática deben definirse al comienzo del proyecto. Si necesita que sea flexible, debe usar una referencia de término en lugar de una lista estática. Las listas estáticas son para cosas como el sexo (masculino / femenino) que, a menos que tengamos un cambio serio en las cosas, no es probable que cambie pronto. Y si lo hace, se agregará , no se eliminará . Siempre que cometí este 'error', siempre encontré que la mejor manera de retroceder es realizar consultas manuales sobre los datos
Clive
1
¿Quieres hacer esta lista dinámica? siendo dinámico en la creación y eliminación.
M ama D
1
Sí, supongo que eso solo depende de la opinión: el fabricante de automóviles siempre sería un tipo de nodo o vocabulario para cualquier sitio que construya. Dado que el fabricante es una categoría de automóvil (o categoría de automóvil que alguien repara), tiene más sentido para mí como una taxonomía que como un tipo de contenido. Pero sé que eso no ayuda ... Sería cauteloso de dejar datos huérfanos en la base de datos, es muy difícil decir qué efecto podría tener sin saber exactamente qué está instalado en su sitio y cómo está configurado
Clive
1
¿Qué hay de malo con views_bulk_operations?
donquixote
1
je, ninguna de estas respuestas tiene votos positivos todavía: /
tenken

Respuestas:

7

Hice algo como esto recientemente con el siguiente enfoque.

  1. Agregue los nuevos valores permitidos.
  2. Agregue una configuración para configurar valores "activos".
  3. Filtre los valores "inactivos" de la pantalla en el formulario.

p.ej:

/**
 * Admin settings form
 */
function MODULE_admin_settings(){

  $form = array();

  // Select active preferences for display
  $field = field_info_field('field_preferences');
  $preferences = list_allowed_values($field);
  $form['field_preferences_active'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Active preferences'),
    '#options' => $preferences,
    '#description' => t('Select the preferences available for user selection.'),
    '#default_value' => variable_get('field_preferences_active', array()),
  );

  return system_settings_form($form);

}

/**
 * Implements hook_field_attach_form
 */
function MODULE_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {

  // Filter out inactive preferences
  if(isset($form['field_preferences'])){
    $preferences = variable_get('field_preferences_active', array());
    foreach($preferences as $key => $preference){
      // If this preference isn't checked, but is set in the field values, unset it.
      if(empty($preference) && isset($form['field_preferences'][LANGUAGE_NONE]['#options'][$key])){
        unset($form['field_preferences'][LANGUAGE_NONE]['#options'][$key]);
      }
    }
  }

}

De esta forma, los datos heredados se conservan como referencia, el formulario se valida y la integridad de los datos está intacta.

David Thomas
fuente
1
Esta opción es esencialmente no destructiva (es decir, ocultar cosas en lugar de eliminar), y es probablemente el mejor punto de partida hasta que pueda determinar el mejor curso de acción sobre cómo tratar con las entidades que tienen las opciones desactualizadas.
mpdonadio
3

Como sé, todos los datos de los campos se almacenan en 2 tablas: field_data_field_FIELDNAME y field_revision_field_FIELDNAME. Y encontré confirmación de mi pensamiento aquí: /programming//a/7773117/1300562

Por lo tanto, para eliminar valores de campo innecesarios, debe eliminar estos valores de las tablas mencionadas anteriormente y luego eliminarlos de la lista de valores permitidos.

Paso 1.

$values_to_remove = array('value1', 'value2'); // an array of unnecessary values
$fieldname = 'FIELDNAME'; // name of your field. For example,
                          // 'territory' for field with machine name 'field_territory'
$entity_type = 'node'; // it's 'node' in your case, but it can be 'taxonomy_term' or something else

db_delete('field_data_field_' . $fieldname)
  ->condition('entity_type', $entity_type)
  ->condition('field_' . $fieldname . '_value', $values_to_remove)
  ->execute();

db_delete('field_revision_field_' . $fieldname)
  ->condition('entity_type', $entity_type)
  ->condition('field_' . $fieldname . '_value', $values_to_remove)
  ->execute();

Paso 2.
Elimine los pares innecesarios de clave | valor en la página de configuración del campo y envíe el formulario para guardar los cambios.
La memoria caché debe borrarse automáticamente después de eso, pero si aún puede ver los valores de campo eliminados en las páginas de nodo, borre la memoria caché manualmente.

PD Recientemente me enfrenté a un problema similar, y ahora prefiero usar campos de tipo "Referencia de término" o (aún mejor) "Referencia de entidad" en lugar de la lista de valores de texto. Al usar el campo de referencia, puede crear vocabulario separado para cada campo y simplemente crear / editar / eliminar términos en cualquier momento.

quotesBro
fuente
Si el campo se repite, esas consultas no ajustarán los deltas para los datos restantes.
mpdonadio
1

En primer lugar, compruebe si tiene algún valor permitido especificado en el campo. Si lo hace, entonces otra opción no será validada. Intente eliminar primero los valores de la pestaña Configuración de campo.

Alternativamente, tiene 2 opciones:


1)

Elimine todos los valores que haya puesto en la lista de valores permitidos que están en uso por las cuentas de usuario. Por ejemplo, puede ejecutar una consulta SQL para encontrar estos:

SELECT * FROM field_data_field_MYFIELDNAME WHERE entity_type = 'user' and value = 'MY VALUE'

o cree una vista de usuario que le muestre qué cuentas de usuario tienen el valor que desea eliminar de la lista de valores permitidos.


2)

Si no desea eliminar valores de los campos, esto se puede lograr mediante un hack.

¡Advertencia, esta no es una solución sugerida para la producción y debe saber lo que está haciendo!

  1. Buscar y editar módulos / field / field.module
  2. Busque la función field_has_data () y agregue return TRUE;la primera línea de función.

    function field_has_data($field) {
      return FALSE; // HACK !!!
      $query = new EntityFieldQuery();
  3. Vuelva a guardar el campo con los valores que desee.
  4. Elimina el truco tan pronto como lo hagas.
kenorb
fuente
0

Creo que realmente puedes hacer esto usando el módulo de Operaciones masivas de Vistas .

  1. agregue una nueva opción en ese campo que le gustaría reemplazar. por ejemplo: na | NA
  2. crear una vista para contener el nodo de la lista con ese campo
  3. agregue campos "Operaciones masivas: Contenido" en esa Vista
  4. marque "Modificar valores de entidad" y "muestre tokens disponibles" (seleccione Todos en valores de visualización)
  5. Agregue el campo que desea cambiar en Criterios de filtro y "exponga" que filtra
  6. establecer la ruta URL en esa vista
  7. Ve a esa página de vista y cambia
  8. Ahora, use las funciones de exposición y operaciones para cambiar la opción de campo
  9. Hecho
Piel de coco
fuente
0

Aquí viene una mejora para la respuesta HL, que creo que es la mejor:

Para resumir, debe asignar nuevos valores al contenido que tiene valores "antiguos" asignados para su campo de selección.

Además de las Operaciones de Bulk de Views , necesitará instalar y habilitar el módulo de Vistas de Administración . Con este módulo, ya tiene una vista lista para usar con operaciones masivas habilitadas (solo vea admin / contenido una vez habilitado). Luego:

1) Vaya a admin / estructura / vistas y edite la vista "Administración: Nodo"

2) Agregue una nueva visualización de página para la vista usando el botón "Agregar -> Página" en la parte superior

3) Asigne una ruta a la nueva pantalla: ejemplo admin / content / custom

4) Agregue un nuevo filtro para su campo de selección: seleccione el operador "es uno de" y luego seleccione todas las opciones que desea eliminar

5) Guardar la vista

6) Vaya a admin / content / custom Ahora verá todo el contenido que necesita para editar en masa (cambie el valor para su campo de selección)

7) Seleccione todas las filas haciendo clic en la primera casilla de verificación a la izquierda de la tabla (si hay más de una página, también seleccione un botón que diga "Seleccionar todas las X filas en esta vista")

8) Seleccione la operación "cambiar valor" y presione "Ejecutar"

9) Para su campo de selección, seleccione un nuevo valor para sobrescribir los que desea eliminar

10) Seleccione la casilla de verificación para ese campo de selección

11) Haga clic en Siguiente y ya está

Roger
fuente
0

Parece que su problema de Drupal se basa en un problema de datos más profundo: ¿qué sucede con las entidades que actualmente utilizan los valores de lista depreciados? Esta pregunta está en la raíz del mensaje de error que Drupal le está enviando.

Veamos más de cerca su ejemplo de estado / territorio. Su cliente ha estado utilizando un sistema que trata a los estados y territorios de la misma manera durante años y ha creado un gran grupo de nodos que contienen estados y territorios. Entonces, un día, los poderes fácticos deciden que los territorios deben manejarse de manera diferente y que el menú desplegable para asignar una región ya no debería contener territorios. Excelente. Simplemente cree una vista que use filtros estándar para representar una lista de todos los nodos del territorio y use las Operaciones en masa de vistas para cambiar todos los valores de su región a ... ¿qué ... algún estado número 51 llamado otro quizás? El destino de los territorios es una pregunta muy seria. Su solución debe incluir un método para preservar o reubicar el estado del territorio. Es posible que deba crear un nuevo campo de lista llamado 'Territorio'

Deberá usar Reglas con Ver operaciones masivas para realizar estos cambios. Si no sabe mucho acerca de las reglas, tómese un tiempo para aprender cómo funcionan. Reglas le brinda la capacidad de manipular información basada en disparadores, condiciones y acciones. Después de aprender sobre las reglas, es posible que las respuestas que busca se presenten intuitivamente. Básicamente, deberá crear una regla, que se active mediante una Operación masiva, que apuntará a todos los territorios y los eliminará, reasignará, cambiará de nombre o los separará del cuerpo principal de información. La Regla debe poder almacenar el estado del territorio de alguna manera y, al mismo tiempo, establecer el menú desplegable de estado en el estado 'otro' o 'N / A'. Esto puede ser todo lo que se necesita. De otra manera...

Una vez realizada la reasignación, debería ser una operación simple alterar el campo de lista original y eliminar los nombres de territorio. Sin embargo, si el sistema aún no le permite alterar la lista, es posible que deba crear un nuevo campo de lista, luego utilice las Operaciones y reglas de visualización masiva para revisar todos los valores de estado actuales y reasignarlos a la nueva lista. Las reglas pueden funcionar con Operaciones masivas de vistas para apuntar a todos los nodos relevantes y actuar sobre ellos en función de los valores de campo. Establecer un valor de un nuevo campo de lista basado en el valor de un campo de lista existente para un grupo de nodos es fácil cuando utiliza Reglas.

También recuerde, si Drupal le causa problemas con una operación, siempre vacíe el caché antes de considerar una alternativa difícil.

Hoytman
fuente
0

Supongo que su cliente quiere que el contenido heredado mantenga su valor original, lo que significa que cambiar la lista de selección destruirá efectivamente cualquier dato anterior. Si eso no es una preocupación, entonces cualquiera de las otras respuestas probablemente funcionaría. Sin embargo, si es así, realmente no puede cambiar la lista de selección sin perder ese historial de datos. Podría seguir una ruta mucho más simple, para permitir datos históricos, mientras que el sitio está un poco más preparado para el futuro. Sugeriría usar permisos de campo:

* configurar un nuevo campo para esa lista de selección utilizando una taxonomía en lugar de datos estáticos

* establecer el permiso de campo para la lista de selección existente como VER, pero no EDITAR por nadie excepto el administrador

Con esto, el campo antiguo debe permanecer visible y buscable (agregue un nuevo título que lo refleje solo como heredado) pero no editable. Esto, por supuesto, depende en gran medida de búsquedas personalizadas, vistas, etc., que pueden necesitar ajustes.

Sugiero esto (tan desordenado como pueda parecer) porque eliminar esos datos, elimina el historial, y eso puede terminar siendo devastador a largo plazo. Incluso podría usar css para ocultar el campo antiguo en el nodo de edición y un gancho para ocultarlo para contenido nuevo (donde no tiene un valor establecido). De esta manera, solo se mostraría para ese contenido heredado.

Por supuesto, podría ir un paso más allá con un módulo único personalizado para copiar los datos de la lista de selección anterior a la nueva taxonomía.

Geoff
fuente
0

Un simple guión drush al rescate! Actualizamos los datos de campo y las tablas de revisión de campo y reemplazamos los valores antiguos por otros nuevos antes de cambiar manualmente la configuración del campo.

Si tenemos algo como esto en nuestra configuración de campo actual:

&date=today|today
&date=last2days|last2days

y quiero reemplazarlo con lo siguiente:

date=today|today
date=last2days|last2days

Primero ejecutamos el script drush y luego cambiamos la configuración del campo en la interfaz de usuario de administración.

Nota: Este código es para un campo con el nombre de la máquina field_foo_bar.

    $field_name = 'foo_bar';

    print "for {$field_name}...\n";

    replace_field("&date=today", "date=today", $field_name);

    replace_field("&date=last2days", "date=last2days", $field_name);

    function replace_field($old_value, $new_value, $field_name, $entity_type='node') {
      print "Replacing {$old_value} with {$new_value}...\n";
      $data_count = replace_options_data_field($field_name, $entity_type, $old_value, $new_value);
      $revision_count = replace_options_revision_field($field_name, $entity_type, $old_value, $new_value);
      print $data_count + $revision_count . " entries replaced.\n";
    }

    function replace_options_data_field($field_name, $entity_type, $old_value, $new_value) {
      $num_updated = db_update('field_data_field_' . $field_name)
        ->fields(array(
                   'field_' . $field_name . '_value' => $new_value,
                 ))
        ->condition('entity_type', $entity_type)
        ->condition('field_' . $field_name . '_value', $old_value)
        ->execute();
      return $num_updated;
    }

function replace_options_revision_field($field_name, $entity_type, $old_value, $new_value) {
  $num_updated = db_update('field_revision_field_' . $field_name)
    ->fields(array(
               'field_' . $field_name . '_value' => $new_value,
             ))
    ->condition('entity_type', $entity_type)
    ->condition('field_' . $field_name . '_value', $old_value)
    ->execute();
  return $num_updated;
}
Badri
fuente
0

Utilicé la segunda sugerencia de kenorb y funcionó para actualizar la lista de valores en un campo Drupal 7.52, Profile2 7.x-1.3. Entonces, si estaba recibiendo la advertencia de drupal: "Lista de valores permitidos: algunos valores se están eliminando mientras están actualmente en uso". Lo siguiente me permitió eliminar valores del campo (perfil2), sin eliminarlos ni reemplazarlos en la base de datos.

En el directorio raíz del núcleo de Drupal, hay una carpeta llamada módulos, y el archivo a editar se encuentra en: modules / field / field.module. ESTE ES UN ARCHIVO PRINCIPAL, debe revertir absolutamente sus cambios cuando termine de actualizar los valores. Desconecté el sitio, reemplacé temporalmente el siguiente bloque de código en (raíz de drupal) /modules/field/field.module

function field_has_data($field) {
  $query = new EntityFieldQuery();
  $query = $query->fieldCondition($field)
    ->range(0, 1)
    ->count()
    // Neutralize the 'entity_field_access' query tag added by
    // field_sql_storage_field_storage_query(). The result cannot depend on the
    // access grants of the current user.
    ->addTag('DANGEROUS_ACCESS_CHECK_OPT_OUT');

  return (bool) $query
    ->execute() || (bool) $query
    ->age(FIELD_LOAD_REVISION)
    ->execute();
}

CON EXACTAMENTE

function field_has_data($field) { 
    return FALSE; // hack 
    $query = new EntityFieldQuery();
}

Y Drupal dejó de quejarse y pude alterar la lista. (En mi caso, es la facultad en la lista de valores que han abandonado la universidad, pero que aún están asociados con el registro de un estudiante, como su asesor, mentor, etc.)

Michael Martelle
fuente