01b06de41d9446ab5754f1dfe755d7b783a7588d
[moodle.git] / blocks / rss_client / block_rss_client.php
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * A block which displays Remote feeds
20  *
21  * @package    rss_client
22  * @copyright  Daryl Hawes
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
24  */
26  class block_rss_client extends block_base {
28     function init() {
29         $this->title = get_string('feedstitle', 'block_rss_client');
30     }
32     function preferred_width() {
33         return 210;
34     }
36     function applicable_formats() {
37         return array('all' => true, 'tag' => false);   // Needs work to make it work on tags MDL-11960
38     }
40     function specialization() {
41         // After the block has been loaded we customize the block's title display
42         if (!empty($this->config) && !empty($this->config->title)) {
43             // There is a customized block title, display it
44             $this->title = $this->config->title;
45         } else {
46             // No customized block title, use localized remote news feed string
47             $this->title = get_string('remotenewsfeed', 'block_rss_client');
48         }
49     }
51     function get_content() {
52         global $CFG, $DB;
54         if ($this->content !== NULL) {
55             return $this->content;
56         }
58         if (!$CFG->enablerssfeeds) {
59             $this->content->text = '';
60             if ($this->page->user_is_editing()) {
61                 $this->content->text = get_string('disabledrssfeeds', 'block_rss_client');
62             }
63             return $this->content;
64         }
66         // initalise block content object
67         $this->content = new stdClass;
68         $this->content->text   = '';
69         $this->content->footer = '';
71         if (empty($this->instance)) {
72             return $this->content;
73         }
75         if (!isset($this->config)) {
76             // The block has yet to be configured - just display configure message in
77             // the block if user has permission to configure it
79             if (has_capability('block/rss_client:manageanyfeeds', $this->context)) {
80                 $this->content->text = get_string('feedsconfigurenewinstance2', 'block_rss_client');
81             }
83             return $this->content;
84         }
86         // How many feed items should we display?
87         $maxentries = 5;
88         if ( !empty($this->config->shownumentries) ) {
89             $maxentries = intval($this->config->shownumentries);
90         }elseif( isset($CFG->block_rss_client_num_entries) ) {
91             $maxentries = intval($CFG->block_rss_client_num_entries);
92         }
95         /* ---------------------------------
96          * Begin Normal Display of Block Content
97          * --------------------------------- */
99         $output = '';
102         if (!empty($this->config->rssid)) {
103             list($rss_ids_sql, $params) = $DB->get_in_or_equal($this->config->rssid);
105             $rss_feeds = $DB->get_records_select('block_rss_client', "id $rss_ids_sql", $params);
107             $showtitle = false;
108             if (count($rss_feeds) > 1) {
109                 // when many feeds show the title for each feed
110                 $showtitle = true;
111             }
113             foreach($rss_feeds as $feed){
114                 $output.= $this->get_feed_html($feed, $maxentries, $showtitle);
115             }
116         }
118         $this->content->text = $output;
120         return $this->content;
121     }
124     function instance_allow_multiple() {
125         return true;
126     }
128     function has_config() {
129         return true;
130     }
132     function instance_allow_config() {
133         return true;
134     }
136     /**
137      * Returns the html of a feed to be displaed in the block
138      *
139      * @param mixed feedrecord The feed record from the database
140      * @param int maxentries The maximum number of entries to be displayed
141      * @param boolean showtitle Should the feed title be displayed in html
142      * @return string html representing the rss feed content
143      */
144     function get_feed_html($feedrecord, $maxentries, $showtitle){
145         global $CFG;
146         require_once($CFG->libdir.'/simplepie/moodle_simplepie.php');
148         $feed = new moodle_simplepie($feedrecord->url);
150         if(isset($CFG->block_rss_client_timeout)){
151             $feed->set_cache_duration($CFG->block_rss_client_timeout*60);
152         }
154         if(debugging() && $feed->error()){
155             return '<p>'. $feedrecord->url .' Failed with code: '.$feed->error().'</p>';
156         }
158         $r = ''; // return string
160         if($this->config->block_rss_client_show_channel_image){
161             if($image = $feed->get_image_url()){
162                 $imagetitle = s($feed->get_image_title());
163                 $imagelink  = $feed->get_image_link();
165                 $r.='<div class="image" title="'.$imagetitle.'">'."\n";
166                 if($imagelink){
167                     $r.='<a href="'.$imagelink.'">';
168                 }
169                 $r.='<img src="'.$image.'" alt="'.$imagetitle.'" />'."\n";
170                 if($imagelink){
171                     $r.='</a>';
172                 }
173                 $r.= '</div>';
174             }
175         }
177         if(empty($feedrecord->preferredtitle)){
178             $feedtitle = $this->format_title($feed->get_title());
179         }else{
180             $feedtitle = $this->format_title($feedrecord->preferredtitle);
181         }
183         if($showtitle){
184             $r.='<div class="title">'.$feedtitle.'</div>';
185         }
188         $r.='<ul class="list no-overflow">'."\n";
190         $feeditems = $feed->get_items(0, $maxentries);
191         foreach($feeditems as $item){
192             $r.= $this->get_item_html($item);
193         }
195         $r.='</ul>';
198         if ($this->config->block_rss_client_show_channel_link) {
200             $channellink = $feed->get_link();
202             if (!empty($channellink)){
203                 //NOTE: this means the 'last feed' display wins the block title - but
204                 //this is exiting behaviour..
205                 $this->content->footer = '<a href="'.htmlspecialchars(clean_param($channellink,PARAM_URL)).'">'. get_string('clientchannellink', 'block_rss_client') .'</a>';
206             }
207         }
209         if (empty($this->config->title)){
210             //NOTE: this means the 'last feed' displayed wins the block title - but
211             //this is exiting behaviour..
212             $this->title = strip_tags($feedtitle);
213         }
215         return $r;
216     }
219     /**
220      * Returns the html list item of a feed item
221      *
222      * @param mixed item simplepie_item representing the feed item
223      * @return string html li representing the rss feed item
224      */
225     function get_item_html($item){
227         $link        = $item->get_link();
228         $title       = $item->get_title();
229         $description = $item->get_description();
232         if(empty($title)){
233             // no title present, use portion of description
234             $title = substr(strip_tags($description), 0, 20) . '...';
235         }else{
236             $title = break_up_long_words($title, 30);
237         }
239         if(empty($link)){
240             $link = $item->get_id();
241         }
243         $r = html_writer::start_tag('li');
244             $r.= html_writer::start_tag('div',array('class'=>'link'));
245                 $r.= html_writer::link(clean_param($link,PARAM_URL), s($title), array('onclick'=>'this.target="_blank"'));
246             $r.= html_writer::end_tag('div');
248             if($this->config->display_description && !empty($description)){
250                 $description = break_up_long_words($description, 30);
252                 $formatoptions = new stdClass();
253                 $formatoptions->para = false;
255                 $r.= html_writer::start_tag('div',array('class'=>'description'));
256                     $r.= format_text($description, FORMAT_HTML, $formatoptions, $this->page->course->id);
257                 $r.= html_writer::end_tag('div');
258             }
259         $r.= html_writer::end_tag('li');
261         return $r;
262     }
264     /**
265      * Strips a large title to size and adds ... if title too long
266      *
267      * @param string title to shorten
268      * @param int max character length of title
269      * @return string title s() quoted and shortened if necessary
270      */
271     function format_title($title,$max=64) {
273         // Loading the textlib singleton instance. We are going to need it.
274         $textlib = textlib_get_instance();
276         if ($textlib->strlen($title) <= $max) {
277             return s($title);
278         } else {
279             return s($textlib->substr($title,0,$max-3).'...');
280         }
281     }
283     /**
284      * cron - goes through all feeds and retrieves them with the cache
285      * duration set to 0 in order to force the retrieval of the item and
286      * refresh the cache
287      *
288      * @return boolean true if all feeds were retrieved succesfully
289      */
290     function cron() {
291         global $CFG, $DB;
292         require_once($CFG->libdir.'/simplepie/moodle_simplepie.php');
294         // We are going to measure execution times
295         $starttime =  microtime();
297         // And we have one initial $status
298         $status = true;
300         // Fetch all site feeds.
301         $rs = $DB->get_recordset('block_rss_client');
302         $counter = 0;
303         mtrace('');
304         foreach ($rs as $rec) {
305             mtrace('    ' . $rec->url . ' ', '');
306             // Fetch the rss feed, using standard simplepie caching
307             // so feeds will be renewed only if cache has expired
308             @set_time_limit(60);
310             $feed =  new moodle_simplepie();
311             // set timeout for longer than normal to be agressive at
312             // fetching feeds if possible..
313             $feed->set_timeout(40);
314             $feed->set_cache_duration(0);
315             $feed->set_feed_url($rec->url);
316             $feed->init();
318             if ($feed->error()) {
319                 mtrace ('error');
320                 mtrace ('SimplePie failed with error:'.$feed->error());
321                 $status = false;
322             } else {
323                 mtrace ('ok');
324             }
325             $counter ++;
326         }
327         $rs->close();
329         // Show times
330         mtrace($counter . ' feeds refreshed (took ' . microtime_diff($starttime, microtime()) . ' seconds)');
332         // And return $status
333         return $status;
334     }