Custom field in Drupal 7 with multiple file fields - php

I'm making a custom "video" field that is supposed to accept several files (for different video formats) and a caption. So far the schema is fine, but I can't get it to upload and store the actual files.
My code in hook_field_widget_form looks like this (only pasting relevant bits):
$element['mp4'] = array(
'#type' => 'file',
'#title' => 'MP4 file',
'#delta' => $delta,
);
$element['ogg'] = ... /* similar to the mp4 one */
$element['caption'] = array(
'#type' => 'textfield',
'#title' => 'Caption',
'#delta' => $delta,
);
Also, in my .install file:
function customvideofield_field_schema($field) {
return array(
'columns' => array(
'mp4' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'ogg' => ... /* similar to mp4 */
'caption' => array(
'type' => 'varchar',
'length' => 255,
),
)
);
}
And the error I'm getting is when I try to store data. I get the form ok, and the database looks fine (the fields Drupal generates at least), but when it tries to do an INSERT, it fails because the value it tries to get into those integer fields is an empty string.
From what I understand, they have to be integers, right? (fids?) But I'm guessing the files are not being uploaded, even though I do get the right interface for uploading files.
Drupal shows you the INSERT query it tries to do, which is too long to post here, but I can see there that the value for the caption field (which is just a text field), is fine in the query, so it's only a problem with the file fields.

You probably want to use the managed_file field type instead, it handles uploading the file and registering it in the managed_files table for you. Then you would just add a submit function to your widget form and put the following code (from the FAPI page linked to above):
// Load the file via file.fid.
$file = file_load($form_state['values']['mp4']);
// Change status to permanent.
$file->status = FILE_STATUS_PERMANENT;
// Save.
file_save($file);
// Record that the module (in this example, user module) is using the file.
file_usage_add($file, 'customvideofield', 'customvideofield', $file->fid);
Hope that helps
EDIT
The core file module handles the actual submission for this using hook_field_presave(), my best guess is that this code would work:
function customvideofield_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
// Make sure that each file which will be saved with this object has a
// permanent status, so that it will not be removed when temporary files are
// cleaned up.
foreach ($items as $item) {
$file = file_load($item['mp4']);
if (!$file->status) {
$file->status = FILE_STATUS_PERMANENT;
file_save($file);
}
}
}
That assumes the file ID column for your field is the one called mp4.
Remember to clear Drupal's caches when you implement the new hook or it won't be registered.

I haven't tried file uploading in my Drupal modules yet, but can you check does your form tag have the attribute enctype
="multipart/form-data"?
I would expect Drupal ought to include this automatically, but without it the file fields won't work, which seems to be what you're experiencing.
James

Related

Drupal 7 - node Form template is not used

I have a Problem with one node type and it's form. I want to alter it with an template file. I already did this with another node type on my drupal site and this worked, but it doesn't work for this second type.
So (as I did for the other node type) I placed this hook in my module:
function MY_MODULE_theme($existing, $type, $theme, $path) {
return array(
'FORM_ID' => array(
'arguments' => array(
'form' => NULL,
),
'render element' => 'form',
'template' => 'TYPE-node-form',
'path' => drupal_get_path('module', 'MY_MODULE'),
),
);
}
And also declared this function (in my module):
function template_preprocess_TYPE_node_form(&$variables) {
/* Some hide(elements) and stuff */
}
And of course, I created the file TYPE-node-form.tpl.php in the module directory
/* Something */
TEST
<?php if($form): ?>
<?php print drupal_render_children($form); ?>
<?php endif; ?>
/* Something more */
But it does not load this template ( I cannot see TEST and the other things). Also after multiply times of clearing cache and refreshing.
With DisplaySuite I was able to set a template in the backend (Administration » Structure » Content types » TYPE » Manage fields). But I want to have my own template file (and also not located in the sites/all/modules/ds/layout/.. folder). Deactivating DisplaySuite also does not do the trick.
I also looked tried to place the MY_THEME_theme() code into the template.php file of the administrator theme, but it also did not work.
Any suggestions? What can I do? Is there a way to find out which template is used or where it is overwritten? I have read that Themes overwrite modules templates declaration?!
If you are using D7, hook_theme implementations do not have 'arguments' key, but 'variables'.
Also in this case remove the 'arguments' or 'variables' key in order for the 'render element' to work. Hope this helps.
Final code:
function MY_MODULE_theme($existing, $type, $theme, $path) {
return array(
'FORM_ID' => array(
'render element' => 'form',
'template' => 'TYPE-node-form',
'path' => drupal_get_path('module', 'MY_MODULE'),
),
);
}

Drupal 7 hook_form_alter and submitting the form

I added some custom field so that i can get more information when someone registers into the website but i want to alter one field on the form. I created a module which has a hook_form_alter function so that i can alter the field_first_name of the registration form. here is the code
function user_registration_form_alter(&$form, &$form_state, $form_id){
if ($form_id == 'user_register_form'){
$form['field_first_name'] = array(
'#type' => 'textfield',
'#title' => t('First Name'),
'#description' => t('Enter your first name.'),
'#maxlength' => 255,
'#required' => TRUE,
);
}
if (isset($form['actions']['submit'])) {
$form['actions']['submit']['#submit'][] ='user_registration_form_submit';
}
}
I also created a the function which handles the form submission.
function user_registration_form_submit(&$form, &$form_state)
{
$fe_id = db_insert('field_revision_field_first_name')
->fields(array(
'field_first_name_value' => $form_state['value']['field_first_name'],
))->execute();
drupal_set_message(t('your form entry has been added'));
}
My problem is that when i submit the form and i check the user details. i find that the first name details does not exist in the database or when i login as the administrator and click on the 'people' link. i find that all information is are submitted except the first name field which i am trying to alter. I also tried to submit the form without the form submit function but it still doesn't work.
and i get the following error message if i add the form_submit function
Notice: Undefined index: value in user_registration_form_submit() (line 37 of /var/www/html/lite/sites/all/modules/user_regestration/user_registration.module).
PDOException: SQLSTATE[HY000]: General error: 1364 Field 'entity_id'
doesn't have a default value: INSERT INTO
{field_revision_field_first_name} (field_first_name_value) VALUES
(:db_insert_placeholder_0); Array ( [:db_insert_placeholder_0] => ) in
user_registration_form_submit() (line 38 of
/var/www/html/lite/sites/all/modules/user_regestration/user_registration.module).
THIS IS LINE 37 AND 38 OF MY CODE
'field_first_name_value' => $form_state['value']['field_first_name'],
))->execute();
I am creating the module on localhost first before i push it to the live website
First, it's values not value.
Why don't you use a module providing this functionality, like profile2 ?
The user is not created in your submithandler, so either you save it:
function foo_user_register_form_submit($form, &$form_state){
$edit = array(
'name' => $form_state['values']['name'],
'pass' => user_password(),
'mail' => $form_state['values']['mail'],
'init' => $form_state['values']['mail'],
'status' => 1,
'access' => REQUEST_TIME,
'field_first_name' => array(LANGUAGE_NONE => array(array('value' => $form_state['values']['field_first_name']))),
);
user_save(drupal_anonymous_user(), $edit);
}
For more details see the docs.
Or you could try to add a custom submit handler, which would be fired after the user is created, in form_alter:
$form['#submit'][] = 'your_custom_submit_handler_function';
In there the user should already be created. so:
function your_custom_submit_handler_function(&$form, &$form_state)
{
$fe_id = db_insert('field_revision_field_first_name')
->fields(array(
'field_first_name_value' => $form_state['values']['field_first_name'],
))->execute();
drupal_set_message(t('your form entry has been added'));
}
But keep in mind, that this custom inserting maybe needs some more
code, here you only add the revision entry ..
You're not passing in an entity_id, and your database schema isn't defining a default one. The database expects one, and so it is failing, and it is failing on insert - which is your lines 37 and 38. It has absolutely nothing to do with your first name part.
Basically, Drupal (technically MySQL, or whatever your database backend is) doesn't know what entity you're trying to associate that field with.
Please look at the table that you're actually putting the information into and ensure that the schema either has a default set
Something like:
db_insert('field_revision_field_first_name')
->fields(array(
'field_first_name_value' => $form_state['values']['field_first_name'],
'entity_id' => 1,
))->execute();
Would probably work better for you. There may be other required fields. I recommend taking a look at your database schema.
You also shouldn't have to define a custom form for this - you can add fields to users, and also there is profile2 as another poster mentioned.

File upload in module configuration panel, Prestashop

I'm trying to create a XML import module that will convert given file to CSV format and then use that CSV to import categories and products.
I have a working configuration page made with getContent() it basically calls a method that generates this form via $helper->generateForm(). $helper is a HelperForm() object.
protected function getConfigForm()
{
return array(
'form' => array(
'legend' => array(
'title' => $this->l('Settings'),
'icon' => 'icon-cogs',
),
'input' => array(
array(
'type' => 'file',
'label' => $this->l('XML file'),
'name' => 'XMLIMPORT_XML_FILE',
'desc' => $this->l('Select file you wish to import.'),
'required' => true
),
array(
'col' => 3,
'type' => 'text',
'prefix' => '<i class="icon icon-envelope"></i>',
'desc' => $this->l('Enter a valid email address'),
'name' => 'XMLIMPORT_LINES',
'label' => $this->l('Records per file'),
),
),
'submit' => array(
'title' => $this->l('Save'),
),
),
);
}
I need to get this data to my XML converter. How do I upload a file (around 10-20MB) to Prestashop to be then able to do other stuff with it? How to save it permanently on the server?
I tried doing this:
return array(
'XMLIMPORT_XML_FILE' => Configuration::get('XMLIMPORT_XML_FILE', null),
'XMLIMPORT_LINES' => Configuration::get('XMLIMPORT_LINES', 1000)
);
And after that this:
$form_values = $this->getConfigFormValues(); // returned array from above
foreach (array_keys($form_values) as $key)
Configuration::updateValue($key, Tools::getValue($key));
And later using my own class for XML conversion like this, hoping that it will give me file handle.
$xml_converter = new XMLToCSVConverter(Configuration::get('XMLIMPORT_XML_FILE'), 'output', 'example_products.php');
Apparently it didn't as nothing happens. The class itself is working fine outside of Prestashop module. The constructor is __construct($xml_file, $csv_filename, $template_file).
I need to pass the file I upload to that constructor. I've been struggling for days now.
#edit: I can see the contents of the file inside the HTTP call when submit is clicked. But how do I pass that file to my class?
As far as I remember 'type' => 'file', doesn't actually save any values in the database. This type is only meant to output a file field in your form.
After submitting, you should then do you custom processing with $_FILES['XMLIMPORT_XML_FILE'] : move to upload/ or whereever you want.
'XMLIMPORT_XML_FILE' => Configuration::get('XMLIMPORT_XML_FILE', null), won't return you anything. After uploading you my wish to save the uploaded file path here, but it won't show up next time in the form unless you build the output yourself.
Module configratuon is meant to save text config values. Handling files is trickier and you have to do them yourself each time.
EDIT:
To intercept the saving process, look up the submit button name and make an if statement:
public function getContent() {
if(Tools::isSubmit('submitButtonName')) {
error_log(print_r($_FILES, 1));
}
}
There's probably a function postProcess which does the same (it looks like you copied the methods from a default module).
prestashop handles the image upload with ImageManager class, this class contains more methods which are useful for handling image upload, resize etc.. so its better refer the default homeslider module for the image upload using a module. This module is handling the image upload process in postProcess method with the help of ImageManager class, this class methods will do the all the processes related to upload.

Drupal form submit action changing at random times

I have created a custom Drupal module/form that when submitted the action takes you to another page and posts data with it. Pretty standard stuff.
Randomly, the form action changes at random (not set) intervals during the day that are not correlating to anything immediately obvious - for example cron runs. It only happens maybe once or twice a day, so if anyone has any idea what might cause this or point me in the right direction.
Anything anyone feels needs adding, let me know.
The is the custom module code:
/**
* Test form declaration
*/
function test_form($form, &$form_state){
$form['#attributes'] = array('id' => "test-form");
$form['search-field'] = array(
'#type' => 'textfield',
'#title' => t('<span class="highlighted">Test</span>'),
'#attributes' => array(
'class' => array('form-control form-text'),
),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Search',
'#attributes' => array(
'class' => array('btn btn-default text-hide'),
),
);
return $form;
}
/**
* search form submit
*/
function test_form_submit($form, &$form_state){
$searchQuery = $form_state['values']['search-field'];
$query = array();
if($search <> ''){
$query = array(
'field_geofield_distance[distance]' => '100',
'field_geofield_distance[unit]' => '3959',
'field_geofield_distance[origin]' => $search
);
}
drupal_goto('test-page', array('query' => $query));
}
If your form creates data (let's say a node) possibly you have a redirection on rules when creating a node that with specific values redirects to another page.
Look for rules that are activated when content creation occur or when submission occur.
Also you could have some redirection magic in the top of Drupal, like a wrong configuration of an .htacess file. If your form does the same thing always it should behave the same always. And why it's redirecting to page of old site?
Finally, if the new site have code from the old site the check submission, creation and form altering hooks.
Hope that helps.

How To Specify Filename When Uploading Product Picture Using The Magento Soap Api

I'm using the Magento Soap Api to upload pictures of products. I can't seem to specify the name I wish Magento so save the file as on the server even though I specify the "name" as per the Magento documentation.
I'm using Magento 1.2.1.2 and can't upgrade as the site uses modules that break in newer version.
Any thoughts on how I can specify the file name that Magento saves the image as?
The code I'm using:
$client->call(
$session_id,
'catalog_product_attribute_media.create',
array(
$sku,
array(
'file' => array(
'content' => base64_encode(file_get_contents($filename)),
'mime' => $imageinfo['mime'],
'name' => $filename
),
'label' => $description,
'types' => array(
'image',
'small_image',
'thumbnail'
),
'exclude' => FALSE
)
)
);
You can't specify the filename. The only solution would be for you change the Magento files to allow a filename as suggested in this thread. For your convenience I've included the solution below (and adapted it based on the fact that you're sending the filename as name above):
Modify ./app/code/core/Mage/Catalog/Model/Product/Attribute/Media/Api.php:
You'll want to replace $fileName = 'image.' . $this->_mimeTypes[$data['file']['mime']]; with:
if ( ! empty($data['file']['name']) )
$fileName = $data['file']['name'];
else
$fileName = 'image.' . $this->_mimeTypes[$data['file']['mime']];
If you feel a little more adventurous, you could extend the class instead of changing it and override the create function with your own functionality.

Categories