source: sipes/modules_contrib/content_taxonomy/content_taxonomy.module @ c43ea01

stableversion-3.0
Last change on this file since c43ea01 was 177a560, checked in by José Gregorio Puentes <jpuentes@…>, 8 años ago

se agrego el directorio de modulos contribuidos de drupal

  • Propiedad mode establecida a 100755
File size: 18.7 KB
Línea 
1<?php
2
3// $Id: content_taxonomy.module,v 1.2.2.15.2.33 2009/08/19 12:45:58 mh86 Exp $
4
5/**
6 * @file
7 * Defines a field type for referencing a taxonomy term.
8 **/
9
10/**
11 * Implementation of hook_help().
12 **/
13function content_taxonomy_help($path, $arg) {
14  switch ($path) {
15     case 'admin/help#content_taxonomy':
16       return '<p>'. t('Defines a CCK field type for referencing taxonomy terms. The fields are independent from vocabulary settings and can be configured through the CCK admin field pages. The Content Taxonomy Module provides different widget types, at the moment including Option Widgets (Radios / Checkboxes, Selects), Autocompletes, Tree). The widget modules have to be enabled separately.') .'</p>';
17  }
18}
19
20/**
21 * Implementation of hook_init().
22 */
23function content_taxonomy_init() {
24  if (module_exists('token')) {
25    module_load_include('inc', 'content_taxonomy', 'includes/content_taxonomy.token');
26  }
27}
28
29/**
30 * Implementation of hook_theme().
31 */
32function content_taxonomy_theme() {
33  return array(
34    'content_taxonomy_formatter_default' => array(
35      'arguments' => array('element' => NULL),
36    ),
37    'content_taxonomy_formatter_link' => array(
38      'arguments' => array('element' => NULL),
39    ),
40  );
41}
42
43/**
44 * Implementation of hook_field_info().
45 */
46function content_taxonomy_field_info() {
47  return array(
48    'content_taxonomy' => array(
49      'label' => t('Content Taxonomy Fields'),
50      'description' => t('Stores terms for nodes in the database.'),
51      'callbacks' => array(
52        'tables' => CONTENT_CALLBACK_DEFAULT,
53        'arguments' => CONTENT_CALLBACK_DEFAULT,
54      ),
55    ),
56  );
57}
58
59/**
60 * Implementation of hook_field_settings().
61 */
62function content_taxonomy_field_settings($op, $field) {
63  switch ($op) {
64    case 'form':
65      $form = array();
66           
67      $form['save_term_node'] = array(
68        '#type' => 'checkbox',
69        '#title' => t('Save values additionally to the core taxonomy system (into the \'term_node\' table).'),
70        '#default_value' => is_numeric($field['save_term_node']) ? $field['save_term_node'] : 0,
71        '#description' => t('If this option is set, saving of terms is additionally handled by the taxonomy module. So saved terms from Content Taxonomy fields will appear as any other terms saved by the core taxonomy module. Set this option if you are using any other taxonomy application, like tagadelic. Otherwise terms are only saved in the cck tables and can only be accessed via the node or a view'),
72      );
73     
74      $options_voc = array();
75      foreach (taxonomy_get_vocabularies() as $voc) {
76        _content_taxonomy_localize_vocabulary($voc);
77        $options_voc[$voc->vid] = $voc->name;
78      }
79     
80      $form['vid'] = array(
81        '#title' => t('Vocabulary'),
82        '#type' => 'select',
83        '#default_value' => is_numeric($field['vid']) ? $field['vid'] : 0,
84        '#options' => $options_voc,
85        '#description' => t('Terms of the selected vocabulary get exposed to the field'),
86      );
87     
88      $form['hierarchical_vocabulary'] = array(
89        '#type' => 'fieldset',
90        '#title' => t('Advanced settings for hierarchical vocabularies'),
91        '#collapsible' => TRUE,
92      );
93     
94      $form['hierarchical_vocabulary']['parent'] = array(
95        '#title' => t('Parent Term'),
96        '#type' => 'select',
97        '#default_value' => is_numeric($field['parent']) ? $field['parent'] : 0,
98        '#options' => _content_taxonomy_get_all_terms(),
99        '#description' => t('If any term is selected here, only child terms of the selected are going to be exposed the field. Otherwise the whole vocabulary selected above'),
100      );
101      $form['hierarchical_vocabulary']['parent_php_code_fieldset'] = array(
102        '#type' => 'fieldset',
103        '#title' => t('Advanced PHP code'),
104        '#collapsible' => TRUE,
105        '#collapsed' => empty($field['parent_php_code']) ,
106      );
107      $form['hierarchical_vocabulary']['parent_php_code_fieldset']['parent_php_code'] = array(
108        '#title' => t('PHP Code for selecting the parent term'),
109        '#type' => 'textarea',
110        '#default_value' => !empty($field['parent_php_code']) ? $field['parent_php_code'] : '',
111        '#rows' => 3,
112        '#description' => t('Advanced usage only: PHP code that returns the parent term ID. Should not include &lt;?php ?&gt; delimiters. If this field is filled out, the ID returned by this code will override the selected parent above.'),
113      );
114
115      $form['hierarchical_vocabulary']['depth'] = array(
116        '#type' => 'textfield',
117        '#title' => t('Depth of taxonomy tree'),
118        '#default_value' => is_numeric($field['depth']) ? $field['depth'] : '',
119        '#description' => t('By setting a numeric value, the depth of the hierarchy shown can be limited. Leave this field blank to show the whole hierarchy.'),
120      );
121     
122     
123      return $form;   
124   
125    case 'save':
126      return array('save_term_node', 'vid', 'parent', 'parent_php_code', 'depth');
127   
128    case 'database columns':
129      return array(
130        'value' => array('type' => 'int', 'not null' => FALSE, 'sortable' => FALSE),
131      );
132   
133    case 'views data':
134      $data = content_views_field_views_data($field);
135      $table_alias = content_views_tablename($field);
136     
137      // Add a relation to the taxonomy term table.
138      $data[$table_alias][$field['field_name'] .'_value']['relationship'] = array(
139        'handler' => 'views_handler_relationship',
140        'base' => 'term_data',
141        'field' => 'tid',
142        'label' => t('@field-title term', array('@field-title' => check_plain(t($field['widget']['label'])))),
143      );
144
145      // Swap the filter handler to the 'in' operator.
146      $data[$table_alias][$field['field_name'] .'_value']['filter']['handler'] = 'content_taxonomy_handler_filter_many_to_one';
147      return $data;
148  }
149}
150
151/**
152 * Implementation of hook_field().
153 */
154function content_taxonomy_field($op, &$node, $field, &$items, $teaser, $page) {
155  switch ($op) {         
156    case 'presave':
157      if ($field['save_term_node']) {
158        static $_content_taxonomy_array_cleared;
159        if (!is_array($_content_taxonomy_array_cleared) || !$_content_taxonomy_array_cleared[$node->nid][$field['vid']]) {
160          _content_taxonomy_taxonomy_unset($node->taxonomy, array($field['vid']));
161          $_content_taxonomy_array_cleared[$node->nid][$field['vid']] = TRUE;
162        }
163       
164        foreach ($items as $key => $entry) {
165          if ($entry['value']) {
166            if (is_object($node->taxonomy[$entry['value']])
167              || (is_array($node->taxonomy) && in_array($entry['value'], $node->taxonomy))
168              || (isset($entry['_remove']) && $entry['_remove'] == 1)) {
169              continue;
170            }
171            elseif (is_array($node->taxonomy[$field['vid']])) {
172              if (!in_array($entry['value'], $node->taxonomy[$field['vid']])) {
173                $node->taxonomy[$field['vid']][] = $entry['value'];
174              }
175            }
176            // when saving an existing node without presenting a form to the user,
177            // the terms are objects keyed by tid. there's no need to re-set these
178            // terms, and to do so causes php warnings because the database rejects
179            // the row insert because of primary key constraints.
180            else {
181              $node->taxonomy[$field['vid']] = array($entry['value']);
182            }
183          }
184        }
185        // the $node->taxonomy array should never be empty, because in this case the
186        // taxonomy nodeapi doesn't call taxonomy_node_save which handles removing
187        // and inserting of terms
188        if (empty($node->taxonomy)) {
189          $node->taxonomy[$field['vid']] = NULL;
190        }
191      }
192      break;
193  }
194}
195
196
197/**
198 * Implementation of hook_field_formatter_info().
199 */
200function content_taxonomy_field_formatter_info() {
201  return array(
202    'default' => array(
203      'label' => t('As Text'),
204      'field types' => array('content_taxonomy'),
205      'multiple values' => CONTENT_HANDLE_CORE,
206    ),
207    'link' => array(
208      'label' => t('As Link'),
209      'field types' => array('content_taxonomy'),
210      'multiple values' => CONTENT_HANDLE_CORE,
211    ),
212  );
213}
214
215
216/**
217 * Theme function for 'default' text field formatter.
218 */
219function theme_content_taxonomy_formatter_default($element) {
220  if (!empty($element['#item']['value'])) {
221    $term = taxonomy_get_term($element['#item']['value']);
222    _content_taxonomy_localize_term($term);
223    return check_plain($term->name);
224  }
225}
226
227
228/**
229 * Theme function for 'link' text field formatter.
230 */
231function theme_content_taxonomy_formatter_link($element) {
232  if (!empty($element['#item']['value'])) {
233    $term = taxonomy_get_term($element['#item']['value']);
234    _content_taxonomy_localize_term($term);
235    return l($term->name, taxonomy_term_path($term), array('attributes' => array('rel' => 'tag', 'title' => $term->description)));
236  }
237}
238
239/**
240 * Implementation of hook_content_is_empty().
241 */
242function content_taxonomy_content_is_empty($item, $field) {
243  if (empty($item['value']) || $item['value'] == 0) {
244    return TRUE;
245  }
246  return FALSE;
247}
248
249/**
250 * Called by content_allowed_values to create the $options array for the content_taxonomy_options
251 */
252function content_taxonomy_allowed_values($field) {
253  $options = array();
254 
255  //for opt groups call different function
256  if (isset($field['widget']['group_parent']) && $field['widget']['group_parent'] > 0) {
257    return content_taxonomy_allowed_values_groups($field);
258  }
259 
260  $depth = (is_numeric($field['depth'])) ? $field['depth'] : NULL;
261
262  $tree = taxonomy_get_tree($field['vid'], content_taxonomy_field_get_parent($field), -1, $depth);
263 
264  if (is_array($tree)) {
265    foreach ($tree as $term) {
266      _content_taxonomy_localize_term($term);
267      if ($field['widget']['show_depth']) {
268        $value = str_repeat(' - ', $term->depth) . $term->name;
269      }
270      else {
271        $value = $term->name;
272      }
273      //do a check_plain except for selects because form api does that
274      $options[$term->tid] = ($field['widget']['type'] == 'content_taxonomy_select') ? $value : check_plain($value);
275    }
276  }
277  if (($field['widget']['type'] == 'content_taxonomy_select' && !$field['multiple']) || ($field['widget']['type'] == 'content_taxonomy_options' && !$field['multiple'] && !$field['required'])) {
278    $options = array('' => theme('content_taxonomy_options_widgets_none', $field)) + $options;
279  }
280  return $options;
281}
282
283/**
284 * Creating Opt Groups for content_taxonomy_options
285 */
286function content_taxonomy_allowed_values_groups($field) {
287  $options = array();
288  $parent = content_taxonomy_field_get_parent($field);
289  $group_parent = $field['widget']['group_parent'];
290 
291  //if children in no group
292  $default_terms = taxonomy_get_children($parent, $field['vid']);
293  foreach ($default_terms as $default_term) {
294    _content_taxonomy_localize_term($default_term);
295    $options[$default_term->tid] = check_plain($default_term->name);
296  }
297  foreach (taxonomy_get_children($group_parent) as $group) {
298    foreach (taxonomy_get_children($group->tid) as $term) {
299      _content_taxonomy_localize_term($term);
300      $options[$group->name][$term->tid] = check_plain($term->name);
301      unset($options[$term->tid]);
302    }
303    unset($options[$group->tid]);
304  }
305  return $options;
306}
307
308/**
309 * Returns the parent term ID for one field
310 * can be 0 is no parent is selected or if the php code returns 0
311 *
312 * use this function instead of directly accessing $field['parent'] because of possible php code
313 *
314 * @param $field The Content Taxonomy Field
315 */
316function content_taxonomy_field_get_parent($field) {
317  if (!empty($field['parent_php_code'])) {
318    return eval($field['parent_php_code']);
319  }
320  return $field['parent'];
321}
322
323
324/**
325 * Implementation of hook_form_alter().
326 *
327 * hides the taxonomy form if there exists a content taxonomy field, which is set to 'hide default taxonomy fields'
328 */
329function content_taxonomy_form_alter(&$form, $form_state, $form_id) {
330  if (isset($form['type']['#value']) && $form['type']['#value'] .'_node_form' == $form_id && isset($form['taxonomy'])) {
331    if (!is_array($form['taxonomy'])) {
332      // empty taxonomy arrays can cause errors on preview
333      if ($form_state['post']['op'] == t('Preview')) {
334        $form['taxonomy'] = array('#tree' => TRUE);
335        $form['taxonomy']['key'] = array('#type' => 'value', '#value' => '');
336        return;
337      }
338    }
339    $_content_taxonomy_vids = array();
340    $info = _content_type_info();
341    $content_type = $info['content types'][$form['type']['#value']];
342    foreach ($content_type['fields'] as $field) {
343      if ($field['type'] == 'content_taxonomy' && (!in_array($field['vid'], $_content_taxonomy_vids))) {
344        $_content_taxonomy_vids[] = $field['vid'];
345      }
346    }
347    _content_taxonomy_taxonomy_unset($form['taxonomy'], $_content_taxonomy_vids);
348   
349    //hide empty 'Vocabularies' fieldsets
350    $empty_fieldset = TRUE;
351    if (is_array($form['taxonomy'])) {
352      foreach ($form['taxonomy'] as $key => $value) {
353        if (is_array($value) && !empty($value)) {
354          $empty_fieldset = FALSE;
355          break;
356        }
357      }
358    }
359    if ($empty_fieldset) {
360      // creating an empty taxonomy array is causing errors on preview in the taxonomy module
361      // so we create an empty value field as placeholder, which is going to prevent the errors
362      $form['taxonomy'] = array('#tree' => TRUE);
363      $form['taxonomy']['key'] = array('#type' => 'value', '#value' => '');
364    }
365  }
366}
367
368/**
369 * Implementation of hook_taxonomy().
370 */
371function content_taxonomy_taxonomy($op, $type, $array = NULL) {
372  //keep the database consistent when either a voc or a term is deleted
373  //in case of voc: delete all associated fields and its data
374  //in case of term: delete all its entries
375  if ($op == 'delete') {
376    $vid = $array['vid'];
377    $needs_refresh = FALSE;
378    foreach (content_taxonomy_fields() as $type_name => $ct_type) {
379      foreach ($ct_type['fields'] as $field_name => $field) {
380        if ($field['vid'] == $vid) {
381          if ($type == 'vocabulary') {
382            module_load_include('inc', 'content', 'includes/content.crud');
383            content_field_instance_delete($field_name, $field['type_name']);
384            $needs_refresh = TRUE;
385            watchdog('content', 'Deleted field %field_name and its data.', array('%field_name' => $field_name));
386          }
387          else {
388            $tid = $array['tid'];
389            if ($tid) {
390              $db_info = content_database_info($field);
391              if ($field['multiple']) {
392                db_query('DELETE FROM {'. $db_info['table'] .'} WHERE '. $db_info['columns']['value']['column'] .' = %d', $tid);
393              }
394              else {
395                db_query('UPDATE {'. $db_info['table'] .'} SET '. $db_info['columns']['value']['column'] .'= NULL  WHERE '. $db_info['columns']['value']['column'] .' = %d', $tid);
396              }
397              $needs_refresh = TRUE;
398              watchdog('content', 'Entries with term id = %tid have been deleted out of %table for field %field_name.', array('%tid' => $tid, '%table' => $db_info['table'], '%field_name' => $field_name));
399            }
400          }
401        }
402      }
403    }
404    if ($needs_refresh) {
405      content_clear_type_cache(TRUE);
406    }
407  }
408}
409
410/**
411 * Implementation of hook_views_api().
412 */
413function content_taxonomy_views_api() {
414  return array(
415    'api' => 2,
416    'path' => drupal_get_path('module', 'content_taxonomy') . '/includes/views',
417  );
418}
419
420
421/**
422 * Helper function that returns all content taxonomy fields, nested in their content types
423 */
424function content_taxonomy_fields() {
425  static $ct_fields;
426 
427  if (!is_array($ct_fields)) {
428    $ct_fields = array();
429    foreach (content_types() as $type_name => $type) {
430      foreach ($type['fields'] as $field_name => $field) {
431        if ($field['type'] == 'content_taxonomy') {
432          $ct_fields[$type_name]['fields'][$field_name] = $field;
433        }
434      }
435    }
436  }
437  return $ct_fields;
438}
439
440
441/**
442 * Helper functions that returns all terms group by their vocabulary
443 *
444 * needed for some settings forms
445 */
446function _content_taxonomy_get_all_terms() {
447  static $options = array();
448  if (!count($options)) {
449    $options[0] = '---';
450    foreach (taxonomy_get_vocabularies() as $voc) {
451      foreach (taxonomy_get_tree($voc->vid) as $term) {
452        _content_taxonomy_localize_term($term);
453        $options[$voc->name][$term->tid] = str_repeat('- ', $term->depth) . $term->name;
454      }
455    }
456  }
457  return $options;
458}
459
460/**
461 * Localize a term by replacing its name attribute with its localized version
462 * for the current language.
463 *
464 * @param $term
465 *   The term to localize.
466 *
467 * This is based on i18ntaxonomy_localize_terms(), but with less overhead.
468 */
469function _content_taxonomy_localize_term(&$term) {
470  // If this term's vocabulary supports localization.
471  if (module_exists('i18ntaxonomy') && i18ntaxonomy_vocabulary($term->vid) == I18N_TAXONOMY_LOCALIZE) {
472    $term->name = tt("taxonomy:term:$term->tid:name", $term->name);
473  }
474}
475
476/**
477 * Localize a vocabulary by replacing its name attribute with its localized
478 * version for the current language.
479 *
480 * @param $vocabulary
481 *   The vocabulary to localize.
482 */
483function _content_taxonomy_localize_vocabulary(&$vocabulary) {
484  // If this vocabulary supports localization.
485  if (module_exists('i18ntaxonomy') && i18ntaxonomy_vocabulary($vocabulary->vid) == I18N_TAXONOMY_LOCALIZE) {
486    $vocabulary->name = tt("taxonomy:vocabulary:$vocabulary->vid:name", $vocabulary->name);
487  }
488}
489
490/**
491 * carefully unsets node or node form taxonomy items
492 *
493 *
494 * @param $form the node or node form's taxonomy selections. nodes are objects and forms are arrays, so only the actual taxonomy value or property is passed
495 * @param $vids an array containing a list of vocabulary IDs whose terms should be unset
496 */
497function _content_taxonomy_taxonomy_unset(&$form, $vids) {
498  if (empty($vids) || !is_array($form)) {
499    return;
500  }
501  foreach ($form as $key => $value) {
502    if ($key == 'tags') {
503      _content_taxonomy_taxonomy_unset($form[$key], $vids);
504    }
505    elseif (is_object($value) && in_array($value->vid, $vids)) {
506      unset($form[$key]);
507    }
508    elseif (in_array($key, $vids)) {
509      unset($form[$key]);
510    }
511  }
512}
513
514/**
515 * Implementation of hook_content_multigroup_allowed_widgets().
516 */
517function content_taxonomy_content_multigroup_allowed_widgets() {
518  return array('content_taxonomy_autocomplete', 'content_taxonomy_options', 'content_taxonomy_select');
519}
520
521/**
522 * Implementation of hook_content_multigroup_no_remove_widgets().
523 */
524function content_taxonomy_content_multigroup_no_remove_widgets() {
525  return array('content_taxonomy_autocomplete', 'content_taxonomy_options', 'content_taxonomy_select');
526}
527
528/**
529 * Implementation of hook_content_diff_values
530 */
531function content_taxonomy_content_diff_values($node, $field, $items) {
532  $return = array();
533  foreach ($items as $item) {
534    if (isset($item['value']) && is_numeric($item['value'])) {
535      $term = taxonomy_get_term($item['value']);
536      $return[] = $term->name;
537    }
538  }
539  return $return;
540}
Nota: Vea TracBrowser para ayuda de uso del navegador del repositorio.