/[drupal]/contributions/modules/similar/similar.module
ViewVC logotype

Contents of /contributions/modules/similar/similar.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.13 - (show annotations) (download) (as text)
Fri May 8 21:10:26 2009 UTC (6 months, 2 weeks ago) by deekayen
Branch: MAIN
CVS Tags: HEAD
Changes since 1.12: +145 -149 lines
File MIME type: text/x-php
DRUPAL-7-UNSTABLE-6 compatability
1 <?php
2 // $Id: similar.module,v 1.8.2.4 2009/05/08 14:25:21 deekayen Exp $
3
4 /**
5 * @file
6 * Module that shows a block listing similar entries.
7 * NOTE: Uses MySQL's FULLTEXT indexing for MyISAM tables.
8 *
9 * @author David Kent Norman http://deekayen.net/
10 * @author Arnab Nandi http://arnab.org/
11 */
12
13 /**
14 * Implementation of hook_help().
15 *
16 * @param string $section
17 */
18 function similar_help($path, $arg) {
19 switch ($path) {
20 case 'admin/help#similar':
21 return t('<p>Lists the most similar nodes to the current node.</p>');
22 break;
23 }
24 }
25
26 /**
27 * Implementation of hook_block_list().
28 */
29 function similar_block_list() {
30 $blocks[0]['info'] = t('Similar entries');
31 $blocks[0]['cache'] = BLOCK_CACHE_PER_PAGE | BLOCK_CACHE_PER_ROLE;
32 return $blocks;
33 }
34
35 /**
36 * Implementation of hook_block_configure().
37 */
38 function similar_block_configure($delta = 0) {
39 $form = array();
40 if ($delta == 0) {
41 $form['similar_teaser_enabled'] = array(
42 '#type' => 'radios',
43 '#title' => t('Include teaser text'),
44 '#default_value' => variable_get('similar_teaser_enabled', 0),
45 '#options' => array(t('No'), t('Yes'))
46 );
47 $form['similar_rel_nofollow'] = array(
48 '#type' => 'radios',
49 '#title' => t('Block search engines'),
50 '#description' => t('Adds rel="nofollow" to the HTML source of similar links so search engines won\'t count similar links in their ranking calculations.'),
51 '#default_value' => variable_get('similar_rel_nofollow', 0),
52 '#options' => array(t('No'), t('Yes'))
53 );
54 for ($i=1, $options=array(); $i < 101; $options[$i] = $i, $i+=1);
55 $form['similar_num_display'] = array(
56 '#type' => 'select',
57 '#title' => t('Number of similar entries to find'),
58 '#default_value' => variable_get('similar_num_display', 5),
59 '#options' => $options
60 );
61 $types = _similar_published_node_types();
62 $form['similar_node_types'] = array(
63 '#type' => 'checkboxes',
64 '#multiple' => TRUE,
65 '#title' => t('Node types to display'),
66 '#default_value' => variable_get('similar_node_types', $types),
67 '#options' => $types
68 );
69
70 if (module_exists('taxonomy')) {
71 $names = _similar_taxonomy_names();
72 $form['similar_taxonomy'] = array(
73 '#type' => 'fieldset',
74 '#title' => t('Taxonomy category filter'),
75 '#collapsible' => TRUE,
76 '#collapsed' => TRUE
77 );
78 $form['similar_taxonomy']['similar_taxonomy_filter'] = array(
79 '#type' => 'radios',
80 '#title' => t('Filter by taxonomy categories'),
81 '#default_value' => variable_get('similar_taxonomy_filter', 0),
82 '#options' => array(t('No category filtering'), t('Only show the similar nodes in the same category as the original node'), t('Use global category filtering')),
83 '#description' => t('By selecting global filtering, only nodes assigned to the following selected categories will display as similar nodes, regardless of the categories the original node is or is not assigned to.')
84 );
85 $form['similar_taxonomy']['similar_taxonomy_select'] = array(
86 '#type' => 'fieldset',
87 '#title' => t('Taxonomy categories to display'),
88 '#collapsible' => TRUE,
89 '#collapsed' => TRUE
90 );
91 $form['similar_taxonomy']['similar_taxonomy_select']['similar_taxonomy_tids'] = array(
92 '#type' => 'select',
93 '#default_value' => variable_get('similar_taxonomy_tids', array_keys($names)),
94 '#description' => t('Hold the CTRL key to (de)select multiple options.'),
95 '#options' => $names,
96 '#multiple' => TRUE
97 );
98 }
99 }
100 return $form;
101 }
102
103 /**
104 * Implementation of hook_block_save().
105 */
106 function similar_block_save($delta = 0, $edit = array()) {
107 if ($delta == 0) {
108 variable_set('similar_teaser_enabled', $edit['similar_teaser_enabled']);
109 variable_set('similar_rel_nofollow', $edit['similar_rel_nofollow']);
110 variable_set('similar_num_display', $edit['similar_num_display']);
111 variable_set('similar_node_types', $edit['similar_node_types']);
112 if (module_exists('taxonomy')) {
113 variable_set('similar_taxonomy_filter', $edit['similar_taxonomy_filter']);
114 variable_set('similar_taxonomy_tids', $edit['similar_taxonomy_tids']);
115 }
116 }
117 }
118
119 /**
120 * Implementation of hook_block_view().
121 */
122 function similar_block_view($delta = 0) {
123 if (arg(0) == 'node' && is_numeric(arg(1)) && arg(2) != 'edit') {
124 $node = node_load(arg(1));
125 }
126 else {
127 return;
128 }
129
130 $similar_node_types = variable_get('similar_node_types', _similar_published_node_types());
131
132 if ($node->nid > 0 && !empty($similar_node_types[$node->type])) {
133 unset($similar_node_types);
134
135 switch ($delta) {
136 case 0:
137 // The subject is displayed at the top of the block. Note that it should
138 // be passed through t() for translation.
139 $block['subject'] = t('Similar entries');
140 $block['content'] = theme('similar_content', $node);
141 }
142 }
143 return empty($block['content']) ? '' : $block;
144 }
145
146 /**
147 * Query for published node types
148 *
149 * @link http://drupal.org/node/33444
150 * @return array
151 */
152 function _similar_published_node_types() {
153 $types = array();
154 $result = db_query('SELECT DISTINCT(n.type) FROM {node} n WHERE n.status <> 0 ORDER BY n.type ASC');
155 while ($type = $result->fetchObject()) {
156 $types[$type->type] = $type->type;
157 }
158 return $types;
159 }
160
161 /**
162 * Query for taxonomy names
163 *
164 * @link http://drupal.org/node/51041
165 * @return array
166 */
167 function _similar_taxonomy_names() {
168 $names = array();
169 $result = db_query('SELECT d.tid, v.vid, v.name AS vocab_name, d.name AS data_name FROM {taxonomy_term_data} d, {taxonomy_vocabulary} v WHERE v.vid = d.vid ORDER BY v.name, d.name ASC');
170 while ($data = $result->fetchObject()) {
171 $names[$data->tid] = $data->vocab_name . ': ' . $data->data_name;
172 }
173 return $names;
174 }
175
176 /**
177 * Query for taxonomies a node belongs to
178 *
179 * @link http://drupal.org/node/51041
180 * @return array
181 */
182 function _similar_taxonomy_membership($nid) {
183 $tids = array();
184 $result = db_query('SELECT t.tid FROM {taxonomy_term_node} t WHERE t.nid = :nid', array(':nid' => $nid));
185 while ($data = $result->fetchObject()) {
186 $tids[$data->tid] = $data->tid;
187 }
188 return $tids;
189 }
190
191 /**
192 * Some characters just shouldn't be in node type names
193 */
194 function _similar_content_type_escape(&$item) {
195 $item = str_replace(array("\x00", "\n", "\r", "\\", "'", "\"", "\x1a"), '', $item);
196 }
197
198 /**
199 * SQL injection prevention. Probably overkill.
200 */
201 function _similar_force_int(&$item) {
202 $item = (int)$item;
203 }
204
205 /**
206 * Implementation of hook_theme().
207 *
208 * @return array
209 */
210 function similar_theme() {
211 return array(
212 'similar_content' => array(
213 'arguments' => array('node' => NULL)
214 )
215 );
216 }
217
218 /**
219 * Queries the database for similar entries and puts them in a HTML list
220 *
221 * @param object $node
222 * @return string
223 */
224 function theme_similar_content($node) {
225 $items = array();
226
227 $text = "$node->title $node->body";
228 $teaser = variable_get('similar_teaser_enabled', 0);
229
230 $types = _similar_published_node_types();
231 $types = variable_get('similar_node_types', $types);
232 array_walk($types, '_similar_content_type_escape');
233
234 $query = db_select('node_revision', 'r');
235 $query->addField('r', 'nid', 'nid');
236 $query->addExpression('MATCH(r.body, r.title) AGAINST (:matchtext)', 'score', array(':matchtext' => $text));
237 $query->innerJoin('node', 'n', 'r.nid = n.nid AND r.vid = n.vid');
238
239 if (module_exists('taxonomy') && (variable_get('similar_taxonomy_filter', 0) == 2 && $taxonomy_tids = variable_get('similar_taxonomy_tids', array()))
240 || (variable_get('similar_taxonomy_filter', 0) == 1 && $taxonomy_tids = _similar_taxonomy_membership($node->nid))) {
241
242 array_walk($taxonomy_tids, '_similar_force_int');
243
244 $query->innerJoin('taxonomy_term_node', 't', 'n.nid = t.nid AND t.tid IN (:tids)', array(':tids' => $taxonomy_tids));
245 }
246
247 $query->where("MATCH(r.body, r.title) AGAINST (:wheretext)", array(':wheretext' => $text));
248 $query->condition('n.status', 0, '<>');
249 $query->condition('r.nid', $node->nid, '<>');
250 $query->condition('n.type', $types, 'IN');
251 $query->groupBy('nid');
252 $query->orderBy('score', 'DESC');
253 $query->orderBy('r.vid', 'DESC');
254 $query->range(0, variable_get('similar_num_display', 5));
255 $result = $query->execute();
256
257 while ($node = $result->fetchObject()) {
258 $content = node_load($node->nid);
259 if ($teaser) {
260 $items[] = '<div class="similar-title">' .
261 l($content->title,
262 'node/' . $node->nid,
263 array(
264 'attributes' => variable_get('similar_rel_nofollow', 0) ? array('rel' => 'nofollow') : NULL,
265 'absolute' => TRUE
266 )
267 ) .
268 '</div><div class="similar-teaser">' . check_markup($content->teaser, $content->format, FALSE) . '</div>';
269 }
270 else {
271 $items[] = l(
272 $content->title,
273 'node/' . $node->nid,
274 array('attributes' => variable_get('similar_rel_nofollow', 0) ? array('rel' => 'nofollow') : NULL)
275 );
276 }
277 }
278
279 return sizeof($items) > 0 ? theme('item_list', $items) : '';
280 }

  ViewVC Help
Powered by ViewVC 1.1.2