fixing nodeapi : programmatically submitting forms.
Hey everyone. I don't have a lot of time for core development right now (I will likely only have time again in august, by the looks of things), but we have a problem in core at the moment. I am talking of course of the fact that FAPI only partially replaced node api, leaving neither of them the right solution for programmatically creating nodes and the like. The solution I have in mind for this , is the following : 1 ) introduce a hook_forms. which registers each of the forms on the site. 2 ) register all the forms, and their inputs and create callbacks for them 3 ) put the form creation code into it's own function, with the registered callback 4) alter fapi to not use _POST at all. Instead use a parameter that is passed to it, which merely defaults to _POST. Instead of PUSHING the form array through the form generation process, we now have the ability to PULL the form array and process it. So whenever you want to display a form, instead of having function mymodule_page_callback() { $form['title'] = array( /* generate your form array here */ ); return drupal_get_form('form_id', $form, 'alternate'); } You have : function mymodule_forms() { $form['mymodule/form_id'] = array( 'callback' => 'mymodule_form_id', 'access' => user_access('can do form_id'), 'title' => 'form title' ); } function mymodule_form_id($input) { $form['title'] = array( /* generate your form array here */ ); return $form; } function mymodule_page_callback() { // get your form input ready return drupal_get_form('mymodule/form_id', array('input' => 'object')); } -- Adrian Rossouw Drupal developer and Bryght Guy http://drupal.org | http://bryght.com
As you say, this is sorely needed. This is a big project, but I'm really contemplating giving it a start. I might do a proof of concept. Anyone else interested in joining? Adrian Rossouw wrote:
Hey everyone.
I don't have a lot of time for core development right now (I will likely only have time again in august, by the looks of things), but we have a problem in core at the moment. I am talking of course of the fact that FAPI only partially replaced node api, leaving neither of them the right solution for programmatically creating nodes and the like.
The solution I have in mind for this , is the following :
1 ) introduce a hook_forms. which registers each of the forms on the site. 2 ) register all the forms, and their inputs and create callbacks for them 3 ) put the form creation code into it's own function, with the registered callback 4) alter fapi to not use _POST at all. Instead use a parameter that is passed to it, which merely defaults to _POST.
Instead of PUSHING the form array through the form generation process, we now have the ability to PULL the form array and process it.
So whenever you want to display a form, instead of having
function mymodule_page_callback() {
$form['title'] = array( /* generate your form array here */ ); return drupal_get_form('form_id', $form, 'alternate'); }
You have :
function mymodule_forms() { $form['mymodule/form_id'] = array( 'callback' => 'mymodule_form_id', 'access' => user_access('can do form_id'), 'title' => 'form title' ); }
function mymodule_form_id($input) { $form['title'] = array( /* generate your form array here */ ); return $form; }
function mymodule_page_callback() { // get your form input ready return drupal_get_form('mymodule/form_id', array('input' => 'object')); }
-- Adrian Rossouw Drupal developer and Bryght Guy http://drupal.org | http://bryght.com
On Wed, 28 Jun 2006 23:26:58 +0200, Moshe Weitzman <weitzman@tejasa.com> wrote:
As you say, this is sorely needed. This is a big project, but I'm really contemplating giving it a start. I might do a proof of concept. Anyone else interested in joining?
I think I would be, but first, I'd like to hear more of the 'why'. Yes, what we have is not ideal. But I can't think we want to compile all forms just to display one of them. That'd be quite a bit slow...
But I can't think we want to compile all forms just to display one of them. That'd be quite a bit slow...
thats a good point. but i don't think it would be slow. we just have to keep a one dimensional array of paths. we don't have to do any fancy hierarchy stuff like hook_menu(), so i don't see this hook being any more expensive than all our other hooks. it is roughly as expensive as hook_link(), for example.
On Thu, 29 Jun 2006 04:59:45 +0200, Moshe Weitzman <weitzman@tejasa.com> wrote:
But I can't think we want to compile all forms just to display one of them. That'd be quite a bit slow...
thats a good point. but i don't think it would be slow. we just have to keep a one dimensional array of paths. we don't have to do any fancy hierarchy stuff like hook_menu(), so i don't see this hook being any more expensive than all our other hooks. it is roughly as expensive as hook_link(), for example.
Forget my previous mail. I should not mail at this ungodly hour...
Adrian Rossouw wrote:
1 ) introduce a hook_forms. which registers each of the forms on the site. 2 ) register all the forms, and their inputs and create callbacks for them
What would this list be used for?
3 ) put the form creation code into it's own function, with the registered callback
Maybe in it's own file too, along with ..._validate, ..._submit, etc. Less code to include up front. Something along the lines of path_to_module/forms/form_id.form.php would get auto-included.
4) alter fapi to not use _POST at all. Instead use a parameter that is passed to it, which merely defaults to _POST.
Would the form creation code need to set #value itself then?
function mymodule_forms() { $form['mymodule/form_id'] = array( 'callback' => 'mymodule_form_id', 'access' => user_access('can do form_id'),
Shouldn't this be handled in ..._validate() or hook_menu()?
'title' => 'form title'
What would the title do?
); }
function mymodule_form_id($input) {
I would go ahead and put _form on the end of that function name.
$form['title'] = array( /* generate your form array here */ ); return $form; }
function mymodule_page_callback() { // get your form input ready return drupal_get_form('mymodule/form_id', array('input' => 'object')); }
-- Neil Drumm http://delocalizedham.com/
Neil Drumm wrote:
Adrian Rossouw wrote:
1 ) introduce a hook_forms. which registers each of the forms on the site. 2 ) register all the forms, and their inputs and create callbacks for them
What would this list be used for?
the idea here is to present a directory to developers of all the forms that they can programmatically submit. For all the user forms, I just browse the forms registered under /user. This is just a directory, not used by the code.
function mymodule_forms() { $form['mymodule/form_id'] = array( 'callback' => 'mymodule_form_id', 'access' => user_access('can do form_id'),
Shouldn't this be handled in ..._validate() or hook_menu()?
we are not wanting to mess with menu system just yet.
3 ) put the form creation code into it's own function, with the registered callback
Maybe in it's own file too, along with ..._validate, ..._submit, etc. Less code to include up front. Something along the lines of path_to_module/forms/form_id.form.php would get auto-included.
maybe. lets see how we do getting all the theme files separated out and modules in own directories.
4) alter fapi to not use _POST at all. Instead use a parameter that is passed to it, which merely defaults to _POST.
Would the form creation code need to set #value itself then?
no, this would still happen in form_build
function mymodule_forms() { $form['mymodule/form_id'] = array( 'callback' => 'mymodule_form_id', 'access' => user_access('can do form_id'),
Shouldn't this be handled in ..._validate() or hook_menu()?
'title' => 'form title'
What would the title do?
just for the directory. i still think this is a much needed improvement
function mymodule_forms() { $form['mymodule/form_id'] = array( 'callback' => 'mymodule_form_id', 'access' => user_access('can do form_id'),
*snip* doing this is blatantly easy. I actually have the script that changes a return drupal_get_form to a hook forms array. Will post the code later in case anyone is interested.
How about making it a drupal_<blah>() and contribbing it into 4.7.3? -- Sammy Spets Synerger Pty Ltd http://www.synerger.com/ On 11-Jul-06 05:26, Karoly Negyesi wrote:
function mymodule_forms() { $form['mymodule/form_id'] = array( 'callback' => 'mymodule_form_id', 'access' => user_access('can do form_id'),
*snip* doing this is blatantly easy. I actually have the script that changes a return drupal_get_form to a hook forms array. Will post the code later in case anyone is interested.
Karoly Negyesi wrote:
function mymodule_forms() { $form['mymodule/form_id'] = array( 'callback' => 'mymodule_form_id', 'access' => user_access('can do form_id'),
*snip* doing this is blatantly easy. I actually have the script that changes a return drupal_get_form to a hook forms array. Will post the code later in case anyone is interested.
yes, please share this script.
Karoly Negyesi wrote:
function mymodule_forms() { $form['mymodule/form_id'] = array( 'callback' => 'mymodule_form_id', 'access' => user_access('can do form_id'),
*snip* doing this is blatantly easy. I actually have the script that changes a return drupal_get_form to a hook forms array. Will post the code later in case anyone is interested.
yes, please share this script.
A couple of tangentially related snippets: 1. Learn about all available forms, with an address they can be fetched at: /** * Implementation of hook_form_alter(). * * Register available forms into an array variable. */ function jstools_form_alter($form_id, &$form) { // If this form_id is not already registered, register it. $options = variable_get('jstools_forms_options', array()); if (!array_key_exists($form_id, $options)) { $options[$form_id] = $_GET['q']; variable_set('jstools_forms_options', $options); } } 2. Fetch a form in JSON format. This is code we're looking at using in the formbuilder module. /** * Implementation of hook_form_alter(). * * Redirect a page request to output a given form in JSON format. * * This method depends on a form_alter done in jstools.module, where the * variable 'jstools_forms_options' is populated with an array of available * forms in the format 'form_id' => 'path'. If desired, relevant code could * be copied from jstools_form_alter() to remove this dependency. * * To use this method, a javascript call needs to issue an AJAX page request * appending a 'formbuilder_form' form_id value to the URL in GET encoding. * The corresponding form will be returned in JSON encoding. */ function example_form_alter($form_id, &$form) { // If the formbuilder has been called, redirect the form output. if (!empty($_GET['example_form']) && ($_GET['example_form'] == $form_id) && (user_access('load forms')) { if (is_array($form['#pre_render'])) { $form['#pre_render'][] = 'example_dispatch'; } else { $form['#pre_render'] = array('example_dispatch'); } } } /** * Send a form as a Javascript object in JSON notation. */ function example_dispatch($form_id = NULL, $form = NULL) { if (user_access('load forms')) { drupal_set_header('Content-Type: text/javascript'); print 'var form = '. drupal_to_js($form) .";\n"; } exit(); }
On 14 Jul 2006, at 9:56 PM, Nedjo Rogers wrote:
A couple of tangentially related snippets:
if we implement this , you could just do a hook_forms call, and do json conversions by just calling the form callback. much much simpler. Also, you can replace forms by just altering the form callbacks. So it calls your replaced forms instead of the basic ones. -- Adrian Rossouw Drupal developer and Bryght Guy http://drupal.org | http://bryght.com
if we implement this , you could just do a hook_forms call, and do json conversions by just calling the form callback.
much much simpler.
Indeed. I've done a similar redirection of form submission in the ajaxsubmit.module (part of Javascript Tools), where we set a form element which triggers the submit to be redirected to a JSON callback. It required some fancy footwork to handle previews vs. submits with errors vs. successful submits. Functional, but again the planned approach would simplify AJAX submissions as well.
participants (6)
-
Adrian Rossouw -
Karoly Negyesi -
Moshe Weitzman -
Nedjo Rogers -
Neil Drumm -
Sammy Spets