Drupal 6 hook_form_FORM_ID_alter adding upload file field - drupal

I'm trying to extend a form and add an upload file field from within a module, I can see the file field just fine, but it's empty when I submit the form, the enctype is set.
$form['#attributes'] = array(
'enctype' => "multipart/form-data"
);
$form['file_upload'] = array(
'#type' => 'file',
'#title' => 'Attach Image'
);
custom form submit hook:
$form['#submit'][] = 'user_images_handler';
is being called, but when I dump the form, the file field is empty, and when I try to access it, it's empty as well.

File uploads are special in that the 'submitted' (uploaded) data does not end up in the form, but needs to be processed separately (uploading is not really a part of form submission but a separate transmission process).
See the docs for file_save_upload(), and as an example, see how it is used on form submission usage from within the upload module.
Basically, you just try to save the upload by calling file_save_upload() with the name of the upload field (and some other arguments) and check the result of this try.

Hmm, I tried that and it didn't work...it still says the upload field is empty.
I have a debugging print statement at the submit function but it doesn't print so I don't think it is even getting to the submit function.
Where are you suppose to put the file_save_upload() call?
Note, my form is named mmil_upload_form ( $form_state ) and the submit function is named function mmil_upload_form_submit ( $form, &$form_state )

Related

SilverStripe edit gridfield success message on save

What's the easiest way to edit the default success message when saving an item in GridField edit view?
The message seems to be in a variable in class GridFieldDetailForm within method doSave.
$message = _t(
'GridFieldDetailForm.Saved',
'Saved {name} {link}',
array(
'name' => $this->record->i18n_singular_name(),
'link' => $link
)
);
Since the message uses the _t() function it will attempt to fetch the value defined in the lang file corresponding to the current user's locale. The default string defined in the function is just a fallback for when no translation could be found within the lang files.
To change the message you can update your site's yml lang file located in mysite/lang/{LANGUAGE_CODE}.yml
For english this would be:
# mysite/lang/en.yml
# remember to flush after editing me :-)
en:
GridFieldDetailForm:
Saved: 'My custom message using {name} and here is a link to the object: {link}'
https://docs.silverstripe.org/en/3.4/developer_guides/i18n/
Something like this should work for specific implementations
$form = $gridField->getConfig()->getComponentByType('GridFieldDetailForm');
$form->setItemEditFormCallback(function($form, $itemRequest)
{
// Replace save action with custom method in here
});
For more general implementations, you'll likely want to extend GridFieldDetailForm and override doSave, then replace the GridFieldDetailForm component with your custom class.

Form tests: How to submit a collection to an existing form? [duplicate]

This question already has answers here:
Symfony2: Test on ArrayCollection gives "Unreachable field"
(4 answers)
Closed 6 years ago.
I use two ways to test my forms:
By using $form = …->form();
Then setting the values of the $form array (more precisely this is a \Symfony\Component\DomCrawler\Form object):
Full example from the documentation:
$form = $crawler->selectButton('submit')->form();
// set some values
$form['name'] = 'Lucas';
$form['form_name[subject]'] = 'Hey there!';
// submit the form
$crawler = $client->submit($form);
By sending the POST data directly:
The previous code doesn't work with forms which manage collections (relying on fields created by Javascript) because it throws an error if the field doesn't exist. That's why I also use this other way.
Full example from the documentation:
// Directly submit a form (but using the Crawler is easier!)
$client->request('POST', '/submit', array('name' => 'Fabien'));
This solution is the only way I know to test forms which manage collections with fields added by Javascript (see link to documentation above). But this second solution is harder to use because:
it doesn't check which fields exist, this is impractical when I have to submit a form with existing fields and a collection which relies on fields created dynamically with Javascript
it requires to add the form _token manually
My question
Is it possible to use the syntax from the first way to define the existing fields then add new dynamically created fields with the second syntax?
In other words, I would like to have something like this:
$form = $crawler->selectButton('submit')->form();
// set some values for the existing fields
$form['name'] = 'Lucas';
$form['form_name[subject]'] = 'Hey there!';
// submit the form with additional data
$crawler = $client->submit($form, array('name' => 'Fabien'));
But I get this error:
Unreachable field "name"
And $form->get('name')->setData('Fabien'); triggers the same error.
This example is not perfect because the form has no collection, but it's enough to show you my problem.
I'm looking for a way to avoid this validation when I add some fields to the existing form.
This can be done by calling slightly modified code from the submit() method:
// Get the form.
$form = $crawler->filter('button')->form();
// Merge existing values with new values.
$values = array_merge_recursive(
$form->getPhpValues(),
array(
// New values.
'FORM_NAME' => array(
'COLLECTION_NAME' => array(
array(
'FIELD_NAME_1' => 'a',
'FIELD_NAME_2' => '1',
)
)
)
)
);
// Submit the form with the existing and new values.
$crawler = $this->client->request($form->getMethod(), $form->getUri(), $values,
$form->getPhpFiles());
The array with the news values in this example correspond to a form where you have a fields with these names:
<input type="…" name="FORM_NAME[COLLECTION_NAME][A_NUMBER][FIELD_NAME_1]" />
<input type="…" name="FORM_NAME[COLLECTION_NAME][A_NUMBER][FIELD_NAME_2]" />
The number (index) of the fields is irrelevant, PHP will merge the arrays and submit the data, Symfony will transform this data in the corresponding fields.

Drupal7 copy filefield to another node at submit

I have a content type that has unlimited filefield fields in addition to other fields. At node save/submit I would like to create an additional node for each file in the field, and assign that filefield to it. I'm fine with the nodeapi hooks and progmatically creating the node, but I can't access the content of the filefield from the node. When I print the filefield contents from within hook_node_insert I get:
...
(
[fid] => 38
[display] => 1
[description] =>
[upload_button] => Upload
[remove_button] => Remove
[upload] =>
)
....
Not the formatted and proceed field I would normally see. My suspicion is that I can access this somehow from the form and do a form submit after modifying it, but I'm not sure how to do this and it may not the best way. Let me know if you have any tips on this, greatly appreciated.
since we have [fid] populated we can use file_load($fid) to load the file object. Then you can cast this file object to array and then attach it to the file field of newly created node.
Loop through the array and for each $fid you encounter..
$file = file_load($fid);
$new_node= new StdClass();
$new_node->type = 'image';
$new_node->language = LANGUAGE_NONE;
node_object_prepare($new_node);
// add additional data about new node.
$new_node->field_custom_files[LANGUAGE_NONE][] = array($file);
node_submit($new_node);
node_save($new_node);
I have not tested this, but do let me know if you face any issues.

Form submit handlers with additional arguments

For some requirement I need to pass additional information to form submit handler. In form api, while defining custom submit handler as
$additional_args = array();
$form['#submit'][] = 'my_submit_handler'
I expect to submit handler as
function my_submit_handler($form, &$form_state, $additional_args){
The submit handler is called by the drupal fapi, so you can't do something like that. Instead what you can do, is to add what you need, either to the $form, or to the $form_state. The usual approaches is to:
Added a field to the form, type value to store the value. Don't do this if you have the value in the form definition.
$form['store'] = array(
'#type' => 'value',
'#value' => $value
);
This will be available in $form_state['values']['store'].
Add the value to $form_state['storage'], done if you variables in your validation handle you want to transfer to your submit handler:
// Validation.
$form_state['storage']['value'] = $value;
...
// Submit
$value = $form_state['storage']['value'];
// Need to unset stored values when not used anymore.
unset($form_state['storage']['value']);
Drupal 7: Custom arguments are automatically propagated troug $form_state['build_info']['args']
This is said in http://api.drupal.org/api/drupal/includes!form.inc/function/drupal_get_form/7
Ex:
hook_form($form, &$form_state, $myAdditionnalArg) {...}
Then in
hook_form_submit($form, &$form_state) {
...
//$form_state['build_info']['args'] is an array containing at index 0 the value of argument $myAdditionnalArg
...
As reported in $form['#submit'] and $form['#validate'] and $form['#process'] no longer support custom parameters, the suggested way to pass parameters to a submission handler set as in the shown code is to use code similar to the following:
$form['#first_paramater'] = $value;
$form['#submit'][] = 'my_submit_handler';
The handler would retrieve the value as $form['#first_paramater'].
To notice that, instead of #first_paramater, the code can use a different string, but it must start with #.
Normally it's not necessary to set a submission handler like the code does, but there are some cases where it is necessary, like to alter a form created by another module, or to set a different submission handler for each of the submission buttons present in a form.
drupal_retrieve_form() saves the parameters passed to the form build handler in $form['#parameters'] which contains:
$form_id
$form_state
parameters passed to the form builder

How do I persist form data across an "access denied" page in Drupal?

We're building a small sub-site that, on the front page, has a one input box form that users can submit. From there, they're taken to a page with a few more associated form fields (add more details, tag it, etc.) with the first main form field already filled in. This works splendidly, thus far.
The problem comes for users that are not logged in. When they submit that first form, they're taken to a (LoginToboggan based) login page that allows them to login. After they login, they redirect to the second form page, but the first main form field isn't filled in -- in other words, the form data didn't persist.
How can we store that data and have it persist across the access denied page?
You could save the data in a cookie that would be passed to the page after the login page.
Assuming that you are using the Form API to create the form, and that you have a field called "fieldname" in the function to generate the form:
function my_form() {
$form['fieldname'] = array (
'#type' => 'textfield',
'#title' => 'Some fieldname'
);
// Second field if you need to save another
$form['fieldname2'] = array (
'#type' => 'textfield',
'#title' => 'Some other fieldname'
);
}
Set the cookie(s) in the submit handler for your form:
function my_form_submit($form, &$form_state) {
// Set the cookie with their data before they are redirected to login
// Use the array syntax if you have one than one related cookie to save,
// otherwise just use setcookie("fieldname",...
setcookie("saved_data[fieldname]", $form_state['values']['fieldname']);
// Your other code
}
After they login and are redirected to page two of your form, you can read the value of the cookie(s) and if they exist, insert them into the default values of the fields:
function my_form() {
if (isset($_COOKIE['saved_data[fieldname]'])) {
$default_fieldname = $_COOKIE['saved_data[fieldname]'];
}
else {
$default_fieldname = '';
}
// Same check for the second field
if (isset($_COOKIE['saved_data[fieldname2]']))...
$form['fieldname'] = array (
'#type' => 'textfield',
'#title' => 'Some fieldname',
'#default_value' => $default_fieldname
);
// Second field if used
$form['fieldname2'] = array (
'#type' => 'textfield',
'#title' => 'Some other fieldname',
'#default_value' => $default_fieldname2
);
}
The cookies(s) will be presented on each page load after they are set, so it doesn't matter if there are several failed login attempts or other page views in between. You should probably delete the cookies after they're used or set a short expiration time so that they are cleaned up automatically.
I don't know if there is a good way to transfer form data from two entirely different forms in Drupal, especially in the context of access denied. The best choices I can find would be to:
Use the url to send the data for the field.
You could also save the data in the db, but it might be a bit tricky to extract the data again.

Resources