I have a nicely working script that can be seen at work over in CVS to add more form fields as needed to my edit page.

I had much magic going on under 4.6, (functional demo of the relationship module but I'm having a blue hell of a time remaking that functionality under 4.7.

First I was no longer able to just create arbitrarily auto-numbered name="[fieldname][]" arrays of fields and count them up on submission, So I've figured out how to force index numbers [fieldname][1] , [fieldname][2] into them.

But although I can see the postdata is now sending all the new fields and structure my client created, the form given back to me by the time I attempt to hook_nodeapi('validate') it is trash.

What do I have to do within Form API to find that unexpected data?
What's the story with this #DANGEROUS_SKIP_CHECK? It seems like I'll need it (my selects are dynamically populated also) , but that's not throwing any errors yet.

I'm trying really hard to work within the new paradigm, but everything I've tried has been 3 x harder than before! I know I'm trying to be too clever, but I know it must be possible!

Tell me what I'm missing!

.dan.

Comments

dman’s picture

chx’s picture

but can't. Really sorry, but I can't understand your problem. Form API now checks whether the option selected is in #options or not. If it's not then it'll throw a form error. You can skip this but I considered it dangerous hence the name.
--
My developer blog. | The news is Now Public | Ask not what Drupal can do for you -- ask what you can do for Drupal.

--
Drupal development: making the world better, one patch at a time. | A bedroom without a teddy is like a face without a smile.

dman’s picture

I understand the dangerous validation, but I'm trying to find where the actual form submission gets put back into the node.

It appears that only fields that were originally output are being read back in.
I also understand that is a fair validation step, but I need to route around it. The data is sitting there in $_REQUEST['edit'] but it didn't make it into my node on preview. I can see the parameters are otherwise OK, but my new data was filtered out somewhere. My question is at what point in the process?

I guess I'll grab it from request and go from there :(

http://www.coders.co.nz/

moshe weitzman’s picture

hi dan. many of us are eally hoping for you to port to 4.7. keep up the faith.

look into the the #tree element in form api. that will help your nested arrays from being flattenned when you read them back out after a POST.

The node form follows is a bit hard to follow but general follows the display/validate/execute model which is common in 4.7. Display is handled in node_form(), validate in node_form_validate() and submit in node_form_submit(). Before those functions see the POST data though it gets sanitized and unknown fields are discarded. You can still access them via the superglobals.

I looked for a minute at your demo form. It seems that your javascript does not add new fields to the $form but rather new items to an existing array. In that case, I don't think you will have a problem with form api discarding your fields. But I did not look closely. If you are seeing the discarding, perhaps you should pre-create hiden fields in the $form and then populate them as needed during display. Or just access the superglobals in the validate or execute operations of hook_nodeapi

Also, feel free to join the developer channel at #drupal on freenode.net IRC server. They can help you work through these forms.

dman’s picture

look into the the #tree element in form api. that will help your nested arrays from being flattenned when you read them back out after a POST.

I haven't found that a problem, I eventually figured out how to create a real structure and correct fieldnames by faking the #parents array

Before those functions see the POST data though it gets sanitized and unknown fields are discarded. You can still access them via the superglobals.

This was the problem. I've given up on trusting this, so I'm now read directly from the $_REQUEST and telling forms api to ignore a few bits.

I looked for a minute at your demo form. It seems that your javascript does not add new fields to the $form but rather new items to an existing array.

That version did, yes.
When I figured out the #parents naming convention (and thought a bit) however I collapsed my parallal indexed arrays into actual structures (which saves some code where I used to remake the statements)

My fields now look like

$edit[statements][key0][subject]   = 'node/1'
$edit[statements][key0][predicate] = 'seeAlso'
$edit[statements][key0][object]    = 'node/5'

$edit[statements][key1][subject]   = 'node/1'
$edit[statements][key1][predicate] = 'seeAlso'
$edit[statements][key1][object]    = 'node/7'

Which (should) unpack automatically into :

$node->statements = (
  key0 => (
    subject   => 'node/1',
    predicate => 'seeAlso',
    object    => 'node/5'
  ),
  key1 => (
    subject   => 'node/1',
    predicate => 'seeAlso',
    object    => 'node/7'
  )
)

... all cool.

BUT

if the form fields (n+1) were not in the original constructed form array thing, they are not looked for, and don't show up.

So I'm bypassing a hunk of the forms code just to get at my data.

If you are seeing the discarding, perhaps you should pre-create hiden fields in the $form and then populate them as needed during display.

No can do, that's all a bit messy, as I want unlimited new rows on-the-fly.

Or just access the superglobals in the validate or execute operations of hook_nodeapi

I'm attacking it this way, but I can no longer fix this in nodeapi(validate) because I cannot modify my node there :( I miss that.
I've eventually put my read_form parser code in the top of my form_alter(). I'm seeing some funny side effects as it overlaps with the normal forms_api value pre-population, and I dunno if the form #node value is a good thing to tweak or if it's a clone. but I've almost got it.

Thanks for the thoughts.

.dan.

moshe weitzman’s picture

fyi - there is now a step between nodeapi validate and nodeapi insert/update caled nodeapi('submit') where such changes belong now. see http://drupal.org/node/22218#node_hook_order

dman’s picture

Thankee moshe, ... I think that sounds like what I was looking for.

Note, I'm layering this onto a normal node save - not my own form - but I think there's some node_invoke_all() or something that loops out and calls this function for me.

I'll see if the data is available then, at that point.
I need to be able to actually change the form, depending on what was just submitted (like some modules do when adding new rows for multiple entries)
Let's find out.

.dan.

http://www.coders.co.nz/

ultimike’s picture

Dan,

Any more progress on this? I'm trying to implement a similar thing and found your javascript code a good starting point.

Thanks in advance,
-mike

dman’s picture

(with scaffolding - only 20% is relevant)
looks like:


/**
 * Make a modification to a from.
 *
 * Note, this hook runs for every possible form!
 * Check to see if it's one we care about
 */
function relationship_form_alter($form_id, &$form) {
  // dsm($form);
  if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id) {
    debug("Adding relationship edit table to the edit form $form_id",2);
    // don't fully understand that check

    // check that we apply relationships to this type at all
    $active_node_types = variable_get('relationship_nodes',array());
    //drupal_set_message("relationships apply to ".print_r($active_node_types,1));
    if (! in_array($node->type, $active_node_types)) {return;} // Not a node type we deal with


    $node = $form['#node']; 
    
    # dsm($node);
    // As form alter is now called to create the structure of the form before
    // we even look at the submitted data, it's hard to manipulate the form 
    // based on what's just happened. http://drupal.org/node/37194
    // I need to check the submission to see if any new fields have appeared (via client insertion)
    // To know how my new version of the form will look.
    // relationship_read_form does this, so we'll call it now.
    relationship_read_form($node);
    
    $form['relationship'] = relationship_form(&$node);
    // the final return is not needed because $form is a reference.
  }
}

function relationship_read_form(&$node){
  debug("Reading submitted form values back into statements. Posted values are:",2);
  #debug_pre($_REQUEST['edit'],2);
  debug_pre($_REQUEST['edit']['statements'],2);
  #debug("Reading submitted form values back into statements. Current known node statements:");
  #debug_pre($node->statements);
  // form api doesn't recognise any fields added by the client (for security reasons) 
  // but I need to bypass that . Read directly from the submission
  $submitted_statements = $_REQUEST['edit']['statements'];
  
  if (is_array($submitted_statements) ) {
    foreach ($submitted_statements as $ix => $statement) {

      if ($statement && $statement['predicate'] && $statement['object']) {
        $statement['subject'] = ($statement['subject'])? $statement['subject'] : $node->nid;
        $statement['object']  = trim($statement['object']);
        $statement['title']   = trim($statement['title']);
        $statement['why']     = ($statement['why'])?$statement['why']:'user/'.$GLOBALS['user']->uid;
        // It's possible a 'sid' number or a 'discard' flag will be sent through here also. Keep it.

        $key = _relationship_hash_key($statement);
        if($key != $ix){ // re-index this item
          unset($node->statements[$ix]);
#            unset($_REQUEST['edit']['statements'][$ix]);
        }
        $node->statements[$key] = $statement;
        debug('Set up statement '.$key,3);
      }
    }
  }
  debug("Finished reading form. statements are now:".print_r($node->statements,1)."",2);
  return $node;
}

Basically I'm side-tracking during form_alter() to go fetch the values I want from the superglobal $_REQUEST.
Bypassing the form_api niceness and working the bog-standard old cgi way.

The node (which seems to be OK handled by reference) seems to accept the extra data OK.

I feel it's dodging some of the forms cleverness ... but it's needed to work for me. It seems forms_api is not capable of handling anonymous arrays (like edit[myfield][] , edit[myfield][] ) anymore. That used to resolve to :
$edit[myfield][1]
$edit[myfield][2]

and be accessable. Now it resolves to nothing :(

.dan.

http://www.coders.co.nz/

moshe weitzman’s picture

if the node form is giving you fits, you might choose to add a metadata tab to the node/x page and then you can display/handle the form on your own callback, and not fight with node api.