Everything works fine when using hook_form - like Wim does in his hs_tutorial module. However when i use hook_form_alter (instead of hook_form) i get a "Received invalid response from the server" error after selecting a root level item. Reloading the page then yields a drupal error: "warning: uasort() [function.uasort]: The argument should be an array in /home/fivthwor/public_html/imaginariums/includes/common.inc on line 2875."

I tried giving the module different weights, disabling contrib modules, clearing and flushing caches - to no avail.

Please see attached module file and i can provide a screencast if necessary.

Comments

Hunabku’s picture

Module file:

// $Id: imaginariums_test.module

function imaginariums_test_node_info() {
  return array(
    'imaginariums_test' => array(
      'name' => t('Imaginariums Test'),
      'module' => 'imaginariums_test',
      'description' => t("A test module using Hierarchical Select with a non-taxonomy-based hierarchy."),
    )
  );
}


function imaginariums_test_menu_alter(&$items) {
	$items ['node/add/activity-story'] = array (
		'title' =>  t('Activity or Story'),
		'title callback' =>  'check_plain',
		'page callback' => 'custom_add',
		'page arguments' => array (0 => 3),
		'access callback' => 'node_access',
		'access arguments' => array (
			0 => 'create',
			1 => 'activity_story',
		),
		'file' => 'node.pages.inc',
		'module' => 'node',
	);	
}


function custom_add ($share_experience_forum) {
		global $hs_structured_array;
		$hs_structured_array = array();
		//I'm building hs array here so that we don't have to build it for each call to imaginariums_test_hierarchy
		//i'm doing it here instead of in form_alter because i am not sure when hs accesses it.
		$root_result = db_query("SELECT node.nid, node.title FROM {node} INNER JOIN {content_field_reference_pod} ON node.nid = content_field_reference_pod.field_reference_pod_nid INNER JOIN {content_type_event_etc} ON content_field_reference_pod.nid = content_type_event_etc.nid INNER JOIN {term_node} ON content_type_event_etc.nid = term_node.nid WHERE term_node.tid = %d", 96);
		$num_root_rows = FALSE;
		while ($root_node = db_fetch_object($root_result)) {
			$num_root_rows = TRUE;
			$hs_structured_array['root']['children'][] =	 $root_node->nid;
			$hs_structured_array[$root_node->nid]['label'] = $root_node->title;
			$child_result = db_query("SELECT node.nid, node.title FROM {node} INNER JOIN {content_field_reference_pod} ON node.nid = content_field_reference_pod.nid INNER JOIN {content_type_event_etc} ON content_field_reference_pod.nid = content_type_event_etc.nid WHERE content_type_event_etc.field_core_type_value = '%s' AND content_field_reference_pod.field_reference_pod_nid = %d", 'Event', $root_node->nid); 
			$temp = array();
			while ($child_node = db_fetch_object($child_result)) {
				$hs_structured_array[$root_node->nid]['children'][] = $child_node->nid;
				$hs_structured_array[$child_node->nid]['label'] = $child_node->title;
			}
		}

		//added node callback code (from node.pages.inc) and slightly modified for this use case
		global $user;
		
		$type = 'activity_story';

	  $types = node_get_types();
	  $type = isset($type) ? str_replace('-', '_', $type) : NULL;
	  // If a node type has been specified, validate its existence.
	  if (isset($types[$type]) && node_access('create', $type)) {
	    // Initialize settings:
	    $node = array('uid' => $user->uid, 'name' => (isset($user->name) ? $user->name : ''), 'type' => $type, 'language' => '');

	    drupal_set_title(t('Create @name', array('@name' => $types[$type]->name)));
	    $output = drupal_get_form($type .'_node_form', $node);
	  }

	  return $output;
		
}


function imaginariums_test_form_alter(&$form, $form_state, $form_id) {
	$form_id = $form['form_id']['#value'];
	if ($form_id == 'activity_story_node_form') {
		if (arg(1) == "add")  {
			$form['imaginariums_custom_select'] = array(
				'#type' => 'hierarchical_select',
				'#weight' => 1,
				'#title' => t('Select your pod'),
				'#required' => FALSE,
				'#default_value' => 204,
				'#config' => array(
					'module' => 'imaginariums_test',
					'params' => array(
						'root' => 'root',
					),
					'save_lineage' => 1,
					'enforce_deepest' => 0,
					'level_labels' => array(
						'status' => 1,
						'labels' => array(
							0 => t('Choose:'),
							1 => t('Select an event (if applicable):'),
						),
					),
				),
			);
		}
		
	}
		
}


/**
* @file
* The hierarchical select functions below originate from the attached help files in this tutorial - http://drupal.org/node/532724
*/


//----------------------------------------------------------------------------
// Main functionality of Hierarchical Select
/**
 * Definition of hierarchy.
 */
function imaginariums_test_hierarchy() {
	//AC_Mod Since this function is called multiple times i just generated the array previously
	//and stored it in global variable $hs_structured_array
	global $hs_structured_array;
	return $hs_structured_array;
}


//----------------------------------------------------------------------------
// Hierarchical Select hooks.

/**
 * Implementation of hook_hierarchical_select_params().
 */
function imaginariums_test_hierarchical_select_params() {
	// This module defines only one hierarchy, so parameters are not necessary.
	return array();
}

/**
 * Implementation of hook_hierarchical_select_root_level().
 */
function imaginariums_test_hierarchical_select_root_level($params) {
	$hierarchy = imaginariums_test_hierarchy();
	$items = $hierarchy['root']['children'];
	return _imaginariums_test_items_associate_labels_with_items($items); 
}

/**
 * Implementation of hook_hierarchical_select_children().
 */
function imaginariums_test_hierarchical_select_children($parent) {
	$hierarchy = imaginariums_test_hierarchy();
	$items = $hierarchy[$parent]['children'];
	return _imaginariums_test_items_associate_labels_with_items($items);
}

/**
 * Implementation of hook_hierarchical_select_lineage().
 */
function imaginariums_test_hierarchical_select_lineage($item, $params) {
	// If given the item "Company A-Accounts Payable-Employee C", this will
	// generate the following lineage:
	// Array
	// (
	//		 [0] => Company A
	//		 [1] => Company A-Accounts Payable
	//		 [2] => Company A-Accounts Payable-Employee C
	// )
	$parts = explode('-', $item);
	 
	$lineage = array();
	for ($i = 0; $i < count($parts); $i++) {
		$lineage[] = implode('-', array_slice($parts, 0, $i + 1));
	}
	return $lineage;

}

/**
 * Implementation of hook_hierarchical_select_valid_item().
 */
function imaginariums_test_hierarchical_select_valid_item($item, $params) {
	$hierarchy = imaginariums_test_hierarchy();
	return isset($hierarchy[$item]['label']);
}

/**
 * Implementation of hook_hierarchical_select_item_get_label().
 */
function imaginariums_test_hierarchical_select_item_get_label($item, $params) {
	$hierarchy = imaginariums_test_hierarchy();
	return $hierarchy[$item]['label'];
}


//----------------------------------------------------------------------------
// Helper functions.

/**
 * Given an array of items, associate the labels with the items.
 *
 * @param $items
 *	 An array of item objects.
 * @return
 *	 An associative array of (item, label) pairs.
 */
function _imaginariums_test_items_associate_labels_with_items($items) {
	$hierarchy = imaginariums_test_hierarchy();
	$options = array();
	 
	if (count($items)) {
		foreach ($items as $item) {
			// Use the translated item when available!
			$options[$item] = t($hierarchy[$item]['label']);
		}
	}
	 
	 return $options;
}


wim leers’s picture

Assigned: Unassigned » wim leers
Status: Active » Postponed (maintainer needs more info)

Instead of generating the hierarchy in custom_add(), generate it in imaginariums_test_hierarchy() and use a static variable to generate it only once. That might help.

Hunabku’s picture

Wim - thanks for your timely response

I went ahead and put the internal_hierarchy array generating code back into imaginariums_test_hierarchy() static array - where it belongs. : )
I also removed the menu_alter and custom_add callback from my modules code. The error persists.

Have you found no problem using a hook_form_alter instead of a hook_form with your example code?

hook_form_alter seems like a fairly common place for implementing hs api for non-taxonomy use cases. Ergo is there anyone else out there who has done this successfully?

Hunabku’s picture

OK - substituting form_alter for form works fine with hs_tutorial module. There is something specific to what i am doing that is creating the error - perhaps i'll post what is causing it incase someone else bumps up against it.

THANK YOU Wim for an awesome module and great support.

Hunabku’s picture

Riddle me this ???

Everything works fine after i removed the following if statement from my hook_form_alter:

if (arg(1) == "add") {}

what that has to do with HS i have no idea - i'm just glad i got it working : )

wim leers’s picture

Status: Postponed (maintainer needs more info) » Fixed

Ahhh, of course! The arg(1) is NOT equal to 'add' when updating HS, since HS uses a callback to a different path for that.

Glad you got it solved :)

Hunabku’s picture

Status: Fixed » Active

Hi Wim

Sorry to reopen this but i really need to execute different hierarchical select depending on arg(n).

i tried to create and use my own uri args but it makes no difference.

$uri_args = explode('/', substr(request_uri(), 1));

Do you think there is anything you could do to hs to make it more amiable to the arg . . . . .

or anything i could do on my side?

wim leers’s picture

Status: Active » Postponed (maintainer needs more info)

There's nothing I can do. That's how it works.

What you could do, is add a GET argument. E.g. node/add/page?bleh=whatever. This will be carried on.

If it is the adding of nodes you want to detect, there's other ways to do that. For example, check if a node object is present. If not, a new node is being created, if it is, an existing node is being edited.

Hunabku’s picture

Status: Postponed (maintainer needs more info) » Fixed

OK - I'll add the GET

mahalos!

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.