Est-il possible d'afficher un formulaire de widget de champ fonctionnel seul?

21

Je souhaite intégrer un formulaire de widget de champ en dehors du contexte de l'ensemble du formulaire de modification de nœud.

J'ai affiché des formulaires complets dans le passé en utilisant drupal_get_form, mais cela ne semble pas s'appliquer aux formulaires de champ solitaires.

Est-il possible d'afficher un formulaire de widget de champ fonctionnel? Quelle serait la meilleure façon de procéder?

Les widgets de champ et les formulaires "normaux" semblent très semblables, donc si cela n'est pas possible, que faudrait-il pour "changer" un formulaire widget en un formulaire normal?

Cette question semble demander quelque chose de similaire, mais je ne comprends pas la réponse. Cette réponse spécifie l'utilisation de hook_field_widget_form_alter ; ce que je ne comprends pas, c'est comment afficher le formulaire de champ et non comment le raccorder une fois qu'il est créé.

SMTF
la source

Réponses:

18

VBO fait quelque chose comme ça dans 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);  

Donc, vous avez besoin du type d'entité, de l'entité (qui peut être un objet vide avec juste le jeu de clés de bundle, c'est ce qui est réellement utilisé), du formulaire où les widgets sont ajoutés et de la langue. Si vous souhaitez intégrer les widgets plus profondément dans le formulaire (pas dans $ form, mais dans $ form [$ form_key] comme je l'ai fait, ou même plus profondément), alors ce tableau de formulaires doit avoir #parents défini.

Bien sûr, notez que cela incorporera les widgets de tous les champs appartenant à ce type d'entité et à cet ensemble. C'est ainsi que les fonctions d'attachement ont été écrites. Contourner cela vous obligerait à réinventer pas mal de code; voir le code réel qui fait le gros du travail. Ce que je fais, c'est passer par les instances de champ, obtenir chaque $ field_name, et si ce type de champ ne m'intéresse pas, j'ai défini $form[$form_key][$field_name]['#access'] = FALSE; ce qui cache ces widgets à la vue.

EDIT: D'accord, ctools a ctools_field_invoke_field () qui pourrait en théorie vous permettre de travailler sur une base par champ. Je ne l'ai jamais utilisé cependant. Le texte ci-dessus est mon expérience directe.

Bojan Zivanovic
la source
Réponse géniale. J'ai passé la plus grande partie d'une journée à travailler avec cela, et cela a fonctionné comme je le voulais. Prime octroyée, et je recommande au PO d'accepter cela comme la bonne réponse. J'ai fini par créer un type de contenu factice afin de pouvoir contrôler mes champs comme n'importe quel autre type de contenu, au lieu de définir #access = FALSEce qui semblait hacky dans ce contexte.
Letharion
Merci d'avoir confirmé ce que j'avais craint: que le widget à champ unique ne soit pratiquement pas utilisable seul.
SMTF
7

J'utilisais intensivement la fonction suggérée par ttk, mais je pense qu'une récente mise à jour a gâché les choses ...

Voici une nouvelle version de la solution précédente qui fonctionne bien avec Drupal 7.22 et ctools 7.x-1.3.

Donc, comme dans le post précédent, vous appelez votre fonction personnalisée comme ceci:

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

Notez que l'entité bundle est maintenant un paramètre. Je l'ai fait parce que j'utilisais également cette fonction pour modifier les utilisateurs. De cette façon, il peut également être utilisé pour le terme de taxonomie, ou toute autre entité.

Et le my_field_attach_formest défini comme:

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

Cette fonction m'a fait gagner beaucoup de temps, j'espère qu'elle le sera aussi pour vous!

jmcouillard
la source
5

Voici la solution utilisant la ctools_field_invoke_field()méthode. Dans votre fonction de formulaire personnalisé, ajoutez:

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

où la my_field_attach_formfonction est définie comme

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

Notez que votre site doit avoir activé les outils ctools. Il est dommage que Drupal n'inclue pas de fonction d'assistance comme celle-ci par défaut.

ttk
la source
2

Je n'ai pas réussi à faire fonctionner la méthode ctools et j'ai décidé de le faire de cette façon à la place.

Ce code serait à l'intérieur d'une fonction de formulaire, donc $ form et $ form_state seraient déjà passés.

function form_function($form, &$form_state) {

Créez d'abord un nœud vide d'un type contenant le champ que vous souhaitez rendre.

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

J'ai dupliqué les variables du formulaire pour ne pas encombrer l'original.

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

Retirez le champ que vous recherchez et ajoutez-le au formulaire.

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

J'ai utilisé cette méthode pour rendre le widget de sélection de taxonomie, le widget de cases à cocher de taxonomie et le widget de sélection hiérarchique sur un formulaire personnalisé. (Le widget de saisie automatique de taxonomie s'affiche mais génère une erreur lors de la soumission)

Enfin rendre et imprimer

drupal_render(drupal_get_form("form_function"))
Scott Joudry
la source
Cela semble être un moyen facile d'utiliser un widget de champ dans un formulaire personnalisé. Cela dépend cependant d'un Bundle existant. Dans mon cas, j'utilise un type de contenu factice où je crée et configure des champs selon les besoins. C'est un peu hacky mais nécessaire pour les autres méthodes aussi. À noter: la ctools_field_invoke_field()méthode décrite ci-dessus fonctionne également.
Bernhard Fürst,
0

J'ai créé des formulaires à partir de champs individuels en utilisant

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

cela devrait renvoyer le formulaire de widget requis qui peut être utilisé sous n'importe quelle forme comme

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

Pour obtenir les valeurs du paramètre 2 ci-dessus, utilisez:

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

Pour d'autres paramètres, vous pouvez vérifier le lien api ici

Cela renvoie le formulaire de widget par défaut défini dans le champ des types de contenu.

J'espère que cela aide quelqu'un :)

akshay daxini
la source