updated synonyms to 1.3

This commit is contained in:
Bachir Soussi Chiadmi
2016-11-05 17:52:37 +01:00
parent 86c993f638
commit 8d24211bf5
37 changed files with 4562 additions and 1923 deletions

View File

@@ -0,0 +1,12 @@
<?php
/**
* @file
* Enables Entity Reference field type for search integration.
*/
/**
* Definition of SearchEntityReferenceSynonymsBehavior class.
*/
class SearchEntityReferenceSynonymsBehavior extends EntityReferenceSynonymsBehavior implements SearchSynonymsBehavior {
}

View File

@@ -0,0 +1,14 @@
<?php
/**
* @file
* Interfaces of synonyms behaviors shipped with Synonyms Search module.
*/
/**
* Interface of search integration synonyms behavior.
*/
interface SearchSynonymsBehavior extends SynonymsSynonymsBehavior {
}

View File

@@ -0,0 +1,12 @@
<?php
/**
* @file
* Enables Taxonomy Term Reference field type for search integration.
*/
/**
* Definition of SearchTaxonomySynonymsBehavior class.
*/
class SearchTaxonomySynonymsBehavior extends TaxonomySynonymsBehavior implements SearchSynonymsBehavior {
}

View File

@@ -0,0 +1,12 @@
<?php
/**
* @file
* Enables text and number field types for search integration.
*/
/**
* Definition of SearchTextSynonymsBehavior class.
*/
class SearchTextSynonymsBehavior extends TextSynonymsBehavior implements SearchSynonymsBehavior {
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* @file
* Plugin definition for synonyms search behavior.
*/
$plugin = array(
'title' => t('Search'),
'description' => t('Integrate synonyms with Search module'),
'interface' => 'SearchSynonymsBehavior',
'enabled callback' => 'synonyms_search_behavior_search_enabled',
'disabled callback' => 'synonyms_search_behavior_search_disabled',
);
/**
* Callback for when the behavior is enabled.
*
* Trigger re-indexing of all the nodes that reference terms from the vocabulary
* where the change has taken place.
*/
function synonyms_search_behavior_search_enabled($behavior_definition, $settings, $instance) {
module_load_include('inc', 'synonyms_search', 'synonyms_search.pages');
synonyms_search_reindex_nodes_by_vocabulary(taxonomy_vocabulary_machine_name_load($instance['bundle']));
}
/**
* Callback for when the behavior is disabled.
*
* Trigger re-indexing of all the nodes that reference terms from the vocabulary
* where the change has taken place.
*/
function synonyms_search_behavior_search_disabled($behavior_definition, $behavior_implementation, $instance) {
module_load_include('inc', 'synonyms_search', 'synonyms_search.pages');
synonyms_search_reindex_nodes_by_vocabulary(taxonomy_vocabulary_machine_name_load($instance['bundle']));
}

View File

@@ -0,0 +1,20 @@
name = Synonyms Search
description = "Provides synonyms integration with searching."
package = Taxonomy
core = 7.x
dependencies[] = synonyms
dependencies[] = search
files[] = synonyms_search.test
files[] = includes/SearchSynonymsBehavior.interface.inc
files[] = includes/SearchTextSynonymsBehavior.class.inc
files[] = includes/SearchTaxonomySynonymsBehavior.class.inc
files[] = includes/SearchEntityReferenceSynonymsBehavior.class.inc
; Information added by Drupal.org packaging script on 2015-11-29
version = "7.x-1.3"
core = "7.x"
project = "synonyms"
datestamp = "1448771941"

View File

@@ -0,0 +1,115 @@
<?php
/**
* @file
* Provides synonyms integration with searching.
*/
/**
* Implements hook_ctools_plugin_directory().
*/
function synonyms_search_ctools_plugin_directory($owner, $plugin_type) {
switch ($owner) {
case 'synonyms':
switch ($plugin_type) {
case 'behavior':
return 'plugins/' . $plugin_type;
}
break;
}
}
/**
* Implements hook_taxonomy_term_update().
*/
function synonyms_search_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)) {
$bundle = field_extract_bundle('taxonomy_term', $term);
$behavior_implementations = synonyms_behavior_get('search', 'taxonomy_term', $bundle, TRUE);
$current_search_synonyms = array();
$previous_search_synonyms = array();
foreach ($behavior_implementations as $behavior_implementation) {
$current_search_synonyms = array_merge($current_search_synonyms, synonyms_extract_synonyms($term, $behavior_implementation));
$previous_search_synonyms = array_merge($previous_search_synonyms, synonyms_extract_synonyms($term->original, $behavior_implementation));
}
$diff = array_diff($current_search_synonyms, $previous_search_synonyms);
if (!empty($diff) || count($current_search_synonyms) != count($previous_search_synonyms)) {
module_load_include('inc', 'synonyms_search', 'synonyms_search.pages');
synonyms_search_reindex_nodes_by_terms(array($term->tid));
}
}
}
/**
* Implements hook_node_update_index().
*/
function synonyms_search_node_update_index($node) {
$output = array();
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 search synonyms, we add them 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)) {
foreach ($terms as $v) {
$output[] = $v['tid'];
}
}
}
}
if (!empty($output)) {
$terms = taxonomy_term_load_multiple($output);
$output = array();
foreach ($terms as $term) {
$bundle = field_extract_bundle('taxonomy_term', $term);
$behavior_implementations = synonyms_behavior_get('search', 'taxonomy_term', $bundle, TRUE);
foreach ($behavior_implementations as $implementation) {
$output = array_merge($output, synonyms_extract_synonyms($term, $implementation));
}
}
}
return empty($output) ? '' : '<strong>' . implode($output, ', ') . '</strong>';
}
/**
* Implements hook_term_update_index().
*/
function synonyms_search_term_update_index($term) {
$bundle = taxonomy_vocabulary_load($term->vid);
$bundle = field_extract_bundle('taxonomy_term', $bundle);
$behavior_implementations = synonyms_behavior_get('search', 'taxonomy_term', $bundle, TRUE);
$synonyms = array();
foreach ($behavior_implementations as $implementation) {
$synonyms = array_merge($synonyms, synonyms_extract_synonyms($term, $implementation));
}
return implode(', ', $synonyms);
}
/**
* Implements hook_synonyms_behavior_implementation_info().
*/
function synonyms_search_synonyms_behavior_implementation_info($behavior) {
switch ($behavior) {
case 'search':
return array(
'number_integer' => 'SearchTextSynonymsBehavior',
'number_decimal' => 'SearchTextSynonymsBehavior',
'number_float' => 'SearchTextSynonymsBehavior',
'text' => 'SearchTextSynonymsBehavior',
'taxonomy_term_reference' => 'SearchTaxonomySynonymsBehavior',
'entityreference' => 'SearchEntityReferenceSynonymsBehavior',
);
break;
}
return array();
}

View File

@@ -0,0 +1,68 @@
<?php
/**
* @file
* Supportive functions for the module.
*/
/**
* Mark nodes that reference specific terms for search re-indexing.
*
* This is particularly useful, when the terms in question have been changed.
*
* @param $tids array
* Array of tids of the terms
*/
function synonyms_search_reindex_nodes_by_terms($tids) {
// In order to speed up the process, we will query DB for nid's that reference
// handled to us tids, and at the end we'll trigger their re-indexing just in
// a single SQL query. Probably it is better to use search_touch_node(), but
// that would imply a big amount of SQL queries on some websites.
$found_nids = array();
foreach (field_info_field_map() as $field_name => $v) {
if ($v['type'] == 'taxonomy_term_reference' && isset($v['bundles']['node'])) {
// This field is taxonomy term reference and it is attached to nodes, so
// we will run EntityFieldQuery on it.
$query = new EntityFieldQuery();
$result = $query->entityCondition('entity_type', 'node')
->fieldCondition($field_name, 'tid', $tids, 'IN')
->execute();
if (isset($result['node'])) {
$found_nids = array_merge($found_nids, array_keys($result['node']));
}
}
}
if (!empty($found_nids)) {
db_update('search_dataset')
->fields(array('reindex' => REQUEST_TIME))
->condition('type', 'node')
->condition('sid', $found_nids, 'IN')
->execute();
}
// Integration with Term Search module: reset terms index too.
if (module_exists('term_search')) {
db_update('search_dataset')
->fields(array('reindex' => REQUEST_TIME))
->condition('type', 'term')
->condition('sid', $tids)
->execute();
}
}
/**
* Mark nodes that reference terms from a vocabulary for search re-indexing.
*
* @param $vocabulary object
* Fully loaded vocabulary object
*/
function synonyms_search_reindex_nodes_by_vocabulary($vocabulary) {
$tids = db_select('taxonomy_term_data', 't')
->fields('t', array('tid'))
->condition('vid', $vocabulary->vid)
->execute()
->fetchCol();
if (!empty($tids)) {
synonyms_search_reindex_nodes_by_terms($tids);
}
}

View File

@@ -0,0 +1,367 @@
<?php
/**
* @file
* Tests for the Synonyms Search module.
*/
/**
* Base class for tests of Synonyms Search module.
*/
abstract class AbstractSearchSynonymsWebTestCase extends SynonymsWebTestCase {
protected $behavior = 'search';
/**
* What search type is being tested.
*
* @var string
*/
protected $search_type = 'node';
/**
* Array of terms that will be used for testing.
*
* @var array
*/
protected $terms = array();
/**
* SetUp method.
*/
public function setUp($modules = array()) {
$modules[] = 'synonyms_search';
parent::setUp($modules);
// Create a few terms and synonyms.
$term = (object) array(
'vid' => $this->vocabulary->vid,
'name' => $this->randomName(),
$this->fields['disabled']['field']['field_name'] => array(
LANGUAGE_NONE => array(
array('value' => $this->randomName()),
),
),
);
taxonomy_term_save($term);
$this->terms['no_synonyms'] = $term;
$term = (object) array(
'vid' => $this->vocabulary->vid,
'name' => $this->randomName(),
$this->fields['enabled']['field']['field_name'] => array(
LANGUAGE_NONE => array(
array('value' => $this->randomName()),
),
),
$this->fields['disabled']['field']['field_name'] => array(
LANGUAGE_NONE => array(
array('value' => $this->randomName()),
),
),
);
taxonomy_term_save($term);
$this->terms['one_synonym'] = $term;
$term = (object) array(
'vid' => $this->vocabulary->vid,
'name' => $this->randomName(),
$this->fields['enabled']['field']['field_name'] => array(
LANGUAGE_NONE => array(
array('value' => $this->randomName()),
array('value' => $this->randomName()),
),
),
$this->fields['disabled']['field']['field_name'] => array(
LANGUAGE_NONE => array(
array('value' => $this->randomName()),
),
),
);
taxonomy_term_save($term);
$this->terms['two_synonyms'] = $term;
}
/**
* Retrieve search results.
*
* @param $keyword string
* Keyword to supply to the search mechanism
*
* @return array
* Array of HTML search results. Each element in this array is a single
* search result represented in HTML code as Drupal search mechanism outputs
* it
*/
protected function getSearchResults($keyword) {
$response = $this->drupalGet('search/' . $this->search_type . '/' . $keyword);
$matches = array();
preg_match_all('#\<li[^>]+class="search-result"[^>]*\>(.*?)\</li\>#si', $response, $matches);
return $matches[1];
}
}
/**
* Test Synonyms module integration with Drupal search functionality for nodes.
*/
class NodeSearchSynonymsWebTestCase extends AbstractSearchSynonymsWebTestCase {
/**
* GetInfo method.
*/
public static function getInfo() {
return array(
'name' => 'Synonyms node search integration',
'description' => 'Ensure that Synonyms module correctly integrates with the Drupal search functionality.',
'group' => 'Synonyms',
);
}
/**
* SetUp method.
*/
public function setUp($modules = array()) {
parent::setUp($modules);
// Creating a test content type.
$this->drupalPost('admin/structure/types/add', array(
'name' => 'Synonyms Test Content',
'type' => 'synonyms_test_content',
), 'Save content type');
// Attaching term reference field to the new content type.
$field = array(
'type' => 'taxonomy_term_reference',
'field_name' => 'synonyms_term_enabled',
'cardinality' => FIELD_CARDINALITY_UNLIMITED,
'settings' => array(
'allowed_values' => array(
array(
'vocabulary' => $this->vocabulary->machine_name,
'parent' => 0,
),
),
),
);
$field = field_create_field($field);
$instance = array(
'field_name' => $field['field_name'],
'entity_type' => 'node',
'bundle' => 'synonyms_test_content',
'label' => 'Synonym Terms',
'widget' => array(
'type' => 'synonyms_autocomplete',
),
);
field_create_instance($instance);
}
/**
* Test searching nodes by a term synonym.
*
* Since logically term and its synonyms represent the same entity, the idea
* is that searching by a term synonym should trigger all content referencing
* that term to be included in search results. Additionally we test that when
* a synonym is deleted/edited in a term, corresponding content is no longer
* encountered when searched by ex-synonym.
*/
public function testSearchTermSynonym() {
// Creating a node, which references all the terms we have.
$node = (object) array(
'type' => 'synonyms_test_content',
'title' => $this->randomName(),
'synonyms_term_enabled' => array(LANGUAGE_NONE => array(
array('tid' => $this->terms['no_synonyms']->tid),
array('tid' => $this->terms['one_synonym']->tid),
array('tid' => $this->terms['two_synonyms']->tid),
)),
);
node_save($node);
// Rebuilding Search index.
$this->cronRun();
foreach ($this->terms as $k => $term) {
$this->assertSearchResults($term->name, array($node), 'Searching by name of the term ' . $k);
$items = field_get_items('taxonomy_term', $term, $this->fields['disabled']['field']['field_name']);
if (is_array($items)) {
foreach ($items as $delta => $item) {
$this->assertSearchResults($item['value'], array(), 'Searching by not enabled search integration field value #' . $delta . ' of term ' . $k);
}
}
$items = field_get_items('taxonomy_term', $term, $this->fields['enabled']['field']['field_name']);
if (is_array($items)) {
foreach ($items as $delta => $item) {
$this->assertSearchResults($item['value'], array($node), 'Searching by synonym #' . $delta . ' of the term ' . $k);
}
}
}
// Removing a synonym from the term. Then asserting node got re-indexed with
// new values of synonyms.
$deleted_synonym = array_pop($this->terms['one_synonym']->{$this->fields['enabled']['field']['field_name']}[LANGUAGE_NONE]);
taxonomy_term_save($this->terms['one_synonym']);
$this->cronRun();
$this->assertSearchResults($deleted_synonym['value'], array(), 'Searching by recently deleted synonym of a taxonomy term yields no results.');
// Editing a synonym in a term. Then asserting node got re-indexed with new
// values of synonyms.
$ex_synonym = $this->terms['two_synonyms']->{$this->fields['enabled']['field']['field_name']}[LANGUAGE_NONE][0]['value'];
$this->terms['two_synonyms']->{$this->fields['enabled']['field']['field_name']}[LANGUAGE_NONE][0]['value'] = $this->randomName();
taxonomy_term_save($this->terms['two_synonyms']);
$this->cronRun();
$this->assertSearchResults($ex_synonym, array(), 'Searching by recently changed synonym of a taxonomy term yields no results.');
// We disable entire field from search integration and make sure for all
// synonyms search results are empty.
synonyms_behavior_settings_delete($this->fields['enabled']['instance']['id'], $this->behavior);
$this->cronRun();
foreach ($this->terms as $k => $term) {
$items = field_get_items('taxonomy_term', $term, $this->fields['enabled']['field']['field_name']);
if (is_array($items)) {
foreach ($items as $synonym) {
$this->assertSearchResults($synonym['value'], array(), 'Searching by ' . $k . ' term synonym, which field was recently disabled from search behavior yields no results.');
}
}
}
}
/**
* Assert search results.
*
* @param $keyword string
* Keyword to supply to the search mechanism
* @param $results array
* Array of fully loaded nodes that are expected to be on search results
* @param $message string
* Drupal assertion message to display on test results page
*/
protected function assertSearchResults($keyword, $results, $message) {
$matches = $this->getSearchResults($keyword);
if (count($matches) != count($results)) {
$this->fail($message);
return;
}
$matches = implode('', $matches);
foreach ($results as $node) {
if (strpos($matches, 'node/' . $node->nid) === FALSE) {
$this->fail($message);
return;
}
}
$this->pass($message);
}
}
/**
* Test Synonyms module integration with Drupal search for taxonomy terms.
*/
class TermSearchSynonymsWebTestCase extends AbstractSearchSynonymsWebTestCase {
protected $search_type = 'term';
/**
* GetInfo method.
*/
public static function getInfo() {
return array(
'name' => 'Synonyms term search integration',
'description' => 'Ensure that Synonyms module correctly integrates with the Term Search module.',
'group' => 'Synonyms',
);
}
/**
* SetUp method.
*/
public function setUp($modules = array()) {
$modules[] = 'term_search';
parent::setUp($modules);
$active_searches = variable_get('search_active_modules', array('node', 'user'));
$active_searches[] = 'term_search';
variable_set('search_active_modules', $active_searches);
}
/**
* Test searching terms by their synonyms.
*/
public function testSearchTermSynonym() {
// Rebuilding Search index.
$this->cronRun();
foreach ($this->terms as $k => $term) {
$this->assertSearchResults($term->name, array($term), 'Searching by name of the term ' . $k);
$items = field_get_items('taxonomy_term', $term, $this->fields['disabled']['field']['field_name']);
if (is_array($items)) {
foreach ($items as $delta => $item) {
$this->assertSearchResults($item['value'], array(), 'Searching by not enabled search integration field value #' . $delta . ' of term ' . $k);
}
}
$items = field_get_items('taxonomy_term', $term, $this->fields['enabled']['field']['field_name']);
if (is_array($items)) {
foreach ($items as $delta => $item) {
$this->assertSearchResults($item['value'], array($term), 'Searching by synonym #' . $delta . ' of the term ' . $k);
}
}
}
// Removing a synonym from the term. Then asserting it got re-indexed with
// new values of synonyms.
$deleted_synonym = array_pop($this->terms['one_synonym']->{$this->fields['enabled']['field']['field_name']}[LANGUAGE_NONE]);
taxonomy_term_save($this->terms['one_synonym']);
$this->cronRun();
$this->assertSearchResults($deleted_synonym['value'], array(), 'Searching by recently deleted synonym of a taxonomy term yields no results.');
// Editing a synonym in a term. Then asserting it got re-indexed with new
// values of synonyms.
$ex_synonym = $this->terms['two_synonyms']->{$this->fields['enabled']['field']['field_name']}[LANGUAGE_NONE][0]['value'];
$this->terms['two_synonyms']->{$this->fields['enabled']['field']['field_name']}[LANGUAGE_NONE][0]['value'] = $this->randomName();
taxonomy_term_save($this->terms['two_synonyms']);
$this->cronRun();
$this->assertSearchResults($ex_synonym, array(), 'Searching by recently changed synonym of a taxonomy term yields no results.');
// We disable entire field from search integration and make sure for all
// synonyms search results are empty.
synonyms_behavior_settings_delete($this->fields['enabled']['instance']['id'], $this->behavior);
$this->cronRun();
foreach ($this->terms as $k => $term) {
$items = field_get_items('taxonomy_term', $term, $this->fields['enabled']['field']['field_name']);
if (is_array($items)) {
foreach ($items as $synonym) {
$this->assertSearchResults($synonym['value'], array(), 'Searching by ' . $k . ' term synonym, which field was recently disabled from search behavior yields no results.');
}
}
}
}
/**
* Assert search results.
*
* @param $keyword string
* Keyword to supply to the search mechanism
* @param $results array
* Array of fully loaded terms that are expected to be on search results
* @param $message string
* Drupal assertion message to display on test results page
*/
protected function assertSearchResults($keyword, $results, $message) {
$matches = $this->getSearchResults($keyword);
if (count($matches) != count($results)) {
$this->fail($message);
return;
}
$matches = implode('', $matches);
foreach ($results as $term) {
if (strpos($matches, 'taxonomy/term/' . $term->tid) === FALSE) {
$this->fail($message);
return;
}
}
$this->pass($message);
}
}