/[drupal]/contributions/modules/simplefeed/simplefeed_item.module
ViewVC logotype

Contents of /contributions/modules/simplefeed/simplefeed_item.module

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


Revision 1.52 - (show annotations) (download) (as text)
Fri Feb 8 00:48:16 2008 UTC (21 months, 2 weeks ago) by csevb10
Branch: MAIN
CVS Tags: DRUPAL-6--1-0, HEAD
Branch point for: DRUPAL-6--1
Changes since 1.51: +2 -2 lines
File MIME type: text/x-php
Purely aesthetic modifications to fix breaks with standard Drupal coding practice.
1 <?php
2 // $Id: simplefeed_item.module,v 1.51 2007/11/16 17:48:37 m3avrck Exp $
3
4 /**
5 * @file
6 * A node feed item.
7 */
8
9
10 /**
11 * Implementation of hook_init().
12 */
13 function simplefeed_item_init() {
14 // ensure we are not serving a cached page
15 if (function_exists('drupal_set_content')) {
16 // we don't do this in hook_menu to ensure the files are already included when
17 // views_menu is executed
18 if (module_exists('views')) {
19 include_once('./'. drupal_get_path('module', 'simplefeed') .'/simplefeed_item_views.inc');
20 }
21 }
22 }
23
24
25 /**
26 * Implementation of hook_perm().
27 */
28 function simplefeed_item_perm() {
29 return array('create feed items', 'edit own feed items', 'edit feed items');
30 }
31
32
33 /**
34 * Implementation of hook_access().
35 */
36 function simplefeed_item_access($op, $node) {
37 global $user;
38
39 switch ($op) {
40 case 'create':
41 return user_access('create feed items');
42 break;
43
44 case 'update':
45 case 'delete':
46 // users who create a feed may edit or delete it later, assuming they have the necessary permissions
47 if ((user_access('edit own feed items') && ($user->uid == $node->uid)) || user_access('edit feed items')) {
48 return TRUE;
49 }
50 break;
51 }
52 }
53
54
55 /**
56 * Implementation of hook_node_info().
57 */
58 function simplefeed_item_node_info() {
59 return array(
60 'feed_item' => array(
61 'name' => t('Feed Item'),
62 'module' => 'simplefeed_item',
63 'description' => t('An item that is part of a parent feed.')
64 )
65 );
66 }
67
68
69 /**
70 * Implementation of hook_form().
71 */
72 function simplefeed_item_form(&$node) {
73 $type = node_get_types('type', $node);
74
75 $form['title'] = array(
76 '#type' => 'textfield',
77 '#title' => check_plain($type->title_label),
78 '#required' => TRUE,
79 '#default_value' => $node->title,
80 '#weight' => -5,
81 );
82 $form['body_filter']['body'] = array(
83 '#type' => 'textarea',
84 '#title' => check_plain($type->body_label),
85 '#default_value' => $node->body,
86 '#rows' => 3,
87 );
88 $form['body_filter']['format'] = filter_form($node->format);
89
90 $form['url'] = array(
91 '#type' => 'textfield',
92 '#title' => t('URL'),
93 '#description' => t('The URL for this feed item.'),
94 '#maxlength' => 255,
95 '#default_value' => isset($node->url) ? $node->url : 'http://www.',
96 '#required' => TRUE
97 );
98
99 $form['feed_item_settings'] = array(
100 '#type' => 'fieldset',
101 '#title' => t('Feed item settings'),
102 '#collapsible' => TRUE,
103 '#collapsed' => TRUE,
104 );
105
106 // note all feed items are linked to their parent feed through the feed's nid
107 // this allows the main feed to be revisioned (e.g., change title, description, etc.)
108 // but still keep the same list of feed items
109 // we select from the node table to get the latest revision's data
110 $feeds = array();
111 $result = db_query("SELECT title, nid FROM {node} WHERE type = 'feed'");
112 while ($feed = db_fetch_object($result)) {
113 $feeds[$feed->nid] = $feed->title;
114 }
115
116 // can't add a feed item if no feeds exist
117 if (count($feeds) < 1) {
118 drupal_set_message(t('No feeds found. You must first <a href="!create_feed">create a feed</a> before adding feed items.', array('!create_feed' => url('node/add/feed'))), 'error');
119 }
120
121 $form['feed_item_settings']['iid'] = array('#type' => 'value', '#value' => $node->iid);
122
123 $form['feed_item_settings']['fid'] = array(
124 '#type' => 'select',
125 '#title' => t('Select parent feed'),
126 '#description' => t('Select the parent feed for this feed item.'),
127 '#options' => $feeds,
128 '#default_value' => $node->fid,
129 );
130
131 if (user_access('administer feeds')) {
132 $period = array(0 => t('Never')) + drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 4838400, 9676800), 'format_interval');
133 $form['feed_item_settings']['expires'] = array(
134 '#type' => 'select',
135 '#title' => t('Discard item older than'),
136 '#default_value' => isset($node->expires) ? $node->expires : variable_get('simplefeed_expires', 86400),
137 '#options' => $period,
138 '#description' => t('This feed item will be automatically discarded. Requires !cron to be running.', array('!cron' => l('cron', 'admin/logs/status')))
139 );
140 }
141 else {
142 $form['feed_item_settings']['expires'] = array('#type' => 'value', '#value' => variable_get('simplefeed_expires', 86400));
143 }
144
145 return $form;
146 }
147
148
149 /**
150 * Implementation of hook_validate().
151 *
152 * @todo - currently there is no check for duplicate feed items if entered manually
153 * we would need to have SimplePie library generate a hash for this feed item
154 */
155 function simplefeed_item_validate($node) {
156 $valid_url = "`(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?`";
157 $url = trim($node->url);
158
159 if (!preg_match($valid_url, $url)) {
160 form_set_error('url', t('The URL entered is not valid. It should be in the format of: <em>http://www.example.com/link/to/feed/item.html</em>'));
161 }
162
163 if (!$node->fid) {
164 form_set_error('fid', t('You must select a valid parent feed.'));
165 }
166 }
167
168
169 /**
170 * Implementation of hook_load().
171 */
172 function simplefeed_item_load($node) {
173 $additions = db_fetch_object(db_query('SELECT iid, fid, expires, url FROM {simplefeed_feed_item} WHERE vid = %d', $node->vid));
174 return $additions;
175 }
176
177
178 /**
179 * Implementation of hook_insert().
180 *
181 * @todo - currently feed items that are manually created have blank iid -- need a way to invoke SimplePie to generate an iid for duplicate checking
182 */
183 function simplefeed_item_insert($node) {
184 db_query("INSERT INTO {simplefeed_feed_item} (vid, nid, iid, fid, expires, url) VALUES (%d, %d, '%s', %d, %d, '%s')", $node->vid, $node->nid, $node->iid, $node->fid, $node->expires, $node->url);
185 }
186
187
188 /**
189 * Implementation of hook_update().
190 */
191 function simplefeed_item_update($node) {
192 // if this is a new node or we're adding a new revision
193 if ($node->revision) {
194 simplefeed_item_insert($node);
195 }
196 else {
197 db_query("UPDATE {simplefeed_feed_item} SET fid = %d, expires = %d, url = '%s' WHERE vid = %d", $node->fid, $node->expires, $node->url, $node->vid);
198 }
199 }
200
201
202 /**
203 * Implementation of hook_delete().
204 */
205 function simplefeed_item_delete($node) {
206 db_query('DELETE FROM {simplefeed_feed_item} WHERE nid = %d', $node->nid);
207 }
208
209
210 /**
211 * Implementation of hook_nodeapi().
212 */
213 function simplefeed_item_nodeapi(&$node, $op, $teaser, $page) {
214 if ($node->type == 'feed_item') {
215 switch ($op) {
216 case 'delete revision':
217 db_query('DELETE FROM {simplefeed_feed_item} WHERE vid = %d', $node->vid);
218 break;
219 case 'submit':
220 // Have to set the date and author here, because non-node administrators aren't able to
221 // change it in node_submit() so feeds added in anon cron jobs will show up as now.
222 $node->created = $node->date ? strtotime($node->date) : NULL;
223 $account = user_load(array('name' => $node->name));
224 $node->uid = $account->uid;
225 break;
226 }
227 }
228 }
229
230
231 /**
232 * Implementation of hook_view().
233 */
234 function simplefeed_item_view($node, $teaser = FALSE, $page = FALSE) {
235 $node = node_prepare($node, $teaser);
236
237 $node->content['simplefeed_item']['#theme'] = 'simplefeed_item_node_view';
238 $node->content['simplefeed_item']['#weight'] = 2;
239 $node->content['simplefeed_item']['url'] = array(
240 '#value' => check_url($node->url),
241 '#weight' => 1,
242 );
243
244 // since only administrators can edit when a feed item expires, only admins can see what this value is
245 if (user_access('administer feeds')) {
246 $node->content['simplefeed_item']['expires'] = array(
247 '#value' => format_interval($node->expires),
248 '#weight' => 2,
249 );
250 }
251
252 return $node;
253 }
254
255
256 /**
257 * Theme the display of a feed node.
258 */
259 function theme_simplefeed_item_node_view($values) {
260 // needs to be a space so default values aren't outputed
261 $output = ' ';
262
263 // since only administrators can edit when a feed item expires, only admins can see what this value is
264 if (user_access('administer feeds')) {
265 drupal_add_css(drupal_get_path('module', 'simplefeed') .'/simplefeed.css');
266
267 $output = '<ul class="simplefeed-item">';
268 $output .= '<li><strong>Expires:</strong> '. $values['expires']['#value'] .'</li>';
269 $output .= '</ul>';
270 }
271
272 return $output;
273 }
274
275
276 /**
277 * Implementation of hook_link().
278 */
279 function simplefeed_item_link($type, $node = NULL, $teaser = FALSE) {
280 $links = array();
281 static $feeds = array();
282
283 if ($type == 'node' && $node->type == 'feed_item' && isset($node->fid)) {
284 // since generally you'll see the same feed items in a row for the same feed
285 // we static cache this query so it doesn't repeat 10x or more per page
286 if (!isset($feeds[$node->fid])) {
287 $feed = db_result(db_query('SELECT title FROM {node} WHERE nid = %d', $node->fid));
288 $feeds[$node->fid] = $feed;
289 }
290 else {
291 $feed = $feeds[$node->fid];
292 }
293 $links['simplefeed_item_parent'] = array(
294 'title' => $feed,
295 'href' => 'node/'. $node->fid,
296 'attributes' => array('title' => t('Goto the feed source for this content'))
297 );
298 $links['simplefeed_item_url'] = array(
299 'title' => t('Source'),
300 // note we don't need to check_url() since we do this in hook_view() on line 244
301 // we decode_entities() to prevent double encoding since this url was already checked above
302 // that way if a user outputs this at the theme layer the url is still safe
303 'href' => decode_entities($node->url),
304 'absolute' => TRUE,
305 'attributes' => array('title' => t('Goto the source of this post'))
306 );
307 }
308
309 return $links;
310 }
311
312
313 /**
314 * Delete any feed items that have expired.
315 */
316 function simplefeed_item_feed_expire() {
317 // delete all expired feed items, ignore $vid since we expire *every* feed item in one call, not specific ones
318 // note if a feed item has multiple revisions, any revision's expiration can trigger deletion of the entire node
319 $items = db_query('SELECT DISTINCT n.nid FROM {simplefeed_feed_item} s JOIN {node_revisions} n ON s.vid = n.vid WHERE s.expires <> 0 AND s.expires <= (%d - n.timestamp)', time());
320
321 while ($item = db_fetch_object($items)) {
322 node_delete($item->nid);
323 }
324
325 // if we actually deleted something
326 if ($items != '') {
327 // since we can end up deleting a lot of feed items quite often, we optimize this table to save space
328 global $db_type;
329 if ($db_type == 'mysql' || $db_type == 'mysqli') {
330 db_query('OPTIMIZE TABLE {simplefeed_feed_item}');
331 }
332 }
333 }
334
335
336 /**
337 * Turn each feed item into a node.
338 *
339 * @param $process_feed
340 * Feed node object
341 * @param $cache_path
342 * Where to cache this feed on the file system
343 */
344 function simplefeed_item_feed_parse($process_feed, $cache_path) {
345 // simplepie processing, fetch feeds
346 include_once './'. drupal_get_path('module', 'simplefeed') .'/simplepie.inc';
347 $feed = new SimplePie();
348
349 /*
350 You tell SimplePie what feed you want to get and where to cache it at.
351 SimplePie looks to see if the feed is already cached:
352 If the cache is fresh use that.
353 If there is no cached copy at all, SimplePie will grab and cache the feed.
354 If the cache is there but it's old (SimplePie defaults to 60 minutes; configurable with set_cache_duration()), then SimplePie will ask the feed if it has changed since the last time we grabbed it (this is the HTTPCG part).
355 If it hasn't changed, we reset the timer on the cache's freshness and keep it for another 60 minutes before checking again.
356 If the cache has changed, SimplePie dumps the existing cache (since the cache is just a copy of the feed), and grabs a new copy of the feed and uses it.
357
358 This cache uses a combination of LAST-MODIFIED and ETAG headers, and other intelligent methods to only grab changed feeds.
359 */
360
361 $feed->set_cache_location($_SERVER['DOCUMENT_ROOT'] . base_path() . $cache_path);
362 $feed->set_feed_url($process_feed->url);
363 $feed->set_timeout(15);
364 // prevent SimplePie from using all of it's data santization since we use Drupal's input formats to handle this
365 $feed->set_stupidly_fast(TRUE);
366 $success = $feed->init();
367
368 if ($success && $feed->data) {
369 // loop through all of the items in the feed, faster than foreach
370 $max = $feed->get_item_quantity();
371
372 for ($i = 0; $i < $max; $i++) {
373 $item = $feed->get_item($i);
374 // unique SHA-1 hash for a feed item
375 $iid = $item->get_id(true);
376
377 // make sure we don't already have this feed item
378 $duplicate = db_result(db_query("SELECT iid FROM {simplefeed_feed_item} WHERE iid = '%s'", $iid));
379
380 if ($duplicate == '') {
381 // add in tags if a vocabulary is set
382 if (variable_get('simplefeed_vocab', 0)) {
383 // add in tags from parent feed
384 $tags = $process_feed->tags;
385 // add in any tags that are found in the feed item itself from the originating site
386 if (variable_get('simplefeed_categories', 0)) {
387 if (count($item->get_categories()) > 0) {
388 foreach ($item->get_categories() as $category) {
389 $tags .= ', '. $category->get_label();
390 }
391 }
392 }
393
394 // add any tags (either inheriting from parent feed or from parsing the feed item) to the feed item node
395 if ($tags != '') {
396 $item->taxonomy['tags'][$process_feed->vocab] = decode_entities($tags);
397 }
398 }
399
400 $link = $item->get_permalink();
401 // this is node created date format for Drupal
402 $date = $item->get_date('Y-m-d H:i:s O');
403 $body = $item->get_content();
404 // this strips out any tags that may appear as <b> in the title, and makes sure &quot; -> " for display
405 $title = strip_tags(decode_entities($item->get_title()));
406
407 // some feeds don't provide titles so we construct one with the first 72 characters of the body
408 if (!$title) {
409 // remove any HTML or line breaks so these don't appear in the title
410 $title = trim(str_replace(array("\n", "\r"), ' ', strip_tags($body)));
411 $title = trim(substr($title, 0, 72));
412 $lastchar = substr($title, -1, 1);
413 // check to see if the last character in the title is a non-alphanumeric character, except for ? or !
414 // if it is strip it off so you don't get strange looking titles
415 if (preg_match('/[^0-9A-Za-z\!\?]/', $lastchar)) {
416 $title = substr($title, 0, -1);
417 }
418 // ? and ! are ok to end a title with since they make sense
419 if ($lastchar != '!' and $lastchar != '?') {
420 $title .= '...';
421 }
422 }
423
424 // create a feed item node
425 $node = array('type' => 'feed_item', 'iid' => $iid);
426 $values['title'] = $title;
427 if ($date) {
428 // "created" is a node property, however we have to use "date" to set this with drupal_execute since it is the form element name
429 $values['date'] = $date;
430 }
431 $values['name'] = db_result(db_query('SELECT u.name FROM {node} n INNER JOIN {users} u ON n.uid = u.uid WHERE nid = %d', $process_feed->nid));
432 $values['format'] = variable_get('simplefeed_format', 1);
433 // $item->get_description() for teaser?
434 $values['body'] = $body;
435 $values['expires'] = $process_feed->expires;
436 $values['url'] = $link != '' ? $link : $feed->get_permalink();
437 $values['fid'] = $process_feed->nid;
438 $values['taxonomy'] = $item->taxonomy;
439
440 // create a new feed-item node, adding in all of the other node defaults
441 drupal_execute('feed_item_node_form', $values, $node);
442 }
443
444 // we unset $item each time to prevent any pass by reference memory leaks that PHP encounters with objects in foreach loops
445 unset($item);
446 }
447 }
448 else if (isset($feed->error)) {
449 watchdog('simplefeed', t('The feed %feed could not be processed due to the following error: %error', array('%feed' => $process_feed->title, '%error' => $feed->error)), WATCHDOG_ERROR, l('view', 'node/'. $process_feed->nid));
450 }
451 }

  ViewVC Help
Powered by ViewVC 1.1.2