Load field widgets manually

lukas.fischer's picture

Hello

I'm looking for a way to programatic access/render CCK field widgets like filefield or imagefield (without using CCK form generation, I want to create my own forms).

Why? I love to work with custom forms and store myself the data to the correct place. Some of the data is stored in cck nodes, some are stored in log files, some are stored in complete custom tables. I know everything is possible with the node_api and form_alter but I like to have clean forms and clean form_submits.

However, working with basic CCK fields like textfield, checkboxes, selects is very easy - I would also like to work with more complext field widgets like filefield, date, imagefield etc.

I don't understand how I can call/populate such a widget.

The way I would like/expect to do it so:

function mycustom_form() {
      $form['images'] = array(
          '#type' => 'imagefield',
        '#title' => t('Images'),
        '#default_value' => $node->field_images,
       '#required' => true
   );
return $form
}

Actually I couldn't find something in the drupal forums (or I looked for the wrong words) but I'm shure there is an easy solution for this. Unfortunately the more complex widgets are not covered in http://api.drupal.org/api/file/developer/topics/forms_api_reference.html.

Thanks for any hint or reference.

All the best
Lukas

Comments

I have been having the same

jeffabailey's picture

I have been having the same or at least a similar problem. Does anyone have or know where some relevant documentation that describes how to add and update custom CCK node fields from within a module is? The closest I came to figuring out how to do this was to somehow export the node using content_copy and use that code.

On a recent project, I

ebeyrent's picture

On a recent project, I created a content type called "Band" which was actually an organic group. The group manager had permission to create "band members", a process which involved creating user accounts and a profile node.

I used the FormAPI to create this form on the group homepage with a custom validator and custom submit handler. Using the FormAPI, I added fields for username and email address. The other fields on the form were defined in the profile content type. However, I didn't want to recreate some of those fields, such as phone number, which was provided by the CCK Phone module. In order to reuse that field in the form, here's what I did:

<?php
$form
['band_member_phone'] = array();
$phonefield = content_fields('field_band_member_phone');
$form['band_member_phone'] = phone_widget('form', $node, $phonefield, $form['band_member_phone'] );
?>

This code renders the widget in the form. I then hooked up the phone formatter in my submit handler:

<?php
$phonefield
= content_fields('field_band_member_phone');
$form_values['band_member_phone'] = format_phone_number('ca', $form_values['band_member_phone'], $phonefield);
?>

I don't know if this helps you out at all or not.

Using op_video widgets in custom forms

vincentdemers-gdo's picture

In D5 I have been able to use imagefield widgets in custom forms using this code

<?php
function mymodule_form() {
   
$node = new stdClass(); //For picture widget we have to create a node object
   
$node->type = 'my_node_type';
   
$picturefield = content_fields('field_picture', 'my_node_type');
   
imagefield_widget('prepare form values', $node, $picturefield, $node->field_picture);
   
$form['field_picture'] = imagefield_widget('form', $node, $picturefield, $node->field_picture);
   
$form['#attributes'] = array("enctype" => "multipart/form-data");

return
$form;
}
function
mymodule_form_validate($form_id, $form_values) {

}
function
mymodule_form_submit($form_id, $form_values) {
   
$values = array();
   
$values['type'] = 'my_node_type';
   
$values['field_picture'] = $form_values['field_picture'];
   
$node = node_submit($values);
   
node_save($node);
}
?>

Now I want to do the same thing with the op_video module that uses op_video_widget($op, &$node, $field, &$node_field) but I can't figure how I should be using the 'validate' and 'submit' operators. These operators do not exist in imagefield_widget($op, &$node, $field, &$node_field)... Anybody knows how I should be using op_video_widget in mymodule_form_validate() and mymodule_form_submit() functions?

Answering myself

vincentdemers-gdo's picture

Here is how I achieved this in D5.. might be useful to someone..

<?php
function mymodule_form($node) {
 
$videofield = content_fields('field_video', 'my_node_type');
 
op_video_widget('prepare form values', $node, $videofield, $node->field_video);
 
$form['field_video'] = op_video_widget('form', $node, $videofield, $node->field_video);
 
$form['#attributes']['enctype'] = 'multipart/form-data';
return
$form;
}
function
mymodule_form_validate($form_id, $form_values, $form) {
 
$file=_op_video_widget_upload_validate('field_video', false);
}
function
mymodule_form_submit($form_id, $form_values) {
 
$deleted_video=false;
  if (
$form_values['field_video'][0]['upload']['delete']) {
   
$deleted_video=true;
   
$file = file_save_upload('field_video', file_directory_temp());
    if(
$file) file_delete($file->filepath);
  } else {
   
$file = file_check_upload('field_video');
  }
 
 
$node=node_load($form_values['nid']);
 
$current_video = _op_video_load($node->field_video[0]['video_id']);
 
$saved_video =_op_video_save_upload('field_video', 'original');
 
$params_id = _op_video_get_params_id('field_video');
 
$video_id=_op_video_create_video($saved_video, $params_id, 'third', null, $node->nid);
  if (!
$deleted_video) {
   
$node->field_video[0]['video_id']=$video_id;
   
_op_video_delete($current_video);
  } else {
   
$node->field_video[0]['video_id'] = 0;
  }
 
node_save($node);
}
?>

An Alternate Approach

spinningbull's picture

After working with this code, I realized I was missing alot of the callback functionality for fields like node reference, user reference, etc... After playing around a bit with the code in content.module I discovered an alternate approach: I use content.node_forms built in functions, abstracting me from any of the work around setting up the widgets, etc...

<?php
   module_load_include
('inc', 'content', 'includes/content.node_form');     
       
// list the field names you'd like to use in your form - they will display in this order.
   
$fields = array('field_projectid', 'field_payer', 'field_payee', 'field_payeeaddr', 'field_amount');
 
      foreach (
$fields as $name) {
      
$field = content_fields($name);
       
$form['#field_info'][$name] = $field;
       
$form += (array) content_field_form($form, $form_state, $field);
   }
 
  
$form['submit'] = array('#type' => 'submit', '#weight' => 10);
 
   return
$form;
?>

  1. Make sure to include content.node_form
  2. Setup an array of the fields you want to include in your form
  3. Loop through each desired field
  4. Get the field definition from content
  5. Setup the field information in the form for additional processing by CCK
  6. Call content_field_form() to return the complete form structure for this element. CCK will use the appropriate widget based on the field defintion

This will add the fields to your form in the order you list them in the array.

I'll post the hook_submit code in a separate comment.

sb

markus_petrux's picture

That may happen if the same field is shared between content types, then if you don't specify the type in content_fields() CCK will give you the first field it find with the given name, and that one may have different per instance settings. ;-)

requires fields to be defined in CCK?

brad.bulger's picture

it looks as if your fields - "field_projectid", "field_payer", etc. - are defined for some CCK content type. is that right?

i'm trying to figure out how to use the CCK widgets to support a field that exists nowhere except in my module code. i guess, though, there is db-based info required for at least some of the widget types that makes that impossible?

Hi Brad, I also exactly needs

pankajshr_jpr's picture

Hi Brad,
I also exactly needs what you asked here- "i'm trying to figure out how to use the CCK widgets to support a field that exists nowhere except in my module code. i guess, though, there is db-based info required for at least some of the widget types that makes that impossible?"

Please let me know if you have figured out about how to user CCK fields in Form API without defining fields in some CCK content type right from the module code.

Regards
Pankaj Kumar Sharma

panks

Thanks for that code. Just

ruphus's picture

Thanks for that code.
Just FYI, not sure if this is because something has been updated but this line:

$form += (array) content_field_form($form, $form_state, $field);

caused me and my colleaugues some trouble with imagefield ( the entire form disapeared after uploading ), as the module will look for the form element in the first level of the $form array. Changed it to:

$form += content_field_form($form, $form_state, $field);

and it worked great.

that seems odd

brad.bulger's picture

if content_field_form() is returning an array, then how could casting it to an array make any difference? and if it's not, then wouldn't the "+=" operator cause a fatal error?

I agree it seems

ruphus's picture

I agree it seems strange.
I've never user += with arrays before, and honestly didnt know it could be used that way until today. It seems it works as a shorthand for array_push.
The main difference being that using the (array) typecast would result in a $form object like $form[0][field_name], while filefield expects $form[field_name].

Like I said in my parent comment, I thought that maybe the behavior of some of these modules has changed in the last year, and that casting it to an array maybe needed to be done in previous versions.

that's not how it works

brad.bulger's picture

+= is like array_merge() except it ignores any keys in the source array that already exist in the target- so array(1=>2) + array(1=>3,2=>4) yields array(1=>2,2=>4)
http://us.php.net/manual/en/language.operators.array.php

casting an array to an array does not make it numerically keyed - it does nothing. or at least it should do nothing. that's why i'm saying it seems odd.

the reason for the cast, i imagine, is that using that += operator with anything other than an array on the right hand side is a fatal PHP error. the cast would avoid that, though it wouldn't help with the real problem, which would be "why is this not an array?". but at least Drupal wouldn't just die. this code is coming from the CCK content_form() function, so unless you have had to patch that as well, it seems like it's not inherently wrong.

well, in any case, it doesn't really matter if it's working for you.

Select lists & radio buttons & autocomplete

Kristen Pol's picture

I'm trying this method and can see all the cck fields in my form but:

1) select list options do not show up
2) radio buttons do not show up
3) autocomplete fields don't work (e.g. State field from location module)

Any ideas? I've been pouring through the code but haven't gotten anywhere.

Thanks,
Kristen

Submit isn't fancy...

spinningbull's picture

So for submit, given this approach, I didn't have to do anything fancy. I just create my Node object as I normally would and call node_save.

For example:

  $node = new stdClass();
    $node->type = 'yourTypeHere';

   $values = $form_state['values'];
$node->title = $values['title'];
  $node->field_projectid = $values['field_projectid'];
  $node->field_payer = $values['field_payer'];
  $node->field_payee = $values['field_payee'];
  $node->field_payeeaddr = $values['field_payeeaddr'];
  $node->field_amount = $values['field_amount'];
    $node->field_status = 'pending';
 
   node_save($node);

This works for me across multiple types. It appears the validation and save handlers work fine for content.

Issue with cck file field

dhakshinait's picture

Thanks for your code. i used it to include one filefield and imagefield. When i tried to upload images for imagefield or files for filefield,it shows an error

"warning: array_shift() expects parameter 1 to be array, null given in E:\xampp\htdocs\mysite\sites\all\modules\filefield\filefield.module on line 597.

"

I debugged the filefield.module for the error,i came to know that the following code cause the error

$args = $form['#parameters'];
  $form_id = array_shift($args);
  $form['#post'] = $_POST;
  $form = form_builder($form_id, $form, $form_state);

File field needs form parameter and so it will extract form id from that and send it to form builder function.Please tell me how can i clear the issue...

subscribe

kkrgopalan's picture

subscribe

for Drupal 5?

kkrgopalan's picture

I am trying to achieve the same functionality in Drupal 5. What would be the equivalent of content_field_form($form, $form_state, $field) in Drupal 5?

Works in D6

coolbung's picture

Just for the record, the solution proposed by vincentdemers-gdo works in D6 with slight modifications
Here's my code -

$node = new stdClass(); //For picture widget we have to create a node object
$node->type = 'trek';
$picturefield = content_fields('field_photos', 'trek');
imagefield_widget($form, $form_state, $picturefield, $node->field_picture);
$form['field_picture'] = imagefield_widget($form, $form_state, $picturefield, $node->field_picture);

Thanks

Content Construction Kit (CCK)

Group organizers

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds:

Hot content this week