function _hierarchical_select_hierarchy_generate in Hierarchical Select 5.3
Same name and namespace in other branches
- 6.3 hierarchical_select.module \_hierarchical_select_hierarchy_generate()
- 7.3 hierarchical_select.module \_hierarchical_select_hierarchy_generate()
Generate the hierarchy object.
Parameters
$config: A config array with at least the following settings:
- module
- params
- enforce_deepest
- save_lineage
- level_labels
- status
- labels
- editability
- status
- allow_new_levels
- max_levels
$selection: The selection based on which a HS should be rendered.
$required: Whether the form element is required or not. (#required in Forms API)
$dropbox: A dropbox object, or FALSE.
Return value
A hierarchy object.
1 call to _hierarchical_select_hierarchy_generate()
- hierarchical_select_process in ./
hierarchical_select.module - Hierarchical select form element type #process callback.
File
- ./
hierarchical_select.module, line 1537 - This module defines the "hierarchical_select" form element, which is a greatly enhanced way for letting the user select items in a hierarchy.
Code
function _hierarchical_select_hierarchy_generate($config, $selection, $required, $dropbox = FALSE) {
$hierarchy = new stdClass();
//
// Build the lineage.
//
$start_lineage = microtime();
// If save_linage is enabled, reconstruct the lineage. This is necessary
// because e.g. the taxonomy module stores the terms by order of weight and
// lexicography, rather than by hierarchy.
if ($config['save_lineage'] && is_array($selection) && count($selection) >= 2) {
// Ensure the item in the root level is the first item in the selection.
$root_level = array_keys(module_invoke($config['module'], 'hierarchical_select_root_level', $config['params']));
for ($i = 0; $i < count($selection); $i++) {
if (in_array($selection[$i], $root_level)) {
if ($i != 0) {
// Don't swap if it's already the first item.
list($selection[0], $selection[$i]) = array(
$selection[$i],
$selection[0],
);
}
break;
}
}
// Reconstruct all sublevels.
for ($i = 0; $i < count($selection); $i++) {
$children = array_keys(module_invoke($config['module'], 'hierarchical_select_children', $selection[$i], $config['params']));
// Ensure the next item in the selection is a child of the current item.
for ($j = $i + 1; $j < count($selection); $j++) {
if (in_array($selection[$j], $children)) {
list($selection[$j], $selection[$i + 1]) = array(
$selection[$i + 1],
$selection[$j],
);
}
}
}
}
// Validate the hierarchy.
$selection = _hierarchical_select_hierarchy_validate($selection, $config['module'], $config['params']);
// When nothing is currently selected, set the root level to:
// - "<none>" when:
// - enforce_deepest is enabled *and* level labels are enabled *and*
// no root level label is set (1), or
// - the dropbox is enabled *and* at least one selection has been added
// to the dropbox (2)
// - "label_0" (the root level label) in all other cases.
if ($selection == -1) {
$root_level = module_invoke($config['module'], 'hierarchical_select_root_level', $config['params']);
$first_case = $config['enforce_deepest'] && $config['level_labels']['status'] && !isset($config['level_labels']['labels'][0]);
$second_case = $dropbox && count($dropbox->lineages) > 0;
$hierarchy->lineage[0] = $first_case || $second_case ? 'none' : 'label_0';
}
else {
// If save_lineage setting is enabled, then the selection *is* a lineage.
// If it's disabled, we have to generate one ourselves based on the
// (deepest) selected item.
if ($config['save_lineage']) {
// When the form element is optional, the "<none>" setting can be
// selected, thus only the first level will be displayed. As a result,
// we won't receive an array as the selection, but only a single item.
// We convert this into an array.
$hierarchy->lineage = is_array($selection) ? $selection : array(
0 => $selection,
);
}
else {
$selection = is_array($selection) ? $selection[0] : $selection;
if (module_invoke($config['module'], 'hierarchical_select_valid_item', $selection, $config['params'])) {
$hierarchy->lineage = module_invoke($config['module'], 'hierarchical_select_lineage', $selection, $config['params']);
}
else {
// If the selected item is invalid, then start with an empty lineage.
$hierarchy->lineage = array();
}
}
}
// If enforce_deepest is enabled, ensure that the lineage goes as deep as
// possible: append values of items that will be selected by default.
if ($config['enforce_deepest'] && !in_array($hierarchy->lineage[0], array(
'none',
'label_0',
))) {
$hierarchy->lineage = _hierarchical_select_hierarchy_enforce_deepest($hierarchy->lineage, $config['module'], $config['params']);
}
$end_lineage = microtime();
//
// Build the levels.
//
$start_levels = microtime();
// Start building the levels, initialize with the root level.
$hierarchy->levels[0] = module_invoke($config['module'], 'hierarchical_select_root_level', $config['params']);
$hierarchy->levels[0] = _hierarchical_select_apply_entity_settings($hierarchy->levels[0], $config);
// Prepend a "<create new item>" option to the root level when:
// - the editability setting is enabled, and
// - the hook is implemented (this is an optional hook), and
// - the allowed_levels setting allows to create new items at this level.
if ($config['editability']['status'] && module_hook($config['module'], 'hierarchical_select_create_item') && _hierarchical_select_create_new_item_is_allowed($config, 0)) {
$item_type = t($config['editability']['item_types'][0]);
$item_type = !empty($item_type) ? $item_type : t('item');
$option = theme('hierarchical_select_special_option', t('create new !item_type', array(
'!item_type' => $item_type,
)));
$hierarchy->levels[0] = array(
'create_new_item' => $option,
) + $hierarchy->levels[0];
}
// Prepend a "<none>" option to the root level when:
// - the form element is optional (1), or
// - enforce_deepest is enabled (2), or
// - the dropbox is enabled *and* at least one selection has been added to
// the dropbox (3)
$first_case = !$required;
$second_case = $config['enforce_deepest'];
$third_case = $dropbox && count($dropbox->lineages) > 0;
if ($first_case || $second_case || $third_case) {
$option = theme('hierarchical_select_special_option', t('none'));
$hierarchy->levels[0] = array(
'none' => $option,
) + $hierarchy->levels[0];
}
// Calculate the lineage's depth (starting from 0).
$max_depth = count($hierarchy->lineage) - 1;
// Build all sublevels, based on the lineage.
for ($depth = 1; $depth <= $max_depth; $depth++) {
$hierarchy->levels[$depth] = module_invoke($config['module'], 'hierarchical_select_children', $hierarchy->lineage[$depth - 1], $config['params']);
$hierarchy->levels[$depth] = _hierarchical_select_apply_entity_settings($hierarchy->levels[$depth], $config);
}
if ($config['enforce_deepest']) {
// Prepend a "<create new item>" option to each level below the root level
// when:
// - the editability setting is enabled, and
// - the hook is implemented (this is an optional hook), and
// - the allowed_levels setting allows to create new items at this level.
if ($config['editability']['status'] && module_hook($config['module'], 'hierarchical_select_create_item')) {
for ($depth = 1; $depth <= $max_depth; $depth++) {
$item_type = t($config['editability']['item_types'][$depth]);
$item_type = !empty($item_type) ? $item_type : t('item');
$option = theme('hierarchical_select_special_option', t('create new !item_type', array(
'!item_type' => $item_type,
)));
if (_hierarchical_select_create_new_item_is_allowed($config, $depth)) {
$hierarchy->levels[$depth] = array(
'create_new_item' => $option,
) + $hierarchy->levels[$depth];
}
}
}
// If level labels are enabled and the root label is set, prepend it.
if ($config['level_labels']['status'] && isset($config['level_labels']['labels'][0])) {
$hierarchy->levels[0] = array(
'label_0' => t($config['level_labels']['labels'][0]),
) + $hierarchy->levels[0];
}
}
else {
if (!$config['enforce_deepest']) {
// Prepend special options to every level.
for ($depth = 0; $depth <= $max_depth; $depth++) {
// Prepend a "<create new item>" option to the current level when:
// - this is not the root level (the root level already has this), and
// - the editability setting is enabled, and
// - the hook is implemented (this is an optional hook), and
// - the allowed_levels setting allows to create new items at this level.
if ($depth > 0 && $config['editability']['status'] && module_hook($config['module'], 'hierarchical_select_create_item') && _hierarchical_select_create_new_item_is_allowed($config, $depth)) {
$item_type = t($config['editability']['item_types'][$depth]);
$item_type = !empty($item_type) ? $item_type : t('item');
$option = theme('hierarchical_select_special_option', t('create new !item_type', array(
'!item_type' => $item_type,
)));
$hierarchy->levels[$depth] = array(
'create_new_item' => $option,
) + $hierarchy->levels[$depth];
}
// Level label: set an empty level label if they've been disabled.
$label = $config['level_labels']['status'] && isset($config['level_labels']['labels'][$depth]) ? t($config['level_labels']['labels'][$depth]) : '';
$hierarchy->levels[$depth] = array(
'label_' . $depth => $label,
) + $hierarchy->levels[$depth];
}
// If the root level label is empty and the none option is present, remove
// the root level label because it's conceptually identical.
if ($hierarchy->levels[0]['label_0'] == '' && isset($hierarchy->levels[0]['none'])) {
unset($hierarchy->levels[0]['label_0']);
// Update the selected lineage when necessary to prevent an item that
// doesn't exist from being "selected" internally.
if ($hierarchy->lineage[0] == 'label_0') {
$hierarchy->lineage[0] = 'none';
}
}
// Add one more level if appropriate.
$parent = $hierarchy->lineage[$max_depth];
if (module_invoke($config['module'], 'hierarchical_select_valid_item', $parent, $config['params'])) {
$children = module_invoke($config['module'], 'hierarchical_select_children', $parent, $config['params']);
if (count($children)) {
// We're good, let's add one level!
$depth = $max_depth + 1;
$hierarchy->levels[$depth] = array();
// Prepend a "<create new item>" option to the current level when:
// - the editability setting is enabled, and
// - the hook is implemented (this is an optional hook), and
// - the allowed_levels setting allows to create new items at this level.
if ($config['editability']['status'] && module_hook($config['module'], 'hierarchical_select_create_item') && _hierarchical_select_create_new_item_is_allowed($config, $depth)) {
$item_type = t($config['editability']['item_types'][$depth]);
$item_type = !empty($item_type) ? $item_type : t('item');
$option = theme('hierarchical_select_special_option', t('create new !item_type', array(
'!item_type' => $item_type,
)));
$hierarchy->levels[$depth] = array(
'create_new_item' => $option,
);
}
// Level label: set an empty level label if they've been disabled.
$hierarchy->lineage[$depth] = 'label_' . $depth;
$label = $config['level_labels']['status'] ? t($config['level_labels']['labels'][$depth]) : '';
$hierarchy->levels[$depth] = array(
'label_' . $depth => $label,
) + $hierarchy->levels[$depth] + $children;
$hierarchy->levels[$depth] = _hierarchical_select_apply_entity_settings($hierarchy->levels[$depth], $config);
}
}
}
}
// Add an extra level with only a level label and a "<create new item>"
// option, if:
// - the editability setting is enabled
// - the allow_new_levels setting is enabled
// - an additional level is permitted by the max_levels setting
// - the deepest item of the lineage is a valid item
// NOTE: this uses an optional hook, so we also check if it's implemented.
if ($config['editability']['status'] && $config['editability']['allow_new_levels'] && ($config['editability']['max_levels'] == 0 || count($hierarchy->lineage) < $config['editability']['max_levels']) && module_invoke($config['module'], 'hierarchical_select_valid_item', end($hierarchy->lineage), $config['params']) && module_hook($config['module'], 'hierarchical_select_create_item')) {
$depth = $max_depth + 1;
// Level label: set an empty level label if they've been disabled.
$hierarchy->lineage[$depth] = 'label_' . $depth;
$label = $config['level_labels']['status'] ? t($config['level_labels']['labels'][$depth]) : '';
// Item type.
$item_type = t($config['editability']['item_types'][$depth]);
$item_type = !empty($item_type) ? $item_type : t('item');
// The new level with only a level label and a "<create new item>" option.
$option = theme('hierarchical_select_special_option', t('create new !item_type', array(
'!item_type' => $item_type,
)));
$hierarchy->levels[$depth] = array(
'label_' . $depth => $label,
'create_new_item' => $option,
);
}
// Calculate the time it took to generate the levels.
$end_levels = microtime();
// Add child information.
$start_childinfo = microtime();
$hierarchy = _hierarchical_select_hierarchy_add_childinfo($hierarchy, $config);
$end_childinfo = microtime();
// Calculate the time it took to build the hierarchy object.
$hierarchy->build_time['total'] = ($end_childinfo - $start_lineage) * 1000;
$hierarchy->build_time['lineage'] = ($end_lineage - $start_lineage) * 1000;
$hierarchy->build_time['levels'] = ($end_levels - $start_levels) * 1000;
$hierarchy->build_time['childinfo'] = ($end_childinfo - $start_childinfo) * 1000;
return $hierarchy;
}