Categorías

Últimos Tweets

dwPalma Nuevo proyecto! Una guía de comercios para un municipio de Mallorca, me parece interesante :) Y cómo no se va a hacer en #codeigniter

dwPalma ¿Cómo programar un feed RSS en Codeigniter? http://bit.ly/gZc6C8 #codeigniter

dwPalma Yay! Listo feed RSS y mandado a feedburner ya de paso, y además aprovecharé la experiencia para un post sobre ello http://bit.ly/eI6K5o

dwPalma Configurar Codeigniter: http://bit.ly/gzNzNa (me parece que me ha salido un poco pesado de leer ¬¬' )

Feed RSS con Codeigniter

Un elemento importante a tener hoy en día para un blog es un Feed RSS de las noticias que se vayan publicando. Con esta entrada, intentaré explicar cómo conseguir programar uno en Codeiniter, que es más sencillo de lo que pueda parecer.

Un feed RSS no es más que una página web con un markup característico, diferente del lenguaje XHTML, para que los diferentes lectoress de RSS puedan interpretarlo correctamente. Entonces, el elemento diferenciador clave a programar va a ser nuestra vista. La estructura básica de una página o feed RSS puedes encontrarla por ejemplo aquí:http://en.wikipedia.org/wiki/RSS#Example.

En mi caso, he creado la vista del feed de la siguiente manera:

<?php echo '<?xml version="1.0" encoding="utf-8"?>' . "\n";?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
    <title><?=$titulo?></title>
    <link><?=$feed_url?></link>
    <atom:link href="<?=$feed_url?>/feed" rel="self" type="application/rss+xml" />
    <description><?=$description?></description>
    <language>es-es</language>
    <pubDate><?=$pubdate?></pubDate>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <lastBuildDate><?=$pubdate?></lastBuildDate>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <generator>Custom dwPalma.com CMS built in Codeigniter</generator>
    <managingEditor>joseluis at dwpalma dot com</managingEditor>
    <webMaster>joseluis at dwpalma dot com</webMaster>
<?php foreach ($posts as $post): ?>
    <item>
        <title><?=$post['titulo']?></title>
        <link><?=base_url()?>blog/<?=$post['url_categoria']?>/ver/<?=$post['url']?></link>
        <comments><?=base_url()?>blog/<?=$post['url_categoria']?>/ver/<?=$post['url']?>#comentarios</comments>
        <description><![CDATA[<?=$post['post_intro']?>]]></description>
        <pubDate><?=$post['fecha']?></pubDate>
        <dc:creator>dwPalma</dc:creator>
        <category><![CDATA[<?=$post['categoria']?>]]></category>
        <guid isPermaLink="true"><?=base_url()?>blog/<?=$post['url_categoria']?>/ver/<?=$post['url']?></guid>
        <content:encoded><![CDATA[<?=$post['post_completo']?>]]></content:encoded>
    </item>    
<?php endforeach;?>
</channel>
</rss>
<?php
/**
 * Archivo ./application/views/feed.php
 */
?>

Es una vista sencilla, aunque conviene tener un par de detalles en cuenta. Por ejemplo la primera línea, podría pensarse que no es necesario mostrarla haciendo un echo en PHP. El problema es que, como empieza con <?xml y es un archivo .php, el intérprete de PHP del servidor puede dar error al mostrarla (por ser <? el método abreviado para abrir una sentencia/archivo en PHP). Después se observa que dentro de las etiquetas description, category y content insertamos los datos entre un <![CDATA[ ]]. Se hace de esta manera para que el lector de RSS interprete correctamente éstos campos y no piense que las diferentes etiquetas que tienen (ya que forman parte del formateado del texto en HTML) corresponden a etiquetas RSS,

A la vista anterior le estamos pasando ciertas variables que, como tiene que ser en Codeigniter, hay hacerlo a través del Controlador, La clase o método para hacerlo no es tampoco muy complicada ya que tan sólo se dedica a cojer unos pocos datos. El constructor del controlador es en realidad más extenso (ya que en mi caso es el mismo que utilizo para todo lo relacionado con el Bog), pero para el caso que nos atañe basta con lo siguiente:

<?php
/**
 * Archivo ./application/controllers/blog.php
 */
?>
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Blog extends Controller {
    
    function Blog()
    {//Constructor
        parent::Controller();
        
        // Cargamos los modelos, librerías, helpers y vistas necesarios
        $this->load->helper('url');
        $this->load->helper('text');
        
        $this->load->model('Blog_model', 'Blog');
    }

    function feed()
    {
        $datos['titulo'] = 'RSS Feed de dwPalma: Desarrollo y Diseño Web en Mallorca';
        $datos['feed_url'] = base_url().'blog';
        $datos['description'] = $this->config->item('site_description');
        $datos['pubdate']= $this->Blog->get_last_post_date();
        $datos['posts'] = $this->Blog->get_feed_posts(8);
        $this->load->view('feed', $datos);
    }
}
?>

Lo último que hace falta ahora son las funciones dentro del modelo blog_model que son las encargadas de obtener la información necesaria (los artículos o posts propiamente dichos) de la Base de Datos:

<?php
/**
 * Archivo ./application/models/blog_model.php
 */
?>
<?php
if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Blog_model extends Model
{
    function get_last_post_date()
    {
        $this->db->select('noticias.fecha');
        $this->db->from('noticias');
        $this->db->where('noticias.estado =', 1);
        $this->db->order_by('noticias.id', 'DESC');
        $this->db->limit(1);
        $query = $this->db->get();
        if($query->num_rows() > 0)
        {
            $result = $query->row();
            return $this->convert_datetime($result->fecha);
        }
    }
    
    function get_feed_posts($numero = null)
    {
        $this->db->select('noticias.id, noticias.post_intro, noticias.post_completo, noticias.foto, noticias.categoria_id, noticias.fecha, noticias.titulo, noticias.url, noticias.author_id, categorias.url AS url_categoria, categorias.categoria');
        $this->db->from('noticias');
        $this->db->join('categorias', 'noticias.categoria_id = categorias.id'); 
        $this->db->where('noticias.estado = 1'); //publicada?
        $this->db->where('noticias.fecha <=', date('Y-m-d H:i:s'));
        $this->db->order_by('fecha', 'DESC');
        $this->db->order_by('id', 'DESC');
        $this->db->limit($numero);
        $query = $this->db->get();
  
        if ($query->num_rows() > 0)
        {
            $result = $query->result_array();
            foreach($result as $key => $post)
            {
                $result[$key]['fecha'] = $this->convert_datetime($result[$key]['fecha']);
            }
            return $result;
        }
    
    function convert_datetime($mysql_tatetime = null)
    {
        list($date, $time) = explode(' ', $mysql_tatetime);
        list($year, $month, $day) = explode('-', $date);
        list($hour, $minute, $second) = explode(':', $time);

        $timestamp = mktime($hour, $minute, $second, $month, $day, $year);
        return date('r', $timestamp);
    }
}
?>

Cabe destacar la función convert_datetime. En la tabla noticias de la Base de Datos guardo las fechas en un campo timestamp propio de MySQL, y por lo tanto es necesario convertir la fecha al formato aceptado por el estándar RSS. Para los curiosos, os voy a dejar también cómo es la estructura de las dos tablas que se necesitan, tal y como las tengo yo:

--
-- Estructura de tabla para la tabla `categorias`
--

CREATE TABLE IF NOT EXISTS `categorias` (
  `id` int(11) NOT NULL auto_increment,
  `categoria` varchar(128) character set utf8 collate utf8_spanish_ci NOT NULL,
  `url` varchar(128) character set utf8 collate utf8_spanish_ci NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;

-- --------------------------------------------------------

--
-- Estructura de tabla para la tabla `noticias`
--

CREATE TABLE IF NOT EXISTS `noticias` (
  `id` int(11) NOT NULL auto_increment,
  `categoria_id` int(11) NOT NULL,
  `fecha` timestamp NOT NULL default CURRENT_TIMESTAMP,
  `titulo` varchar(128) character set utf8 collate utf8_spanish_ci NOT NULL,
  `url` varchar(128) character set utf8 collate utf8_spanish_ci NOT NULL,
  `post_intro` text character set utf8 collate utf8_spanish_ci NOT NULL,
  `post_completo` text character set utf8 collate utf8_spanish_ci,
  `foto` varchar(255) character set utf8 collate utf8_spanish_ci default NULL,
  `estado` tinyint(1) NOT NULL,
  `allow_comments` tinyint(1) NOT NULL default '1',
  `author_id` int(11) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;

Esto es todo. Ahora, si accediésemos a la dirección miweb.com/blog/feed veríamos las últimas 8 entradas(esto es configurable fácilmente) en formato RSS.

dwPalma Feed

En mi caso particular, además envié el feed al popular servicio de feedburner, haciendo así aun más sencillo el poder suscribirse y obteniendo al mismo tiempo estadísticas sobre las suscripciones. Para cualquier duda o sugerencia, los comentarios :)

más contenido de

1 comentario

Avatar
Mauricio 14 de may. de 2011, 12:43

La verdad que muy bueno, no pensé que fuera tan simple(la teoría) veremos en la práctica al implementar.. :P.
Muy lindo el sitio, los efectos e interesante lo del boton de previsualizar.

permalink

escribir comentario