/[drupal]/contributions/modules/ed_classified/ed_classified_utils.inc
ViewVC logotype

Contents of /contributions/modules/ed_classified/ed_classified_utils.inc

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


Revision 1.4 - (show annotations) (download) (as text)
Sun Sep 13 03:06:58 2009 UTC (2 months, 2 weeks ago) by milesgillham
Branch: MAIN
CVS Tags: HEAD
Changes since 1.3: +23 -7 lines
File MIME type: text/x-php
stable checkin
1 <?php
2 // $Id: ed_classified_utils.inc,v 1.3 2009/09/11 04:01:36 milesgillham Exp $
3
4 /**
5 * @file
6 * Simple text-based classified ads module.
7 * Michael Curry, Exodus Development, Inc.
8 * exodusdev@gmail.com
9 * for more information, please visit http://exodusdev.com/drupal/modules/classified.module
10 * Copyright (c) 2006, 2007 Exodus Development, Inc. All Rights Reserved.
11 * Licensed under the terms of the GNU Public License (GPL) version 2. Please see LICENSE.txt for
12 * license terms. Possession and use of this code signifies acceptance of license
13 * terms.
14 */
15
16 /**
17 * taxonomy_vocabulary_load() is in Drupal 6, not Drupal 5
18 */
19 if (!function_exists('taxonomy_vocabulary_load')) {
20 function taxonomy_vocabulary_load($vid) {
21 // Drupal 5
22 return taxonomy_get_vocabulary(_ed_classified_get_vid());
23 }
24 }
25
26 /**
27 * config variable helpers
28 */
29
30 function _ed_classified_cfg_varname($name) {
31 // ensure unique varnames for this module
32 return EDI_CLASSIFIED_MODULE_NAME .'_'. $name;
33 }
34
35 function _ed_classified_variable_get($name, $defval, $log=FALSE) {
36 $val = variable_get(_ed_classified_cfg_varname($name), $defval);
37 if ($log) {
38 _edi_wd(sprintf('variable_get \'%s\'= \'%s\'',
39 _ed_classified_cfg_varname($name),
40 $val));
41 }
42 return $val;
43 }
44
45 function _ed_classified_variable_set($name, $newval, $log=FALSE) {
46 if ($log) {
47 _edi_wd(sprintf('variable_set \'%s\' changed from \'%s\' to \'%s\'',
48 _ed_classified_cfg_varname($name),
49 _ed_classified_variable_get($name, ''),
50 $newval));
51 }
52 variable_set(_ed_classified_cfg_varname($name), $newval);
53 }
54
55 /**
56 * Convert db_query results to an array
57 */
58 function _ed_classified_query_results_to_array($qr) {
59 $arr = array();
60 while ($info = db_fetch_object($qr)) {
61 $arr[] = $info;
62 }
63 return $arr;
64 }
65
66 /**
67 * Helper function to determine the single ad category name to which this node belongs.
68 */
69 function _ed_classified_get_primary_category($node) {
70 // lifted from _nodeapi implementation - crude, need to find out if there's a better way to get the single term for this node.
71 $terms = taxonomy_node_get_terms_by_vocabulary($node, _ed_classified_get_vid());
72 $term = array_pop($terms);
73 if ($term) {
74 $vocabulary = taxonomy_vocabulary_load(_ed_classified_get_vid());
75 if ($parents = taxonomy_get_parents_all($term->tid)) {
76 return $parents[0];
77 }
78 }
79 return 0;
80 }
81
82 /**
83 * convert days to # seconds
84 */
85
86 function _ed_classified_days_to_seconds($days) {
87 return $days * 86400; // 60 * 60 * 24 = 86400
88 }
89
90
91 /**
92 * Is a node really a classified ad?
93 */
94
95 function _ed_classified_node_is_classified($node) {
96 return EDI_CLASSIFIED_MODULE_NAME == $node->type;
97 }
98
99 /**
100 * Is a tid a 'classified' term? Is a tid a child of our taxonomy?
101 * @param $tid The term id to check.
102 * @return true if the term is a child of our vocabulary.
103 */
104
105 function _ed_tid_is_classified_term($tid) {
106 $vid = _ed_classified_get_vid();
107 $vocab = taxonomy_vocabulary_load($vid);
108 $term = taxonomy_get_term($tid);
109 if ($vocab->hierarchy && $vocab->module == EDI_CLASSIFIED_MODULE_NAME) {
110 return $term->vid == $vid;
111 }
112 else {
113 //
114 // TODO: warn user about problems in a non-log-filling way.
115 // _edi_wd(t('Internal error: Vocabulary !vid (@vocab_name) is not our dedicated classified ads vocabulary - someone has tampered with the vocabulary, or our stored variables.', array('!vid' => $vid, '@vocab_name' => $vocab->name)), WATCHDOG_ERROR);
116 return FALSE; // sanity check: not possible since the vocab is not hierarchical or is not our vocabulary
117 }
118 }
119
120 /**
121 * Get default ad duration in seconds
122 */
123
124 function _ed_classified_get_default_ad_duration_in_seconds() {
125 $duration = _ed_classified_days_to_seconds(_ed_classified_variable_get('default_ad_duration', EDI_CLASSIFIED_VAR_DEF_EXPIRATION_DAYS));
126 return $duration;
127 }
128
129 /**
130 * Find the longest duration, in days, for a given set of terms
131 * @param $terms, an array of vid/tid pairs with vid as the key
132 * sub-arrays are allowed, for example:
133 * Array = (
134 * [63]=>5,
135 * [10]=> Array ([0]=>234, [1]=>984)
136 * )
137 * equivalent to:
138 * Array = (
139 * [63]=>5,
140 * [10]=>234,
141 * [10]=>984
142 * )
143 * @return the duration, in days, of the largest duration found.
144 */
145 function _ed_classified_get_longest_duration($terms) {
146 $duration = 0;
147 if (!empty($terms)) {
148 // Normally we expect an array of taxonomy terms
149 if (is_array($terms)) {
150 reset($terms);
151 while (list($key, $val) = each($terms)) {
152 if (is_array($val)) {
153 reset($val);
154 while (list($subkey, $subval) = each($val)) {
155 $d = _ed_classified_get_duration(array($key => $subval));
156 if ($d > $duration) $duration = $d;
157 }
158 }
159 else {
160 $d = _ed_classified_get_duration(array($key => $val));
161 if ($d > $duration) $duration = $d;
162 }
163 }
164 }
165 }
166 // If we couldn't find a duration then set to default rather than zero
167 if (0 == $duration) {
168 $duration = _ed_classified_get_default_ad_duration_in_seconds();
169 }
170 return $duration;
171 }
172
173 /**
174 * Get stats
175 */
176 function ed_classified_get_ad_stats() {
177 return theme('ed_classified_ads_stats');
178 }
179
180 function ed_classified_get_adcount($only_published) {
181 $status = '';
182 if ($only_published) $status = 'status=1 AND';
183 $qr = db_query("SELECT COUNT(nid) as c FROM {node} WHERE ". $status ." type='ed_classified';");
184 $o = db_fetch_object($qr);
185 return $o->c;
186 }
187 /**
188 * Get ad count for time range
189 */
190 function ed_classified_get_adcount_for_time_range($start_time, $end_time, $only_published) {
191 $status = '';
192 if ($only_published) $status = 'status=1 AND';
193 $qr = db_query("SELECT COUNT(nid) as c FROM {node} WHERE ". $status ." type='ed_classified' AND created >= %d AND created <=%d;", $start_time, $end_time);
194 $o= db_fetch_object($qr);
195 return $o->c;
196 }
197
198 /**
199 * Get a list of popular ads for block use
200 */
201 function ed_classified_get_popular_ads_list() {
202 $output = '';
203 $have_statistics = _ed_classified_module_exists('statistics');
204 if ($have_statistics) {
205 $q = db_query("SELECT n.nid, n.title, n.created, n.changed, s.totalcount as counter FROM {node_counter} s INNER JOIN {node} n ON s.nid = n.nid WHERE n.status = 1 AND n.type = '%s' ORDER BY s.totalcount DESC LIMIT %d;", EDI_CLASSIFIED_MODULE_NAME, _ed_classified_variable_get('block_popular_limit', 4));
206 $output = theme('ed_classified_ads_block', _ed_classified_query_results_to_array($q), FALSE, TRUE, TRUE);
207 }
208 return $output;
209 }
210
211
212 /**
213 * Get a list of latest ads for block use
214 */
215 function ed_classified_get_latest_ads_list() {
216 // Show recent nodes, but only if they haven't expired
217 $q = db_query('SELECT n.title, n.nid, n.created AS timestamp, n.changed'
218 .' FROM {node} AS n, {edi_classified_nodes} AS ec'
219 .' WHERE n.type = \'ed_classified\' AND n.status = 1 AND n.nid = ec.nid AND n.vid = ec.vid AND ec.expires_on > '. REQUEST_TIME
220 .' ORDER BY created DESC LIMIT %d;', _ed_classified_variable_get('block_latest_limit', 4));
221
222 return theme('ed_classified_ads_block', _ed_classified_query_results_to_array($q), TRUE, FALSE, TRUE );
223 }
224
225 /**
226 * expire old ads
227 */
228
229 function _ed_classified_expire_ads($time) {
230 // mark ads matching criteria. Set $node->status=>unpublished,
231 $query = _ed_classified_get_aged_ads(0, $time, 1); // get published but old ads
232 while ($node = db_fetch_object($query)) {
233 _ed_classified_unpublish_ad($node->nid);
234 _ed_classified_notify_user_of_ad_expiration($node);
235 }
236 }
237
238
239
240 /**
241 * Get a query result with any ads that have expired prior to a given date, and having a specific publish status
242 */
243 function _ed_classified_get_aged_ads($expire_time_start, $expire_time_end, $status=1) {
244 return db_query("SELECT * FROM {node} n, {edi_classified_nodes} ec WHERE n.type='ed_classified' AND n.vid = ec.vid AND n.status = %d AND (ec.expires_on >= %d AND ec.expires_on <= %d)", $status, $expire_time_start, $expire_time_end );
245 }
246
247
248 /**
249 * Get the expiration date of a classified ad node
250 */
251 function ed_classified_get_ad_expiration($node) {
252 $expires = 0;// TODO: need windows-compatible old date - use time()?
253 $q = db_query("SELECT expires_on FROM {edi_classified_nodes} ecn WHERE ecn.nid = '%d' AND ecn.vid = '%d'", $node->nid, $node->vid);
254 if ($q) {
255 $expires = db_result($q);
256 }
257 return $expires;
258 }
259
260 /**
261 * Get settings 'banner'
262 */
263 function _ed_classified_settings_get_banner(&$form) {
264 $name = EDI_CLASSIFIED_MODULE_NAME;
265 $d = '<a target="_blank" href="https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=exodus.paypal%40gmail.com&item_name='. $name .'&item_number= '. $name .'-donation&page_style=PayPal&no_shipping=1&return=http%3A%2F%2Fexodusdev.com%2Fproducts&cancel_return=http%3A%2F%2Fexodusdev.com%2Fproducts&no_note=1&tax=0&currency_code=USD&lc=US&bn=PP%2dDonationsBF&charset=UTF%2d8"><img src="http://www.paypal.com/en_US/i/btn/x-click-but7.gif" alt="Support ongoing development!" title="Support ongoing development!"></a>';
266 $form['module_banner'] = array('#type' => 'markup',
267 '#value' => '<div style="border: solid 1px #eee; margin: .5em; padding: .5em;"><div style="float:right;">'. $d .'</div><strong>Module development by <a href="http://exodusdev.com">Exodus Development</a></strong>.<br/>');
268 $form['module_id'] = array('#type' => 'markup', '#value' => EDI_CLASSIFIED_MODULE_VERSION .'<br/></div>');
269 }
270
271 /**
272 * do the sanity-check dance.
273 */
274 function _ed_classified_check_settings(&$form) {
275 $vid = _ed_classified_get_vid();
276 $taxonomy = taxonomy_get_tree($vid);
277 $warning ="";
278 if (empty($taxonomy)) {
279 if (!empty($vid)) {
280 $url = "admin/content/taxonomy/$vid/add/term";
281 $url = l('taxonomy administration', $url);
282 $warning = t('<div class="error">It appears that you have not configured any vocabulary terms to be used with the Classified Ads module. This module will not function correctly until you define vocabulary terms for vocabulary id !vid. Please visit !url to add terms such as "For Sale" or "Wanted" (or other categories as appropriate for your needs).</div>', array('!url' => $url, '!vid' => $vid));
283 }
284 else {
285 $url='http://exodusdev.com/drupal/modules/ed_classified.module';
286 $url=l('the project homepage', $url);
287 $warning = t('<div class="error">The classified ads vocabulary settings are not configured correctly. This is mostly likely due to a failed installation or an administrator deleting the automatically configured taxonomy or other problems. Please visit the online handbook page(s) at !url.</div>', array('!url' => $url));
288 }
289 $form['warning'] = array('#type' => 'markup', '#value' => $warning);
290 return FALSE;
291 }
292 return TRUE;
293 }
294
295 /**
296 * Get just the raw text describing expiration date
297 */
298 function _ed_classified_get_ending_date_string($ad_expiration_date) {
299 // TODO: get time string for how long ago expired
300 $interval = $ad_expiration_date - REQUEST_TIME;
301 $expired = FALSE;
302 if ($interval < 0) {
303 $interval = -$interval; $expired =TRUE;
304 }
305 $str = '';
306 if ($ad_expiration_date != 0) {
307 $str = sprintf(t('%s on %s (%s%s)'),
308 $expired ? t('expired') : t('expires'),
309 format_date($ad_expiration_date), format_interval($interval, 2),
310 $expired ? t(' ago') : '');
311 }
312 return $str;
313 }
314
315
316 /**
317 * Helper function: does $expiration date expire "soon" (soon depends on who you ask)
318 */
319 function _ed_classified_ad_expires_soon($expiration_date) {
320 return ($expiration_date - REQUEST_TIME > 0 && ($expiration_date - REQUEST_TIME) < _ed_classified_days_to_seconds(3)); // TODO: use config var
321 }
322
323 /**
324 * return true if ad has expired
325 */
326 function _ed_classified_ad_expired_already($expiration_date) {
327 return $expiration_date <= REQUEST_TIME;
328 }
329 /**
330 * Returns (and possibly creates) a new vocabulary for classified
331 * Lifted from image.module.
332 * TODO: Create some built-in terms for the created taxonomy: Miscellaneous, Cars, Pets, etc. (look at craigslist for inspiration)
333 */
334 function _ed_classified_get_vid() {
335 $vid = _ed_classified_variable_get('vocabulary', '');
336 if (empty($vid)) {
337 // Check to see if classified ads vocabulary exists
338 $vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE module='%s'", EDI_CLASSIFIED_MODULE_NAME));
339 if (!$vid) {
340 _edi_wd("Classified Ads vocabulary not found - creating taxonomy.");
341 $vocabulary
342 = array('name' => _ed_classified_displayname() . t(' Category'),
343 'description' => t('Vocabulary required by Classified Ads (ed_classified) module. <strong>Warning: You should not delete this vocabulary unless you intend to uninstall (or have already uninstalled) the Classified Ads module.</strong>'),
344 'multiple' => '0',
345 'required' => '1',
346 'hierarchy' => '1',
347 'relations' => '0',
348 'module' => EDI_CLASSIFIED_MODULE_NAME,
349 'nodes' => array(EDI_CLASSIFIED_MODULE_NAME => 1));
350 taxonomy_save_vocabulary($vocabulary);
351 $vid = $vocabulary['vid'];
352 $msg = "Classified Ads taxonomy". $vocabulary->name ." (id=$vid) created.";
353 _edi_wd($msg);
354 drupal_set_message($msg);
355 // TODO: create standard terms and subterms specified in external file (or, at a minimum, create a few standard categories)
356 // taxonomy_save_term(...);
357 }
358 _ed_classified_variable_set('vocabulary', $vid);
359 }
360
361 return $vid;
362 }
363
364 /**
365 * Make a 'path' to a category view for a given tid.
366 */
367
368 function _ed_classified_make_category_path($tid) {
369 return drupal_get_path_alias(EDI_CLASSIFIED_PATH_NAME .'/tid/'. $tid);
370 }
371
372 /**
373 * Determine, in a version-friendly way, if a module exists.
374 * some folks have decided to change module_exist() to module_exists() for 4.8/5.0. see: http://drupal.org/node/79601
375 */
376 function _ed_classified_module_exists($module) {
377 $module_exists = FALSE;
378 if (function_exists('module_exist'))
379 $module_exists = module_exist($module); // 4.7
380 if (function_exists('module_exists'))
381 $module_exists = module_exists($module); // 4.8/5.0?
382 return $module_exists;
383 }
384
385 /**
386 * shortcut - log something to the watchdog log
387 */
388 function _edi_wd($message, $severity = WATCHDOG_NOTICE, $link = NULL) {
389 switch (reset(explode('.', DRUPAL_VERSION))) {
390 case 5:
391 watchdog(EDI_CLASSIFIED_MODULE_NAME, $message, $severity, $link);
392 break;
393 case 6:
394 case 7:
395 watchdog(EDI_CLASSIFIED_MODULE_NAME, $message, NULL, $severity, $link);
396 break;
397 }
398 }
399
400 function _edi_safe_date_fmt($date) {
401 return ($date ==0) ? "_the beginning of time_" : format_date($date);
402 }
403 /**
404 * Determine whether a node is expired given a target timestamp
405 * An ad is considered to have 'expired' if the $time parameter
406 * is larger than the node's expires_on field.
407 */
408
409 function ed_classified_ad_expired($node, $time) {
410 if ($node->type != EDI_CLASSIFIED_MODULE_NAME)
411 return FALSE;
412 return ($time >= $node->expires_on);
413 }
414
415 /**
416 * Helper gets content display name
417 */
418
419 function _ed_classified_displayname() {
420 switch (reset(explode('.', DRUPAL_VERSION))) {
421 case 5:
422 case 6:
423 $name = node_get_types('name', 'ed_classified');
424 break;
425 case 7:
426 $name = node_type_get_name('ed_classified');
427 break;
428 }
429 if (isset($name)) {
430 return $name;
431 }
432 else {
433 return 'undefined';
434 }
435 }
436
437 function _ed_classified_displayname_parms() {
438 $name = _ed_classified_displayname();
439 $parms=array('@name' => $name, '!name' => $name, '%name' => $name );
440 return $parms;
441 }
442
443 /**
444 * Make a node edit link
445 */
446 function _ed_classified_make_edit_link($node, $text, $attributes=array()) {
447 return l($text, "node/$node->nid/edit", array('attributes' => $attributes));
448 }
449
450 /**
451 * Get duration in days for taxonomy term (array of tids, indexed by vid);
452 * Expecting array of size 1, so any more is ignored
453 * if nothing set, use the default value
454 * TODO - if a single value, not an array, then assume the vid to be the
455 * Classified Ads vid
456 */
457 function _ed_classified_get_duration($term) {
458 $duration=0;
459 reset($term);
460 list($vid, $tid) = each($term);
461 $def = _ed_classified_variable_get('default_ad_duration', EDI_CLASSIFIED_VAR_DEF_EXPIRATION_DAYS);
462 $name = 'vid_'. $vid .'_tid_'. $tid .'_duration';
463 $duration = _ed_classified_variable_get($name, $def);
464 return $duration;
465 }
466
467
468 // generic debug function
469 /**
470 function _dbg($thing, $heading=NULL) {
471 drupal_set_message("<strong>$heading</strong><pre>".htmlspecialchars(print_r($thing, true)).'</pre>');
472 }
473
474 */

  ViewVC Help
Powered by ViewVC 1.1.2