Como posso remover itens da lista de valores permitidos de um campo de seleção que possui dados para os valores?

16

Criei um tipo de conteúdo que possui um campo de opção de lista / seleção e inseri os pares de chave | valor conforme necessário para que a lista de seleção funcione.

Os dados foram inseridos e foi decidido que certos termos não se aplicam mais e que eles devem ser excluídos.

No entanto, ao tentar remover os termos mencionados, recebo o seguinte erro:

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

Obviamente, na vida de um projeto, os valores vão mudar. Qual é a maneira prática de remover itens depois que os nós são associados aos termos listados?

Essa é a coisa mais próxima que eu pude encontrar:

https://drupal.org/node/1653012

Ele faz referência a um plugin d6 e alguns truques de patch que eu preferiria não ter que recorrer. Se eu tivesse que finalmente usar o patch para remover a verificação de validação nesse campo, há algum mal em deixar esses itens órfãos nos nós aos quais eles estavam associados?

Atualização, deparei-me com esse problema novamente com um cliente do governo que, nos últimos 7 anos com um site do Drupal, teve 50 estados e territórios em uma lista de seleção. Agora, a política mudou e os territórios não precisam mais ser incluídos. Ser capaz de remover itens das listas de seleção é importante e, portanto, estou oferecendo uma recompensa.

Estou procurando uma solução segura para poder remover itens de uma lista de seleção. O que eu não sei é se essa solução deve atualizar qualquer um dos nós, pois não tenho certeza de como os valores do campo são armazenados em relação ao conteúdo total de um nó.

Estou feliz com uma solução SQL pura para executar no MySQL; ou, estou procurando um módulo.

blue928
fonte
3
Obviamente, na vida de um projeto, os valores vão mudar. Eu contestaria que - os valores para uma lista de seleção estática devem ser definidos no início do projeto. Se você precisar que ele seja flexível, use um termo de referência em vez de uma lista estática. As listas estáticas são para coisas como sexo (masculino / feminino) que, a menos que tenhamos uma mudança séria, provavelmente não mudará tão cedo. E, se o fizer, será adicionado , não removido . Sempre que cometi esse 'erro', sempre achei que a melhor maneira de voltar atrás era executar consultas manuais nos dados
Clive
1
Deseja tornar esta lista dinâmica? sendo dinâmico na criação e exclusão.
M AMA D
1
Sim, acho que isso é apenas uma opinião - o fabricante do carro sempre seria um tipo de nó ou vocabulário para qualquer site que eu construísse. Como o fabricante é uma categoria de carro (ou categoria de carro que alguém repara), faz mais sentido como taxonomia para mim do que como tipo de conteúdo. Mas eu sei que isso não ajuda ... Eu seria cauteloso em deixar dados órfãos no banco de dados, é muito difícil dizer que efeito isso poderia ter sem saber exatamente o que está instalado no seu site e como ele está configurado
Clive
1
O que há de errado com views_bulk_operations?
Donquixote
1
heh, nenhuma destas respostas ainda tem
votos positivos

Respostas:

7

Eu fiz algo assim recentemente com a seguinte abordagem.

  1. Adicione os novos valores permitidos.
  2. Adicione uma configuração para configurar valores "ativos".
  3. Filtre os valores "inativos" da exibição no formulário.

por exemplo:

/**
 * 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]);
      }
    }
  }

}

Dessa maneira, os dados herdados são preservados para referência, o formulário é validado e a integridade dos dados permanece intacta.

David Thomas
fonte
1
Essa opção é essencialmente não-destrutiva (ou seja, ocultar itens em vez de excluir) e provavelmente é o melhor ponto de partida até que você possa determinar o melhor curso de ação para lidar com qualquer entidade que possua as opções desatualizadas.
mpdonadio
3

Como eu sei, todos os dados dos campos são armazenados em 2 tabelas: field_data_field_FIELDNAME e field_revision_field_FIELDNAME. E encontrei a confirmação do meu pensamento aqui: /programming//a/7773117/1300562

Portanto, para remover valores de campo desnecessários, você deve excluir esses valores das tabelas mencionadas acima e removê-los da lista de valores permitidos.

Passo 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();

Etapa 2.
Remova os pares desnecessários de valor da chave na página de configurações de campo e envie o formulário para salvar as alterações.
O cache deve ser limpo automaticamente depois disso, mas se você ainda conseguir ver os valores de campo removidos nas páginas do nó, limpe o cache manualmente.

PS: Recentemente, enfrentei um problema semelhante, e agora prefiro usar campos do tipo "Referência de termo" ou (melhor ainda) "Referência de entidade" em vez de lista de valores de texto. Ao usar o campo de referência, você pode criar vocabulário separado para cada campo e simplesmente criar / editar / excluir termos a qualquer momento.

quotesBro
fonte
Se o campo estiver se repetindo, essas consultas não ajustarão os deltas para os dados restantes.
mpdonadio
1

Antes de mais nada, verifique se você tem algum valor permitido especificado no campo? Se o fizer, uma outra opção não será validada. Portanto, tente remover os valores da guia Configurações do campo primeiro.

Alternativamente, você tem 2 opções:


1

Remova todos os valores que você colocou na lista de valores permitidos que estão em uso pelas contas de usuário. Por exemplo, você pode executar uma consulta SQL para encontrar estes:

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

ou crie uma visualização do usuário que mostre quais contas de usuário têm o valor que você deseja remover da lista de valores permitidos.


2)

Se você não deseja remover valores dos campos, isso pode ser alcançado através do hack.

Atenção, essa não é uma solução sugerida para produção e você deve saber o que está fazendo!

  1. Localize e edite os módulos / campo / campo.modulo
  2. Encontre a função field_has_data () e adicione return TRUE;a primeira linha da função.

    function field_has_data($field) {
      return FALSE; // HACK !!!
      $query = new EntityFieldQuery();
  3. Salve novamente o campo com os valores desejados.
  4. Remova o hack assim que você fizer isso.
kenorb
fonte
0

Eu acho que você realmente pode fazer isso usando o módulo Views Bulk Operations .

  1. adicione uma nova opção nesse campo que você deseja substituir. por exemplo: na | NA
  2. crie um nó View to list que contenha com esse campo
  3. adicione os campos "Operações em massa: Conteúdo" nessa Visualização
  4. marque "Modificar valores da entidade" e "mostrar tokens disponíveis" (selecione Tudo nos valores exibidos)
  5. Adicione o campo que deseja alterar nos Critérios de filtro e "exponha" que filtra
  6. definir caminho do URL nessa visualização
  7. Vá para essa página de visualização e altere
  8. Agora, use os recursos de exposição e operações para alterar a opção de campo
  9. Feito
CocoSkin
fonte
0

Aí vem uma melhoria para a resposta HL, que eu acho que é a melhor:

Para resumir, você precisa atribuir novos valores ao conteúdo que possui valores "antigos" atribuídos ao seu campo de seleção.

Além do Views Bulk Operations , você precisará instalar e ativar o módulo Views de Administração . Com este módulo, você já tem uma visualização pronta para uso com operações em massa ativadas (basta ver admin / conteúdo uma vez ativado). Então:

1) Vá para admin / structure / views e edite a visualização "Administração: Nó"

2) Adicione uma nova página para a visualização usando o botão "Adicionar -> Página" na parte superior

3) Atribua um caminho para a nova exibição: Exemplo admin / content / custom

4) Adicione um novo filtro ao seu campo de seleção: Selecione o operador "é um dos" e selecione todas as opções que deseja excluir

5) Salve a vista

6) Vá para admin / content / custom Agora você vê todo o conteúdo que precisa editar em massa (altere o valor para o campo de seleção)

7) Selecione todas as linhas clicando na primeira caixa de seleção à esquerda da tabela (se houver mais de uma página, selecione também um botão que diz "Selecionar todas as X linhas nesta exibição")

8) Selecione a operação "alterar valor" e pressione "Executar"

9) Para o seu campo de seleção, selecione um novo valor para substituir os que você deseja excluir

10) Marque a caixa de seleção para esse campo de seleção

11) Clique em Avançar e pronto

Roger
fonte
0

Parece que o problema do Drupal se baseia em um problema de dados mais profundo: o que acontece com as entidades que estão usando os valores de lista depreciados no momento? Esta pergunta está na raiz da mensagem de erro que o Drupal está lhe enviando.

Vamos dar uma olhada no seu exemplo de estado / território. Seu cliente usa um sistema que trata estados e territórios da mesma maneira há anos e construiu um enorme grupo de nós que contêm estados e territórios. Então, um dia, os poderes que decidem que os territórios precisam ser tratados de maneira diferente e que o menu suspenso para atribuir a região não deve mais conter territórios. Ótimo. Simplesmente crie uma exibição que use filtros padrão para renderizar uma lista de todos os nós do território e use o Views Bulk Operations para alterar todos os valores de suas regiões para ... o que ... um 51º estado chamou outro talvez? O destino dos territórios é uma questão muito séria. Sua solução deve incluir um método para preservar ou realocar o status do território. Pode ser necessário criar um novo campo de lista chamado 'Território'

Você precisará usar regras com Exibir operações em massa para executar essas alterações. Se você não sabe muito sobre regras, reserve um tempo para aprender sobre como elas funcionam. Rules fornece a capacidade de manipular informações com base em gatilhos, condições e ações. Depois de aprender sobre as regras, você pode descobrir que as respostas que procura estão apresentando-se intuitivamente. Basicamente, você precisará criar uma regra, que é acionada por uma operação em massa, que terá como alvo todos os territórios e removerá, reatribuirá, renomeará ou de outra forma os separará do corpo principal de informações. A Regra deve ser capaz de armazenar o estado do território de alguma forma e, ao mesmo tempo, definir o status suspenso para o status 'outro' ou 'N / D'. Isso pode ser tudo o que é necessário. De outra forma...

Após a reatribuição, deve ser uma operação simples alterar o campo da lista original e remover os nomes dos territórios. No entanto, se o sistema ainda não permitir que você altere a lista, talvez seja necessário criar um novo campo de lista e use as Regras e Operação em Massa de Exibições para revisar todos os valores de estado atuais e reatribuí-los à nova lista. As regras podem trabalhar com o Views Bulk Operations para direcionar todos os nós relevantes e agir sobre eles com base nos valores do campo. É fácil definir o valor de um novo campo de lista com base no valor de um campo de lista existente para um grupo de nós quando você usa Regras.

Lembre-se também de que, se o Drupal apresentar problemas com uma operação, sempre lave o cache antes de considerar uma alternativa difícil.

Hoytman
fonte
0

Suponho que seu cliente deseja que o conteúdo herdado mantenha seu valor original, o que significa que alterar a lista de seleção destruirá efetivamente quaisquer dados anteriores. Se isso não for uma preocupação, provavelmente qualquer uma das outras respostas funcionaria. Se for esse o caso, você não poderá realmente alterar a lista de seleção sem perder esse histórico de dados. Eu poderia seguir uma rota muito mais simples, para permitir dados históricos, enquanto tornava o site um pouco mais à prova de futuro - eu sugeriria o uso de permissões de campo:

* configure um novo campo para essa lista de seleção usando uma taxonomia em vez de dados estáticos

* defina a permissão de campo para a lista de seleção existente como VIEW, mas não EDIT por ninguém, exceto admin

Com isso, o campo antigo deve permanecer visível e pesquisável (adicione um novo título refletindo-o apenas como legado), mas não editável. É claro que isso depende muito de pesquisas personalizadas, visualizações etc. que talvez precisem ser ajustadas.

Eu sugiro isso (por mais confuso que possa parecer) porque a remoção desses dados remove o histórico e isso pode acabar sendo devastador a longo prazo. Você pode até usar css para ocultar o campo antigo no nó de edição e um gancho para ocultá-lo para o novo conteúdo (onde ele não tem um valor definido). Dessa forma, seria exibido apenas para esse conteúdo herdado.

Obviamente, você poderia dar um passo adiante com um módulo único personalizado para copiar os dados da lista de seleção antiga para a nova taxonomia.

Geoff
fonte
0

Um script drush simples para o resgate! Atualizamos os dados dos campos e as tabelas de revisão de campos e substituímos os valores antigos pelos novos antes de alterar manualmente as configurações do campo.

Se tivermos algo assim em nossas configurações de campo atuais:

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

e deseja substituí-lo pelo seguinte:

date=today|today
date=last2days|last2days

Primeiro, executamos o script drush e, em seguida, alteramos as configurações de campo na UI do administrador.

Nota: Este código é para um campo com o nome da 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
fonte
0

Usei a segunda sugestão de kenorb e ela trabalhou para atualizar a lista de valores em um campo Drupal 7.52, Profile2 7.x-1.3. Portanto, se você recebeu o aviso drupal: “Lista de valores permitidos: alguns valores estão sendo removidos enquanto estão em uso no momento.” O seguinte me permitiu remover valores do campo (profile2), sem removê-los ou substituí-los no banco de dados.

No diretório raiz do núcleo do Drupal, há uma pasta chamada modules, e o arquivo a ser editado está localizado em: modules / field / field.module. ESTE É UM ARQUIVO NÚCLEO, você deve absolutamente reverter suas alterações quando terminar de atualizar os valores. Coloquei o site offline, substituí temporariamente o seguinte bloco de código em (drupal root) /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();
}

COM EXATAMENTE

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

E o drupal parou de reclamar e eu pude alterar a lista. (No meu caso, é o corpo docente na lista de valores que deixaram a universidade, mas ainda estão associados a um registro de alunos, como orientador, mentor etc.)

Michael Martelle
fonte