fc.module in Field Complete 7
Field Complete - Provides field-based completeness for any entity.
File
fc.moduleView source
<?php
/**
* @file
* Field Complete - Provides field-based completeness for any entity.
*/
/**
* Implements hook_entity_info_alter()
*/
function fc_entity_info_alter(&$entity_info) {
foreach ($entity_info as &$info) {
if ($info['fieldable'] && empty($info['fc handler class'])) {
$info['fc handler class'] = 'fcComplete';
}
}
}
function fc_ctools_plugin_directory($module, $plugin) {
static $modules = array(
'fc' => array(
'fields' => 'fields',
),
);
if (!empty($modules[$module][$plugin])) {
return "plugins/{$modules[$module][$plugin]}";
}
}
function fc_get_plugin($type) {
static $plugins;
if (empty($plugins)) {
ctools_include('plugins');
$plugins = ctools_get_plugins('fc', 'fields');
}
return !empty($plugins[$type]) ? $plugins[$type] : $plugins['default'];
}
/**
* Implements hook_ctools_plugin_type().
*/
function fc_ctools_plugin_type() {
module_load_include('registry.inc', 'fc');
return _fc_ctools_plugin_type();
}
/**
* Implements hook_menu().
*/
function fc_menu() {
module_load_include('registry.inc', 'fc');
return _fc_menu();
}
/**
* Implements hook_permission().
*/
function fc_permission() {
module_load_include('registry.inc', 'fc');
return _fc_permission();
}
/**
* Implements hook_theme().
*/
function fc_theme() {
module_load_include('registry.inc', 'fc');
return _fc_theme();
}
/**
* Implements hook_theme_registry_alter().
*/
function fc_theme_registry_alter(&$registry) {
$registry['form_element_label']['function'] = 'fc_form_element_label';
$registry['field_multiple_value_form']['function'] = 'fc_field_multiple_value_form';
}
/**
* Implements hook_views_api().
*/
function fc_views_api() {
return array(
'api' => 3,
'path' => drupal_get_path('module', 'fc') . '/views',
);
}
/**
* Implements hook_field_widget_settings_form().
*
* This function adds the checkbox to every field to determine whether it
* should be used in the completeness calculation. It is set differently
* for every field instance.
*/
function fc_form_field_ui_field_edit_form_alter(&$form, &$form_state) {
module_load_include('form.inc', 'fc');
return _fc_form_field_ui_field_edit_form_alter($form, $form_state);
}
function fc_field_attach_after_build($element, &$form_state) {
module_load_include('form.inc', 'fc');
return _fc_field_attach_after_build($element, $form_state);
}
/**
* Implements hook_entity_insert().
*/
function fc_entity_insert($entity, $entity_type) {
if (fc_entity_is_enabled($entity_type)) {
$entity->fc = fcComplete::build($entity_type, $entity);
$entity->fc
->completeness();
$entity->fc
->save();
}
}
/**
* Implements hook_entity_update().
*/
function fc_entity_update($entity, $entity_type) {
if (fc_entity_is_enabled($entity_type)) {
$entity->fc = fcComplete::build($entity_type, $entity);
$entity->fc
->completeness();
$entity->fc
->save();
}
}
/**
* Implements hook_entity_load().
*/
function fc_entity_load($entities, $entity_type) {
if (fc_entity_is_enabled($entity_type)) {
foreach ($entities as $entity) {
$entity->fc = fcComplete::load($entity_type, $entity);
}
}
}
/**
* Implements hook_entity_delete().
*/
function fc_entity_delete($entity, $entity_type) {
if (fc_entity_is_enabled($entity_type)) {
if (empty($entity->fc)) {
$entity->fc = fcComplete::build($entity_type, $entity);
}
$entity->fc
->delete();
}
}
// Utility functions for building completeness
function fc_default_field_cardinality($function, $field_items, $instance, $field) {
// Fetch an array of completed items
$completed = array();
$function($field_items, $instance, $field, $completed);
// Test each field item to determine if it's not empty = complete
// we also need to take into account cardinality
$cardinality = $field['cardinality'];
if ($cardinality == FIELD_CARDINALITY_UNLIMITED) {
// If we can have unlimited then we must have at least one,
// but if we have a number of items make the cardinality
// equal to the total. This means that someone can create a
// while bunch of items but they must all be complete for the
// field itself to counted as complete.
$cardinality = empty($field_items) ? 1 : count($field_items);
}
// It's complete as long as we have /at least/ the cardinality
return count(array_filter($completed)) >= $cardinality;
}
/**
* Implements hook_fc_instances_alter().
*
* Remove all fields that are deleted or specifically
* not intended to be included in completeness.
*/
function fc_fc_instances_alter(&$instances, $entity_type, $entity, $options) {
foreach ($instances as $field_name => $instance) {
if (empty($instance['settings']['fc']['fc_include']) || !empty($instance['deleted'])) {
$instances[$field_name]['settings']['fc']['disable'] = TRUE;
}
}
}
/**
* Implements hook_field_attach_form().
*/
function fc_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
module_load_include('form.inc', 'fc');
return _fc_field_attach_form($entity_type, $entity, $form, $form_state, $langcode);
}
function fc_form_pre_render($form) {
module_load_include('form.inc', 'fc');
return _fc_form_pre_render($form);
}
/**
* Modified form_element_label theme function.
*/
function fc_form_element_label($variables) {
$element = $variables['element'];
// This is also used in the installer, pre-database setup.
$t = get_t();
// If title and required marker are both empty, output no label.
if (empty($element['#title'])) {
return '';
}
// If the element is required, a required marker is appended to the label.
$required = !empty($element['#required']) ? theme('form_required_marker', array(
'element' => $element,
)) : '';
$complete = !empty($element['#field_complete']) ? theme('form_complete_marker', array(
'element' => $element,
)) : '';
$title = filter_xss_admin($element['#title']);
$attributes = array();
// Style the label as class option to display inline with the element.
if ($element['#title_display'] == 'after') {
$attributes['class'] = 'option';
}
elseif ($element['#title_display'] == 'invisible') {
$attributes['class'] = 'element-invisible';
}
if (!empty($element['#id'])) {
$attributes['for'] = $element['#id'];
}
// The leading whitespace helps visually separate fields from inline labels.
return ' <label' . drupal_attributes($attributes) . '>' . $t('!title !required', array(
'!title' => $title,
'!required' => $required . $complete,
)) . "</label>\n";
}
/**
* Returns HTML for an individual form element.
*
* Combine multiple values into a table with drag-n-drop reordering.
* TODO : convert to a template.
*
* @param $variables
* An associative array containing:
* - element: A render element representing the form element.
*
* @ingroup themeable
*/
function fc_field_multiple_value_form($variables) {
$element = $variables['element'];
$output = '';
if ($element['#cardinality'] > 1 || $element['#cardinality'] == FIELD_CARDINALITY_UNLIMITED) {
$table_id = drupal_html_id($element['#field_name'] . '_values');
$order_class = $element['#field_name'] . '-delta-order';
$required = !empty($element['#required']) ? theme('form_required_marker', $variables) : '';
$complete = !empty($element['#field_complete']) ? theme('form_complete_marker', array(
'element' => $element,
)) : '';
$header = array(
array(
'data' => '<label>' . t('!title !required', array(
'!title' => $element['#title'],
'!required' => $required . $complete,
)) . "</label>",
'colspan' => 2,
'class' => array(
'field-label',
),
),
t('Order'),
);
$rows = array();
// Sort items according to '_weight' (needed when the form comes back after
// preview or failed validation)
$items = array();
foreach (element_children($element) as $key) {
if ($key === 'add_more') {
$add_more_button =& $element[$key];
}
else {
$items[] =& $element[$key];
}
}
usort($items, '_field_sort_items_value_helper');
// Add the items as table rows.
foreach ($items as $key => $item) {
$item['_weight']['#attributes']['class'] = array(
$order_class,
);
$delta_element = drupal_render($item['_weight']);
$cells = array(
array(
'data' => '',
'class' => array(
'field-multiple-drag',
),
),
drupal_render($item),
array(
'data' => $delta_element,
'class' => array(
'delta-order',
),
),
);
$rows[] = array(
'data' => $cells,
'class' => array(
'draggable',
),
);
}
$output = '<div class="form-item">';
$output .= theme('table', array(
'header' => $header,
'rows' => $rows,
'attributes' => array(
'id' => $table_id,
'class' => array(
'field-multiple-table',
),
),
));
$output .= $element['#description'] ? '<div class="description">' . $element['#description'] . '</div>' : '';
$output .= '<div class="clearfix">' . drupal_render($add_more_button) . '</div>';
$output .= '</div>';
drupal_add_tabledrag($table_id, 'order', 'sibling', $order_class);
}
else {
foreach (element_children($element) as $key) {
// The #field_complete flag is inherited so we have to re-check
// whether this specific field should have a 'complete' marker.
// There's probably a better way of doing this.
$subelement =& $element[$key];
if (!empty($subelement['#field_complete']) && !empty($subelement['#entity'])) {
list(, , $bundle) = entity_extract_ids($subelement['#entity_type'], $subelement['#entity']);
$instance = field_info_instance($subelement['#entity_type'], $element['#field_name'], $bundle);
$subelement['#field_complete'] = !empty($instance['settings']['fc']['fc_include']);
foreach ($subelement['#columns'] as $column) {
if (!empty($subelement[$column])) {
$subelement[$column]['#field_complete'] = $subelement['#field_complete'];
}
}
}
$output .= drupal_render($subelement);
}
}
return $output;
}
/**
* Theme preprocess function for theme_field() and field.tpl.php.
*
* @see theme_field()
* @see field.tpl.php
*/
function fc_preprocess_field(&$variables) {
$element = $variables['element'];
$types = fc_enabled_entity_types();
if (in_array($element['#entity_type'], $types)) {
$instance = field_info_instance($element['#entity_type'], $element['#field_name'], $element['#bundle']);
$fc_extras = array();
if (!empty($element['#formatter']) && $element['#formatter'] == 'editable') {
$variables['classes_array'][] = drupal_html_class('field-formatter-' . $element['#formatter']);
$variables['field_is_editable'] = TRUE;
if (!empty($instance['settings']['fc']['fc_include'])) {
$variables['classes_array'][] = 'field-complete';
$variables['field_is_complete'] = TRUE;
$fc_extras = array(
'#theme' => 'form_complete_marker',
);
}
if (!empty($instance['required'])) {
$variables['classes_array'][] = 'field-required';
$variables['field_is_required'] = TRUE;
$fc_extras = array(
'#theme' => 'form_required_marker',
);
}
}
$variables['fc_extras'] = $fc_extras;
}
}
/**
* Implements hook_form_profile2_form_alter().
*
* Profile2 behaves very non-standardly with its edit-form handling
* so we have to try to see if we can't get round its nonsense.
*/
function fc_form_profile2_form_alter(&$form, &$form_state) {
module_load_include('form.inc', 'fc');
return _fc_form_profile2_form_alter($form, $form_state);
}
function fc_get_page_entity($entity_type) {
$entity = NULL;
$entity_info = entity_get_info($entity_type);
if ($entity_type == 'profile2') {
// Special handling for profile2 (again)
$router_item = menu_get_item();
foreach ($router_item['page_arguments'] as $arg) {
if ($arg instanceof Profile) {
$entity = $arg;
break;
}
}
}
else {
// Figure out the URL structure, build a dummy entity
// then fetch its URL.
$dummy = (object) array(
$entity_info['entity keys']['id'] => 0,
);
$uri = $entity_info['uri callback']($dummy);
$path = explode('/', $uri['path']);
$pos = 0;
while (($el = array_shift($path)) && ++$pos) {
if (is_numeric($el)) {
break;
}
}
// Get the actual entity for this page
$entity = menu_get_object($entity_type, $pos);
}
return $entity;
}
//-----------------------------------------------------------
/**
* Return all entity_types that can benefit from Field Complete
*/
function fc_entity_types() {
static $entity_types = array();
foreach (entity_get_info() as $entity_type => $entity_info) {
if (empty($entity_info['uri callback']) || empty($entity_info['fieldable'])) {
// There's no display URI for this entity so it'll never appear
// rendered, or it's not fieldable so Field Complete doesn't apply
continue;
}
$entity_types[$entity_type] = $entity_info;
}
return $entity_types;
}
/**
* Returns the list of enabled entity types
*/
function fc_enabled_entity_types() {
return variable_get('fc_entity_types', array(
'node' => 'node',
'user' => 'user',
));
}
/**
* Returns TRUE if the given entity is enabled with fc, FALSE otherwise.
*/
function fc_entity_is_enabled($entity_type) {
if (!empty($entity_type) && is_string($entity_type)) {
$types = fc_enabled_entity_types();
return in_array($entity_type, $types, true);
}
return FALSE;
}