我对Drupal很新,并尝试构建一个模块,允许管理员使用关键字标记节点,将节点提升到搜索结果的顶部。
我有一个单独的数据库表用于关键字和相应的节点ID。此表通过hook_query_alter ...
与search_index表进行UNIONedfunction mos_search_result_forcer_query_alter(QueryAlterableInterface &$query) {
if (get_class($query) !== 'PagerDefault') { //<< check this because this function will mod all queries elsewise
return;
}
// create unioned search index result set...
$index = db_select('search_index', 's');
$index->addField('s', 'sid');
$index->addField('s', 'word');
$index->addField('s', 'score');
$index->addField('s', 'type');
$msrfi = db_select('mos_search_result_forcer', 'm');
$msrfi->addField('m', 'nid', 'sid');
$msrfi->addField('m', 'keyword', 'word');
$msrfi->addExpression('(SELECT MAX(score) + m.id / (SELECT MAX(id) FROM {mos_search_result_forcer}) FROM {search_index})', 'score');
$msrfi->addExpression(':type', 'type', array(':type' => 'node'));
$index->union($msrfi);
$tables =& $query->getTables();
$tables['i']['table'] = $index;
return $query;
}
Drupal然后生成几乎正确的查询...
SELECT
i.type AS type, i.sid AS sid, SUM(CAST('10' AS DECIMAL) * COALESCE(( (12.048628015788 * i.score * t.count)), 0) / CAST('10' AS DECIMAL)) AS calculated_score
FROM (
SELECT
s.sid AS sid, s.word AS word, s.score AS score, s.type AS type
FROM
search_index s
UNION SELECT
m.nid AS sid, m.keyword AS word, (
SELECT
MAX(score) + m.id / (SELECT MAX(id) FROM mos_search_result_forcer)
FROM
search_index
) AS score, 'node' AS type
FROM
mos_search_result_forcer m
) i
INNER JOIN node n ON n.nid = i.sid
INNER JOIN search_total t ON i.word = t.word
INNER JOIN search_dataset d ON i.sid = d.sid AND i.type = d.type
WHERE (n.status = '1')
AND( (i.word = 'turtles') )
AND (i.type = 'node')
/* this is the problem line... */
AND( (d.data LIKE '% turtles %' ESCAPE '\\') )
/* ...end problem line */
GROUP BY i.type, i.sid
HAVING (COUNT(*) >= '1')
ORDER BY calculated_score DESC
LIMIT 10 OFFSET 0
......我需要&#34;问题行&#34;阅读...
AND( (d.data LIKE '% turtles %' ESCAPE '\\') OR (d.sid IN (SELECT nid FROM mos_search_result_forcer)) )
...我可以使用什么钩子来添加OR条件?
谢谢,聪明的人!
答案 0 :(得分:0)
基本原则是获取conditions数组,循环遍历并找到问题条件的索引,将其删除,然后重新添加相同的条件以及新条件作为{{3的一部分}}
这是未经测试的,很可能不会逐字逐句地工作,但它应该给你一个起点:
$conditions =& $query->conditions();
$index = FALSE;
$removed_condition = NULL;
for ($i = 0, $l < count($conditions); $i < $l; $i++) {
if ($conditions[$i]['field'] == 'd.data' && $conditions[$i]['operator'] == 'LIKE') {
$index = $i;
$removed_condition = $condition;
break;
}
}
if ($index !== FALSE) {
unset($conditions[$index]);
$sub_query = db_select('mos_search_result_forcer')->fields('mos_search_result_forcer', array('nid'));
$new_condition = db_or()
->condition('d.data', $removed_condition['value'], 'LIKE')
->condition('d.sid', $sub_query, 'IN');
$query->condition($new_condition);
}
答案 1 :(得分:0)
感谢来自@Clive和hook_module_implements_alter
的一些有用的建议,以及大量的试错,我终于解决了这个问题。
这是最终的代码......
function mos_search_result_forcer_module_implements_alter(&$imps, $hook) {
if ($hook !== 'query_alter' || !array_key_exists('mos_search_result_forcer', $imps)) {
return;
}
$imp = $imps['mos_search_result_forcer'];
unset($imps['mos_search_result_forcer']);
$imps['mos_search_result_forcer'] = $imp;
}
function mos_search_result_forcer_query_alter(QueryAlterableInterface &$query) {
if (get_class($query) !== 'PagerDefault') { //<< check this because this function will mod all queries elsewise
return;
}
// create unioned search index result set...
$index = db_select('search_index', 's');
$index->addField('s', 'sid');
$index->addField('s', 'word');
$index->addField('s', 'score');
$index->addField('s', 'type');
$msrfi = db_select('mos_search_result_forcer', 'm');
$msrfi->addField('m', 'nid', 'sid');
$msrfi->addField('m', 'keyword', 'word');
$msrfi->addExpression('(SELECT MAX(score) + m.id / (SELECT MAX(id) FROM {mos_search_result_forcer}) FROM {search_index})', 'score');
$msrfi->addExpression(':type', 'type', array(':type' => 'node'));
$index->union($msrfi);
$tables =& $query->getTables();
$tables['i']['table'] = $index;
// needs special "or" condition to keep from filtering out forced resutls...
class MSRFPagerDefaultHelper extends PagerDefault { //<< override to gain access to protected props
static function msrfHelp(PagerDefault &$pagerDefault) {
$searchQuery =& $pagerDefault->query;
MSRFSearchQueryHelper::msrfHelp($searchQuery);
}
}
class MSRFSearchQueryHelper extends SearchQuery { //<< override to gain access to protected props
static function msrfHelp(SearchQuery &$searchQuery) {
$conditions =& $searchQuery->conditions;
$condition = db_or()->condition($conditions)->condition('d.sid', db_select('mos_search_result_forcer')->fields('mos_search_result_forcer', array('nid')), 'IN');
$searchQuery->conditions = $condition;
}
}
MSRFPagerDefaultHelper::msrfHelp($query);
return $query; //<< i don't think this is needed as var is reffed - just for good measure, i guess
}