Simpletest Coverage - modules/aggregator/aggregator.pages.inc

1 <?php
2 // $Id: aggregator.pages.inc,v 1.30 2009/07/30 19:24:20 dries Exp $
3
4 /**
5 * @file
6 * User page callbacks for the aggregator module.
7 */
8
9 /**
10 * Menu callback; displays the most recent items gathered from any feed.
11 *
12 * @return
13 * The items HTML.
14 */
15 function aggregator_page_last() {
16 drupal_add_feed(url('aggregator/rss'), variable_get('site_name', 'Drupal') . ' ' . t('aggregator'));
17
18 $items = aggregator_feed_items_load('sum');
19
20 return _aggregator_page_list($items, arg(1));
21 }
22
23 /**
24 * Menu callback; displays all the items captured from a particular feed.
25 *
26 * If there are two arguments then this function is the categorize form.
27 *
28 * @param $arg1
29 * If there are two arguments then $arg1 is $form_state. Otherwise, $arg1 is $feed.
30 * @param $arg2
31 * If there are two arguments then $arg2 is feed.
32 * @return
33 * The item's HTML.
34 */
35 function aggregator_page_source($arg1, $arg2 = NULL) {
36 // If there are two arguments then this function is the categorize form, and
37 // $arg1 is $form_state and $arg2 is $feed. Otherwise, $arg1 is $feed.
38 $feed = is_object($arg2) ? $arg2 : $arg1;
39 drupal_set_title($feed->title);
40 $feed_source = theme('aggregator_feed_source', $feed);
41
42 // It is safe to include the fid in the query because it's loaded from the
43 // database by aggregator_feed_load.
44 $items = aggregator_feed_items_load('source', $feed);
45
46 return _aggregator_page_list($items, arg(3), $feed_source);
47 }
48
49 /**
50 * Menu callback; displays all the items aggregated in a particular category.
51 *
52 * If there are two arguments then this function is called as a form.
53 *
54 * @param $arg1
55 * If there are two arguments then $arg1 is $form_state. Otherwise, $arg1 is $category.
56 * @param $arg2
57 * If there are two arguments then $arg2 is $category.
58 * @return
59 * The items HTML.
60 */
61 function aggregator_page_category($arg1, $arg2 = NULL) {
62 // If there are two arguments then we are called as a form, $arg1 is
63 // $form_state and $arg2 is $category. Otherwise, $arg1 is $category.
64 $category = is_array($arg2) ? $arg2 : $arg1;
65
66 drupal_add_feed(url('aggregator/rss/' . $category['cid']), variable_get('site_name', 'Drupal') . ' ' . t('aggregator - @title', array('@title' => $category['title'])));
67
68 // It is safe to include the cid in the query because it's loaded from the
69 // database by aggregator_category_load.
70 $items = aggregator_feed_items_load('category', $category);
71
72 return _aggregator_page_list($items, arg(3));
73 }
74
75 /**
76 * Load feed items
77 *
78 * @param $type
79 * The filter for the items. Possible values: 'sum', 'source', 'category'
80 * @param $data
81 * Feed or category data for filtering
82 * @return
83 * An array of the feed items.
84 */
85 function aggregator_feed_items_load($type, $data = NULL) {
86 $items = array();
87 $range_limit = 20;
88 switch ($type) {
89 case 'sum':
90 $result = db_query_range('SELECT i.*, f.title AS ftitle, f.link AS flink FROM {aggregator_item} i INNER JOIN {aggregator_feed} f ON i.fid = f.fid ORDER BY i.timestamp DESC, i.iid DESC', 0, $range_limit);
91 break;
92 case 'source':
93 $result = db_query_range('SELECT * FROM {aggregator_item} WHERE fid = :fid ORDER BY timestamp DESC, iid DESC', array(':fid' => $data->fid), 0, $range_limit);
94 break;
95 case 'category':
96 $result = db_query_range('SELECT i.*, f.title AS ftitle, f.link AS flink FROM {aggregator_category_item} c LEFT JOIN {aggregator_item} i ON c.iid = i.iid LEFT JOIN {aggregator_feed} f ON i.fid = f.fid WHERE cid = :cid ORDER BY timestamp DESC, i.iid DESC', array(':cid' => $data['cid']), 0, $range_limit);
97 break;
98 }
99
100 foreach ($result as $item) {
101 $item->categories = db_query('SELECT c.title, c.cid FROM {aggregator_category_item} ci LEFT JOIN {aggregator_category} c ON ci.cid = c.cid WHERE ci.iid = :iid ORDER BY c.title', array(':iid' => $item->iid))->fetchAll();
102 $items[] = $item;
103 }
104
105 return $items;
106 }
107
108 /**
109 * Prints an aggregator page listing a number of feed items.
110 *
111 * Various menu callbacks use this function to print their feeds.
112 *
113 * @param $items
114 * The items to be listed.
115 * @param $op
116 * Which form should be added to the items. Only 'categorize' is now recognized.
117 * @param $feed_source
118 * The feed source URL.
119 * @return
120 * The items HTML.
121 */
122 function _aggregator_page_list($items, $op, $feed_source = '') {
123 if (user_access('administer news feeds') && ($op == 'categorize')) {
124 // Get form data.
125 $output = aggregator_categorize_items($items, $feed_source);
126 }
127 else {
128 // Assemble themed output.
129 $output = $feed_source;
130 foreach ($items as $item) {
131 $output .= theme('aggregator_item', $item);
132 }
133 $output = theme('aggregator_wrapper', $output);
134 }
135
136 return $output;
137 }
138
139 /**
140 * Form builder; build the page list form.
141 *
142 * @param $items
143 * An array of the feed items.
144 * @param $feed_source
145 * The feed source URL.
146 * @return
147 * The form structure.
148 * @ingroup forms
149 * @see aggregator_categorize_items_validate()
150 * @see aggregator_categorize_items_submit()
151 */
152 function aggregator_categorize_items($items, $feed_source = '') {
153 $form['#submit'][] = 'aggregator_categorize_items_submit';
154 $form['#validate'][] = 'aggregator_categorize_items_validate';
155 $form['#theme'] = 'aggregator_categorize_items';
156 $form['feed_source'] = array(
157 '#value' => $feed_source,
158 );
159 $categories = array();
160 $done = FALSE;
161 $form['items'] = array();
162 $form['categories'] = array(
163 '#tree' => TRUE,
164 );
165 foreach ($items as $item) {
166 $form['items'][$item->iid] = array('#markup' => theme('aggregator_item', $item));
167 $form['categories'][$item->iid] = array();
168 $categories_result = db_query('SELECT c.cid, c.title, ci.iid FROM {aggregator_category} c LEFT JOIN {aggregator_category_item} ci ON c.cid = ci.cid AND ci.iid = :iid', array(':iid' => $item->iid));
169 $selected = array();
170 foreach ($categories_result as $category) {
171 if (!$done) {
172 $categories[$category->cid] = check_plain($category->title);
173 }
174 if ($category->iid) {
175 $selected[] = $category->cid;
176 }
177 }
178 $done = TRUE;
179 $form['categories'][$item->iid] = array(
180 '#type' => variable_get('aggregator_category_selector', 'checkboxes'),
181 '#default_value' => $selected,
182 '#options' => $categories,
183 '#size' => 10,
184 '#multiple' => TRUE
185 );
186 }
187 $form['submit'] = array('#type' => 'submit', '#value' => t('Save categories'));
188
189 return $form;
190 }
191
192 /**
193 * Validate aggregator_categorize_items() form submissions.
194 */
195 function aggregator_categorize_items_validate($form, &$form_state) {
196 if (!user_access('administer news feeds')) {
197 form_error($form, t('You are not allowed to categorize this feed item.'));
198 }
199 }
200
201 /**
202 * Process aggregator_categorize_items() form submissions.
203 */
204 function aggregator_categorize_items_submit($form, &$form_state) {
205 if (!empty($form_state['values']['categories'])) {
206 foreach ($form_state['values']['categories'] as $iid => $selection) {
207 db_delete('aggregator_category_item')
208 ->condition('iid', $iid)
209 ->execute();
210 $insert = db_insert('aggregator_category_item')->fields(array('iid', 'cid'));
211 $has_values = FALSE;
212 foreach ($selection as $cid) {
213 if ($cid && $iid) {
214 $has_values = TRUE;
215 $insert->values(array(
216 'iid' => $iid,
217 'cid' => $cid,
218 ));
219 }
220 }
221 if ($has_values) {
222 $insert->execute();
223 }
224 }
225 }
226 drupal_set_message(t('The categories have been saved.'));
227 }
228
229 /**
230 * Theme the page list form for assigning categories.
231 *
232 * @param $form
233 * An associative array containing the structure of the form.
234 * @return
235 * The output HTML.
236 * @ingroup themeable
237 */
238 function theme_aggregator_categorize_items($form) {
239 $output = drupal_render($form['feed_source']);
240 $rows = array();
241 if (!empty($form['items'])) {
242 foreach (element_children($form['items']) as $key) {
243 $rows[] = array(
244 drupal_render($form['items'][$key]),
245 array('data' => drupal_render($form['categories'][$key]), 'class' => 'categorize-item'),
246 );
247 }
248 }
249 $output .= theme('table', array('', t('Categorize')), $rows);
250 $output .= drupal_render($form['submit']);
251 $output .= drupal_render_children($form);
252
253 return theme('aggregator_wrapper', $output);
254 }
255
256 /**
257 * Process variables for aggregator-wrapper.tpl.php.
258 *
259 * @see aggregator-wrapper.tpl.php
260 */
261 function template_preprocess_aggregator_wrapper(&$variables) {
262 $variables['pager'] = theme('pager', NULL);
263 }
264
265 /**
266 * Process variables for aggregator-item.tpl.php.
267 *
268 * @see aggregator-item.tpl.php
269 */
270 function template_preprocess_aggregator_item(&$variables) {
271 $item = $variables['item'];
272
273 $variables['feed_url'] = check_url($item->link);
274 $variables['feed_title'] = check_plain($item->title);
275 $variables['content'] = aggregator_filter_xss($item->description);
276
277 $variables['source_url'] = '';
278 $variables['source_title'] = '';
279 if (isset($item->ftitle) && isset($item->fid)) {
280 $variables['source_url'] = url("aggregator/sources/$item->fid");
281 $variables['source_title'] = check_plain($item->ftitle);
282 }
283 if (date('Ymd', $item->timestamp) == date('Ymd')) {
284 $variables['source_date'] = t('%ago ago', array('%ago' => format_interval(REQUEST_TIME - $item->timestamp)));
285 }
286 else {
287 $variables['source_date'] = format_date($item->timestamp, 'custom', variable_get('date_format_medium', 'D, m/d/Y - H:i'));
288 }
289
290 $variables['categories'] = array();
291 foreach ($item->categories as $category) {
292 $variables['categories'][$category->cid] = l($category->title, 'aggregator/categories/' . $category->cid);
293 }
294 }
295
296 /**
297 * Menu callback; displays all the feeds used by the aggregator.
298 */
299 function aggregator_page_sources() {
300 $result = db_query('SELECT f.fid, f.title, f.description, f.image, MAX(i.timestamp) AS last FROM {aggregator_feed} f LEFT JOIN {aggregator_item} i ON f.fid = i.fid GROUP BY f.fid, f.title, f.description, f.image ORDER BY last DESC, f.title');
301
302 $output = '';
303 foreach ($result as $feed) {
304 // Most recent items:
305 $summary_items = array();
306 if (variable_get('aggregator_summary_items', 3)) {
307 $items = db_query_range('SELECT i.title, i.timestamp, i.link FROM {aggregator_item} i WHERE i.fid = :fid ORDER BY i.timestamp DESC', array(':fid' => $feed->fid), 0, variable_get('aggregator_summary_items', 3));
308 foreach ($items as $item) {
309 $summary_items[] = theme('aggregator_summary_item', $item);
310 }
311 }
312 $feed->url = url('aggregator/sources/' . $feed->fid);
313 $output .= theme('aggregator_summary_items', $summary_items, $feed);
314 }
315 $output .= theme('feed_icon', url('aggregator/opml'), t('OPML feed'));
316
317 return theme('aggregator_wrapper', $output);
318 }
319
320 /**
321 * Menu callback; displays all the categories used by the aggregator.
322 */
323 function aggregator_page_categories() {
324 $result = db_query('SELECT c.cid, c.title, c.description FROM {aggregator_category} c LEFT JOIN {aggregator_category_item} ci ON c.cid = ci.cid LEFT JOIN {aggregator_item} i ON ci.iid = i.iid GROUP BY c.cid, c.title, c.description');
325
326 $output = '';
327 foreach ($result as $category) {
328 if (variable_get('aggregator_summary_items', 3)) {
329 $summary_items = array();
330 $items = db_query_range('SELECT i.title, i.timestamp, i.link, f.title as feed_title, f.link as feed_link FROM {aggregator_category_item} ci LEFT JOIN {aggregator_item} i ON i.iid = ci.iid LEFT JOIN {aggregator_feed} f ON i.fid = f.fid WHERE ci.cid = :cid ORDER BY i.timestamp DESC', array(':cid' => $category->cid), 0, variable_get('aggregator_summary_items', 3));
331 foreach ($items as $item) {
332 $summary_items[] = theme('aggregator_summary_item', $item);
333 }
334 }
335 $category->url = url('aggregator/categories/' . $category->cid);
336 $output .= theme('aggregator_summary_items', $summary_items, $category);
337 }
338
339 return theme('aggregator_wrapper', $output);
340 }
341
342 /**
343 * Menu callback; generate an RSS 0.92 feed of aggregator items or categories.
344 */
345 function aggregator_page_rss() {
346 $result = NULL;
347 // arg(2) is the passed cid, only select for that category.
348 if (arg(2)) {
349 $category = db_query('SELECT cid, title FROM {aggregator_category} WHERE cid = :cid', array(':cid' => arg(2)))->fetchObject();
350 $result = db_query_range('SELECT i.*, f.title AS ftitle, f.link AS flink FROM {aggregator_category_item} c LEFT JOIN {aggregator_item} i ON c.iid = i.iid LEFT JOIN {aggregator_feed} f ON i.fid = f.fid WHERE cid = :cid ORDER BY timestamp DESC, i.iid DESC', array(':cid' => $category->cid), 0, variable_get('feed_default_items', 10));
351 }
352 // Or, get the default aggregator items.
353 else {
354 $category = NULL;
355 $result = db_query_range('SELECT i.*, f.title AS ftitle, f.link AS flink FROM {aggregator_item} i INNER JOIN {aggregator_feed} f ON i.fid = f.fid ORDER BY i.timestamp DESC, i.iid DESC', 0, variable_get('feed_default_items', 10));
356 }
357
358 $feeds = $result->fetchAll();
359 return theme('aggregator_page_rss', $feeds, $category);
360 }
361
362 /**
363 * Theme the RSS output.
364 *
365 * @param $feeds
366 * An array of the feeds to theme.
367 * @param $category
368 * A common category, if any, for all the feeds.
369 * @ingroup themeable
370 */
371 function theme_aggregator_page_rss($feeds, $category = NULL) {
372 drupal_set_header('Content-Type', 'application/rss+xml; charset=utf-8');
373
374 $items = '';
375 $feed_length = variable_get('feed_item_length', 'teaser');
376 foreach ($feeds as $feed) {
377 switch ($feed_length) {
378 case 'teaser':
379 $summary = text_summary($feed->description, NULL, variable_get('aggregator_teaser_length', 600));
380 if ($summary != $feed->description) {
381 $summary .= '<p><a href="' . check_url($feed->link) . '">' . t('read more') . "</a></p>\n";
382 }
383 $feed->description = $summary;
384 break;
385 case 'title':
386 $feed->description = '';
387 break;
388 }
389 $items .= format_rss_item($feed->ftitle . ': ' . $feed->title, $feed->link, $feed->description, array('pubDate' => date('r', $feed->timestamp)));
390 }
391
392 $site_name = variable_get('site_name', 'Drupal');
393 $url = url((isset($category) ? 'aggregator/categories/' . $category->cid : 'aggregator'), array('absolute' => TRUE));
394 $description = isset($category) ? t('@site_name - aggregated feeds in category @title', array('@site_name' => $site_name, '@title' => $category->title)) : t('@site_name - aggregated feeds', array('@site_name' => $site_name));
395
396 $output = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
397 $output .= "<rss version=\"2.0\">\n";
398 $output .= format_rss_channel(t('@site_name aggregator', array('@site_name' => $site_name)), $url, $description, $items);
399 $output .= "</rss>\n";
400
401 print $output;
402 }
403
404 /**
405 * Menu callback; generates an OPML representation of all feeds.
406 *
407 * @param $cid
408 * If set, feeds are exported only from a category with this ID. Otherwise, all feeds are exported.
409 * @return
410 * The output XML.
411 */
412 function aggregator_page_opml($cid = NULL) {
413 if ($cid) {
414 $result = db_query('SELECT f.title, f.url FROM {aggregator_feed} f LEFT JOIN {aggregator_category_feed} c on f.fid = c.fid WHERE c.cid = :cid ORDER BY title', array(':cid' => $cid));
415 }
416 else {
417 $result = db_query('SELECT * FROM {aggregator_feed} ORDER BY title');
418 }
419
420 $feeds = $result->fetchAll();
421 return theme('aggregator_page_opml', $feeds);
422 }
423
424 /**
425 * Theme the OPML feed output.
426 *
427 * @param $feeds
428 * An array of the feeds to theme.
429 * @ingroup themeable
430 */
431 function theme_aggregator_page_opml($feeds) {
432 drupal_set_header('Content-Type', 'text/xml; charset=utf-8');
433
434 $output = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
435 $output .= "<opml version=\"1.1\">\n";
436 $output .= "<head>\n";
437 $output .= '<title>' . check_plain(variable_get('site_name', 'Drupal')) . "</title>\n";
438 $output .= '<dateModified>' . gmdate('r') . "</dateModified>\n";
439 $output .= "</head>\n";
440 $output .= "<body>\n";
441 foreach ($feeds as $feed) {
442 $output .= '<outline text="' . check_plain($feed->title) . '" xmlUrl="' . check_url($feed->url) . "\" />\n";
443 }
444 $output .= "</body>\n";
445 $output .= "</opml>\n";
446
447 print $output;
448 }
449
450 /**
451 * Process variables for aggregator-summary-items.tpl.php.
452 *
453 * @see aggregator-summary-item.tpl.php
454 */
455 function template_preprocess_aggregator_summary_items(&$variables) {
456 $variables['title'] = check_plain($variables['source']->title);
457 $variables['summary_list'] = theme('item_list', $variables['summary_items']);
458 $variables['source_url'] = $variables['source']->url;
459 }
460
461 /**
462 * Process variables for aggregator-summary-item.tpl.php.
463 *
464 * @see aggregator-summary-item.tpl.php
465 */
466 function template_preprocess_aggregator_summary_item(&$variables) {
467 $item = $variables['item'];
468
469 $variables['feed_url'] = check_url($item->link);
470 $variables['feed_title'] = check_plain($item->title);
471 $variables['feed_age'] = t('%age old', array('%age' => format_interval(REQUEST_TIME - $item->timestamp)));
472
473 $variables['source_url'] = '';
474 $variables['source_title'] = '';
475 if (!empty($item->feed_link)) {
476 $variables['source_url'] = check_url($item->feed_link);
477 $variables['source_title'] = check_plain($item->feed_title);
478 }
479 }
480
481 /**
482 * Process variables for aggregator-feed-source.tpl.php.
483 *
484 * @see aggregator-feed-source.tpl.php
485 */
486 function template_preprocess_aggregator_feed_source(&$variables) {
487 $feed = $variables['feed'];
488
489 $variables['source_icon'] = theme('feed_icon', $feed->url, t('!title feed', array('!title' => $feed->title)));
490 $variables['source_image'] = $feed->image;
491 $variables['source_description'] = aggregator_filter_xss($feed->description);
492 $variables['source_url'] = check_url(url($feed->link, array('absolute' => TRUE)));
493
494 if ($feed->checked) {
495 $variables['last_checked'] = t('@time ago', array('@time' => format_interval(REQUEST_TIME - $feed->checked)));
496 }
497 else {
498 $variables['last_checked'] = t('never');
499 }
500
501 if (user_access('administer news feeds')) {
502 $variables['last_checked'] = l($variables['last_checked'], 'admin/settings/aggregator');
503 }
504 }
505

Legend

Missed
lines code that were not excersized during program execution.
Covered
lines code were excersized during program execution.
Comment/non executable
Comment or non-executable line of code.
Dead
lines of code that according to xdebug could not be executed. This is counted as coverage code because in almost all cases it is code that runnable.