2

I am working with Drupal as part of a student project. As background, I work professionally doing front end development and I've taught myself at least the basics of the back end.

Here's my problem, I have the form set up as expected, it validates upon hitting the submit button, and the user is created. However, none of the custom fields populate the db. I've tried so many different approaches/tutorials and nothing actually works. Without writing a rant this has been very frustrating because it would be simple to do this task in straight PHP. Anyways, here is my code, any help would be vastly appreciated.

function user_creation_form_user_register_form_alter(&$form, &$form_state, &$form_id){

// Adds form validation
$form['#validate'][] = 'user_creation_user_form_validate';

$form['account']['confirm_email'] = array(
    '#type' => 'textfield',
    '#title' => 'Confirm your email:',
    '#required' => TRUE,
);

$form['account']['password_confirm'] = array(
    '#type' => 'password_confirm',
    '#required' => TRUE,
);

$form['account']['password_hint_question'] = array(
    '#type' => 'select',
    '#title' => 'Password Hint:',
    '#required' => TRUE,
    '#options' => array(
        t('What was your first car?'),
        t('What was the name of your first pet?'),
        t('What was the name of your high school?'),
        t('What is the name of your favorite sports team?'),
    ),
);

$form['account']['password_hint_answer'] = array(
    '#type' => 'textfield',
    '#title' => 'Password Hint Answer:',
    '#required' => TRUE,
);

$form['account']['first_name'] = array(
    '#type' => 'textfield',
    '#title' => 'First Name:',
);

$form['account']['last_name'] = array(
    '#type' => 'textfield',
    '#title' => 'Last Name:',
);

$form['account']['user_icon'] = array(
    '#type' => 'file',
    '#title' => 'User Icon:',
);

$form['account']['location'] = array(
    '#type' => 'textfield',
    '#title' => 'Location:',
);

// Adds the year began drop down
$form['account']['year_began'] = array(
    '#type' => 'select',
    '#title' => 'Began Playing in Year:',
    '#options' => year_array(),
    '#description' => t('Select the year you began playing.'),
);

$form['extra_info']['about_me'] = array(
    '#type' => 'textarea',
    '#title' => 'Tell us about yourself',
);

$form['approve']['read_rules'] = array(
    '#type' => 'fieldset',
    '#title' => t('Rules Agreement'),
);

$form['approve']['read_rules']['rules'] = array(
    '#markup' => '<div class="agreement">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam tempus velit ante. Nullam semper pellentesque est, sit amet ultrices ante scelerisque vel. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer accumsan vulputate arcu in pharetra. Etiam nec dolor quis magna scelerisque pretium. In hac habitasse platea dictumst. Aliquam dictum condimentum viverra. Nullam rutrum, magna eu semper vehicula, nisl leo bibendum dui, ac scelerisque velit nisl et sem. Proin lobortis tellus vel lacus ultrices vel ultricies purus convallis. In hac habitasse platea dictumst. Quisque a blandit neque.</p>

    <p>Mauris faucibus placerat ipsum non ultricies. Suspendisse vel est a velit dignissim molestie. Maecenas mollis porttitor lorem, a facilisis mauris lobortis quis. Nunc non felis sit amet justo scelerisque pulvinar in vitae quam. Nullam vulputate lectus sit amet quam pulvinar euismod. Maecenas bibendum tortor nec lorem fermentum ornare. Quisque suscipit, velit id consectetur consequat, velit mauris condimentum purus, a pretium lorem lorem eu risus. Nullam id ante neque, at convallis quam. Morbi varius turpis et lacus scelerisque eleifend. Nullam nisl sem, porttitor a venenatis id, fermentum eget leo.</p>
    </div>',
);

$form['approve']['read_rules']['decision'] = array(
    '#type' => 'radios',
    '#description' => t('By clicking yes you agree to abide by the rules of BGRA.net stated above.'),
    '#default_value' => 1,
    '#options' => array(t('I agree'), t('I disagree')),
);
}

function year_array(){
$years = array();
array_push($years, t(' '));

for($i = date('Y'); $i >= 1950; $i--){
    array_push($years, t($i));
}

return $years;
}
/**
* Implements hook_user_form_validate
*/
function user_creation_user_form_validate($form, &$form_state){
global $user;
// Do emails match
if ($form_state['input']['mail'] <> $form_state['input']['confirm_email']){
        form_set_error('confirm_email', t('Your original email and confirmation email must match.'));
}

// Did user agree?
if ($form_state['input']['decision'] <> 0) {
    form_set_error('decision', t('You must agree to the Rules Agreement before registration can be completed.'));
}
}
/**
 * Implements hook_form_submit
 */
function user_creation_form_submit_handler($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,
    'first_name' => array(LANGUAGE_NONE => array(array('value' => $form_state['values']['first_name']))),
    'last_name' => array(LANGUAGE_NONE => array(array('value' => $form_state['values']['last_name']))),
    'password_hint_question' => array(LANGUAGE_NONE => array(array('value' => $form_state['values']['password_hint_question']))),
    'password_hint_answer' => array(LANGUAGE_NONE => array(array('value' => $form_state['values']['password_hint_answer']))),
    'user_icon' => array(LANGUAGE_NONE => array(array('value' => $form_state['values']['user_icon']))),
    'year_began' => array(LANGUAGE_NONE => array(array('value' => $form_state['values']['year_began']))),
    'location' => array(LANGUAGE_NONE => array(array('value' => $form_state['values']['location']))),
    'about_me' => array(LANGUAGE_NONE => array(array('value' => $form_state['values']['about_me']))),
);
user_save(drupal_anonymous_user(), $edit);
} 

As a separate and non-essential issue, I couldn't figure out how to get the .install file to alter the schema for the users table w/o errors, so I manually made an ALTER TABLE call in phpmyadmin. I know this would probably be a problem when the Drupal version is updated and likely overrides the users table. But again, this is a student project - so while I'm curious as to how to do it properly it's not essential.

  • you can create custom fields for users from Drupal UI admin/config/people/accounts/fields. – Aboodred1 Apr 22 '13 at 18:27
  • One of the requirements for the class is that we do it programmatically. – JR Smith Apr 22 '13 at 18:28
  • then search for 'how to create user fields programmatically'. what you are doing is not the right way. By the way; try to clear Drupal cache it might work. – Aboodred1 Apr 22 '13 at 18:31
  • I'm not sure how that helps. The fields show up on the form, but the custom ones do not populate the db. And if the way I'm doing it is not correct, then what is? I've exhausted what I can learn by googling at this point. – JR Smith Apr 22 '13 at 19:02
  • Why you need custom db schema? You can use existing 'data' field, and add custom form submissions to it, see: hook_user_presave – malcolm Apr 22 '13 at 19:33
2

You can add custom fields to the User Account at the page admin/config/people/accounts/fields. This page uses the Field UI.

You can export these fields to PHP code and install them via a custom modules hook_install() function call by following the sample directions here a blog post on how to export the Field definition array structure from Drupal. Your entity_type would be user as would the bundle i believe. An excerpt from this blog is:

$entity_type = '';
$field_name = 'field_';
$bundle_name = '';

$info_config = field_info_field($field_name);
$info_instance = field_info_instance($entity_type, $field_name, $bundle_name);
unset($info_config['id']);
unset($info_instance['id'], $info_instance['field_id']);
include_once DRUPAL_ROOT . '/includes/utility.inc';
$output = "field_create_field(" . drupal_var_export($info_config) . ");\n";
$output .= "field_create_instance(" . drupal_var_export($info_instance) . ");";
drupal_set_message("<textarea rows=30 style=\"width: 100%;\">" . $output . '</textarea>');

You would then take the outputted code, and place it into your modules hook_install() function. Then when your module is enabled the fields are created.

You can then save custom Drupal Fields you've made on form submit rather easily along with the default User values as this example code shows I've yoinked from code I have laying around:

$userinfo = array(
  'name' => $name,
  'pass' => user_password(),
  'init' => $name,
  'status' => 1,
  'access' => REQUEST_TIME,
  // This is where we are different from the default function.
  'roles'        => $provisioned_roles,
  'field_first_name'   => array(LANGUAGE_NONE => array( 0 => array('value' => $ldap_details['first_name']))),
  'field_last_name'    => array(LANGUAGE_NONE => array( 0 => array('value' => $ldap_details['last_name']))),
  'field_perm_number'  => array(LANGUAGE_NONE => array( 0 => array('value' => $ldap_details['perm_number']))),
  'field_school_employee_id'  => array(LANGUAGE_NONE => array( 0 => array('value' => @ldap_details['employee_number']))),
  'mail' => $ldap_details['mail'],
);
$account = user_save(drupal_anonymous_user(), $userinfo);

In general, these questions have been answered before, but sometimes finding the answers here can be tough. There is a great Examples project for developers, also the Core modules found in /modules all do alot of this same application logic as well (such as user_external_login_register())

  • So this didn't get me all the way (ran into some PDO Exceptions along the way). I'm going to try and figure those out tomorrow. But as for as your answer goes, it is the most helpful I've received thus far. Also, just to note, but the examples module has user registration under its wish list. I'm sure you meant that the parts I needed are present in the other examples, but it still made me chuckle. – JR Smith Apr 23 '13 at 4:45
0

You must implement hook_schema_alter() in your module. Look how I added custom field to node table i mymodule.install file:

/**
 * Implements hook_install().
 */
function MYMODULE_install() {
  // Add the new field to the node table
  $field = array(
    'description' => 'Stores the last activity on node',
    'type' => 'int',
    'unsigned' => TRUE
  );

  db_add_field('node', 'activity', $field);
  db_add_index('node', 'activity', array('activity'));
}

and in mymodule.module file:

/**
 * Implements hook_schema_alter().
 */
function MYMODULE_schema_alter(&$schema) {
  // Add the new field to the schema cache
  $schema['node']['fields']['activity'] = array(
    'description' => 'Stores the last activity on node',
    'type' => 'int',
    'unsigned' => TRUE
  );
}

To access this custom field in views, implement hook_views_data_alter()

/**
 * Implements hook_views_data_alter().
 */
function MYMODULE_views_data_alter(&$data) {

  $data['node']['activity'] = array(
    'title' => t('Node activity'),
    'help' => t('Last activity on node'),
    'field' => array(
      'handler' => 'views_handler_field_date',
      'click sortable' => TRUE,
    ),
    'sort' => array(
      'handler' => 'views_handler_sort_date',
    ),
    'filter' => array(
      'handler' => 'views_handler_filter_date',
    ),
  );
}
  • this wont make the db field into a Drupal Field, eg reusable by Views, EntityFieldQuery, etc. – tenken Apr 22 '13 at 21:00
  • How You know that? You check it or just guessing? This is not a fields, its like entity properties. With EFQ you can access it by propertyCondition or propertyOrderBy. About views I editet my answer, about etc. - can you provide example where you cannot use it? As you can see @JR Smith wants data like name, last name, and thus can have access to this data by $GLOBALS['user'], not needed to call every time user_load(). Sry for my poor english. – malcolm Apr 22 '13 at 23:15
  • hook_schema_alter() does not tell the EntityAPI about the field. You have to also tell EntityAPI about the custom DB with hook_entity_property_info_alter. Your approach adds a column to a DB table and makes it visible by Views. Your way is almost correct, but falls short. My approach above uses the full Drupal Fields API. I'm sure there are other ways. To completely use your DB column example you have todo this approach I outline here. Using $GLOBALS['user'] is bad. – tenken Apr 23 '13 at 1:09
  • Sure, your approach is the best in the world, do not worry, do not want to be better than you :) but I know what I do, I dont want install entityApi module to access this db field. You can look at entity.inc, in function buildQuery: // Add fields from the {entity} table. $entity_fields = $this->entityInfo['schema_fields_sql']['base table']; this means that the custom fields are visible to EFQ. Why the hell using $GLOBALS is bad? My god, so Drupal is bad also, with many bad function like super bad user_is_logged_in()... no questions anymore... – malcolm Apr 23 '13 at 1:28
  • ah i see. you are correct that the schema alter makes these visible to EFQ. I was wrong on that. It also looks like the GLOBALS['user'] object should get the fields as well as long they are placed in the user table. I'm still not sure drupal would see these fields using your approach in the Field UI screen ... they might show up there. Ideally, they would so you could make display formatters and include/exclude them from specific display_modes. Thanks for the corrections. – tenken Apr 23 '13 at 2:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.