Drupal 7 hook_form_alter and submitting the form - php

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.

Related

Chtml::link not getting ID of event attendee

I'm currently trying to redirect a user from a view in the events folder, going to the user folder with the id of the event attendee.
The issue I'm having is that the url is returning without the idea, in this case it should be 56. /user/InviteGuest/eventId but no ID
<p>You can also invite a guest to attend this event with you.
<?php echo CHtml::link("Click here to invite a guest", array('/user/InviteGuest', 'eventId' => EventAttendees::model()->id))?></p>
It doesn't seem to be getting the ID from the model and populating the field ID, it works fine when I link from within the event attendee views.
edit. for example in a view in the eventattendees folder
array('label' => 'Invite Guests','buttonType'=>'link', 'icon' => 'group', 'url' => array('/user/InviteGuest', 'eventId' => $data->id)),
work fine
'eventId' => EventAttendees::model()->id
This is not getting any data, unless your EventAttendees' id is set to 56 by default, which is really odd. "id" is usually used for primary keys.
I think what you're missing is to load your data. Maybe something like this:
// Exemple, not actual tested code
// In your controller
$attendee = EventAttendees::model()->findByAttributes( array(
'whatever'=>$something,
));
$this->render('view', array(
'attendee'=>$attendee,
));
// In your view
<?php echo CHtml::link("Click here to invite a guest", array('/user/InviteGuest', 'eventId' => $attendee->id))?></p>

Opencart adding a new field to the customer view of the admin section

I have added a new field to my database. I also have managed to add necessary codes and functions in catalog section. This new field is related to the customer. The data related to this new field gets added successfully to the database.
This new field belongs to Customer table.
Now, I want to know, when viewing customer's details in the admin section, how this new field should be retrieved from database? I mean which file should be edited for this purpose?
getCustomer($customer_id) and getCustomers($data = array()) are the functions used to get customer data.
Since they are SELECT * querys your field is being processed automatically.
Afterwards you need to go in the Controller section in the controller\sale folder and there you have customer.php, custom_field.php and and edit the ones that you need. For example:
$this->data['customers'][] = array(
'customer_id' => $result['customer_id'],
'name' => $result['name'],
'email' => $result['email'],
'customer_group' => $result['customer_group'],
'status' => ($result['status'] ? $this->language->get('text_enabled') : $this->language->get('text_disabled')),
'approved' => ($result['approved'] ? $this->language->get('text_yes') : $this->language->get('text_no')),
'ip' => $result['ip'],
'date_added' => date($this->language->get('date_format_short'), strtotime($result['date_added'])),
'selected' => isset($this->request->post['selected']) && in_array($result['customer_id'], $this->request->post['selected']),
'action' => $action
);
add your field in this array (this is from customer.php).
And finally edit the .tpl files that are called from the view\template\sale folder so they appear where they want them to.
Hope i was clear enough.

Custom field in Drupal 7 with multiple file fields

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

Access custom error messages for InArray validator when using Zend_Form_Element_Select

I'm using Zend Framework 1.62 (becuase we are deploying the finished product to a Red Hat instance, which doesn't have a hgih enough PHP version to support > ZF1.62).
When creating a Form using Zend Form, I add a select element, add some multi options.
I use the Zend Form as an in-object validation layer, passing an objects values through it and using the isValid method to determine if all the values fall within normal parameters.
Zend_Form_Element_Select works exactly as expected, showing invalid if any other value is input other than one of the multi select options I added.
The problem comes when I want to display the form at some point, I cant edit the error message created by the pre registered 'InArray' validator added automatically by ZF. I know I can disable this behaviour, but it works great apart from the error messages. I've tryed the following:
$this->getElement('country')->getValidator('InArray')->setMessage('The country is not in the approved lists of countries');
// Doesn't work at all.
$this->getElement('country')->setErrorMessage('The country is not in the approved lists of countries');
// Causes a conflict elswhere in the application and doesnt allow granular control of error messages.
Anyone have any ideas?
Ben
I usually set validators as per my example below:
$this->addElement('text', 'employee_email', array(
'filters' => array('StringTrim'),
'validators' => array(
array('Db_NoRecordExists', false, array(
'employees',
'employee_email',
'messages' => array(Zend_Validate_Db_Abstract::ERROR_RECORD_FOUND => 'A user with email address %value% already exists')
))
),
'label' => 'Email address',
'required' => true,
));
The validators array in the element options can take a validator name (string) or an array.
When an array is passed, the first value is the name, and the third is an array of options for the validator. You can specify a key messages with custom messages for your element in this array of options.
If your using Zend_Form_Element_Select (or any of the Multi subclasses), on validation the InArray validator will only be automatically added if there is not one present.
You can set a validator as so:
$options = array(...);
$this->addElement('select', 'agree', array(
'validators' => array(
array('InArray', true, array(
'messages' => array(
Zend_Validate_InArray::NOT_IN_ARRAY => 'Custom message here',
),
'haystack' => array_keys($options),
)),
'multiOptions' => $options,
));
and then your validator will be used instead of the automatically attached one.
$el = $this->addElement($name, $label, $require, 'select');
$validator = new Zend_Validate_InArray(array_keys(AZend_Geo::getStatesList()));
$validator->setMessage('Invalid US State.');
$el
->setMultiOptions(AZend_Geo::getStatesList())
->setRegisterInArrayValidator(false)
->addValidator($validator)
->addFilter(new Zend_Filter_StringToUpper())
->addFilter(new T3LeadBody_Filter_SetNull())
->setDescription('US State. 2 char.');

Zend Form Edit and Zend_Validate_Db_NoRecordExists

I am slowly building up my Zend skills by building some utility websites for my own use. I have been using Zend Forms and Form validation and so far have been happy that I have been understanding the Zend way of doing things. However I am a bit confused with how to use Zend_Validate_Db_NoRecordExists() in the context of an edit form and a field that maps to database column that has to be unique.
For example using this simple table
TABLE Test
(
ID INT AUTO_INCREMENT,
Data INT UNIQUE
);
If I was simply adding a new row to the Table Test, I could add a validator to the Zend Form element for the Data field as such:
$data = new Zend_Form_Element_Text('Data');
$data->addValidator( new Zend_Validate_Db_NoRecordExists('Test', 'Data') )
At form validation this validator will check that the contents of the Data element does not already exist in the table. Thus the insert into Test can go ahead without violating the Data fields UNIQUE qualifier.
However the situation is different when editing an existing row of the Test table. In that case the validator needs to check that the element value meets one of two mutually exclusive conditions conditions:
The user has changed the element value, and the new value does not currently
exist in the table.
The user has Not changed the element value. Thus the value does currently exist in the table (and this is OK).
The Zend Validation Docs talk about adding a parameter to the NoRecordExists() validator for the purpose of excluding records from the validation process. The idea being to "validate the table looking for any matching rows, but ignore any hits where the a field has this specific value". Such a use case is what is needed for the validating the element when editing a table. The pseudo code to do this in 1.9 is like so (actually I got this from the 1.9 source code - I think the current docs may be wrong):
$data = new Zend_Form_Element_Text('Data');
$data->addValidator( new Zend_Validate_Db_NoRecordExists('Test', 'Data',
array ('field'=>'Data', 'Value'=> $Value) );
The problem is that the value that is to be excluded ($Value) is bound to the validator at the time it is instantiated (also when the form is instantiated). But when the form is editing a record, that value needs to be bound to the contents of the $data field when the form was initially populated with data - IE the Data value initially read from the Test table row. But in typical Zend patterns a form is instantiated and populated in two separate steps which precludes binding the exclude value to the desired element value.
The following Zend psuedo code marks where I would like the binding of $Value to the NoRecordExists() validator to occur (and note that this is a common Zend controller pattern):
$form = new Form()
if (is Post) {
$formData = GetPostData()
if ($form->isValid($formData)) {
Update Table with $formData
Redirect out of here
} else {
$form->populate($formData)
}
} else {
$RowData = Get Data from Table
$form->populate($RowData) <=== This is where I want ('value' => $Value) bound
}
I could sub-class Zend_Form and override the populate() method to do a one-shot insertion of the NoRecordExists() validator on initial form population, but that seems like a huge hack to me. So I wanted to know what other people think and is there some pattern already written down that solves this problem?
Edit 2009-02-04
I've been thinking that the only decent solution to this problem is to write a custom validator and forget about the Zend version. My form has the record ID as hidden field, so that given the table and column names I could craft some SQL to test for uniqueness and exclude the row with an ID of such an such. Of course this started me thinking about how I would be tying the form to the dB layer that the Model is supposed to hide!
This is how it's done:
I your FORM, you add this validator (for example email field):
$email->addValidator('Db_NoRecordExists', true, array('table' => 'user', 'field' => 'email'));
Don't add custom error message for this since after that it didn't work for me, e.g.:
$email->getValidator('Db_NoRecordExists')->setMessage('This email is already registered.');
In your Controller add this:
/* Don't check for Db_NoRecordExists if editing the same field */
$form->getElement('email')
->addValidator('Db_NoRecordExists',
false,
array('table' => 'user',
'field' => 'email',
'exclude' => array ('field' => 'id', 'value' => $this->request->get('id'))));
And after this you do verifications, e.g.:
if ($this->getRequest()->isPost())
{
if($form->isValid($this->getRequest()->getPost()))
{
....
That's it!
This will also work :
$this->addElement('text', 'email', array(
'label' => 'Your email address:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array(
'EmailAddress',
array('Db_NoRecordExists', true, array(
'table' => 'guestbook',
'field' => 'email',
'messages' => array(
'recordFound' => 'Email already taken'
)
)
)
)
));
After reviewing the overwhelming response I've decided that I'm going with a custom validator
Look at this one:
Answer raised by me and well-solved by Dickie
private $_id;
public function setId($id=null)
{
$this->_id=$id;
}
public function init()
{
.....
if(isset($this->_id)){
$email->addValidator('Db_NoRecordExists', false, array('table' => 'user', 'field' => 'email','exclude' => array ('field' => 'id', 'value' => $this->_id) ));
$email->getValidator('Db_NoRecordExists')->setMessage('This email is already registered.');
}
Now u can use:
$form = new Form_Test(array('id'=>$id));
You could just call $form->getElement('input')->removeValidator('Zend_Validator_Db_NoRecordExists'); instead of supplying the exclusion.
I have just tried this example for email address uniqueness and it works perfectly with below stuffs :
1] In my form:
// Add an email element
$this->addElement('text', 'email', array(
'label' => 'Email :',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array(
'EmailAddress',
)
));
Here's something special that I needed to add for unique email address to work:
$email = new Zend_Form_Element_Text('email');
$email->addValidator('Db_NoRecordExists', true, array('table' => 'guestbook', 'field' => 'email'));
2] In my controller:
$form->getElement('email')
->addValidator('Db_NoRecordExists',
false,
array('table' => 'guestbook',
'field' => 'email',
'exclude' => array ('field' => 'id', 'value' => $request->get('id'))));
if ($this->getRequest()->isPost()) {
if ($form->isValid($request->getPost())) {
Hope it helps you people !
Thanks

Categories