') {
$inline_css = '';
}
else {
$inline_css = ' style="' . check_plain($element['#component_css']) . '"';
}
}
else {
// Language will be LANGUAGE_LTR (0) or LANGUAGE_RTL (1).
if ($language->direction) {
if ($style = variable_get('name_inline_styles_rtl', 'float: right; margin-left: 1em;')) {
$inline_css = ' style="' . $style . '"';
}
}
else {
if ($style = variable_get('name_inline_styles', 'float: left; margin-right: 1em;')) {
$inline_css = ' style="' . $style . '"';
}
}
}
foreach ($parts as $key => $title) {
if (!isset($components[$key]['exclude'])) {
$element[$key] = _name_render_component($components, $key, $element, isset($min_components[$key]));
$class = 'name-' . $key . '-wrapper';
if ($key == 'credentials' && empty($element['#credentials_inline'])) {
$element[$key]['#prefix'] = '';
$element[$key]['#suffix'] = '
';
}
else {
$element[$key]['#prefix'] = '';
$element[$key]['#suffix'] = '
';
}
}
}
if (variable_get('name_element_wrapper', 1)) {
$element['#prefix'] = '';
$element['#suffix'] = '
';
}
return $element;
}
/**
* Helper function to render a component within a name element.
*
* @param array $components
* Core properties for all components.
* @param string $component_key
* The component key of the component that is being rendered.
* @param array $base_element
* Base FAPI element that makes up a name element.
* @param bool $core
* Flag that indicates that the component is required as part of a valid
* name.
*
* @return array
* The constructed component FAPI structure for a name element.
*/
function _name_render_component($components, $component_key, $base_element, $core) {
$component = $components[$component_key];
$element = array();
// Allow other modules to append additional FAPI properties to the element.
foreach (element_properties($component) as $key) {
$element[$key] = $component[$key];
}
$element['#attributes']['class'][] = 'name-element';
$element['#attributes']['class'][] = 'name-' . $component_key;
if ($core) {
$element['#attributes']['class'][] = 'name-core-component';
}
if (isset($component['attributes'])) {
foreach ($component['attributes'] as $key => $attribute) {
if (isset($element['#attributes'][$key])) {
if (is_array($attribute)) {
$element['#attributes'][$key] = array_merge($element['#attributes'][$key], $attribute);
}
else {
$element['#attributes'][$key] .= ' ' . $attribute;
}
}
else {
$element['#attributes'][$key] = $attribute;
}
}
}
$base_attributes = array('type', 'title', 'size', 'maxlength');
foreach ($base_attributes as $key) {
$element['#' . $key] = $component[$key];
}
$element['#default_value'] = $base_element['#value'][$component_key];
if ($component['type'] == 'select') {
$element['#options'] = $component['options'];
$element['#size'] = 1;
}
elseif (!empty($component['autocomplete'])) {
$element['#autocomplete_path'] = $component['autocomplete'];
}
if ($core && !empty($base_element['#show_component_required_marker'])) {
$element['#title'] .= theme('name_component_required_marker', array(
'components' => $components,
'component_key' => $component_key,
'base_element' => $base_element,
));
}
// Enable the title options.
$title_display = isset($component['title_display']) ? $component['title_display'] : 'description';
switch ($title_display) {
case 'title':
break;
case 'placeholder':
$element['#attributes']['placeholder'] = t($element['#title']);
$element['#title_display'] = 'invisible';
break;
case 'none':
$element['#title_display'] = 'invisible';
break;
case 'description':
default:
$element['#title_display'] = 'invisible';
$element['#description'] = t($element['#title']);
break;
}
return $element;
}
/**
* A custom validator to check the components of a name_element element.
*/
function name_element_validate($element, &$form_state) {
// Limits validation to posted values only.
if (empty($element['#needs_validation'])) {
return $element;
}
$minimum_components = array_filter($element['#minimum_components']);
$labels = array();
foreach ($element['#components'] as $key => $component) {
if (!isset($component['exclude'])) {
$labels[$key] = $component['title'];
}
}
$item = $element['#value'];
$empty = name_field_is_empty($item, NULL);
$item_components = array();
foreach (_name_translations() as $key => $title) {
if (isset($labels[$key]) && !empty($item[$key])) {
$item_components[$key] = 1;
}
}
// Conditionally allow either a single given or family name.
if (!empty($element['#allow_family_or_given'])) {
// This option is only valid if there are both components.
if (isset($labels['given']) && isset($labels['family'])) {
if (!empty($item['given']) || !empty($item['family'])) {
$item_components['given'] = 1;
$item_components['family'] = 1;
}
}
}
if (!$empty && (count($minimum_components) != count(array_intersect_key($minimum_components, $item_components)))) {
$missing_labels = array_diff_key(array_intersect_key($labels, $minimum_components), $item_components);
$label = empty($element['#title']) ? (empty($element['#label']) ? 'Field' : $element['#label']) : $element['#title'];
// Note that field_default_form() has already sanitized #title.
form_error($element[key($missing_labels)], t('!name also requires the following parts: !components.',
array('!name' => $label, '!components' => implode(', ', $missing_labels))));
}
if ($empty && $element['#required']) {
form_error($element, t('!name is required.', array('!name' => t($element['#title']))));
}
return $element;
}
/**
* This function themes the element and controls the title display.
*/
function name_element_pre_render($element) {
// Add a wrapper to fields if required.
if (variable_get('name_element_wrapper', 1)) {
$element['_name'] = array(
'#prefix' => '',
'#suffix' => '
',
);
}
foreach (_name_translations() as $key => $title) {
if (isset($element[$key])) {
$element['_name'][$key] = $element[$key];
unset($element[$key]);
}
}
if (!empty($element['#component_layout'])) {
_name_component_layout($element['_name'], $element['#component_layout']);
}
if (!empty($element['#description'])) {
$field = isset($element['#field']) ? $element['#field'] : NULL;
if (!$field || $field['cardinality'] != 1) {
$element['_description'] = array(
'#value' => '' . $element['#description'] . '
',
);
unset($element['#description']);
}
}
return $element;
}
/**
* Sorts the widgets according to the language type.
*/
function _name_component_layout(&$element, $layout = 'default') {
$weights = array(
'asian' => array(
'family' => 1,
'middle' => 2,
'given' => 3,
'title' => 4,
// 'generational' is removed from the display
'generational' => 5,
'credentials' => 6,
),
'eastern' => array(
'title' => 1,
'family' => 2,
'given' => 3,
'middle' => 4,
// 'generational' is removed from the display
'generational' => 5,
'credentials' => 6,
),
);
if (isset($weights[$layout])) {
foreach ($weights[$layout] as $component => $weight) {
if (isset($element[$component])) {
$element[$component]['#weight'] = $weight;
}
}
}
if ($layout == 'asian') {
if (isset($element['generational'])) {
$element['generational']['#default_value'] = '';
$element['generational']['#access'] = FALSE;
}
}
}
/* ----------------------------- Field Code --------------------------------- */
/**
* Implements hook_field_info().
*/
function name_field_info() {
$parts = _name_translations();
$keys = array_keys($parts);
$count = count($keys);
return array(
'name' => array(
'label' => t('Name'),
'description' => t('This field stores a users title, given, middle, family name, generational suffix and credentials in the database.'),
'default_widget' => 'name_widget',
'default_formatter' => 'name_formatter',
'settings' => array(
// Components used. At least given or family name is required.
'components' => drupal_map_assoc($keys),
// Minimal set of components before considered incomplete.
'minimum_components' => array(
'given' => 'given',
'family' => 'family',
),
// Allows a given or family component value to filful either both the
// minimal components. Allows singular names like "Prince".
'allow_family_or_given' => 0,
'labels' => _name_translations(),
'max_length' => array(
'title' => 31,
'given' => 63,
'middle' => 127,
'family' => 63,
'generational' => 15,
'credentials' => 255,
),
'autocomplete_source' => array(
'title' => array('title'),
'given' => array(),
'middle' => array(),
'family' => array(),
'generational' => array('generation'),
'credentials' => array(),
),
'autocomplete_separator' => array(
'title' => ' ',
'given' => ' -',
'middle' => ' -',
'family' => ' -',
'generational' => ' ',
'credentials' => ', ',
),
'title_options' => implode("\n", array(t('-- --'), t('Mr.'), t('Mrs.'), t('Miss'), t('Ms.'), t('Dr.'), t('Prof.'))),
'generational_options' => implode("\n", array(t('-- --'), t('Jr.'), t('Sr.'), t('I'), t('II'), t('III'), t('IV'), t('V'), t('VI'), t('VII'), t('VIII'), t('IX'), t('X'))),
'sort_options' => array(
'title' => 'title',
'generational' => 0,
),
),
'instance_settings' => array(
// Possible elements for either (free) text, autocomplete, select.
'title_field' => 'select',
'generational_field' => 'select',
'size' => array(
'title' => 6,
'given' => 20,
'middle' => 20,
'family' => 20,
'generational' => 5,
'credentials' => 35,
),
'inline_css' => array_combine($keys, array_fill(0, $count, '')),
'title_display' => array_combine($keys, array_fill(0, $count, 'description')),
// Field instance overrides.
'components' => array(),
'minimum_components' => array(),
'labels' => array_combine($keys, array_fill(0, $count, '')),
// New settings to override the user name. Only applies to user entities.
'override_format' => 'default',
'preferred_field_reference' => '',
// Prevents the default break between the name components and credentials.
'credentials_inline' => 0,
'component_css' => '',
'component_layout' => 'default',
'show_component_required_marker' => 0,
),
'property_type' => 'field_item_name',
'property_callbacks' => array('name_field_property_info_callback'),
),
);
}
/**
* Implements hook_field_settings_form().
*/
function name_field_settings_form($field, $instance, $has_data) {
module_load_include('inc', 'name', 'includes/name.content');
return _name_field_settings_form($field, $instance, $has_data);
}
/**
* Implements hook_field_settings_form_validate().
*
* Called via #element_validate from name_field_settings_form().
*/
function name_field_settings_form_validate($form, &$form_state) {
module_load_include('inc', 'name', 'includes/name.content');
_name_field_settings_form_validate($form, $form_state);
}
/**
* Implements hook_field_validate().
*
* @todo
* Look at reintroducing this at some stage. Currently, this is problematic as
* Drupal appears to loss track of what fields are shown on the form and this
* results in validation errors.
*/
// @code
//function name_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
// // Hack to test the default settings form.
// if (empty($entity) && empty($entity_type)) {
// return;
// }
//
// if ($instance['required']) {
// if (is_array($items)) {
// foreach ($items as $delta => $item) {
// if (!name_field_is_empty($item, $field)) {
// return;
// }
// }
// }
// $errors[$field['field_name']][$langcode][0][] = array(
// 'error' => 'required_components',
// 'message' => t('%name is required.', array('%name' => t($instance['label']))),
// );
// }
//}
// @endcode
/**
* Implements hook_field_load().
*/
function name_field_load($entity_type, $entities, $field, $instances, $langcode, &$items) {
foreach ($entities as $id => $entity) {
// Use populated overrides if present.
$instances[$id]['settings'] += array('components' => array());
$components = name_get_instance_components($field['settings']['components'], $instances[$id]['settings']['components']);
foreach ($items[$id] as $delta => $item) {
foreach (_name_translations() as $key => $title) {
if (empty($components[$key])) {
unset($items[$id][$delta][$key]);
}
else {
$items[$id][$delta]['safe'][$key] = _name_value_sanitize($item, $key);
}
}
}
}
}
/**
* Implements hook_field_is_empty().
*/
function name_field_is_empty($item, $field) {
foreach (_name_translations() as $key => $title) {
// Title & generational have no meaning by themselves.
if ($key == 'title' || $key == 'generational') {
continue;
}
if (!empty($item[$key])) {
return FALSE;
}
}
return TRUE;
}
/**
* Checks that a component is not selected as a minimal component when the
* component is not selected.
*/
function _name_field_minimal_component_requirements($element, &$form_state) {
$values = array_filter((array) $element['#value']);
if ($values) {
$required_field_set = array_flip(array('given', 'family'));
$values = array_intersect_key($required_field_set, $values);
if (empty($values)) {
$required_fields = array_intersect_key(_name_translations(), $required_field_set);
form_set_error(implode('][', $element['#parents']) . '][given]',
t('!label must have one of the following components: %components',
array('!label' => $element['#title'], '%components' => implode(', ', $required_fields))));
}
}
}
/* ----------------------------- Widget Code -------------------------------- */
/**
* Implements hook_field_widget_info().
*/
function name_field_widget_info() {
return array(
'name_widget' => array(
'label' => t('Name'),
'field types' => array('name'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
'default value' => FIELD_BEHAVIOR_DEFAULT,
),
'settings' => array(),
),
);
}
/**
* Implements hook_field_widget_error().
*
* Validation on required is done here. The max. length is done via Drupal.
* Min. components is done via name_element validation callback.
*
* @todo
* Re-add this with name_field_validate().
*/
// @code
//function name_field_widget_error($element, $error, $form, &$form_state) {
// $error_element = NULL;
// switch ($error['error']) {
// case 'required_components':
// $error_element = $element[$element['#columns'][1]];
// break;
//
// }
// if ($error_element) {
// form_error($error_element, $error['message']);
// }
//}
// @endcode
/**
* Implements hook_field_widget_form().
*/
function name_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
module_load_include('inc', 'name', 'includes/name.content');
return _name_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $element);
}
/**
* Implements hook_field_instance_settings_form().
*/
function name_field_instance_settings_form($field, $instance) {
module_load_include('inc', 'name', 'includes/name.content');
return _name_field_instance_settings_form($field, $instance);
}
/**
* Name autocomplete data sources callback.
*
* Generates a full listing for title and generational options.
*
* @param array $field
* The field requesting the data.
*
* @param array $component
* The key that the data has been requested for.
*
* @param mixed $arguments
* Additional arguments defined in hook_name_data_sources().
*
* @return array
* The matches ready to use directly in the autocomplete response.
*/
function name_field_get_options($field, $component = 'title', $arguments = array()) {
module_load_include('inc', 'name', 'includes/name.content');
return _name_field_get_options($field, $component, $arguments);
}
/**
* Name autocomplete sources query callback.
*
* Handles the autocomplete for title and generational options.
*
* @param array $components
* The keys that the autocomplete is active on.
*
* @param string $base_string
* Autocomplete strings are split and individual pieces are parsed
* sequentially. The base string is the concatanated results of
* previous segment lookups.
*
* @param string $string
* Current segment of the search string.
*
* @param array|null $field
* If run in the context of the Field API, the field is supplied.
*
* @param int $limit
*
* @param mixed $arguments
* Additional arguments defined in hook_name_data_sources().
*
* @return array
* The matches ready to use directly in the autocomplete response.
*/
function name_field_autocomplete_query($components, $base_string, $string, $field, $limit, $arguments) {
$component_key = $arguments;
$matches = array();
foreach (name_field_get_options($field, $component_key) as $key => $option) {
if (strpos(drupal_strtolower($key), $string) === 0 || strpos(drupal_strtolower($option), $string) === 0) {
$matches[$base_string . $key] = $key;
$limit--;
}
if (!$limit) {
break;
}
}
return $matches;
}
/* ---------------------------- Formatter Code ------------------------------ */
/**
* Implements hook_field_formatter_info().
*/
function name_field_formatter_info() {
$formatters = array();
$formatters['name_formatter'] = array(
'label' => t('Default'),
'field types' => array('name'),
'settings' => array(
'markup' => 0,
// default, plain, or raw.
'output' => 'default',
'format' => 'default',
'multiple' => 'default',
// These define how the multiple list option is configured.
'multiple_delimiter' => ', ',
// Text or symbol.
'multiple_and' => 'text',
// contextual, always, never.
'multiple_delimiter_precedes_last' => 'never',
'multiple_el_al_min' => 3,
'multiple_el_al_first' => 1,
),
);
return $formatters;
}
/**
* Helper function to define the available output formatter options.
*/
function _name_formatter_output_options() {
return array(
'default' => t('Default'),
'plain' => t('Plain text'),
'raw' => t('Raw value (not recommended)'),
);
}
/**
* Helper function to define the available multiple formatter options.
*/
function _name_formatter_multiple_options() {
return array(
'default' => t('Default'),
'inline_list' => t('Inline list'),
);
}
/**
* Implements hook_field_formatter_settings_form().
*/
function name_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$element = array();
$element['format'] = array(
'#type' => 'select',
'#title' => t('Name format'),
'#default_value' => isset($settings['format']) ? $settings['format'] : 'default',
'#options' => array('default' => t('Default')) + name_get_custom_format_options(),
'#required' => TRUE,
);
$element['markup'] = array(
'#type' => 'checkbox',
'#title' => t('Markup'),
'#default_value' => !empty($settings['markup']),
'#description' => t('This option wraps the individual components of the name in SPAN elements with corresponding classes to the component.'),
);
$element['output'] = array(
'#type' => 'radios',
'#title' => t('Output'),
'#default_value' => empty($settings['output']) ? 'default' : $settings['output'],
'#options' => _name_formatter_output_options(),
'#description' => t('This option provides additional options for rendering the field. Normally, using the "Raw value" option would be a security risk.'),
'#required' => TRUE,
);
$element['multiple'] = array(
'#type' => 'radios',
'#title' => t('Multiple format options'),
'#default_value' => empty($settings['multiple']) ? 'default' : $settings['multiple'],
'#options' => _name_formatter_multiple_options(),
'#required' => TRUE,
);
$settings += array(
'multiple_delimiter' => ', ',
// And or symbol.
'multiple_and' => 'text',
// contextual, always, never.
'multiple_delimiter_precedes_last' => 'never',
'multiple_el_al_min' => 3,
'multiple_el_al_first' => 1,
);
$base = array(
'#states' => array(
'visible' => array(
':input[name="fields[' . $field['field_name'] . '][settings_edit_form][settings][multiple]"]' => array('value' => 'inline_list'),
),
),
'#prefix' => '',
'#suffix' => '
',
);
// We can not nest this field, so use a prefix / suffix with padding to help
// to provide context.
$element['multiple_delimiter'] = $base + array(
'#type' => 'textfield',
'#title' => t('Delimiter'),
'#default_value' => $settings['multiple_delimiter'],
'#description' => t('This specifies the delimiter between the second to last and the last name.'),
);
$element['multiple_and'] = $base + array(
'#type' => 'radios',
'#title' => t('Last delimiter type'),
'#options' => array(
'text' => t('Textual (and)'),
'symbol' => t('Ampersand (&)'),
'inherit' => t('Inherit'),
),
'#default_value' => $settings['multiple_and'],
'#description' => t('This specifies the delimiter between the second to last and the last name.'),
);
$element['multiple_delimiter_precedes_last'] = $base + array(
'#type' => 'radios',
'#title' => t('Standard delimiter precedes last delimiter'),
'#options' => array(
'never' => t('Never (i.e. "J. Doe and T. Williams")'),
'always' => t('Always (i.e. "J. Doe, and T. Williams")'),
'contextual' => t('Contextual (i.e. "J. Doe and T. Williams" or "J. Doe, S. Smith, and T. Williams")'),
),
'#default_value' => $settings['multiple_delimiter_precedes_last'],
'#description' => t('This specifies the delimiter between the second to last and the last name. Contextual means that the delimiter is only included for lists with three or more names.'),
);
$element['multiple_el_al_min'] = $base + array(
'#type' => 'select',
'#title' => t('Reduce list and append el al'),
'#options' => array(0 => t('Never reduce')) + drupal_map_assoc(range(1, 20)),
'#default_value' => $settings['multiple_el_al_min'],
'#description' => t('This specifies a limit on the number of names to display. After this limit, names are removed and the abbrivation et al is appended. This Latin abbrivation of et alii means "and others".'),
);
$element['multiple_el_al_first'] = $base + array(
'#type' => 'select',
'#title' => t('Number of names to display when using el al'),
'#options' => drupal_map_assoc(range(1, 20)),
'#default_value' => $settings['multiple_el_al_first'],
);
return $element;
}
/**
* Implements hook_field_formatter_settings_summary().
*/
function name_field_formatter_settings_summary($field, $instance, $view_mode) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$summary = array();
$machine_name = isset($settings['format']) ? $settings['format'] : 'default';
if ($machine_name == 'default') {
$summary[] = t('Format: Default');
}
else {
$info = db_select('name_custom_format', 'n')
->fields('n')
->condition('machine_name', $machine_name)
->execute()
->fetchObject();
if ($info) {
$summary[] = t('Format: %format (@machine_name)', array(
'%format' => $info->name,
'@machine_name' => $info->machine_name,
));
}
else {
$summary[] = t('Format: Missing format.
This field will be displayed using the Default format.');
$machine_name = 'default';
}
}
// Provide an example of the selected format.
module_load_include('admin.inc', 'name');
$used_components = array_filter($field['settings']['components']);
$excluded_components = array_diff_key($used_components, _name_translations());
$examples = name_example_names($excluded_components, $field['field_name']);
if ($examples && $example = array_shift($examples)) {
$format = name_get_format_by_machine_name($machine_name);
$formatted = check_plain(name_format($example, $format));
if (empty($formatted)) {
$formatted = '<<empty>>';
}
$summary[] = t('Example: !example', array(
'!example' => $formatted,
));
}
$summary[] = t('Markup: @yesno', array(
'@yesno' => empty($settings['markup']) ? t('no') : t('yes'),
));
$output_options = _name_formatter_output_options();
$output = empty($settings['output']) ? 'default' : $settings['output'];
$summary[] = t('Output: @format', array(
'@format' => $output_options[$output],
));
return implode('
', $summary);
}
/**
* Implements hook_field_formatter_view().
*/
function name_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
$element = array();
$settings = $display['settings'];
$type = empty($settings['output']) ? 'default' : $settings['output'];
$format = isset($settings['format']) ? $settings['format'] : 'default';
$format = name_get_format_by_machine_name($format);
if (empty($format)) {
$format = name_get_format_by_machine_name('default');
}
foreach ($items as $delta => $item) {
$item += name_field_parse_additional_components($entity_type, $entity, $instance);
// We still have raw user input here unless the markup flag has been used.
$value = name_format($item, $format, array(
'object' => $entity,
'type' => $entity_type,
'markup' => !empty($display['settings']['markup']),
));
if (empty($display['settings']['markup'])) {
$element[$delta] = array(
'#markup' => _name_value_sanitize($value, NULL, $type),
);
}
else {
$element[$delta] = array('#markup' => $value);
}
}
if (isset($settings['multiple']) && $settings['multiple'] == 'inline_list') {
$items = array();
foreach (element_children($element) as $delta) {
if (!empty($element[$delta]['#markup'])) {
$items[] = $element[$delta]['#markup'];
unset($element[$delta]);
}
}
if (!empty($items)) {
$element[0]['#markup'] = theme('name_item_list', array('items' => $items, 'settings' => $settings));
}
}
return $element;
}
/**
* Helper function to get alternative name component sources.
*/
function name_get_additional_sources($instance) {
$sources = array();
$info = entity_get_info();
$sources['_self'] = t('@label label', array(
'@label' => $info[$instance['entity_type']]['label'],
));
if ($instance['entity_type'] == 'user') {
$sources['_self_property_name'] = t('@label login name', array(
'@label' => $info[$instance['entity_type']]['label'],
));
}
foreach (field_info_instances($instance['entity_type'], $instance['bundle']) as $_field_name => $_instance) {
if ($_field_name != $instance['field_name']) {
$sources[$_field_name] = $_instance['label'];
}
}
return $sources;
}
/**
* Helper function to discover alternative name component sources.
*/
function name_field_parse_additional_components($entity_type, $entity, $instance) {
$settings = $instance['settings'];
$extra = array();
$map = array(
'preferred' => 'preferred_field_reference',
);
list(,, $bundle) = entity_extract_ids($entity_type, $entity);
foreach ($map as $component => $key) {
if (!empty($settings[$key])) {
if ($settings[$key] == '_self') {
if ($label = entity_label($entity_type, $entity)) {
$extra[$component] = $label;
}
}
elseif (strpos($settings[$key], '_self_property') === 0) {
$property = str_replace('_self_property_', '', $settings[$key]);
if (!empty($entity->{$property}) && is_scalar($entity->{$property})) {
$extra[$component] = $entity->{$property};
}
}
elseif ($_instance = field_info_instance($entity_type, $settings[$key], $bundle)) {
$_field = field_info_field($settings[$key]);
$_values = array();
if (field_access('view', $_field, $entity_type) || field_access('edit', $_field, $entity_type)) {
$clone = clone $entity;
$_langcode = field_language($entity_type, $entity, $settings[$key]);
// @todo
$_view_mode = 'default';
$_display = field_get_display($_instance, $_view_mode, $clone);
if ($_display['type'] == 'hidden') {
$cache = _field_info_field_cache();
$_display = array();
$_display = $cache->prepareInstanceDisplay($_display, $_field["type"]);
}
$_display['label'] = 'hidden';
$_element = field_view_field($entity_type, $clone, $settings[$key], $_display, $_langcode);
if ($output = trim(strip_tags(drupal_render($_element)))) {
$extra[$component] = decode_entities($output);
}
}
}
}
}
return $extra;
}
/**
* Helper function to sanitize a name component or name string.
*
* @param string $langcode
* @param mixed $item
* If this is a string, then the processing happens on this.
* If this is an array, the processing happens on the column index.
* @param string $column
* @param string $type
* Tells the function how to handle the text processing:
* 'default' runs through check_plain()
* 'plain' runs through strip_tags()
* 'raw' has no processing applied to it.
*/
function _name_value_sanitize($item, $column = NULL, $type = 'default') {
$safe_key = 'safe' . ($type == 'default' ? '' : '_' . $type);
if (is_array($item) && isset($item[$safe_key])) {
return $item[$safe_key][$column];
}
$value = is_array($item) ? (string) $item[$column] : $item;
switch ($type) {
case 'plain':
return strip_tags($value);
case 'raw':
return $value;
default:
return check_plain($value);
}
}
/* -------------------------- FAPI Form Alters ------------------------------ */
/**
* Provides a hook into the theming of the field, instance and display settings,
* using #pre_render callbacks.
*/
function name_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
$field = $form['#field'];
if ($field['module'] != 'name') {
return;
}
// Moves the instance settings into a nicer table.
if (isset($form['instance']['settings'])) {
$form['instance']['#pre_render'][] = 'name_field_instance_settings_pre_render';
}
// Moves the field settings into a nicer table.
if (isset($form['field']['settings'])) {
$form['field']['settings']['#pre_render'][] = 'name_field_settings_pre_render';
}
}
/**
*
*/
function name_form_field_ui_field_settings_form_alter(&$form) {
if ($form['field']['module']['#value'] != 'name') {
return;
}
if (isset($form['field']['settings'])) {
$form['field']['settings']['#pre_render'][] = 'name_field_settings_pre_render';
}
}
/**
* A #pre_render function callback for formatting field instance settings.
*/
function name_field_instance_settings_pre_render($form) {
module_load_include('inc', 'name', 'name.admin');
return _name_field_instance_settings_pre_render($form);
}
/**
* A #pre_render function callback for formatting field settings.
*/
function name_field_settings_pre_render($form) {
module_load_include('inc', 'name', 'name.admin');
return _name_field_settings_pre_render($form);
}
/**
* Implements hook_field_create_instance().
*/
function name_field_create_instance($instance) {
if ($instance['entity_type'] == 'user' && !empty($instance['settings']['name_user_preferred'])) {
variable_set('name_user_preferred', $instance['field_name']);
}
}
/**
* Implements hook_field_update_instance().
*/
function name_field_update_instance($instance, $prior_instance) {
// I'm only targeting user entities here.
if ($instance['entity_type'] == 'user') {
if (!empty($instance['settings']['name_user_preferred'])) {
variable_set('name_user_preferred', $instance['field_name']);
}
elseif (!empty($prior_instance['settings']['name_user_preferred'])) {
variable_set('name_user_preferred', '');
}
}
}
/**
* Implements hook_field_delete_instance().
*/
function name_field_delete_instance($instance) {
if ($instance['entity_type'] == 'user' && !empty($instance['settings']['name_user_preferred'])) {
variable_set('name_user_preferred', '');
}
}
/* -------------------------- namedb integration ---------------------------- */
/**
* Implements hook_field_insert().
*
* Triggers a custom hook for name field inserts. Field API only calls the
* module that defines the field.
*/
function name_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
// Ensure that $items are passed by reference.
foreach (module_implements('name_field_insert_notification') as $module) {
$function = $module . '_name_field_insert_notification';
$function($entity_type, $entity, $field, $instance, $langcode, $items);
}
}
/**
* Implements hook_field_update().
*
* Triggers a custom hook for name field updates. Field API only calls the
* module that defines the field.
*/
function name_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
// Ensure that $items are passed by reference.
foreach (module_implements('name_field_update_notification') as $module) {
$function = $module . '_name_field_insert_notification';
$function($entity_type, $entity, $field, $instance, $langcode, $items);
}
}
/**
* Helper function to normalise the word for sorting.
*
* @todo Better functions in PHP?
*
* All credit goes to the PathAuto module for this!
*/
function name_translite_word($word) {
static $translations;
if (!isset($translations)) {
$file = drupal_get_path('module', 'name') . '/' . 'i18n-ascii.txt';
$translations = parse_ini_file($file);
}
return strtr($word, $translations);
}
/**
* Helper function to get all of the allowed letters in a name.
*/
function name_translite_letters($base = 'a-zA-Z') {
static $letters;
if (!isset($letters)) {
$file = drupal_get_path('module', 'name') . '/' . 'i18n-ascii.txt';
$letters = '';
$translations = parse_ini_file($file);
foreach ($translations as $l => $t) {
$letters .= $l;
}
}
return $base . $letters;
}
/**
* Checks that the name matches a reasonable format before saving it to the
* database.
*
* The valid list so far is:
*
* xxx > Xxx
* d'xxx > D'Xxx
* l'xxx > L'Xxx
* m'xxx > M'Xxx
* o'xxx > O'Xxx
* de|del|des|di|du|la|le|van|von xxx > De Xxx
* de la xxx > De la Xxx
* van|von de|den|der xxx > Van Xxx
* st|st.|staint xxx > Staint Xxx
* van der xxx > Van der Xxx
* mc|mac xxx > McXxx
*
* Ignored list includes:
*
* xxx xxx
* etc
*
* Configurable options:
*
* xxx-xxx
* x
*
* Note that this is an API change from Name Field 7.x-1.4 to 7.x-1.5 that was
* required after implementing theme_name_component(). The previous version of
* this function was name_process_name_component().
*/
function name_clean_name_component($name, $data_key = 'user_data', $letters = 'a-z') {
$name = trim($name);
$settings = namedb_settings();
$min = intval($settings[$data_key]['minimum_length']);
if ($min <= 0) {
$min = 1;
}
if (empty($name) || strpos($name, '-') || drupal_strlen($name) < $min) {
return FALSE;
}
if (preg_match('/^de la ([' . $letters . ']{' . $min . ',})$/i', $name, $match)) {
return 'De la ' . drupal_ucfirst($match[1]);
}
elseif (preg_match('/^(van|von) (de|den|der) ([' . $letters . ']{' . $min . ',})$/i', $name, $match)) {
return drupal_ucfirst(drupal_strtolower($match[1])) . ' ' . drupal_strtolower($match[2]) . ' ' . drupal_ucfirst($match[3]);
}
elseif (preg_match('/^(st\.|st|staint) ([' . $letters . ']{' . $min . ',})$/i', $name, $match)) {
return 'Staint ' . drupal_ucfirst($match[2]);
}
elseif (preg_match('/^(d|l|m|o) *\' *([' . $letters . ']{' . $min . ',})$/i', $name, $match)) {
return drupal_strtoupper($match[1]) . "'" . drupal_ucfirst($match[2]);
}
elseif (preg_match('/^(de|del|des|di|du|la|le|van|von) ([' . $letters . ']{' . $min . ',})$/i', $name, $match)) {
return drupal_ucfirst(drupal_strtolower($match[1])) . ' ' . drupal_ucfirst($match[2]);
}
elseif (preg_match('/^(mc|mac) ([' . $letters . ']{' . $min . ',})$/i', $name, $match)) {
return drupal_ucfirst(drupal_strtolower($match[1])) . drupal_ucfirst($match[2]);
}
elseif (preg_match('/^([' . $letters . ']{' . $min . ',}) de ([' . $letters . ']{' . $min . ',})$/i', $name, $match)) {
return drupal_ucfirst(drupal_strtolower($match[1])) . ' de ' . drupal_ucfirst($match[2]);
}
elseif (preg_match('/^[' . $letters . ']{' . $min . ',}$/i', $name)) {
return drupal_ucfirst($name);
}
if ($settings[$data_key]['hyphenated']) {
if (preg_match('/^([' . $letters . ']{' . $min . ',}) *\- *([' . $letters . ']{' . $min . ',})$/i', $name)) {
return drupal_ucfirst($match[1]) . '-' . drupal_ucfirst($match[2]);
}
}
return FALSE;
}
/**
* Implements hook_views_api().
*/
function name_views_api() {
return array('version' => '3.0');
}
/**
* Additional callback to adapt the property info of name fields.
*
* @see entity_metadata_field_entity_property_info()
*/
function name_field_property_info_callback(&$info, $entity_type, $field, $instance, $field_type) {
$property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$field['field_name']];
$property['getter callback'] = 'entity_metadata_field_verbatim_get';
$property['setter callback'] = 'entity_metadata_field_verbatim_set';
// Auto-create the field item as soon as a property is set.
$property['auto creation'] = 'name_field_item_create';
$property['property info'] = name_field_item_property_info();
foreach ($property['property info'] as $property_key => $property_info) {
$property['property info'][$property_key]['required'] = !empty($field['settings']['minimun_components'][$property_key]);
if (empty($field['settings']['components'][$property_key])) {
unset($property['property info'][$property_key]);
}
}
unset($property['query callback']);
}
/**
* Callback for creating a new, empty name fields item.
*
* @see name_field_property_info_callback()
*/
function name_field_item_create() {
return array(
'title' => NULL,
'given' => NULL,
'middle' => NULL,
'family' => NULL,
'generational' => NULL,
'credentials' => NULL,
);
}
/**
* Defines info for the properties of the name-field item data structure.
*/
function name_field_item_property_info() {
$properties['title'] = array(
'type' => 'text',
'label' => t('The title of the name.'),
'setter callback' => 'entity_property_verbatim_set',
);
$properties['given'] = array(
'type' => 'text',
'label' => t('The given name.'),
'setter callback' => 'entity_property_verbatim_set',
);
$properties['middle'] = array(
'type' => 'text',
'label' => t('The middle of the name.'),
'setter callback' => 'entity_property_verbatim_set',
);
$properties['family'] = array(
'type' => 'text',
'label' => t('The family of the name.'),
'setter callback' => 'entity_property_verbatim_set',
);
$properties['generational'] = array(
'type' => 'text',
'label' => t('The generational of the name.'),
'setter callback' => 'entity_property_verbatim_set',
);
$properties['credentials'] = array(
'type' => 'text',
'label' => t('The credentials of the name.'),
'setter callback' => 'entity_property_verbatim_set',
);
return $properties;
}
/**
* Implements hook_migrate_api().
*/
function name_migrate_api() {
return array(
'api' => 2,
'field handlers' => array(
'MigrateNameHandler',
),
);
}
/**
* Implements hook_features_api().
*/
function name_features_api() {
return array(
'namefield' => array(
'name' => t('Name formats'),
'default_hook' => 'name_default_formats',
'feature_source' => TRUE,
'file' => drupal_get_path('module', 'name') . '/includes/name.features.inc',
),
);
}
/**
* Implements hook_name_data_sources().
*
* @todo
* Consider using field data as a source.
*/
function name_name_data_sources() {
return array(
'title' => array(
'name' => t('Title options'),
'components' => array('title'),
'autocomplete callback' => 'name_field_autocomplete_query',
'autocomplete arguments' => array('title'),
'list callback' => 'name_field_get_options',
),
'generational' => array(
'name' => t('Generational options'),
'components' => array('generational'),
'autocomplete callback' => 'name_field_autocomplete_query',
'autocomplete arguments' => array('generational'),
'list callback' => 'name_field_get_options',
),
);
}