É possível exibir um formulário de widget de campo por conta própria?

21

Estou interessado em incorporar um formulário de widget de campo fora do contexto de todo o formulário de edição do nó.

Eu exibi formulários completos no passado usando drupal_get_form, mas isso não parece se aplicar a formulários de campo solitários.

É possível exibir um formulário de widget de campo em funcionamento? Qual seria a melhor maneira de fazer isso?

Os widgets de campo e os formulários "normais" parecem muito semelhantes; portanto, se isso não for possível, o que seria necessário para "alterar" um formulário de widget para um formato normal?

Esta pergunta parece estar pedindo algo semelhante, mas não entendo a resposta. Essa resposta especifica o uso de hook_field_widget_form_alter ; o que eu não entendo é como exibir o formulário de campo e não como conectá-lo após a criação.

SMTF
fonte

Respostas:

18

O VBO faz algo assim em modify.action.inc:

$form_key = 'bundle_' . $bundle_name;
$form[$form_key] = array(
  '#type' => 'fieldset',
  '#title' => $label,
  '#parents' => array($form_key),
);  
field_attach_form($context['entity_type'], $entity, $form[$form_key], $form_state, LANGUAGE_NONE);  

Portanto, você precisa do tipo de entidade, a entidade (que pode ser um objeto em branco com apenas o conjunto de chaves do pacote configurável, o que é realmente usado), o formulário em que os widgets são adicionados e o idioma. Se você deseja incorporar os widgets mais profundamente no formulário (não no formato $, mas em $ form [$ form_key] como eu fiz, ou ainda mais), essa matriz de formulários precisa ter #parents definidos.

Obviamente, observe que isso incorporará os widgets de todos os campos pertencentes a esse tipo e pacote de entidades. É assim que as funções de anexação foram escritas. Contornar isso exigiria que você reinventasse bastante código; veja o código real que faz o trabalho pesado. O que faço é passar por instâncias de campo, obter cada $ field_name e, se esse tipo de campo não me interessar, defino o $form[$form_key][$field_name]['#access'] = FALSE; que oculta esses widgets de vista.

EDIT: Ok, o ctools possui ctools_field_invoke_field () que, em teoria, poderia permitir que você trabalhasse por campo. Eu nunca usei isso embora. O texto acima é minha experiência direta.

Bojan Zivanovic
fonte
Resposta incrível. Passei a maior parte do dia trabalhando com isso, e funcionou exatamente como eu queria. Recompensa concedida, e eu recomendo que o OP aceite isso como a resposta correta. Acabei criando um tipo de conteúdo fictício para poder controlar meus campos como qualquer outro tipo de conteúdo, em vez de definir o #access = FALSEque parecia hacky nesse contexto.
Letharion
Obrigado por confirmar o que eu temia: que o widget de campo único não seja praticamente utilizável por si só.
SMTF 20/03/12
7

Eu estava usando intensamente a função sugerida pelo ttk, mas acho que uma atualização recente estragou tudo ...

Aqui está uma nova versão da solução anterior que funciona bem com o Drupal 7.22 e o ctools 7.x-1.3.

Assim, como no post anterior, você chama sua função personalizada assim:

my_field_attach_form('field_body', 'node', 'blog',  $node, $form, $form_state, LANGUAGE_NONE);

Observe que o pacote configurável da entidade agora é um parâmetro. Fiz isso porque também estava usando esta função para editar usuários. Dessa forma, também pode ser usado para o termo de taxonomia ou qualquer outra entidade.

E o my_field_attach_formé definido como:

function my_field_attach_form($field_name, $entity_type, $bundle, $entity, &$form, &$form_state, $langcode = NULL) {

  // Set #parents to 'top-level' if it doesn't exist.
  $form += array('#parents' => array());

  // If no language is provided use the default site language.
  $options = array(
    'language' => field_valid_language($langcode),
    'default' => TRUE,
  );

  // Append to the form
  ctools_include('fields');
  $field_instance = field_info_instance($entity_type, $field_name, $bundle);
  $form += (array) ctools_field_invoke_field($field_instance, 'form', $entity_type, $entity, $form, $form_state, $options);
}

Essa função me salvou muito tempo, espero que seja para você também!

jmcouillard
fonte
5

Aqui está a solução usando o ctools_field_invoke_field()método Na sua função de formulário personalizado, adicione:

$form = array();
$node = new stdClass();
$node->type = 'blog';
my_field_attach_form('field_body', 'node', $node, $form, $form_state, LANGUAGE_NONE);

onde a my_field_attach_formfunção é definida como

function my_field_attach_form($field_name, $entity_type, $entity, &$form, &$form_state, $langcode = NULL) {
  // Set #parents to 'top-level' if it doesn't exist.
  $form += array('#parents' => array());

  // If no language is provided use the default site language.
  $options = array(
    'language' => field_valid_language($langcode),
    'default' => TRUE,
  );
  module_load_include("inc","ctools","includes/fields");
  $form += (array) ctools_field_invoke_field($field_name, 'form', $entity_type, $entity, $form, $form_state, $options);
}

Observe que seu site precisa ter o ctools ativado. É uma pena que o Drupal não inclua uma função auxiliar como essa por padrão.

ttk
fonte
2

Não consegui fazer o método ctools funcionar e decidi fazê-lo dessa maneira.

Esse código estaria dentro de uma função de formulário, portanto $ form e $ form_state já seriam passados.

function form_function($form, &$form_state) {

Primeiro, crie um nó vazio de um tipo que tenha o campo que você deseja processar.

    $entity = new stdClass();
    $entity->title = "Temp Object";
    $entity->type = "node_type";
    node_object_prepare($entity);

Dupliquei as variáveis ​​do formulário para não prejudicar o original.

    $temp_form       = $form;
    $temp_form_state = $form_state;
    field_attach_form("node", $entity, $temp_form, $temp_form_state);

Retire o campo que você está procurando e adicione-o ao formulário.

    $form["field"] = $temp_form["existing_field"];
}

Usei esse método para renderizar o widget de seleção de taxonomia, o widget de caixas de seleção de taxonomia e o widget Seleção Hierárquica em um formulário personalizado. (O widget de preenchimento automático de taxonomia é processado, mas gera um erro ao enviar)

Finalmente renderize e imprima

drupal_render(drupal_get_form("form_function"))
Scott Joudry
fonte
Essa parece ser uma maneira fácil de usar um widget de campo em um formulário personalizado. Depende de um pacote existente. No meu caso, eu uso um Tipo de Conteúdo fictício, onde crio e configuro os campos conforme necessário. Isso é um pouco hacky, mas necessário para os outros métodos também. Apenas para observar: o ctools_field_invoke_field()método descrito acima também funciona.
Bernhard Fürst
0

Criei formulários a partir de campos indivisuais usando

field_default_form('entity_type', $entity, $field,$field_instance,LANGUAGE_NONE,$default_value, $form, $form_state);

isso deve retornar o formulário de widget necessário, que pode ser usado de qualquer forma como

 $custom_form['form_element_to_display'] = field_default_form('entity_type', $entity, $field,$field_instance,LANGUAGE_NONE,$default_value, $custom_form, $custom_form_state);

Para obter os valores para o parâmetro 2 acima, use:

$field = field_info_field($field_name);
$field_instance = field_info_instance('node', $field_name, $node_type);

Para outros parâmetros, você pode verificar o link da API aqui

Isso retorna o formulário de widget padrão definido no campo tipos de conteúdo.

Espero que isso ajude alguém :)

akshay daxini
fonte