|
@@ -5,11 +5,6 @@
|
|
|
* Provide synonyms feature for Drupal Taxonomy.
|
|
|
*/
|
|
|
|
|
|
-/**
|
|
|
- * The default field name to be used as a source of synonyms for a term.
|
|
|
- */
|
|
|
-define('SYNONYMS_DEFAULT_FIELD_NAME', 'synonyms_synonyms');
|
|
|
-
|
|
|
/**
|
|
|
* Implements hook_menu().
|
|
|
*/
|
|
@@ -29,33 +24,58 @@ function synonyms_menu() {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Implements hook_taxonomy_term_update().
|
|
|
+ * Implements hook_ctools_plugin_type().
|
|
|
*/
|
|
|
-function synonyms_taxonomy_term_update($term) {
|
|
|
- // If we notice at least some change in synonyms of this term, we want to
|
|
|
- // trigger search re-indexing of nodes, where this term is referenced, since
|
|
|
- // change in term synonyms affects nodes ranking in the search.
|
|
|
- if (isset($term->original)) {
|
|
|
- $current_synonyms = synonyms_get_raw($term);
|
|
|
- $previous_synonyms = synonyms_get_raw($term->original);
|
|
|
- if (count($current_synonyms) != count($previous_synonyms)) {
|
|
|
- // Schedule re-indexing, because amount of synonyms has changed.
|
|
|
- module_load_include('inc', 'synonyms', 'synonyms.pages');
|
|
|
- synonyms_reindex_nodes_by_terms(array($term->tid));
|
|
|
- }
|
|
|
- else {
|
|
|
- foreach ($current_synonyms as $k => $current_synonym) {
|
|
|
- if ($current_synonyms[$k] != $previous_synonyms[$k]) {
|
|
|
- // Schedule re-indexing, because some synonym has changed.
|
|
|
- module_load_include('inc', 'synonyms', 'synonyms.pages');
|
|
|
- synonyms_reindex_nodes_by_terms(array($term->tid));
|
|
|
- break;
|
|
|
- }
|
|
|
+function synonyms_ctools_plugin_type() {
|
|
|
+ $plugins = array();
|
|
|
+
|
|
|
+ $plugins['behavior'] = array(
|
|
|
+ 'defaults' => array(
|
|
|
+ 'title' => NULL,
|
|
|
+ 'description' => NULL,
|
|
|
+ 'settings form callback' => NULL,
|
|
|
+ 'interface' => NULL,
|
|
|
+ 'enabled callback' => NULL,
|
|
|
+ 'disabled callback' => NULL,
|
|
|
+ ),
|
|
|
+ );
|
|
|
+
|
|
|
+ return $plugins;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Implements hook_ctools_plugin_directory().
|
|
|
+ */
|
|
|
+function synonyms_ctools_plugin_directory($owner, $plugin_type) {
|
|
|
+ switch ($owner) {
|
|
|
+ case 'synonyms':
|
|
|
+ switch ($plugin_type) {
|
|
|
+ case 'behavior':
|
|
|
+ return 'plugins/' . $plugin_type;
|
|
|
}
|
|
|
- }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'ctools':
|
|
|
+ switch ($plugin_type) {
|
|
|
+ case 'arguments':
|
|
|
+ return 'plugins/' . $plugin_type;
|
|
|
+ }
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * Implements hook_theme().
|
|
|
+ */
|
|
|
+function synonyms_theme() {
|
|
|
+ return array(
|
|
|
+ 'synonyms_behaviors_settings' => array(
|
|
|
+ 'render element' => 'element',
|
|
|
+ 'file' => 'synonyms.pages.inc',
|
|
|
+ ),
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* Implements hook_entity_property_info().
|
|
|
*/
|
|
@@ -75,105 +95,38 @@ function synonyms_entity_property_info() {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Implements hook_node_update_index().
|
|
|
+ * Implements hook_field_delete_instance().
|
|
|
*/
|
|
|
-function synonyms_node_update_index($node) {
|
|
|
- $output = '';
|
|
|
- foreach (field_info_instances('node', $node->type) as $instance) {
|
|
|
- // We go a field by field looking for taxonomy term reference and
|
|
|
- // if that vocabulary has enabled synonyms, we add term's synonyms
|
|
|
- // to the search index.
|
|
|
- $field_info = field_info_field($instance['field_name']);
|
|
|
- if ($field_info['type'] == 'taxonomy_term_reference') {
|
|
|
- // For each term referenced in this node we have to add synonyms.
|
|
|
- $_terms = field_get_items('node', $node, $instance['field_name']);
|
|
|
- if (is_array($_terms) && !empty($_terms)) {
|
|
|
- $terms = array();
|
|
|
- foreach ($_terms as $v) {
|
|
|
- $terms[] = $v['tid'];
|
|
|
- }
|
|
|
- $terms = taxonomy_term_load_multiple($terms);
|
|
|
- foreach ($terms as $term) {
|
|
|
- $synonyms = synonyms_get_sanitized($term);
|
|
|
- if (!empty($synonyms)) {
|
|
|
- $output .= '<strong>' . implode(', ', $synonyms) . '</strong>';
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+function synonyms_field_delete_instance($instance) {
|
|
|
+ // Remove, if necessary, any synonyms behaviors enabled on this instance.
|
|
|
+ $result = db_select('synonyms_settings', 's')
|
|
|
+ ->fields('s', array('behavior'))
|
|
|
+ ->condition('s.instance_id', $instance['id'])
|
|
|
+ ->execute();
|
|
|
+ foreach ($result as $row) {
|
|
|
+ synonyms_behavior_settings_delete($instance['id'], $row->behavior);
|
|
|
}
|
|
|
- return $output;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Implements hook_synonyms_extractor_info().
|
|
|
+ * Implements hook_synonyms_behavior_implementation_info().
|
|
|
*/
|
|
|
-function synonyms_synonyms_extractor_info() {
|
|
|
- // Here we provide synonyms extractors that come along with Synonyms module.
|
|
|
- return array(
|
|
|
- 'SynonymsSynonymsExtractor',
|
|
|
- 'TaxonomySynonymsExtractor',
|
|
|
- 'EntityReferenceSynonymsExtractor',
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * Public function.
|
|
|
- *
|
|
|
- * Provide info about what class reports ability to extract synonyms from
|
|
|
- * which field type. The output information of this function is collected via
|
|
|
- * hook_synonyms_extractor_info().
|
|
|
- *
|
|
|
- * @param string $field_type
|
|
|
- * Optionally you may specify to get a class responsible for a specific field
|
|
|
- * type only. If nothing is supplied, array of field_type => class_extractor
|
|
|
- * relation is returned
|
|
|
- * @param bool $reset
|
|
|
- * Whether collect all the info again from hooks, or cached info is fine
|
|
|
- *
|
|
|
- * @return array
|
|
|
- * Key of this array denotes the field type while value of the array denotes
|
|
|
- * which class reports ability to extract synonyms from such field type.
|
|
|
- */
|
|
|
-function synonyms_extractor_info($field_type = NULL, $reset = FALSE) {
|
|
|
- $cache = &drupal_static(__FUNCTION__);
|
|
|
-
|
|
|
- // Trying static cache.
|
|
|
- if (!is_array($cache) || $reset) {
|
|
|
- // Trying Drupal DB cache layer.
|
|
|
- $cid = 'synonyms_extractor_info';
|
|
|
- $cache = cache_get($cid);
|
|
|
- if (!isset($cache->data) || $reset) {
|
|
|
- // No cache has been found at all. So we call hooks and collect data.
|
|
|
- $info = array();
|
|
|
-
|
|
|
- $extractor_classes = module_invoke_all('synonyms_extractor_info');
|
|
|
-
|
|
|
- if (is_array($extractor_classes)) {
|
|
|
- foreach ($extractor_classes as $class) {
|
|
|
- foreach (call_user_func(array($class, 'fieldTypesSupported')) as $_field_type) {
|
|
|
- $info[$_field_type] = $class;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Letting whoever wants to implement any changes after preprocessing the
|
|
|
- // data.
|
|
|
- drupal_alter('synonyms_extractor_info', $info);
|
|
|
-
|
|
|
- $cache = $info;
|
|
|
- cache_set($cid, $cache, 'cache', CACHE_TEMPORARY);
|
|
|
- }
|
|
|
- else {
|
|
|
- $cache = $cache->data;
|
|
|
- }
|
|
|
+function synonyms_synonyms_behavior_implementation_info($behavior) {
|
|
|
+ switch ($behavior) {
|
|
|
+ case 'autocomplete':
|
|
|
+ case 'select':
|
|
|
+ case 'synonyms':
|
|
|
+ return array(
|
|
|
+ 'number_integer' => 'TextSynonymsBehavior',
|
|
|
+ 'number_decimal' => 'TextSynonymsBehavior',
|
|
|
+ 'number_float' => 'TextSynonymsBehavior',
|
|
|
+ 'text' => 'TextSynonymsBehavior',
|
|
|
+ 'taxonomy_term_reference' => 'TaxonomySynonymsBehavior',
|
|
|
+ 'entityreference' => 'EntityReferenceSynonymsBehavior',
|
|
|
+ );
|
|
|
+ break;
|
|
|
}
|
|
|
-
|
|
|
- if (!is_null($field_type) && isset($cache[$field_type])) {
|
|
|
- return $cache[$field_type];
|
|
|
- }
|
|
|
-
|
|
|
- return $cache;
|
|
|
+ return array();
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -184,7 +137,9 @@ function synonyms_form_taxonomy_form_vocabulary_alter(&$form, &$form_state) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- module_load_include('inc', 'synonyms', 'synonyms.pages');
|
|
|
+ if (!isset($form['#vocabulary']->vid) || !$form['#vocabulary']->vid) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
$form['synonyms'] = array(
|
|
|
'#type' => 'fieldset',
|
|
@@ -193,30 +148,96 @@ function synonyms_form_taxonomy_form_vocabulary_alter(&$form, &$form_state) {
|
|
|
'#tree' => TRUE,
|
|
|
);
|
|
|
|
|
|
- $options = array(
|
|
|
- SYNONYMS_DEFAULT_FIELD_NAME => t('Default synonyms field'),
|
|
|
+ $behaviors = synonyms_behaviors();
|
|
|
+ $bundle = field_extract_bundle('taxonomy_term', $form['#vocabulary']);
|
|
|
+
|
|
|
+ $form['synonyms']['behaviors'] = array(
|
|
|
+ '#theme' => 'synonyms_behaviors_settings',
|
|
|
+ '#id' => 'synonyms-behaviors-settings-wrapper',
|
|
|
);
|
|
|
- if (isset($form['#vocabulary']->vid)) {
|
|
|
- $instances = synonyms_instances_extract_applicable($form['#vocabulary']);
|
|
|
- foreach ($instances as $instance) {
|
|
|
- // Here we prefer some informative text for the default synonyms field
|
|
|
- // rather its label.
|
|
|
- if ($instance['field_name'] != SYNONYMS_DEFAULT_FIELD_NAME) {
|
|
|
- $options[$instance['field_name']] = $instance['label'];
|
|
|
+
|
|
|
+ foreach ($behaviors as $behavior => $behavior_info) {
|
|
|
+ $form['synonyms']['behaviors'][$behavior] = array(
|
|
|
+ '#title' => $behavior_info['title'],
|
|
|
+ );
|
|
|
+
|
|
|
+ $behavior_implementations = synonyms_behavior_get($behavior, 'taxonomy_term', $bundle);
|
|
|
+
|
|
|
+ foreach ($behavior_implementations as $implementation) {
|
|
|
+ $instance = field_info_instance($implementation['entity_type'], $implementation['field_name'], $implementation['bundle']);
|
|
|
+ $form['synonyms']['behaviors'][$behavior][$implementation['instance_id']]['#title'] = $instance['label'];
|
|
|
+
|
|
|
+ if (isset($form_state['values']['synonyms']['behaviors'][$behavior][$implementation['instance_id']])) {
|
|
|
+ $behavior_settings = (bool) $form_state['values']['synonyms']['behaviors'][$behavior][$implementation['instance_id']]['enabled'];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ $behavior_settings = !is_null($implementation['settings']);
|
|
|
+ }
|
|
|
+ if ($behavior_settings) {
|
|
|
+ if (isset($form_state['values']['synonyms']['behaviors'][$behavior][$implementation['instance_id']]['settings'])) {
|
|
|
+ $behavior_settings = $form_state['values']['synonyms']['behaviors'][$behavior][$implementation['instance_id']]['settings'];
|
|
|
+ }
|
|
|
+ elseif ($implementation['settings']) {
|
|
|
+ $behavior_settings = $implementation['settings'];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ $behavior_settings = array();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $form['synonyms']['behaviors'][$behavior][$implementation['instance_id']]['enabled'] = array(
|
|
|
+ '#type' => 'checkbox',
|
|
|
+ '#title' => t('Enable'),
|
|
|
+ '#default_value' => $behavior_settings !== FALSE,
|
|
|
+ );
|
|
|
+
|
|
|
+ $settings_form = ctools_plugin_get_function($behavior_info, 'settings form callback');
|
|
|
+ if ($settings_form) {
|
|
|
+ $form['synonyms']['behaviors'][$behavior][$implementation['instance_id']]['enabled']['#ajax'] = array(
|
|
|
+ 'callback' => 'synonyms_behaviors_settings_form_ajax',
|
|
|
+ 'wrapper' => $form['synonyms']['behaviors']['#id'],
|
|
|
+ );
|
|
|
+
|
|
|
+ if ($behavior_settings !== FALSE) {
|
|
|
+ $form['synonyms']['behaviors'][$behavior][$implementation['instance_id']]['settings'] = $settings_form($form, $form_state, $behavior_settings);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ $form['#submit'][] = 'synonyms_taxonomy_form_vocabulary_submit';
|
|
|
+}
|
|
|
|
|
|
- $form['synonyms']['synonyms'] = array(
|
|
|
- '#type' => 'checkboxes',
|
|
|
- '#title' => t('Synonyms Fields'),
|
|
|
- '#options' => $options,
|
|
|
- '#description' => t('<p>This option allows you to assign synonym fields for each term of the vocabulary, allowing to reduce the amount of duplicates.</p><p><b>Important note:</b> unticking %default_field on a production website will result in loss of your synonyms.</p>', array('%default_field' => $options[SYNONYMS_DEFAULT_FIELD_NAME])),
|
|
|
- '#default_value' => synonyms_synonyms_fields($form['#vocabulary']),
|
|
|
- );
|
|
|
+/**
|
|
|
+ * Submit handler for Taxonomy vocabulary edit form.
|
|
|
+ *
|
|
|
+ * Store synonyms behavior settings.
|
|
|
+ */
|
|
|
+function synonyms_taxonomy_form_vocabulary_submit($form, &$form_state) {
|
|
|
+ $values = $form_state['values'];
|
|
|
+
|
|
|
+ if ($values['op'] == $form['actions']['submit']['#value']) {
|
|
|
+ foreach ($values['synonyms']['behaviors'] as $behavior => $settings) {
|
|
|
+ foreach ($settings as $instance_id => $behavior_settings) {
|
|
|
+ if ($behavior_settings['enabled']) {
|
|
|
+ synonyms_behavior_settings_save(array(
|
|
|
+ 'instance_id' => $instance_id,
|
|
|
+ 'behavior' => $behavior,
|
|
|
+ 'settings' => isset($behavior_settings['settings']) ? $behavior_settings['settings'] : NULL,
|
|
|
+ ));
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ synonyms_behavior_settings_delete($instance_id, $behavior);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- // Adding our own submit handler.
|
|
|
- $form['#submit'][] = 'synonyms_taxonomy_form_vocabulary_submit';
|
|
|
+/**
|
|
|
+ * Ajax callback function for synonyms behavior settings form.
|
|
|
+ */
|
|
|
+function synonyms_behaviors_settings_form_ajax($form, &$form_state) {
|
|
|
+ return $form['synonyms']['behaviors'];
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -229,7 +250,7 @@ function synonyms_field_widget_info() {
|
|
|
'field types' => array('taxonomy_term_reference'),
|
|
|
'settings' => array(
|
|
|
'size' => 60,
|
|
|
- 'autocomplete_path' => 'synonyms/autocomplete',
|
|
|
+ 'synonyms_autocomplete_path' => 'synonyms/autocomplete',
|
|
|
'suggestion_size' => 10,
|
|
|
'suggest_only_unique' => FALSE,
|
|
|
'auto_creation' => 1,
|
|
@@ -238,6 +259,16 @@ function synonyms_field_widget_info() {
|
|
|
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
|
|
|
),
|
|
|
),
|
|
|
+ 'synonyms_select' => array(
|
|
|
+ 'label' => t('Synonyms friendly select list'),
|
|
|
+ 'field types' => array('taxonomy_term_reference'),
|
|
|
+ 'settings' => array(
|
|
|
+ 'sort' => 'weight',
|
|
|
+ ),
|
|
|
+ 'behaviors' => array(
|
|
|
+ 'multiple values' => FIELD_BEHAVIOR_CUSTOM,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
);
|
|
|
}
|
|
|
|
|
@@ -246,32 +277,49 @@ function synonyms_field_widget_info() {
|
|
|
*/
|
|
|
function synonyms_field_widget_settings_form($field, $instance) {
|
|
|
$widget = $instance['widget'];
|
|
|
- $settings = $widget['settings'];
|
|
|
+ $settings = $widget['settings'] + field_info_widget_settings($widget['type']);
|
|
|
|
|
|
$form = array();
|
|
|
|
|
|
- $form['auto_creation'] = array(
|
|
|
- '#type' => 'checkbox',
|
|
|
- '#title' => t('Allow auto-creation?'),
|
|
|
- '#description' => t('Whether users may create a new term by typing in a non-existing name into this field.'),
|
|
|
- '#default_value' => $settings['auto_creation'],
|
|
|
- );
|
|
|
-
|
|
|
- $form['suggestion_size'] = array(
|
|
|
- '#type' => 'textfield',
|
|
|
- '#title' => t('Suggestions Size'),
|
|
|
- '#description' => t('Please, enter how many suggested entities to show in the autocomplete textfield.'),
|
|
|
- '#required' => TRUE,
|
|
|
- '#element_validate' => array('element_validate_integer_positive'),
|
|
|
- '#default_value' => $settings['suggestion_size'],
|
|
|
- );
|
|
|
-
|
|
|
- $form['suggest_only_unique'] = array(
|
|
|
- '#type' => 'checkbox',
|
|
|
- '#title' => t('Suggest only one entry per term'),
|
|
|
- '#description' => t('If you want to include only term name or a single synonym, suggesting a particular term, while disregarding all ongoing ones, please, tick this checkbox on.'),
|
|
|
- '#default_value' => $settings['suggest_only_unique'],
|
|
|
- );
|
|
|
+ switch ($widget['type']) {
|
|
|
+ case 'synonyms_autocomplete':
|
|
|
+ $form['auto_creation'] = array(
|
|
|
+ '#type' => 'checkbox',
|
|
|
+ '#title' => t('Allow auto-creation?'),
|
|
|
+ '#description' => t('Whether users may create a new term by typing in a non-existing name into this field.'),
|
|
|
+ '#default_value' => $settings['auto_creation'],
|
|
|
+ );
|
|
|
+
|
|
|
+ $form['suggestion_size'] = array(
|
|
|
+ '#type' => 'textfield',
|
|
|
+ '#title' => t('Suggestions Size'),
|
|
|
+ '#description' => t('Please, enter how many suggested entities to show in the autocomplete textfield.'),
|
|
|
+ '#required' => TRUE,
|
|
|
+ '#element_validate' => array('element_validate_integer_positive'),
|
|
|
+ '#default_value' => $settings['suggestion_size'],
|
|
|
+ );
|
|
|
+
|
|
|
+ $form['suggest_only_unique'] = array(
|
|
|
+ '#type' => 'checkbox',
|
|
|
+ '#title' => t('Suggest only one entry per term'),
|
|
|
+ '#description' => t('If you want to include only term name or a single synonym, suggesting a particular term, while disregarding all ongoing ones, please, tick this checkbox on.'),
|
|
|
+ '#default_value' => $settings['suggest_only_unique'],
|
|
|
+ );
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'synonyms_select':
|
|
|
+ $form['sort'] = array(
|
|
|
+ '#type' => 'radios',
|
|
|
+ '#title' => t('Sort'),
|
|
|
+ '#description' => t('Choose by what criterion the items within select should be sorted.'),
|
|
|
+ '#options' => array(
|
|
|
+ 'weight' => t('As in taxonomy vocabulary (by weight)'),
|
|
|
+ 'name' => t('By name of terms and their synonyms'),
|
|
|
+ ),
|
|
|
+ '#default_value' => $settings['sort'],
|
|
|
+ );
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
return $form;
|
|
|
}
|
|
@@ -280,20 +328,76 @@ function synonyms_field_widget_settings_form($field, $instance) {
|
|
|
* Implements hook_field_widget_form().
|
|
|
*/
|
|
|
function synonyms_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
|
|
|
- $tags = array();
|
|
|
+ $default_value = array();
|
|
|
foreach ($items as $item) {
|
|
|
- $tags[$item['tid']] = isset($item['taxonomy_term']) ? $item['taxonomy_term'] : taxonomy_term_load($item['tid']);
|
|
|
+ $default_value[] = $item['tid'];
|
|
|
}
|
|
|
|
|
|
- $element += array(
|
|
|
- '#type' => 'textfield',
|
|
|
- '#default_value' => taxonomy_implode_tags($tags),
|
|
|
- '#autocomplete_path' => $instance['widget']['settings']['autocomplete_path'] . '/' . $field['field_name'] . '/' . $instance['entity_type'] . '/' . $instance['bundle'],
|
|
|
- '#size' => $instance['widget']['settings']['size'],
|
|
|
- '#maxlength' => 1024,
|
|
|
- '#element_validate' => array('taxonomy_autocomplete_validate', 'synonyms_autocomplete_validate'),
|
|
|
- '#auto_creation' => $instance['widget']['settings']['auto_creation'],
|
|
|
- );
|
|
|
+ switch ($instance['widget']['type']) {
|
|
|
+ case 'synonyms_autocomplete':
|
|
|
+ $tags = taxonomy_term_load_multiple($default_value);
|
|
|
+
|
|
|
+ $element += array(
|
|
|
+ '#type' => 'textfield',
|
|
|
+ '#default_value' => taxonomy_implode_tags($tags),
|
|
|
+ '#autocomplete_path' => $instance['widget']['settings']['synonyms_autocomplete_path'] . '/' . $field['field_name'] . '/' . $instance['entity_type'] . '/' . $instance['bundle'],
|
|
|
+ '#size' => $instance['widget']['settings']['size'],
|
|
|
+ '#maxlength' => 1024,
|
|
|
+ '#element_validate' => array('taxonomy_autocomplete_validate', 'synonyms_autocomplete_validate'),
|
|
|
+ '#auto_creation' => $instance['widget']['settings']['auto_creation'],
|
|
|
+ '#attached' => array(
|
|
|
+ 'js' => array(
|
|
|
+ drupal_get_path('module', 'synonyms') . '/js/synonyms-autocomplete.js' => array(),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ '#attributes' => array(
|
|
|
+ 'class' => array('synonyms-autocomplete'),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'synonyms_select':
|
|
|
+ $multiple = $field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED;
|
|
|
+
|
|
|
+ $options = array();
|
|
|
+ foreach ($field['settings']['allowed_values'] as $tree) {
|
|
|
+ if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
|
|
|
+ switch ($instance['widget']['settings']['sort']) {
|
|
|
+ case 'weight':
|
|
|
+ if ($terms = taxonomy_get_tree($vocabulary->vid, $tree['parent'], NULL, TRUE)) {
|
|
|
+ $behavior_implementations = synonyms_behavior_get('select', 'taxonomy_term', field_extract_bundle('taxonomy_term', $vocabulary), TRUE);
|
|
|
+ foreach ($terms as $term) {
|
|
|
+ $options[] = synonyms_select_option($term);
|
|
|
+ foreach ($behavior_implementations as $implementation) {
|
|
|
+ foreach (synonyms_extract_synonyms($term, $implementation) as $synonym) {
|
|
|
+ $options[] = synonyms_select_option($term, $synonym, $implementation);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'name':
|
|
|
+ // TODO: is there any way to leverage DB for the sorting routine?
|
|
|
+ $options = synonyms_select_sort_name_options_recursive($vocabulary, $tree['parent']);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!$multiple && !$element['#required']) {
|
|
|
+ $options = array('' => t('- None -')) + $options;
|
|
|
+ }
|
|
|
+
|
|
|
+ $element += array(
|
|
|
+ '#type' => 'select',
|
|
|
+ '#multiple' => $multiple,
|
|
|
+ '#options' => $options,
|
|
|
+ '#default_value' => $default_value,
|
|
|
+ '#element_validate' => array('synonyms_select_form_to_storage'),
|
|
|
+ );
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
return $element;
|
|
|
}
|
|
@@ -316,14 +420,26 @@ function synonyms_autocomplete_validate($element, &$form_state) {
|
|
|
// (a) Double-check that those terms are not synonyms.
|
|
|
// (b) Check that synonyms' configurable auto-creation option is enabled.
|
|
|
$value = drupal_array_get_nested_value($form_state['values'], $element['#parents']);
|
|
|
+
|
|
|
+ $field = field_widget_field($element, $form_state);
|
|
|
foreach ($value as $delta => $term) {
|
|
|
if ($term['tid'] == 'autocreate') {
|
|
|
- $vocabulary = taxonomy_vocabulary_load($term['vid']);
|
|
|
- $synonym_tid = synonyms_get_term_by_synonym($term['name'], $vocabulary);
|
|
|
+ $synonym_tid = 0;
|
|
|
+ foreach ($field['settings']['allowed_values'] as $tree) {
|
|
|
+ $behavior_implementations = synonyms_behavior_get('autocomplete', 'taxonomy_term', $tree['vocabulary'], TRUE);
|
|
|
+ foreach ($behavior_implementations as $behavior_implementation) {
|
|
|
+ $synonyms = synonyms_synonyms_find_behavior(db_and()->condition(AbstractSynonymsSynonymsBehavior::COLUMN_PLACEHOLDER, $term['name']), $behavior_implementation);
|
|
|
+ foreach ($synonyms as $synonym) {
|
|
|
+ $synonym_tid = $synonym->entity_id;
|
|
|
+ break(2);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if ($synonym_tid != 0) {
|
|
|
$value[$delta]['tid'] = $synonym_tid;
|
|
|
}
|
|
|
- elseif (empty($element['#auto_creation'])) {
|
|
|
+ elseif (!$element['#auto_creation']) {
|
|
|
unset($value[$delta]);
|
|
|
}
|
|
|
}
|
|
@@ -335,8 +451,6 @@ function synonyms_autocomplete_validate($element, &$form_state) {
|
|
|
/**
|
|
|
* Try to find a term by its name or synonym.
|
|
|
*
|
|
|
- * To maximize the match trimming and case-insensitive comparison is used.
|
|
|
- *
|
|
|
* @param string $name
|
|
|
* The string to be searched for its {taxonomy_term_data}.tid
|
|
|
* @param object $vocabulary
|
|
@@ -351,20 +465,28 @@ function synonyms_autocomplete_validate($element, &$form_state) {
|
|
|
* found term, otherwise returns 0
|
|
|
*/
|
|
|
function synonyms_get_term_by_synonym($name, $vocabulary, $parent = 0) {
|
|
|
- $name = mb_strtoupper(trim($name), 'UTF-8');
|
|
|
-
|
|
|
- $tree = taxonomy_get_tree($vocabulary->vid, $parent, NULL, TRUE);
|
|
|
- foreach ($tree as $term) {
|
|
|
- if (mb_strtoupper($term->name, 'UTF-8') == $name) {
|
|
|
+ $name = trim($name);
|
|
|
+
|
|
|
+ $terms = taxonomy_get_term_by_name($name, $vocabulary->machine_name);
|
|
|
+ foreach ($terms as $term) {
|
|
|
+ if (!$parent || synonyms_taxonomy_term_is_child_of($term->tid, $parent)) {
|
|
|
+ // TODO: actually it could be so that there is more than 1 term that
|
|
|
+ // satisfies the search query, i.e. the name and parent constraints. At
|
|
|
+ // the moment we are going to return the first one we encounter, though
|
|
|
+ // something better could be thought of in the future.
|
|
|
return $term->tid;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- // We additionally scan through the synonyms.
|
|
|
- $synonyms = synonyms_get_sanitized($term);
|
|
|
- foreach ($synonyms as $item) {
|
|
|
- if (mb_strtoupper($item, 'UTF-8') == $name) {
|
|
|
- return $term->tid;
|
|
|
- }
|
|
|
+ // We have failed to find a term with the provided $name. So let's search now
|
|
|
+ // among the term synonyms.
|
|
|
+ $bundle = field_extract_bundle('taxonomy_term', $vocabulary);
|
|
|
+ $synonyms = synonyms_synonyms_find(db_and()->condition(AbstractSynonymsSynonymsBehavior::COLUMN_PLACEHOLDER, $name), 'taxonomy_term', $bundle);
|
|
|
+ foreach ($synonyms as $synonym) {
|
|
|
+ if (!$parent || synonyms_taxonomy_term_is_child_of($synonym->entity_id, $parent)) {
|
|
|
+ // TODO: similarly here, as above, we could have more than 1 match, but
|
|
|
+ // for now we will simply return the first one encountered.
|
|
|
+ return $synonym->entity_id;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -374,7 +496,7 @@ function synonyms_get_term_by_synonym($name, $vocabulary, $parent = 0) {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Look up a term considering synonyms and if nothing found add one.
|
|
|
+ * Look up a term considering synonyms and if nothing is found add one.
|
|
|
*
|
|
|
* This function is useful for automated creation of new terms as it won't
|
|
|
* generate the same terms over and over again.
|
|
@@ -454,6 +576,9 @@ function synonyms_get_raw($item) {
|
|
|
/**
|
|
|
* Public function for retrieving synonyms of a taxonomy term.
|
|
|
*
|
|
|
+ * You are encouraged to use synonyms_get_sanitized() or synonyms_get_raw()
|
|
|
+ * instead. This function soon will be removed from the source code.
|
|
|
+ *
|
|
|
* @param object $term
|
|
|
* Fully loaded taxonomy term for which the synonyms are desired
|
|
|
*
|
|
@@ -463,30 +588,151 @@ function synonyms_get_raw($item) {
|
|
|
* the following keys:
|
|
|
* - value: (string) the value of a synonym as it was input by user
|
|
|
* - safe_value: (string) a sanitized value of a synonym
|
|
|
+ *
|
|
|
+ * @deprecated
|
|
|
*/
|
|
|
function synonyms_get_term_synonyms($term) {
|
|
|
$synonyms = array();
|
|
|
$vocabulary = taxonomy_vocabulary_load($term->vid);
|
|
|
- foreach (synonyms_synonyms_fields($vocabulary) as $field) {
|
|
|
- $bundle = field_extract_bundle('taxonomy_term', $vocabulary);
|
|
|
- $instance = field_info_instance('taxonomy_term', $field, $bundle);
|
|
|
- $field = field_info_field($field);
|
|
|
- $items = field_get_items('taxonomy_term', $term, $field['field_name']);
|
|
|
-
|
|
|
- if (is_array($items) && !empty($items)) {
|
|
|
- $class = synonyms_extractor_info($field['type']);
|
|
|
- foreach (call_user_func(array($class, 'synonymsExtract'), $items, $field, $instance, $term, 'taxonomy_term') as $synonym) {
|
|
|
+ $bundle = field_extract_bundle('taxonomy_term', $vocabulary);
|
|
|
+
|
|
|
+ $behavior_implementations = synonyms_behavior_get('synonyms', 'taxonomy_term', $bundle, TRUE);
|
|
|
+ foreach ($behavior_implementations as $implementation) {
|
|
|
+ foreach (synonyms_extract_synonyms($term, $implementation) as $synonym) {
|
|
|
$synonyms[] = array(
|
|
|
'value' => $synonym,
|
|
|
'safe_value' => check_plain($synonym),
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
return $synonyms;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * Extract synonyms of an entity within a certain field and behavior.
|
|
|
+ *
|
|
|
+ * Do not use this function, if you want to get synonyms of an entity, unless
|
|
|
+ * you know what you are doing. This function extracts the synonyms from a field
|
|
|
+ * that is specified by $behavior_implementation parameter. The behavior may not
|
|
|
+ * necessarily be of 'synonyms' type, so it's not 100% valid to say that the
|
|
|
+ * entity has the returned array as its synonyms. However, this function is very
|
|
|
+ * useful for behaviors that "extend" the basic synonyms behavior.
|
|
|
+ *
|
|
|
+ * @param object $entity
|
|
|
+ * Fully loaded entity, synonyms from which should be extracted
|
|
|
+ * @param array $behavior_implementation
|
|
|
+ * Fully loaded behavior implementation. Supply here one of the values from
|
|
|
+ * the return of synonyms_behavior_get() function
|
|
|
+ *
|
|
|
+ * @return array
|
|
|
+ * Array of synonyms that reside in the field dictated by
|
|
|
+ * $behavior_implementation parameter
|
|
|
+ */
|
|
|
+function synonyms_extract_synonyms($entity, $behavior_implementation) {
|
|
|
+ $synonyms = array();
|
|
|
+ $field = field_info_field($behavior_implementation['field_name']);
|
|
|
+ $instance = field_info_instance($behavior_implementation['entity_type'], $behavior_implementation['field_name'], $behavior_implementation['bundle']);
|
|
|
+ $items = field_get_items($behavior_implementation['entity_type'], $entity, $field['field_name']);
|
|
|
+
|
|
|
+ if (is_array($items) && !empty($items)) {
|
|
|
+ $object = synonyms_behavior_implementation_class($behavior_implementation['behavior'], $field);
|
|
|
+ $object = new $object();
|
|
|
+
|
|
|
+ $synonyms = array_merge($synonyms, $object->extractSynonyms($items, $field, $instance, $entity, $behavior_implementation['entity_type']));
|
|
|
+ }
|
|
|
+ return $synonyms;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Look up entities by their synonyms.
|
|
|
+ *
|
|
|
+ * @param QueryConditionInterface $condition
|
|
|
+ * Object of QueryConditionInterface that specifies conditions by which you
|
|
|
+ * want to find synonyms. When building this condition object, use
|
|
|
+ * AbstractSynonymsSynonymsBehavior::COLUMN_PLACEHOLDER as a placeholder for
|
|
|
+ * real column name that contains synonym as text. For example, if you were to
|
|
|
+ * find all entities with synonyms that begin with "synonym-come-here"
|
|
|
+ * substring, case insensitive and replacing all spaces in original synonym
|
|
|
+ * string by a dash sign, then you would have to create the following
|
|
|
+ * condition object:
|
|
|
+ * db_and()
|
|
|
+ * ->where("LOWER(REPLACE(" . AbstractSynonymsSynonymsBehavior::COLUMN_PLACEHOLDER . ", ' ', '-')) LIKE 'synonym-come-here%'")
|
|
|
+ * And then just supply this object as an input parameter to this function
|
|
|
+ * @param string $entity_type
|
|
|
+ * Among synonyms of what entity type to search
|
|
|
+ * @param string $bundle
|
|
|
+ * Among synonyms of what bundle to search
|
|
|
+ *
|
|
|
+ * @return array
|
|
|
+ * Array of found synonyms and entity IDs to which those belong. Each element
|
|
|
+ * in the array will be an object and will have the following structure:
|
|
|
+ * - synonym: (string) Synonym that was found and which satisfies the
|
|
|
+ * $condition you specified
|
|
|
+ * - entity_id: (int) ID of the entity to which the found synonym belongs
|
|
|
+ */
|
|
|
+function synonyms_synonyms_find(QueryConditionInterface $condition, $entity_type, $bundle) {
|
|
|
+ $rows = array();
|
|
|
+
|
|
|
+ $behavior_implementations = synonyms_behavior_get('synonyms', $entity_type, $bundle, TRUE);
|
|
|
+ foreach ($behavior_implementations as $behavior_implementation) {
|
|
|
+ foreach (synonyms_synonyms_find_behavior($condition, $behavior_implementation) as $row) {
|
|
|
+ $rows[] = $row;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return $rows;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Find entities with a provided synonym within certain behavior implementation.
|
|
|
+ *
|
|
|
+ * Do not use this function, if you want to find entities that have specific
|
|
|
+ * synonyms, unless you know what you are doing. This function searches for the
|
|
|
+ * entities with synonyms from a field that is specified by
|
|
|
+ * $behavior_implementation parameter. The behavior may not necessarily be of
|
|
|
+ * 'synonyms' type, so it's not 100% valid to say that the returned entities
|
|
|
+ * have the specified synonyms. However, this function is very useful for
|
|
|
+ * behaviors that "extend" the basic synonyms behavior.
|
|
|
+ *
|
|
|
+ * You have full SQL flexibility to specify parameters of how to search for
|
|
|
+ * synonyms. You can create arbitrary set of SQL conditions that will be plugged
|
|
|
+ * into specific SELECT queries by behavior implementations.
|
|
|
+ *
|
|
|
+ * @param QueryConditionInterface $condition
|
|
|
+ * Object of QueryConditionInterface that specifies conditions by which you
|
|
|
+ * want to find synonyms. When building this condition object, use
|
|
|
+ * AbstractSynonymsSynonymsBehavior::COLUMN_PLACEHOLDER as a placeholder for
|
|
|
+ * real column name that contains synonym as text. For example, if you were to
|
|
|
+ * find all entities with synonyms that begin with "synonym-come-here"
|
|
|
+ * substring, case insensitive and replacing all spaces in original synonym
|
|
|
+ * string by a dash sign, then you would have to create the following
|
|
|
+ * condition object:
|
|
|
+ * db_and()
|
|
|
+ * ->where("LOWER(REPLACE(" . AbstractSynonymsSynonymsBehavior::COLUMN_PLACEHOLDER . ", ' ', '-')) LIKE 'synonym-come-here%'")
|
|
|
+ * And then just supply this object as an input parameter to this function
|
|
|
+ * @param array $behavior_implementation
|
|
|
+ * Fully loaded behavior implementation. Supply here one of the values from
|
|
|
+ * the return of synonyms_behavior_get() function
|
|
|
+ *
|
|
|
+ * @return Traversable
|
|
|
+ * Traversable result set of found synonyms and entity IDs to which those
|
|
|
+ * belong. Each element in the result set will be an object and will have the
|
|
|
+ * following structure:
|
|
|
+ * - synonym: (string) Synonym that was found and which satisfies the
|
|
|
+ * $condition you specified
|
|
|
+ * - entity_id: (int) ID of the entity to which the found synonym belongs
|
|
|
+ */
|
|
|
+function synonyms_synonyms_find_behavior(QueryConditionInterface $condition, $behavior_implementation) {
|
|
|
+ $field = field_info_field($behavior_implementation['field_name']);
|
|
|
+ $instance = field_info_instance($behavior_implementation['entity_type'], $behavior_implementation['field_name'], $behavior_implementation['bundle']);
|
|
|
+
|
|
|
+ $object = synonyms_behavior_implementation_class($behavior_implementation['behavior'], $field);
|
|
|
+ $object = new $object();
|
|
|
+
|
|
|
+ return $object->synonymsFind($condition, $field, $instance);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* Allow to merge $synonym_entity as a synonym into $trunk_entity.
|
|
|
*
|
|
@@ -502,8 +748,8 @@ function synonyms_get_term_synonyms($term) {
|
|
|
* @param string $trunk_entity_type
|
|
|
* Entity type of $trunk_entity
|
|
|
* @param string $field
|
|
|
- * Field name that should exist in $trunk_entity and be enabled as a synonym
|
|
|
- * source. Into this field synonym will be added
|
|
|
+ * Field name that should exist in $trunk_entity and have enabled the
|
|
|
+ * "synonyms" behavior. Into this field synonym will be added
|
|
|
* @param object $synonym_entity
|
|
|
* Fully loaded entity object which will be added as a synonym
|
|
|
* @param string $synonym_entity_type
|
|
@@ -517,26 +763,47 @@ function synonyms_add_entity_as_synonym($trunk_entity, $trunk_entity_type, $fiel
|
|
|
// Currently synonyms module only operates on taxonomy terms.
|
|
|
return FALSE;
|
|
|
}
|
|
|
- if (!in_array($field, synonyms_synonyms_fields(taxonomy_vocabulary_load($trunk_entity->vid)))) {
|
|
|
- // $field either doesn't exist in the $trunk_entity or it's not enabled as
|
|
|
- // a source of synonyms.
|
|
|
+
|
|
|
+ $bundle = entity_extract_ids($trunk_entity_type, $trunk_entity);
|
|
|
+ $bundle = $bundle[2];
|
|
|
+ $behavior_implementations = synonyms_behavior_get('synonyms', $trunk_entity_type, $bundle, TRUE);
|
|
|
+
|
|
|
+ $field = field_info_field($field);
|
|
|
+ $instance = field_info_instance($trunk_entity_type, $field['field_name'], $bundle);
|
|
|
+ if (!isset($behavior_implementations[$instance['id']])) {
|
|
|
+ // $field either doesn't exist in the $trunk_entity or it does not have
|
|
|
+ // enabled the behavior of synonyms.
|
|
|
return FALSE;
|
|
|
}
|
|
|
- // Preparing arguments for calling a method of Extractor class.
|
|
|
- $field = field_info_field($field);
|
|
|
- $extractor = synonyms_extractor_info($field['type']);
|
|
|
+
|
|
|
$items = field_get_items($trunk_entity_type, $trunk_entity, $field['field_name']);
|
|
|
$items = is_array($items) ? $items : array();
|
|
|
- $trunk_entity_ids = entity_extract_ids($trunk_entity_type, $trunk_entity);
|
|
|
- $instance = field_info_instance($trunk_entity_type, $field['field_name'], $trunk_entity_ids[2]);
|
|
|
|
|
|
- $extra_items = call_user_func(array($extractor, 'mergeEntityAsSynonym'), $items, $field, $instance, $synonym_entity, $synonym_entity_type);
|
|
|
+ $object = synonyms_behavior_implementation_class('synonyms', $field);
|
|
|
+ $object = new $object();
|
|
|
+ $extra_items = $object->mergeEntityAsSynonym($items, $field, $instance, $synonym_entity, $synonym_entity_type);
|
|
|
+
|
|
|
+ if (empty($extra_items)) {
|
|
|
+ // For some reason the behavior implementation couldn't merge it. Otherwise
|
|
|
+ // it would have not returned an empty array.
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
|
|
|
// Merging extracted synonym items into the values of the field that already
|
|
|
// exist.
|
|
|
// @todo: Currently we hardcode to LANGUAGE_NONE, but in future it would be
|
|
|
// nice to have multilanguage support.
|
|
|
$items = array_merge($items, $extra_items);
|
|
|
+
|
|
|
+ // Now we want to keep only unique values of the $items. Since we know nothing
|
|
|
+ // about what determines uniqueness of an item, we will ask the synonym
|
|
|
+ // behavior to hash each of them and then will compare hashes.
|
|
|
+ $unique_items = array();
|
|
|
+ foreach ($items as $item) {
|
|
|
+ $unique_items[$object->synonymItemHash($item, $field, $instance)] = $item;
|
|
|
+ }
|
|
|
+ $items = array_values($unique_items);
|
|
|
+
|
|
|
$trunk_entity->{$field['field_name']}[LANGUAGE_NONE] = $items;
|
|
|
// In future if this module eventually becomes a gateway for synonyms for any
|
|
|
// entity types, we'll substitute it with entity_save().
|
|
@@ -547,177 +814,433 @@ function synonyms_add_entity_as_synonym($trunk_entity, $trunk_entity_type, $fiel
|
|
|
/**
|
|
|
* Return array of field names that are sources of synonyms.
|
|
|
*
|
|
|
- * Return array of field names that are currently enabled as source of
|
|
|
- * synonyms in the supplied vocabulary.
|
|
|
+ * Return array of field names that are currently have enabled the synonyms
|
|
|
+ * behavior in the supplied vocabulary. This function is deprecated and shortly
|
|
|
+ * will be removed from the code. All clients of this function are encourage to
|
|
|
+ * use synonyms_behavior_get() function, which provides a richer set of
|
|
|
+ * functionality than this one.
|
|
|
*
|
|
|
* @param object $vocabulary
|
|
|
* Fully loaded taxonomy vocabulary object
|
|
|
*
|
|
|
* @return array
|
|
|
* Array of field names
|
|
|
+ *
|
|
|
+ * @deprecated
|
|
|
*/
|
|
|
function synonyms_synonyms_fields($vocabulary) {
|
|
|
- $settings = synonyms_vocabulary_settings($vocabulary);
|
|
|
- if (!isset($settings['synonyms']) || !is_array($settings['synonyms'])) {
|
|
|
- // Weird as normally we expect to see here at least an empty array but
|
|
|
- // no problem. We simply initialize it.
|
|
|
- $settings['synonyms'] = array();
|
|
|
- }
|
|
|
-
|
|
|
- // It's not just as easy as pulling up already saved value. After this
|
|
|
- // we have to make sure that all the fields are still present and have not
|
|
|
- // been deleted from the vocabulary.
|
|
|
+ $fields = array();
|
|
|
$bundle = field_extract_bundle('taxonomy_term', $vocabulary);
|
|
|
- $instances = field_info_instances('taxonomy_term', $bundle);
|
|
|
- $settings['synonyms'] = array_intersect($settings['synonyms'], array_keys($instances));
|
|
|
+ $behavior_implementations = synonyms_behavior_get('synonyms', 'taxonomy_term', $bundle, TRUE);
|
|
|
+ foreach ($behavior_implementations as $v) {
|
|
|
+ $fields[] = $v['field_name'];
|
|
|
+ }
|
|
|
+ return $fields;
|
|
|
+}
|
|
|
|
|
|
- return $settings['synonyms'];
|
|
|
+/**
|
|
|
+ * Implements hook_views_api().
|
|
|
+ */
|
|
|
+function synonyms_views_api() {
|
|
|
+ return array(
|
|
|
+ 'api' => 3,
|
|
|
+ 'path' => drupal_get_path('module', 'synonyms') . '/views',
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Enforce the setting "synonyms".
|
|
|
+ * Load function for existing implementations of synonyms behaviors.
|
|
|
*
|
|
|
- * @param object $vocabulary
|
|
|
- * Fully loaded entity of a taxonomy vocabulary
|
|
|
- * @param array $fields
|
|
|
- * Array of fields that are enabled as a source of synonyms
|
|
|
+ * @param string $behavior
|
|
|
+ * Name of the synonyms behavior whose existing implementations should be
|
|
|
+ * loaded. Basically it has to be name of a ctools plugin of "behavior" type.
|
|
|
+ * @param string $entity_type
|
|
|
+ * Optional filter to limit the search for existing implementations only to
|
|
|
+ * those that apply to the provided entity type
|
|
|
+ * @param string $bundle
|
|
|
+ * Optional filter to limit the search for existing implementations only to
|
|
|
+ * those that apply to the provided bundle and entity type (the $entity_type
|
|
|
+ * argument)
|
|
|
+ * @param bool $only_enabled
|
|
|
+ * Optional filter to limit the search for existing implementations only to
|
|
|
+ * those that are currently enabled
|
|
|
+ * @param bool $include_deleted
|
|
|
+ * Optional filter to include the behaviors from deleted instances
|
|
|
+ *
|
|
|
+ * @return array
|
|
|
+ * Array of loaded existing synonyms behavior implementations. It is keyed
|
|
|
+ * by ID of the field instance to which the behavior implementation applies.
|
|
|
+ * The underlying array will have the following structure:
|
|
|
+ * - behavior: (string) Behavior name of this behavior implementation, i.e.
|
|
|
+ * name of a ctools plugin of "behavior" type
|
|
|
+ * - settings: (mixed) Behavior settings, its internal structure depends on
|
|
|
+ * the type of behavior. If this value is NULL, it means the behavior
|
|
|
+ * implementation is currently disabled for the field instance
|
|
|
+ * - entity_type: (string) Entity type to which this behavior implementation
|
|
|
+ * applies
|
|
|
+ * - bundle: (string) Bundle name to which this behavior implementation
|
|
|
+ * applies
|
|
|
+ * - field_name: (string) Name of a field to which this behavior
|
|
|
+ * implementation applies
|
|
|
+ * - instance_id: (int) ID of the instance to which this behavior
|
|
|
+ * implementation applies
|
|
|
*/
|
|
|
-function synonyms_synonyms_enforce($vocabulary, $fields) {
|
|
|
- $bundle = field_extract_bundle('taxonomy_term', $vocabulary);
|
|
|
+function synonyms_behavior_get($behavior, $entity_type = NULL, $bundle = NULL, $only_enabled = FALSE, $include_deleted = FALSE) {
|
|
|
+ $behavior_implementation_info = synonyms_behavior_implementation_info($behavior);
|
|
|
+ $supported_field_types = array_keys($behavior_implementation_info);
|
|
|
|
|
|
- // Normally all the fields already exist, we just need to assure that
|
|
|
- // default synonyms field exists if it is enabled as a source of synonyms.
|
|
|
- // Otherwise we make sure we delete instance of the default field in the
|
|
|
- // vocabulary.
|
|
|
- $instance = field_info_instance('taxonomy_term', SYNONYMS_DEFAULT_FIELD_NAME, $bundle);
|
|
|
- if (in_array(SYNONYMS_DEFAULT_FIELD_NAME, $fields)) {
|
|
|
- if (is_null($instance)) {
|
|
|
- // Make sure the field exists.
|
|
|
- synonyms_default_field_ensure();
|
|
|
-
|
|
|
- field_create_instance(array(
|
|
|
- 'field_name' => SYNONYMS_DEFAULT_FIELD_NAME,
|
|
|
- 'entity_type' => 'taxonomy_term',
|
|
|
- 'bundle' => $bundle,
|
|
|
- 'label' => t('Synonyms'),
|
|
|
- 'description' => t('Please, enter the synonyms which should be related to this term.'),
|
|
|
- ));
|
|
|
- }
|
|
|
+ if (empty($supported_field_types)) {
|
|
|
+ return array();
|
|
|
+ }
|
|
|
|
|
|
+ $query = db_select('field_config_instance', 'i');
|
|
|
+ $field_alias = $query->innerJoin('field_config', 'f', 'f.id = i.field_id');
|
|
|
+ $query->condition($field_alias . '.type', $supported_field_types);
|
|
|
+ if ($entity_type) {
|
|
|
+ $query->condition('i.entity_type', $entity_type);
|
|
|
+ }
|
|
|
+ if ($bundle) {
|
|
|
+ $query->condition('i.bundle', $bundle);
|
|
|
}
|
|
|
- elseif (!is_null($instance)) {
|
|
|
- // Deleting the instance, we will delete the field separately when the
|
|
|
- // module gets uninstalled.
|
|
|
- field_delete_instance($instance, FALSE);
|
|
|
+ if (!$include_deleted) {
|
|
|
+ $query->condition('i.deleted', 0);
|
|
|
}
|
|
|
+
|
|
|
+ $settings_alias = $query->addJoin($only_enabled ? 'INNER' : 'LEFT OUTER', 'synonyms_settings', 's', 's.instance_id = i.id AND s.behavior = :behavior', array(
|
|
|
+ ':behavior' => $behavior,
|
|
|
+ ));
|
|
|
+ $query->fields($settings_alias, array('behavior', 'settings_serialized'));
|
|
|
+
|
|
|
+ $query->fields('i', array('entity_type', 'bundle', 'field_name'));
|
|
|
+ $query->addField('i', 'id', 'instance_id');
|
|
|
+ $result = $query->execute();
|
|
|
+ $result = $result->fetchAllAssoc('instance_id', PDO::FETCH_ASSOC);
|
|
|
+
|
|
|
+ return synonyms_behavior_settings_unpack($result);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Return the current settings for the supplied $vocabulary.
|
|
|
+ * Retrieve information about all ctools plugins of type 'synonyms behavior'.
|
|
|
*
|
|
|
- * @param object $vocabulary
|
|
|
- * Fully loaded entity of a taxonomy vocabulary
|
|
|
+ * @return array
|
|
|
+ * Array of information on all available synonyms behavior plugins
|
|
|
+ */
|
|
|
+function synonyms_behaviors() {
|
|
|
+ ctools_include('plugins');
|
|
|
+ return ctools_get_plugins('synonyms', 'behavior');
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Fetch information about synonyms behaviors implementations per field type.
|
|
|
+ *
|
|
|
+ * Fetch the map between field types and the PHP classes that implement synonyms
|
|
|
+ * behaviors for them.
|
|
|
+ *
|
|
|
+ * @param string $behavior
|
|
|
+ * What specific behavior is queried. Supply here keys from the return of
|
|
|
+ * synonyms_behaviors() function
|
|
|
*
|
|
|
* @return array
|
|
|
- * Array of current synonyms settings for the supplied vocabulary.
|
|
|
- * Should include the following keys:
|
|
|
- * - synonyms: (array) array of field names that are enabled as source of
|
|
|
- * synonyms
|
|
|
+ * Array of information about what field types implement the provided behavior
|
|
|
+ * through what PHP classes. Keys of this array are field types, whereas their
|
|
|
+ * values are names of PHP classes that implement the provided behavior for
|
|
|
+ * that particular field type
|
|
|
*/
|
|
|
-function synonyms_vocabulary_settings($vocabulary) {
|
|
|
- $settings = array();
|
|
|
+function synonyms_behavior_implementation_info($behavior) {
|
|
|
+ $info = module_invoke_all('synonyms_behavior_implementation_info', $behavior);
|
|
|
+ drupal_alter('synonyms_behavior_implementation_info', $info, $behavior);
|
|
|
+ return $info;
|
|
|
+}
|
|
|
|
|
|
- if (isset($vocabulary->vid)) {
|
|
|
- $settings = variable_get('synonyms_settings_' . $vocabulary->vid, array(
|
|
|
- 'synonyms' => array(),
|
|
|
- ));
|
|
|
- }
|
|
|
+/**
|
|
|
+ * Determine what PHP class implements specific behavior for specific field.
|
|
|
+ *
|
|
|
+ * @param string $behavior
|
|
|
+ * Name of the behavior, implementation of which is requested. It should be
|
|
|
+ * one of the keys of the return of synonyms_behaviors() function.
|
|
|
+ * @param array $field
|
|
|
+ * Field definition array for which PHP class implementing $behavior is
|
|
|
+ * requested
|
|
|
+ *
|
|
|
+ * @return string
|
|
|
+ * Name of the PHP class that implements $behavior for $field field
|
|
|
+ */
|
|
|
+function synonyms_behavior_implementation_class($behavior, $field) {
|
|
|
+ $map = synonyms_behavior_implementation_info($behavior);
|
|
|
+ return $map[$field['type']];
|
|
|
+}
|
|
|
|
|
|
+/**
|
|
|
+ * Execute unpacking operation on the just loaded synonyms behavior settings.
|
|
|
+ *
|
|
|
+ * @param array $settings
|
|
|
+ * Array of the just loaded settings. Each sub array should contain the
|
|
|
+ * following keys:
|
|
|
+ * - instance_id: (int) ID of the instance to which it applies
|
|
|
+ * - behavior: (string) name of the synonyms behavior to which these settings
|
|
|
+ * apply
|
|
|
+ * - settings_serialized: (string) serialized content of the settings
|
|
|
+ *
|
|
|
+ * @return array
|
|
|
+ * Unpacked version of the provided $settings
|
|
|
+ */
|
|
|
+function synonyms_behavior_settings_unpack($settings) {
|
|
|
+ foreach ($settings as &$setting) {
|
|
|
+ $setting['settings'] = $setting['settings_serialized'] ? unserialize($setting['settings_serialized']) : NULL;
|
|
|
+ }
|
|
|
return $settings;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Save the current settings for the supplied $vocabulary.
|
|
|
+ * Save the provided synonyms behavior settings into the database.
|
|
|
*
|
|
|
- * @param object $vocabulary
|
|
|
- * Fully loaded entity of a taxonomy vocabulary
|
|
|
* @param array $settings
|
|
|
- * Settings the have to be stored. The structure of this array has to be
|
|
|
- * identical to the output array of the function
|
|
|
- * synonyms_vocabulary_settings()
|
|
|
- */
|
|
|
-function synonyms_vocabulary_settings_save($vocabulary, $settings) {
|
|
|
- // If source of synonyms has changed for this vocabulary, we have to trigger
|
|
|
- // search re-indexing on all the nodes that reference at least 1 term from
|
|
|
- // this vocabulary.
|
|
|
- $previous_settings = synonyms_vocabulary_settings($vocabulary);
|
|
|
- if (implode('', $settings['synonyms']) != implode('', $previous_settings['synonyms'])) {
|
|
|
- module_load_include('inc', 'synonyms', 'synonyms.pages');
|
|
|
- synonyms_reindex_nodes_by_vocabulary($vocabulary);
|
|
|
- }
|
|
|
-
|
|
|
- variable_set('synonyms_settings_' . $vocabulary->vid, $settings);
|
|
|
-
|
|
|
- // Now enforcing each setting.
|
|
|
- foreach ($settings as $k => $v) {
|
|
|
- switch ($k) {
|
|
|
- case 'synonyms':
|
|
|
- synonyms_synonyms_enforce($vocabulary, $v);
|
|
|
- break;
|
|
|
+ * Array of settings. It must have the following structure:
|
|
|
+ * - instance_id: (int) ID of the instance to which it applies
|
|
|
+ * - behavior: (string) name of the synonyms behavior to which it applies
|
|
|
+ * - settings: (mixed) the content of settings themselves
|
|
|
+ */
|
|
|
+function synonyms_behavior_settings_save($settings) {
|
|
|
+ if (!isset($settings['settings'])) {
|
|
|
+ $settings['settings'] = array();
|
|
|
+ }
|
|
|
+ $settings['settings_serialized'] = serialize($settings['settings']);
|
|
|
+ $result = db_merge('synonyms_settings')
|
|
|
+ ->key(array(
|
|
|
+ 'instance_id' => $settings['instance_id'],
|
|
|
+ 'behavior' => $settings['behavior'],
|
|
|
+ ))
|
|
|
+ ->fields(array(
|
|
|
+ 'instance_id' => $settings['instance_id'],
|
|
|
+ 'behavior' => $settings['behavior'],
|
|
|
+ 'settings_serialized' => $settings['settings_serialized'],
|
|
|
+ ))
|
|
|
+ ->execute();
|
|
|
+
|
|
|
+ switch ($result) {
|
|
|
+ case MergeQuery::STATUS_INSERT:
|
|
|
+ $behavior_definition = synonyms_behaviors();
|
|
|
+ $behavior_definition = $behavior_definition[$settings['behavior']];
|
|
|
+ $enabled_callback = ctools_plugin_get_function($behavior_definition, 'enabled callback');
|
|
|
+ if ($enabled_callback) {
|
|
|
+ $enabled_callback($behavior_definition, $settings['settings'], synonyms_instance_id_load($settings['instance_id']));
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Delete settings for specific behavior and field instance.
|
|
|
+ *
|
|
|
+ * @param int $instance_id
|
|
|
+ * ID of the instance for which settings should be removed
|
|
|
+ * @param string $behavior
|
|
|
+ * Name of behavior for which settings should be removed
|
|
|
+ */
|
|
|
+function synonyms_behavior_settings_delete($instance_id, $behavior) {
|
|
|
+ $behavior_definition = synonyms_behaviors();
|
|
|
+ $behavior_definition = $behavior_definition[$behavior];
|
|
|
+ $disabled_callback = ctools_plugin_get_function($behavior_definition, 'disabled callback');
|
|
|
+ if ($disabled_callback) {
|
|
|
+ $instance = synonyms_instance_id_load($instance_id);
|
|
|
+ $behavior_implementation = synonyms_behavior_get($behavior, $instance['entity_type'], $instance['bundle'], FALSE, TRUE);
|
|
|
+ $behavior_implementation = $behavior_implementation[$instance_id];
|
|
|
+ $disabled_callback($behavior_definition, $behavior_implementation, $instance);
|
|
|
+ }
|
|
|
+ db_delete('synonyms_settings')
|
|
|
+ ->condition('instance_id', $instance_id)
|
|
|
+ ->condition('behavior', $behavior)
|
|
|
+ ->execute();
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Supportive function to load a field instance by its ID.
|
|
|
+ *
|
|
|
+ * @param int $instance_id
|
|
|
+ * ID of the instance that should be loaded
|
|
|
+ *
|
|
|
+ * @return array
|
|
|
+ * Instance definition array
|
|
|
+ */
|
|
|
+function synonyms_instance_id_load($instance_id) {
|
|
|
+ $result = db_select('field_config_instance', 'i')
|
|
|
+ ->fields('i', array('entity_type', 'bundle', 'field_name'))
|
|
|
+ ->condition('id', $instance_id)
|
|
|
+ ->execute()
|
|
|
+ ->fetchAssoc();
|
|
|
+ return field_info_instance($result['entity_type'], $result['field_name'], $result['bundle']);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Convert synonyms friendly select widget values for storage friendly format.
|
|
|
+ *
|
|
|
+ * It acts similar to what the _options_form_to_storage() function does -
|
|
|
+ * bridges between how values are returned from form API to how they are
|
|
|
+ * expected by Field module.
|
|
|
+ */
|
|
|
+function synonyms_select_form_to_storage($element, &$form_state) {
|
|
|
+ $value = array();
|
|
|
+ if ($element['#multiple']) {
|
|
|
+ $value = $element['#value'];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ $value[] = $element['#value'];
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach ($value as $k => $v) {
|
|
|
+ // For the cases when a synonym was selected and not a term option, we
|
|
|
+ // process the selected values stripping everything that goes after
|
|
|
+ // semicolon.
|
|
|
+ if (!is_numeric($v)) {
|
|
|
+ $tid = explode(':', $v);
|
|
|
+ $value[$k] = $tid[0];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // The user also might have selected multiple times the same term, given that
|
|
|
+ // a term can be represented by more than 1 option (a term and its synonym),
|
|
|
+ // then it's possible in theory, so we should be ready for this scenario.
|
|
|
+ $value = array_unique($value);
|
|
|
+
|
|
|
+ $form_state_value = array();
|
|
|
+ foreach ($value as $tid) {
|
|
|
+ $form_state_value[] = array('tid' => $tid);
|
|
|
+ }
|
|
|
+
|
|
|
+ form_set_value($element, $form_state_value, $form_state);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Check whether a taxonomy term $tid is a child of a taxonomy term $parent_tid.
|
|
|
+ *
|
|
|
+ * Supportive function, used throughout this module for parent constrains.
|
|
|
+ *
|
|
|
+ * @param int $tid
|
|
|
+ * {taxonomy_term}.tid of the term that is tested for being a child of the
|
|
|
+ * $parent_tid term
|
|
|
+ * @param int $parent_tid
|
|
|
+ * {taxonomy_term}.tid of the term that is tested for being parent of the $tid
|
|
|
+ * term
|
|
|
+ *
|
|
|
+ * @return bool
|
|
|
+ * Whether $tid is a child of $parent_tid
|
|
|
+ */
|
|
|
+function synonyms_taxonomy_term_is_child_of($tid, $parent_tid) {
|
|
|
+ $term_parents = taxonomy_get_parents_all($tid);
|
|
|
+
|
|
|
+ // Dropping out the term itself from its array of parents.
|
|
|
+ array_shift($term_parents);
|
|
|
+
|
|
|
+ foreach ($term_parents as $term_parent) {
|
|
|
+ if ($term_parent->tid == $parent_tid) {
|
|
|
+ return TRUE;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ return FALSE;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Make sure the default synonyms field exists.
|
|
|
+ * Format an option for select form element.
|
|
|
*
|
|
|
- * If the field doesn't exist function creates one, if the field exists,
|
|
|
- * the function does nothing.
|
|
|
+ * @param object $term
|
|
|
+ * Fully loaded taxonomy term which is represented by this option
|
|
|
+ * @param string $synonym
|
|
|
+ * If the provided term is represented in this option by a synonym, then
|
|
|
+ * provide it here
|
|
|
+ * @param array $behavior_implementation
|
|
|
+ * Behavior implementation array from which the $synonym comes from
|
|
|
+ *
|
|
|
+ * @return object
|
|
|
+ * An option for select form element
|
|
|
*/
|
|
|
-function synonyms_default_field_ensure() {
|
|
|
- $field = field_info_field(SYNONYMS_DEFAULT_FIELD_NAME);
|
|
|
- if (is_null($field)) {
|
|
|
- $field = array(
|
|
|
- 'field_name' => SYNONYMS_DEFAULT_FIELD_NAME,
|
|
|
- 'cardinality' => FIELD_CARDINALITY_UNLIMITED,
|
|
|
- 'locked' => TRUE,
|
|
|
- 'type' => 'text',
|
|
|
- );
|
|
|
- field_create_field($field);
|
|
|
+function synonyms_select_option($term, $synonym = NULL, $behavior_implementation = NULL) {
|
|
|
+ $key = $synonym ? $term->tid . ':' . drupal_html_class($synonym) : $term->tid;
|
|
|
+ $wording = $term->name;
|
|
|
+ if ($synonym) {
|
|
|
+ $instance = field_info_instance($behavior_implementation['entity_type'], $behavior_implementation['field_name'], $behavior_implementation['bundle']);
|
|
|
+ $wording = format_string($behavior_implementation['settings']['wording'], array(
|
|
|
+ '@synonym' => $synonym,
|
|
|
+ '@term' => $term->name,
|
|
|
+ '@field_name' => drupal_strtolower($instance['label']),
|
|
|
+ ));
|
|
|
}
|
|
|
+ return (object) array(
|
|
|
+ 'option' => array($key => str_repeat('-', $term->depth) . $wording),
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Extract instances that are applicable for being source of synonyms.
|
|
|
+ * Supportive function to build options array with sorting by name logic.
|
|
|
*
|
|
|
- * Walk through all instances of a vocabulary and extract only valid candidates
|
|
|
- * for becoming a source of synonyms for the vocabulary terms.
|
|
|
+ * The function starts from the 0-depth level and starts to recursively build
|
|
|
+ * the options and to sort the labels on each level, then it merges the bottom
|
|
|
+ * to up all the levels maintaining correct order within the final options
|
|
|
+ * array.
|
|
|
*
|
|
|
* @param object $vocabulary
|
|
|
- * Fully loaded vocabulary object
|
|
|
+ * Within which vocabulary to execute the function. Supply here the fully
|
|
|
+ * loaded taxonomy vocabulary object
|
|
|
+ * @param int $parent
|
|
|
+ * Only children of this term will be included in the output. You can supply
|
|
|
+ * 0 which means to include all the terms from the vocabulary
|
|
|
+ * @param int $depth
|
|
|
+ * Used for internal purposes. Clients of this function should supply here 0,
|
|
|
+ * unless they know what they are doing. It is used internally to keep track
|
|
|
+ * of the nesting level
|
|
|
*
|
|
|
* @return array
|
|
|
- * Array of instance arrays
|
|
|
+ * Array of options that can be inserted directly into 'select' form element.
|
|
|
+ * The options will be sorted by name (term or synonym), respecting the
|
|
|
+ * hierarchy restrictions
|
|
|
*/
|
|
|
-function synonyms_instances_extract_applicable($vocabulary) {
|
|
|
- $applicable_field_types = array_keys(synonyms_extractor_info());
|
|
|
- $applicable = array();
|
|
|
+function synonyms_select_sort_name_options_recursive($vocabulary, $parent = 0, $depth = 0) {
|
|
|
+ // We statically cache behavior implementations in order to not DDOS the data
|
|
|
+ // base.
|
|
|
+ $behavior_implementations = drupal_static(__FUNCTION__, array());
|
|
|
+
|
|
|
$bundle = field_extract_bundle('taxonomy_term', $vocabulary);
|
|
|
- foreach (field_info_instances('taxonomy_term', $bundle) as $instance) {
|
|
|
- $field = field_info_field($instance['field_name']);
|
|
|
- if (in_array($field['type'], $applicable_field_types)) {
|
|
|
- $applicable[] = $instance;
|
|
|
+ if (!isset($behavior_implementations[$bundle])) {
|
|
|
+ $behavior_implementations[$bundle] = synonyms_behavior_get('select', 'taxonomy_term', $bundle, TRUE);
|
|
|
+ }
|
|
|
+
|
|
|
+ $options = array();
|
|
|
+ if ($terms = taxonomy_get_tree($vocabulary->vid, $parent, 1, TRUE)) {
|
|
|
+ $options = array();
|
|
|
+ foreach ($terms as $term) {
|
|
|
+ $term->depth = $depth;
|
|
|
+ $options[] = synonyms_select_option($term);
|
|
|
+ foreach ($behavior_implementations[$bundle] as $implementation) {
|
|
|
+ foreach (synonyms_extract_synonyms($term, $implementation) as $synonym) {
|
|
|
+ $options[] = synonyms_select_option($term, $synonym, $implementation);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ usort($options, 'synonyms_select_sort_name');
|
|
|
+
|
|
|
+ // Now recursively go one level nested into each of the terms that we have
|
|
|
+ // on this level.
|
|
|
+ $options_copy = $options;
|
|
|
+ $i = 0;
|
|
|
+ foreach ($options_copy as $v) {
|
|
|
+ $i++;
|
|
|
+ $tid = array_keys($v->option);
|
|
|
+ $tid = $tid[0];
|
|
|
+ if (is_numeric($tid)) {
|
|
|
+ $nested_options = synonyms_select_sort_name_options_recursive($vocabulary, $tid, $depth + 1);
|
|
|
+ $options = array_merge(array_slice($options, 0, $i), $nested_options, array_slice($options, $i));
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- return $applicable;
|
|
|
+ return $options;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Implements hook_views_api().
|
|
|
+ * Supportive function.
|
|
|
+ *
|
|
|
+ * It is used for string comparison within synonyms friendly select widget.
|
|
|
*/
|
|
|
-function synonyms_views_api() {
|
|
|
- return array(
|
|
|
- 'api' => 3,
|
|
|
- 'path' => drupal_get_path('module', 'synonyms') . '/views',
|
|
|
- );
|
|
|
+function synonyms_select_sort_name($a, $b) {
|
|
|
+ return strcasecmp(reset($a->option), reset($b->option));
|
|
|
}
|