I have a 2-D array:
$stats['name'] = name1, name2, name3, etc
$stats['ladder'] = 12.5, 10, 20, etc
$stats['rounds'] = 4, 2, 10, etc
$stats['matches'] = 1, 1, 0, etc
This array is created dynamically by reading the filenames associated with keys in this key array:
$key_array[ladder] = 'ladder.txt'
$key_array[rounds] = 'won_rounds.txt'
$key_array[matches] = 'won_matches.txt'
Now, I create a function into which I pass, a sort_key which matches one of the keys above, the $stats array, and $key_array.
Now I want to sort the sort_key element of the $stats array and also keep the positional relationship in all of the other elements in $stats.
I'm currently doing this with array_multisort, but to do it, I have to separate each element of the $stats array and feed them individually into the array_multisort function in the ordered determine by my sort key. So, my implementation is totally hardcoded with a switch statement in which I typed out each array_multisort parameter combination.
Anybody have any idea how to easily do this dynamically, using a foreach to get the keys out of the key array and sorting the $stats array appropriately?
The long way would be to write my own sort function to sort the keyed element of $stats, save off the new order, and then apply that order to each of the other elements... but there should be a simpler way.
- gss
How to sort dynamic multi-dimensional arrays in PHP?
- Lucifer
- Project Developer
- Posts: 8683
- Joined: Sun Aug 15, 2004 3:32 pm
- Location: Republic of Texas
- Contact:
The simple way is to use the provided function.
http://www.php.net/manual/en/function.ksort.php
Er, after reading your description of the data, I'm going to suggest you do something a little differently. FIrst thing's first, whatever you do, use the sort functions provided by php. Those are implemented in C code and are very fast, several orders of magnitude faster than anything you'll write in php. So don't bother. Instead, spend your time formatting the data to be used by php's sort functions.
An example. Copy the array by the key into a regular array, then use ksort on it. When you then do something like this:
php treats numeric keys the same way it treats string keys, they're just keys. php has no concept of a numerical array internally, it just provides syntactical shortcuts so you can think that way for such arrays, but internally all is dict.
http://www.php.net/manual/en/function.ksort.php
Er, after reading your description of the data, I'm going to suggest you do something a little differently. FIrst thing's first, whatever you do, use the sort functions provided by php. Those are implemented in C code and are very fast, several orders of magnitude faster than anything you'll write in php. So don't bother. Instead, spend your time formatting the data to be used by php's sort functions.
An example. Copy the array by the key into a regular array, then use ksort on it. When you then do something like this:
Code: Select all
foreach $sortedarray as $key=>$value {
echo $stats['rounds'][$key];
}
Hmm... either I misunderstand your reponse, or you misunderstand my question. The problem with sorting each array individually is I lose the relationship between the data across keys. For instance, element 0 of each array within $stats belongs together. So, if I sort based on ladder score, I want all of the other arrays to change order the same way. Here's how I'm achieving this today:
array_multisort preserves the relationship across the arrays... but I don't want to have to hardcode the function calls. This function shouldn't need to know anything about ladders , won_rounds, etc. It should simply pull the key elements out of $key_array, sort the appropriate sub-array from $stats, and push that same reording to the other sub-arrays in $stats.
Code: Select all
function sort_stats_array ($key_array, $stats_array, $sort_key) {
// Create individual arrays for each key value
foreach ($key_array as $key => $array) {
$$key = $stats_array[$key];
}
switch ($sort_key) {
case 'name': {
array_multisort($name, SORT_ASC, $Ladder, SORT_DESC, $High_score, SORT_DESC, $Won_rounds, SORT_DESC, $Won_matches, SORT_DESC);
break;
}
case 'Ladder': {
array_multisort($Ladder, SORT_DESC, $name, SORT_ASC, $High_score, SORT_DESC, $Won_rounds, SORT_DESC, $Won_matches, SORT_DESC);
break;
}
case 'High_score': {
array_multisort($High_score, SORT_DESC, $Ladder, SORT_DESC, $name, SORT_ASC, $Won_rounds, SORT_DESC, $Won_matches, SORT_DESC);
break;
}
case 'Won_rounds': {
array_multisort($Won_rounds, SORT_DESC, $Ladder, SORT_DESC, $High_score, SORT_DESC, $name, SORT_ASC, $Won_matches, SORT_DESC);
break;
}
case 'Won_matches': {
array_multisort($Won_matches, SORT_DESC, $Ladder, SORT_DESC, $High_score, SORT_DESC, $Won_rounds, SORT_DESC, $name, SORT_ASC);
break;
}
}
// Put the key arrays back together into the stats_array
$stats_array['name'] = $name;
foreach ($key_array as $key => $array) {
$stats_array[$key] = $$key;
}
return ($stats_array);
}
Taking your idea of reformatting the data...
I should map each of my keys from $key_array to a number, reorder those elements by putting the key indicated by $sort_key first, combing all of my $stats sub-arrays into a single array, perhaps with implode, do an asort on the new combined array, and then pull the data back out (explode) into the separate sub arrays again.
I think that should be fairly straightforward.
I should map each of my keys from $key_array to a number, reorder those elements by putting the key indicated by $sort_key first, combing all of my $stats sub-arrays into a single array, perhaps with implode, do an asort on the new combined array, and then pull the data back out (explode) into the separate sub arrays again.
I think that should be fairly straightforward.
- Lucifer
- Project Developer
- Posts: 8683
- Joined: Sun Aug 15, 2004 3:32 pm
- Location: Republic of Texas
- Contact:
Hmm, that might work, but it's not exactly what I was suggesting. I was suggesting sorting the array of interest, using ksort, which keeps the key-value associations, even in a numeric array. Then iterate through the now sorted array with a foreach with $key=>$value, and use the $key you get. Here, it winds up like this:
Not guaranteed to be syntactically correct, I just typed it in here, didn't run it, and I've been doing a lot of python lately.
The point is that a numerically indexed array in php is still a map (dictionary, whatever). It's just a map of keys to values that happen to be numeric, and you can treat the array like any other dictionary. So you can sort the array you care about, then iterate with both the key and value and use the key to get the data from the other arrays that were not sorted.
Copy the array first, of course, because you don't want to lose the original's association with the others. Once you get one array out of sync, you'll never get them back in sync. (You could sort the keys and keep the association, but why bother when you can just copy the array you want? Since php does copy-on-write, the sort will still be very efficient because the array gets copied as it gets sorted, and it all happens in the c library)
Code: Select all
$something = array("b", "e", "a", "d", "c");
asort($something)
foreach $something as $key=>$value {
echo $key
echo " "
echo $value
echo "\n"
}
output:
2, a
0, b
4, c
3, d
1, e
The point is that a numerically indexed array in php is still a map (dictionary, whatever). It's just a map of keys to values that happen to be numeric, and you can treat the array like any other dictionary. So you can sort the array you care about, then iterate with both the key and value and use the key to get the data from the other arrays that were not sorted.
Copy the array first, of course, because you don't want to lose the original's association with the others. Once you get one array out of sync, you'll never get them back in sync. (You could sort the keys and keep the association, but why bother when you can just copy the array you want? Since php does copy-on-write, the sort will still be very efficient because the array gets copied as it gets sorted, and it all happens in the c library)
If anybody cares, this is my code now:
Next step is to do something about making the key 'name' more like the others so I don't have to hardcode references to it. It's unique because it isn't associated with a file, in fact it ties all of the various files' data together, and I want to sort it ascending unlike the others.
Likely I'll have 2 separate key arrays, one for file processing which won't have 'name', and one for everything else, which will. I can add a field to the non-file processing one for sort direction.
- gss
Code: Select all
function sort_stats_array ($key_array, $stats_array, $sort_key) {
$array_to_sort = $stats_array[$sort_key];
if ($sort_key == "name") asort($array_to_sort);
else arsort ($array_to_sort);
$stats_array_copy = $stats_array;
$i=0;
foreach ($array_to_sort as $reordered_index=>$reordered_data) {
foreach ($key_array as $key=>$key_array_data) {
$stats_array[$key][$i] = $stats_array_copy[$key][$reordered_index];
}
$stats_array['name'][$i] = $stats_array_copy['name'][$reordered_index];
$i++;
}
return ($stats_array);
}
Likely I'll have 2 separate key arrays, one for file processing which won't have 'name', and one for everything else, which will. I can add a field to the non-file processing one for sort direction.
- gss
How do i change this code to multi dimensional array
Hi
I have the following code given below...however as u can see..to be able to do multiple levels...i need a dynamic multi dimensional array in place of my own levels..which go maximum to 5...
if someone is good enough with php to do this..would be excellent
Pls check the code..and give me a solution. thanks
<?php
// ; $Id: dropdown_taxonomy.module,v 1.1 2007/07/03 04:45:42 ksm Exp $
function dropdown_taxonomy_form_alter($form_id, &$form) {
// Taxonomy Edit Form
if($form_id == 'taxonomy_form_vocabulary'){
$vid = $form['#parameters'][1]['vid'];
$vocab = taxonomy_get_vocabulary($vid);
if($vocab){
$dtf = variable_get('dropdown_taxonomy_vid_'.$vid, 0);
// Position the name field higher
$form['name']['#weight'] = -2;
// Add our own submit handler
$form['#submit']['dropdown_taxonomy_submit'] = array();
// Create fieldset and form elements
$form['dtf'] = array(
'#type' => 'fieldset',
'#title' => t('Dropdown Taxonomy'),
'#value' => $info,
'#collapsible' => TRUE,
'#collapsed' => $dtf ? FALSE : TRUE,
'#tree' => TRUE,
'#weight' => 0,
);
// Get list of all content types
$types = node_get_types('names');
// Loop through all types that are enabled for this vocab
foreach($vocab->nodes AS $index => $type){
$options[$type] = $types[$type];
}
$form['dtf']['dropdown_taxonomy_vid_'.$vid]['types'] = array(
'#type' => 'checkboxes',
'#title' => t('Enable Taxonomy Select for the Vocabulary Content Types Below'),
'#options' => $options,
'#default_value' => $dtf['types'],
'#weight' => -1,
);
$form['dtf']['dropdown_taxonomy_vid_'.$vid]['parents'] = array(
'#type' => 'checkbox',
'#title' => t('Display parent terms as form items'),
'#default_value' => $dtf['parents'],
'#return_value' => 1,
'#weight' => 0,
'#description' => t('Leaving this disabled forces users to select dangling child terms. Useful for grouping terms with descriptive parent terms that are not themselves needed for display.'),
);
}
}
// Node Edit Form
if(strstr($form_id,'_node_form') AND strstr($form['form_id']['#value'], '_node_form')){
$content_type = $form['type']['#value'];
// Get all vocabs for this content type
$vocabularies = taxonomy_get_vocabularies($content_type);
$valid_vocabs = array();
foreach($vocabularies AS $vid => $vocabulary){
$dtf[$vid] = variable_get('dropdown_taxonomy_vid_'.$vid, 0);
// Only operate on types for a vocabulary that are enabled
if($dtf[$vid]['types'][$content_type]){
// Show radio or checkbox based on the selection type
$valid_vocabs[$vid] = $vocabulary->multiple ? 'checkbox' : 'radio';
if($vocabulary->tags){
// Remove any tags from the autocomplete form item (prevent duplicates)
$tags[$vid] = $form['taxonomy']['tags'][$vid];
$tags[$vid]['#default_value'] = '';
$tags[$vid]['#required'] = FALSE;
$tags[$vid]['#parents'] = array('taxonomy', 'tags', $vid);
$tags[$vid]['#weight'] = -12;
$tags[$vid]['#title'] = t('Enter New Tags');
unset($form['taxonomy']['tags'][$vid]);
}
else{
// Remove the default form rendering except for freetagging vocabs
unset($form['taxonomy'][$vid]);
}
}
}
// Go through each enabled vocab and create Dropdown Taxonomy
foreach($valid_vocabs AS $vid => $input){
// Get root terms for vocabulary only
$terms = taxonomy_get_tree($vid, 0, -1, 1);
$form['taxonomy'][$vid] = _dtf_branch($vid, $vocabularies[$vid]);
if($tags[$vid]){
$form['taxonomy'][$vid]['tags'] = $tags[$vid];
}
// First level terms
foreach($terms AS $index => $term){
$child1 = taxonomy_get_children($term->tid, $vid);
if(count($child1)){
if($dtf[$vid]['parents']){
$term->is_parent = TRUE;
$term->parent_type = $input;
$term->parent_value = $form['#node']->taxonomy[$term->tid]->tid;
}
$form['taxonomy'][$vid][$term->tid] = _dtf_branch($vid, $term);
// Second level terms
foreach($child1 AS $c1tid => $c1term){
$child2 = taxonomy_get_children($c1term->tid, $vid);
if(count($child2)){
if($dtf[$vid]['parents']){
$c1term->is_parent = TRUE;
$c1term->parent_type = $input;
$c1term->parent_value = $form['#node']->taxonomy[$c1term->tid]->tid;
}
$form['taxonomy'][$vid][$term->tid][$c1term->tid] = _dtf_branch($vid, $c1term);
// Third level terms
foreach($child2 AS $c2tid => $c2term){
$child3 = taxonomy_get_children($c2term->tid, $vid);
if(count($child3)){
if($dtf[$vid]['parents']){
$c2term->is_parent = TRUE;
$c2term->parent_type = $input;
$c2term->parent_value = $form['#node']->taxonomy[$c2term->tid]->tid;
}
$form['taxonomy'][$vid][$term->tid][$c1term->tid][$c2term->tid] = _dtf_branch($vid, $c2term);
// Fourth level terms
foreach($child3 AS $c3tid => $c3term){
$child4 = taxonomy_get_children($c3term->tid, $vid);
if(count($child4)){
if($dtf[$vid]['parents']){
$c3term->is_parent = TRUE;
$c3term->parent_type = $input;
$c3term->parent_value = $form['#node']->taxonomy[$c3term->tid]->tid;
}
$form['taxonomy'][$vid][$term->tid][$c1term->tid][$c2term->tid][$c3term->tid] = _dtf_branch($vid, $c3term);
// Fifth level terms
foreach($child4 AS $c4tid => $c4term){
$child5 = taxonomy_get_children($c4term->tid, $vid);
if(count($child5)){
if($dtf[$vid]['parents']){
$c4term->is_parent = TRUE;
$c4term->parent_type = $input;
$c4term->parent_value = $form['#node']->taxonomy[$c4term->tid]->tid;
}
$form['taxonomy'][$vid][$term->tid][$c1term->tid][$c2term->tid][$c3term->tid][$c4term->tid] = _dtf_branch($vid, $c4term);
}
else{
if($c4value = $form['#node']->taxonomy[$c4term->tid]->tid){
$form['taxonomy'][$vid]['#collapsed'] = FALSE;
$form['taxonomy'][$vid][$term->tid]['#collapsed'] = FALSE;
$form['taxonomy'][$vid][$term->tid][$c1term->tid][$c2term->tid][$c3term->tid]['#collapsed'] = FALSE;
}
$form['taxonomy'][$vid][$term->tid][$c1term->tid][$c2term->tid][$c3term->tid][$c4term->tid] = _dtf_branch($vid, $c4term, $c4value, $input);
}
}
}
else{
if($c3value = $form['#node']->taxonomy[$c3term->tid]->tid){
$form['taxonomy'][$vid]['#collapsed'] = FALSE;
$form['taxonomy'][$vid][$term->tid]['#collapsed'] = FALSE;
$form['taxonomy'][$vid][$term->tid][$c1term->tid][$c2term->tid]['#collapsed'] = FALSE;
}
$form['taxonomy'][$vid][$term->tid][$c1term->tid][$c2term->tid][$c3term->tid] = _dtf_branch($vid, $c3term, $c3value, $input);
}
}
}
else{
if($c2value = $form['#node']->taxonomy[$c2term->tid]->tid){
$form['taxonomy'][$vid]['#collapsed'] = FALSE;
$form['taxonomy'][$vid][$term->tid]['#collapsed'] = FALSE;
$form['taxonomy'][$vid][$term->tid][$c1term->tid]['#collapsed'] = FALSE;
}
$form['taxonomy'][$vid][$term->tid][$c1term->tid][$c2term->tid] = _dtf_branch($vid, $c2term, $c2value, $input);
}
}
}
else{
if($c1value = $form['#node']->taxonomy[$c1term->tid]->tid){
$form['taxonomy'][$vid]['#collapsed'] = FALSE;
$form['taxonomy'][$vid][$term->tid]['#collapsed'] = FALSE;
}
$form['taxonomy'][$vid][$term->tid][$c1term->tid] = _dtf_branch($vid, $c1term, $c1value, $input);
}
}
}
else{
if($value = $form['#node']->taxonomy[$term->tid]->tid){
$form['taxonomy'][$vid]['#collapsed'] = FALSE;
}
$form['taxonomy'][$vid][$term->tid] = _dtf_branch($vid, $term, $value, $input);
}
}
}
}
}
function _dtf_branch($vid, $term, $value = NULL, $type = 'fieldset'){
$required = $term->required ? ' <span class="form-required" title="'.t('This field is required.').'">*</span>' : '';
switch($type){
case 'fieldset':
// Automatically expand required vocabs or if the parent term is selected
$collapsed = ($required OR $term->parent_value) ? FALSE : TRUE;
$form = array(
'#type' => 'fieldset',
'#title' => t($term->name).$required,
'#collapsible' => TRUE,
'#collapsed' => $collapsed,
'#weight' => $term->weight,
'#parents' => array('taxonomy', $vid),
'#description' => t($term->description),
);
// If we have vocabulary that is single select and not required or is freetagging we need a way to unselect the term
if((!$required OR $term->tags) AND $term->multiple == 0 AND $term->module == 'taxonomy'){
$form['none'] = array(
'#type' => 'radio',
'#title' => '<em>'.t('Select None').'</em>',
'#return_value' => 0,
'#default_value' => '',
'#weight' => -12,
'#parents' => array('taxonomy', $term->vid),
);
}
if($term->is_parent){
$term->weight = -11;
$form['parent'] = _dtf_branch($term->vid, $term, $term->parent_value, $term->parent_type);
}
break;
case 'radio':
$form = array(
'#type' => 'radio',
'#title' => ($term->is_parent ? '<strong>' : '').t($term->name).($term->is_parent ? '</strong>' : ''),
'#return_value' => $term->tid,
'#default_value' => $value,
'#weight' => $term->weight,
'#parents' => array('taxonomy', $vid),
);
break;
case 'checkbox':
$form = array(
'#type' => 'checkbox',
'#title' => ($term->is_parent ? '<strong>' : '').t($term->name).($term->is_parent ? '</strong>' : ''),
'#return_value' => $term->tid,
'#default_value' => $value,
'#weight' => $term->weight,
);
break;
}
return $form;
}
function dropdown_taxonomy_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL){
if($op == 'validate'){
// Content type agnostic so far, look for any node that has a vocabulary we handle
if(count($node->taxonomy)){
foreach($node->taxonomy AS $vid => $terms){
// Only check vocabularies present
if(is_numeric($vid)){
$dtf = variable_get('dropdown_taxonomy_vid_'.$vid, FALSE);
// Validation required
if($dtf['types'][$node->type]){
$vocabulary = taxonomy_get_vocabulary($vid);
$single = TRUE;
$has_term = FALSE;
// Check for freetagging items in the form
if($vocabulary->tags){
if($node->taxonomy['tags'][$vid] != ''){
$free = explode(', ', $node->taxonomy['tags'][$vid]);
$has_term = TRUE;
}
}
else{
$free = FALSE;
}
if($vocabulary->required){
// Checkboxes
if($vocabulary->multiple){
// Loop through all the terms as unchecked checkboxes return zero which fools the FAPI required code
foreach($terms AS $tid => $value){
// Check the freetagging form item for duplicate selected terms
if($vocabulary->tags AND $free){
if($value){
$this_term = taxonomy_get_term($value);
$found = array_search($this_term->name, $free);
if($found !== FALSE){
$duplicates[$vid] .= '"'.t($this_term->name).'" ';
}
}
}
// Regular flat list of terms
if($value > 0){
$has_term = TRUE;
}
}
}
else{
// Radio box that is single select and required
if($free AND $terms){
$single = FALSE;
}
elseif($terms){
$has_term = TRUE;
}
}
}
// Not required phase
else{
// Radio Select
if($vocabulary->multiple == 0){
if($free AND $terms){
$single = FALSE;
}
elseif($free XOR $terms){
$has_term = TRUE;
}
}
// Checkboxes
else{
if(is_array($terms)){
// Freetagging terms are present
if(count($free)){
foreach($terms AS $tid => $value){
// Terms set in vocab
if($value > 0){
$single = FALSE;
}
}
}
}
}
}
// Catch freetagging vocabs that are single select with a radio checked as well as a new tag
if(!$single AND !$vocabulary->multiple){
form_set_error('taxonomy][tags]['.$vid, t('Only one selection allowed for %vocab', array('%vocab' => $vocabulary->name)));
}
// Catch required vocabs with no terms or freetagging entries
if(!$has_term AND $vocabulary->required){
form_set_error('taxonomy]['.$vid, t('%vocab is required.', array('%vocab' => $vocabulary->name)));
}
// Catch freetagging terms that are duplicated in the vocab already
if($duplicates){
// Display duplicate terms for each vocabulary that is freetagging
foreach($duplicates AS $vid => $terms){
// Warn user that they have entered terms that already exist into the free tag field
form_set_error('taxonomy][tags]['.$vid, t('Tag(s) %dupes already exists in the vocabulary.', array('%dupes' => $terms)));
}
}
}
}
}
}
}
}
function dropdown_taxonomy_submit($form_id, $form_values){
if($vid = $form_values['vid'] AND $form_id == 'taxonomy_form_vocabulary'){
if(count($form_values['dtf']['dropdown_taxonomy_vid_'.$vid])){
variable_set('dropdown_taxonomy_vid_'.$form_values['vid'], $form_values['dtf']['dropdown_taxonomy_vid_'.$vid]);
}
else{
variable_del('dropdown_taxonomy_vid_'.$form_values['vid']);
}
}
}
I have the following code given below...however as u can see..to be able to do multiple levels...i need a dynamic multi dimensional array in place of my own levels..which go maximum to 5...
if someone is good enough with php to do this..would be excellent
Pls check the code..and give me a solution. thanks
<?php
// ; $Id: dropdown_taxonomy.module,v 1.1 2007/07/03 04:45:42 ksm Exp $
function dropdown_taxonomy_form_alter($form_id, &$form) {
// Taxonomy Edit Form
if($form_id == 'taxonomy_form_vocabulary'){
$vid = $form['#parameters'][1]['vid'];
$vocab = taxonomy_get_vocabulary($vid);
if($vocab){
$dtf = variable_get('dropdown_taxonomy_vid_'.$vid, 0);
// Position the name field higher
$form['name']['#weight'] = -2;
// Add our own submit handler
$form['#submit']['dropdown_taxonomy_submit'] = array();
// Create fieldset and form elements
$form['dtf'] = array(
'#type' => 'fieldset',
'#title' => t('Dropdown Taxonomy'),
'#value' => $info,
'#collapsible' => TRUE,
'#collapsed' => $dtf ? FALSE : TRUE,
'#tree' => TRUE,
'#weight' => 0,
);
// Get list of all content types
$types = node_get_types('names');
// Loop through all types that are enabled for this vocab
foreach($vocab->nodes AS $index => $type){
$options[$type] = $types[$type];
}
$form['dtf']['dropdown_taxonomy_vid_'.$vid]['types'] = array(
'#type' => 'checkboxes',
'#title' => t('Enable Taxonomy Select for the Vocabulary Content Types Below'),
'#options' => $options,
'#default_value' => $dtf['types'],
'#weight' => -1,
);
$form['dtf']['dropdown_taxonomy_vid_'.$vid]['parents'] = array(
'#type' => 'checkbox',
'#title' => t('Display parent terms as form items'),
'#default_value' => $dtf['parents'],
'#return_value' => 1,
'#weight' => 0,
'#description' => t('Leaving this disabled forces users to select dangling child terms. Useful for grouping terms with descriptive parent terms that are not themselves needed for display.'),
);
}
}
// Node Edit Form
if(strstr($form_id,'_node_form') AND strstr($form['form_id']['#value'], '_node_form')){
$content_type = $form['type']['#value'];
// Get all vocabs for this content type
$vocabularies = taxonomy_get_vocabularies($content_type);
$valid_vocabs = array();
foreach($vocabularies AS $vid => $vocabulary){
$dtf[$vid] = variable_get('dropdown_taxonomy_vid_'.$vid, 0);
// Only operate on types for a vocabulary that are enabled
if($dtf[$vid]['types'][$content_type]){
// Show radio or checkbox based on the selection type
$valid_vocabs[$vid] = $vocabulary->multiple ? 'checkbox' : 'radio';
if($vocabulary->tags){
// Remove any tags from the autocomplete form item (prevent duplicates)
$tags[$vid] = $form['taxonomy']['tags'][$vid];
$tags[$vid]['#default_value'] = '';
$tags[$vid]['#required'] = FALSE;
$tags[$vid]['#parents'] = array('taxonomy', 'tags', $vid);
$tags[$vid]['#weight'] = -12;
$tags[$vid]['#title'] = t('Enter New Tags');
unset($form['taxonomy']['tags'][$vid]);
}
else{
// Remove the default form rendering except for freetagging vocabs
unset($form['taxonomy'][$vid]);
}
}
}
// Go through each enabled vocab and create Dropdown Taxonomy
foreach($valid_vocabs AS $vid => $input){
// Get root terms for vocabulary only
$terms = taxonomy_get_tree($vid, 0, -1, 1);
$form['taxonomy'][$vid] = _dtf_branch($vid, $vocabularies[$vid]);
if($tags[$vid]){
$form['taxonomy'][$vid]['tags'] = $tags[$vid];
}
// First level terms
foreach($terms AS $index => $term){
$child1 = taxonomy_get_children($term->tid, $vid);
if(count($child1)){
if($dtf[$vid]['parents']){
$term->is_parent = TRUE;
$term->parent_type = $input;
$term->parent_value = $form['#node']->taxonomy[$term->tid]->tid;
}
$form['taxonomy'][$vid][$term->tid] = _dtf_branch($vid, $term);
// Second level terms
foreach($child1 AS $c1tid => $c1term){
$child2 = taxonomy_get_children($c1term->tid, $vid);
if(count($child2)){
if($dtf[$vid]['parents']){
$c1term->is_parent = TRUE;
$c1term->parent_type = $input;
$c1term->parent_value = $form['#node']->taxonomy[$c1term->tid]->tid;
}
$form['taxonomy'][$vid][$term->tid][$c1term->tid] = _dtf_branch($vid, $c1term);
// Third level terms
foreach($child2 AS $c2tid => $c2term){
$child3 = taxonomy_get_children($c2term->tid, $vid);
if(count($child3)){
if($dtf[$vid]['parents']){
$c2term->is_parent = TRUE;
$c2term->parent_type = $input;
$c2term->parent_value = $form['#node']->taxonomy[$c2term->tid]->tid;
}
$form['taxonomy'][$vid][$term->tid][$c1term->tid][$c2term->tid] = _dtf_branch($vid, $c2term);
// Fourth level terms
foreach($child3 AS $c3tid => $c3term){
$child4 = taxonomy_get_children($c3term->tid, $vid);
if(count($child4)){
if($dtf[$vid]['parents']){
$c3term->is_parent = TRUE;
$c3term->parent_type = $input;
$c3term->parent_value = $form['#node']->taxonomy[$c3term->tid]->tid;
}
$form['taxonomy'][$vid][$term->tid][$c1term->tid][$c2term->tid][$c3term->tid] = _dtf_branch($vid, $c3term);
// Fifth level terms
foreach($child4 AS $c4tid => $c4term){
$child5 = taxonomy_get_children($c4term->tid, $vid);
if(count($child5)){
if($dtf[$vid]['parents']){
$c4term->is_parent = TRUE;
$c4term->parent_type = $input;
$c4term->parent_value = $form['#node']->taxonomy[$c4term->tid]->tid;
}
$form['taxonomy'][$vid][$term->tid][$c1term->tid][$c2term->tid][$c3term->tid][$c4term->tid] = _dtf_branch($vid, $c4term);
}
else{
if($c4value = $form['#node']->taxonomy[$c4term->tid]->tid){
$form['taxonomy'][$vid]['#collapsed'] = FALSE;
$form['taxonomy'][$vid][$term->tid]['#collapsed'] = FALSE;
$form['taxonomy'][$vid][$term->tid][$c1term->tid][$c2term->tid][$c3term->tid]['#collapsed'] = FALSE;
}
$form['taxonomy'][$vid][$term->tid][$c1term->tid][$c2term->tid][$c3term->tid][$c4term->tid] = _dtf_branch($vid, $c4term, $c4value, $input);
}
}
}
else{
if($c3value = $form['#node']->taxonomy[$c3term->tid]->tid){
$form['taxonomy'][$vid]['#collapsed'] = FALSE;
$form['taxonomy'][$vid][$term->tid]['#collapsed'] = FALSE;
$form['taxonomy'][$vid][$term->tid][$c1term->tid][$c2term->tid]['#collapsed'] = FALSE;
}
$form['taxonomy'][$vid][$term->tid][$c1term->tid][$c2term->tid][$c3term->tid] = _dtf_branch($vid, $c3term, $c3value, $input);
}
}
}
else{
if($c2value = $form['#node']->taxonomy[$c2term->tid]->tid){
$form['taxonomy'][$vid]['#collapsed'] = FALSE;
$form['taxonomy'][$vid][$term->tid]['#collapsed'] = FALSE;
$form['taxonomy'][$vid][$term->tid][$c1term->tid]['#collapsed'] = FALSE;
}
$form['taxonomy'][$vid][$term->tid][$c1term->tid][$c2term->tid] = _dtf_branch($vid, $c2term, $c2value, $input);
}
}
}
else{
if($c1value = $form['#node']->taxonomy[$c1term->tid]->tid){
$form['taxonomy'][$vid]['#collapsed'] = FALSE;
$form['taxonomy'][$vid][$term->tid]['#collapsed'] = FALSE;
}
$form['taxonomy'][$vid][$term->tid][$c1term->tid] = _dtf_branch($vid, $c1term, $c1value, $input);
}
}
}
else{
if($value = $form['#node']->taxonomy[$term->tid]->tid){
$form['taxonomy'][$vid]['#collapsed'] = FALSE;
}
$form['taxonomy'][$vid][$term->tid] = _dtf_branch($vid, $term, $value, $input);
}
}
}
}
}
function _dtf_branch($vid, $term, $value = NULL, $type = 'fieldset'){
$required = $term->required ? ' <span class="form-required" title="'.t('This field is required.').'">*</span>' : '';
switch($type){
case 'fieldset':
// Automatically expand required vocabs or if the parent term is selected
$collapsed = ($required OR $term->parent_value) ? FALSE : TRUE;
$form = array(
'#type' => 'fieldset',
'#title' => t($term->name).$required,
'#collapsible' => TRUE,
'#collapsed' => $collapsed,
'#weight' => $term->weight,
'#parents' => array('taxonomy', $vid),
'#description' => t($term->description),
);
// If we have vocabulary that is single select and not required or is freetagging we need a way to unselect the term
if((!$required OR $term->tags) AND $term->multiple == 0 AND $term->module == 'taxonomy'){
$form['none'] = array(
'#type' => 'radio',
'#title' => '<em>'.t('Select None').'</em>',
'#return_value' => 0,
'#default_value' => '',
'#weight' => -12,
'#parents' => array('taxonomy', $term->vid),
);
}
if($term->is_parent){
$term->weight = -11;
$form['parent'] = _dtf_branch($term->vid, $term, $term->parent_value, $term->parent_type);
}
break;
case 'radio':
$form = array(
'#type' => 'radio',
'#title' => ($term->is_parent ? '<strong>' : '').t($term->name).($term->is_parent ? '</strong>' : ''),
'#return_value' => $term->tid,
'#default_value' => $value,
'#weight' => $term->weight,
'#parents' => array('taxonomy', $vid),
);
break;
case 'checkbox':
$form = array(
'#type' => 'checkbox',
'#title' => ($term->is_parent ? '<strong>' : '').t($term->name).($term->is_parent ? '</strong>' : ''),
'#return_value' => $term->tid,
'#default_value' => $value,
'#weight' => $term->weight,
);
break;
}
return $form;
}
function dropdown_taxonomy_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL){
if($op == 'validate'){
// Content type agnostic so far, look for any node that has a vocabulary we handle
if(count($node->taxonomy)){
foreach($node->taxonomy AS $vid => $terms){
// Only check vocabularies present
if(is_numeric($vid)){
$dtf = variable_get('dropdown_taxonomy_vid_'.$vid, FALSE);
// Validation required
if($dtf['types'][$node->type]){
$vocabulary = taxonomy_get_vocabulary($vid);
$single = TRUE;
$has_term = FALSE;
// Check for freetagging items in the form
if($vocabulary->tags){
if($node->taxonomy['tags'][$vid] != ''){
$free = explode(', ', $node->taxonomy['tags'][$vid]);
$has_term = TRUE;
}
}
else{
$free = FALSE;
}
if($vocabulary->required){
// Checkboxes
if($vocabulary->multiple){
// Loop through all the terms as unchecked checkboxes return zero which fools the FAPI required code
foreach($terms AS $tid => $value){
// Check the freetagging form item for duplicate selected terms
if($vocabulary->tags AND $free){
if($value){
$this_term = taxonomy_get_term($value);
$found = array_search($this_term->name, $free);
if($found !== FALSE){
$duplicates[$vid] .= '"'.t($this_term->name).'" ';
}
}
}
// Regular flat list of terms
if($value > 0){
$has_term = TRUE;
}
}
}
else{
// Radio box that is single select and required
if($free AND $terms){
$single = FALSE;
}
elseif($terms){
$has_term = TRUE;
}
}
}
// Not required phase
else{
// Radio Select
if($vocabulary->multiple == 0){
if($free AND $terms){
$single = FALSE;
}
elseif($free XOR $terms){
$has_term = TRUE;
}
}
// Checkboxes
else{
if(is_array($terms)){
// Freetagging terms are present
if(count($free)){
foreach($terms AS $tid => $value){
// Terms set in vocab
if($value > 0){
$single = FALSE;
}
}
}
}
}
}
// Catch freetagging vocabs that are single select with a radio checked as well as a new tag
if(!$single AND !$vocabulary->multiple){
form_set_error('taxonomy][tags]['.$vid, t('Only one selection allowed for %vocab', array('%vocab' => $vocabulary->name)));
}
// Catch required vocabs with no terms or freetagging entries
if(!$has_term AND $vocabulary->required){
form_set_error('taxonomy]['.$vid, t('%vocab is required.', array('%vocab' => $vocabulary->name)));
}
// Catch freetagging terms that are duplicated in the vocab already
if($duplicates){
// Display duplicate terms for each vocabulary that is freetagging
foreach($duplicates AS $vid => $terms){
// Warn user that they have entered terms that already exist into the free tag field
form_set_error('taxonomy][tags]['.$vid, t('Tag(s) %dupes already exists in the vocabulary.', array('%dupes' => $terms)));
}
}
}
}
}
}
}
}
function dropdown_taxonomy_submit($form_id, $form_values){
if($vid = $form_values['vid'] AND $form_id == 'taxonomy_form_vocabulary'){
if(count($form_values['dtf']['dropdown_taxonomy_vid_'.$vid])){
variable_set('dropdown_taxonomy_vid_'.$form_values['vid'], $form_values['dtf']['dropdown_taxonomy_vid_'.$vid]);
}
else{
variable_del('dropdown_taxonomy_vid_'.$form_values['vid']);
}
}
}
i love making new stuff