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

Contents of /contributions/modules/morelikethis/morelikethis.module

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


Revision 1.1 - (show annotations) (download) (as text)
Fri Oct 3 16:36:58 2008 UTC (13 months, 3 weeks ago) by febbraro
Branch: MAIN
CVS Tags: DRUPAL-6--0-9, HEAD
Branch point for: DRUPAL-6--1
File MIME type: text/x-php
initial commit of new module
1 <?php
2 /*
3 Copyright (C) 2008 by Phase2 Technology.
4 Author(s): Frank Febbraro
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY. See the LICENSE.txt file for more details.
10
11 $Id$
12 */
13 /**
14 * @file morelikethis.module
15 * TODO: - Caching for performance improvements of internal search.
16 * - Add pluggable more like this mechanism that supports:
17 * - the current taxonomy search
18 * - an internal calais search
19 * - yahoo boss search
20 * - internal drupal search
21 * - apache solr search
22 * - any other mechanism that could be imagined
23 */
24
25 /**
26 * Implementation of hook_perm().
27 */
28 function morelikethis_perm() {
29 return array('administer morelikethis');
30 }
31
32 /**
33 * Implementation of hook_theme().
34 */
35 function morelikethis_theme() {
36 return array(
37 'morelikethis_block' => array(
38 'arguments' => array('items' => NULL),
39 ),
40 'morelikethis_item' => array(
41 'arguments' => array('item' => NULL),
42 ),
43 );
44 }
45
46 /**
47 * Implementation of hook_menu().
48 */
49 function morelikethis_menu() {
50
51 $items['admin/settings/morelikethis'] = array(
52 'title' => 'More Like This settings',
53 'description' => 'Configuration for More Like This.',
54 'page callback' => 'drupal_get_form',
55 'page arguments' => array('morelikethis_settings_form'),
56 'access arguments' => array('administer morelikethis'),
57 'file' => 'morelikethis.admin.inc',
58 );
59
60 return $items;
61 }
62
63 /**
64 * Implementation of hook_block().
65 */
66 function morelikethis_block($op = 'list', $delta = 0, $edit = array()) {
67
68 switch ($op) {
69 case 'list':
70 return _mlt_block_list();
71 break;
72 case 'view':
73 return _mlt_block_view($delta);
74 break;
75 }
76 }
77
78 /**
79 * Provide block listing.
80 */
81 function _mlt_block_list(){
82 $blocks = array();
83 $blocks[0] = array(
84 'info' => t('More Like This Block'),
85 );
86 return $blocks;
87 }
88
89 /**
90 * Display More Like This block.
91 */
92 function _mlt_block_view($delta){
93 switch ($delta) {
94 case 0:
95 if(arg(0) == 'node' && is_numeric(arg(1))) {
96 $block['subject'] = t('More Like This');
97 $more = morelikethis_find(arg(1));
98 $block['content'] = theme('morelikethis_block', $more);
99 }
100 break;
101 }
102 return $block;
103 }
104
105 /**
106 * Load term data for a node
107 */
108 function morelikethis_load($vid) {
109 $result = db_query("SELECT term FROM {morelikethis} WHERE vid = %d", $vid);
110 $terms = array();
111 while($term = db_result($result)) {
112 $terms[] = $term;
113 }
114 return $terms;
115 }
116
117
118 /**
119 * Save the data used to render the morelikethis terms.
120 */
121 function morelikethis_save($node, $data) {
122 $terms = drupal_explode_tags($data['terms']);
123 foreach($terms as $term) {
124 db_query("INSERT INTO {morelikethis} (nid, vid, term) VALUES (%d, %d, '%s')", $node->nid, $node->vid, $term);
125 }
126 }
127
128 /**
129 * Attempt to find internal nodes that are like the provided node. Use the list of terms
130 * provided in the morelikethis DNA to search the taxonomy for other nodes matching these
131 * terms. This is the guts behind the internal More Like This search.
132 *
133 * @param nid
134 * The node id to find related content
135 */
136 function morelikethis_find($nid) {
137 $node = node_load($nid);
138 $key = drupal_strtolower($node->type);
139 $types = variable_get("morelikethis_target_types_{$key}", FALSE);
140
141 if(empty($types))
142 return FALSE;
143
144 $terms = morelikethis_load($node->vid);
145 $term_count = count($terms);
146
147 if($term_count == 0)
148 return FALSE;
149
150 $types = array_keys($types);
151 $count = intval(variable_get("morelikethis_count_{$key}", 10));
152 $threshold = floatval(variable_get("morelikethis_threshold_{$key}", 0.0));
153
154 $sql = "SELECT n.nid, n.title, count(*) as hits, count(*)/$term_count as relevance";
155 $sql .= " FROM {node} n";
156 $sql .= " JOIN {term_node} tn ON n.nid = tn.nid";
157 $sql .= " JOIN {term_data} td ON tn.tid = td.tid";
158 $sql .= " WHERE n.nid <> %d";
159 $sql .= " AND n.type IN (" . db_placeholders($types, 'varchar') . ")";
160 $sql .= " AND td.name IN (" . db_placeholders($terms, 'varchar') . ")";
161 $sql .= " GROUP BY n.nid";
162 $sql .= " HAVING relevance >= %f";
163 $sql .= " ORDER BY hits DESC, n.nid DESC";
164 $args = array_merge(array($node->nid), $types, $terms, array($threshold));
165
166 $result = db_query_range($sql, $args, 0, $count);
167
168 $likeness = array();
169 while($likenode = db_fetch_object($result)) {
170 $likeness[] = $likenode;
171 }
172 return $likeness;
173 }
174
175 /**
176 * Implementation of hook_form_alter().
177 *
178 * Add the More Like This fields to the node edit form.
179 */
180 function morelikethis_form_alter(&$form, $form_state, $form_id) {
181
182 if (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] .'_node_form' == $form_id) {
183 $node = $form['#node'];
184 $key = drupal_strtolower($node->type);
185
186 if(!variable_get("morelikethis_enabled_{$key}", FALSE))
187 return;
188
189 if($node->taxonomy) {
190 $options = array();
191 foreach ($node->taxonomy as $term) {
192 $vocab = taxonomy_vocabulary_load($term->vid);
193 $key = $vocab->name;
194
195 if(!array_key_exists($key, $options)) {
196 $options[$key] = array();
197 }
198 // Remove quotes surrounding terms
199 $term_name = preg_replace('/^"(.*)"$/', '\1', $term->name);
200 $options[$key][$term_name] = $term_name;
201 }
202 }
203
204 $terms = drupal_implode_tags(morelikethis_load($node->vid));
205
206 $form['morelikethis'] = array(
207 '#type' => 'fieldset',
208 '#title' => t('More Like This'),
209 '#tree' => TRUE,
210 '#collapsible' => TRUE,
211 '#collapsed' => FALSE,
212 );
213
214 $form['morelikethis']['terms'] = array(
215 '#type' => 'textfield',
216 '#title' => t('More Like This Terms'),
217 '#description' => t('A comma-separated list of terms that will be used as the "identity" of this content item to find more content that is like this. You can select existing taxonomy terms form the list below, or enter in your own manually. Example: election, stock market, "Company, Inc.".'),
218 '#maxlength' => 255,
219 '#default_value' => $terms,
220 );
221
222 if(!empty($options)) {
223 $form['morelikethis']['taxonomy-terms'] = array(
224 '#type' => 'select',
225 '#title' => t('Choose existing terms'),
226 '#description' => t('Selecting terms will put them in the above textfield.'),
227 '#size' => 5,
228 '#options' => $options,
229 );
230 }
231
232 $path = drupal_get_path('module', 'morelikethis');
233 drupal_add_js("$path/morelikethis.js", 'module');
234 }
235 }
236
237 /**
238 * Implementation of hook_nodeapi().
239 */
240 function morelikethis_nodeapi(&$node, $op) {
241 switch ($op) {
242 case 'insert':
243 case 'update':
244 if(property_exists($node, 'morelikethis')) {
245 morelikethis_save($node, $node->morelikethis);
246 }
247 break;
248 case 'delete':
249 db_query('DELETE FROM {morelikethis} WHERE nid = %d', $node->nid);
250 break;
251 case 'view':
252 $more = morelikethis_find($node->nid);
253 if($more) {
254 _morelikethis_build_node_property($node, $more);
255 }
256 break;
257 }
258 }
259
260 /**
261 * Builds the morelikethis property for a node.
262 *
263 * @param $node
264 * The node to add a property that contains More Like This data.
265 * @param $more
266 * An array of More Like This data for the provided node.
267 */
268 function _morelikethis_build_node_property(&$node, $more) {
269 $node->morelikethis = array();
270
271 foreach($more as $item) {
272 $entry = array(
273 '#item' => $item,
274 '#view' => theme('morelikethis_item', $item),
275 );
276 $node->morelikethis[] = $entry;
277 }
278 }
279
280 /**
281 * Theme the body of the More Like This block.
282 *
283 * @param $items
284 * An array of More Like This objects for the provided node.
285 */
286 function theme_morelikethis_block($items){
287 if(!$items)
288 return t('No related items were found.');
289
290 $links = array();
291 foreach($items as $item){
292 $links[] = theme('morelikethis_item', $item);
293 }
294 return theme('item_list', $links);
295 }
296
297 /**
298 * Theme an individual morelikethis item.
299 *
300 * @param $item
301 * An More Like This object for the provided node.
302 */
303 function theme_morelikethis_item($item) {
304 $percentage = sprintf('%.1f%%', $item->relevance * 100);
305 return l("$item->title ($percentage)", "node/$item->nid");
306 }

  ViewVC Help
Powered by ViewVC 1.1.2