Page 1 sur 2

Une petite classe qui lit les newsfeed ( rss/atom )

Posté : 06 oct. 2010, 11:58
par AoSiX
Hello,

tout d'abord je tiens à remercier stealth35 pour son coup de main, lui qui connait par cœur toutes les classes de la SPL :P

NewsFeedReader qui lit purement et simplement les fils de news RSS/ATOM, et vous envoi l'ensemble des news sous forme de tableau PHP et d'objet. Elle nécessite CURL et SimpleXml, donc à priori, PHP > 5

Fonctionnement global de la classe :
- Récupération du flux avec CURL,
- Lecture avec SimpleXML,
- Détermination automatique de la nature du flux ( RSS ou ATOM )
- On renvoi l'ensemble des news sous forme de tableau et d'objet ( grâce à ArrayObject )

Fonctions disponible pour toi, ami développeur :
- Constructeur : possibilité de lui passé un unique argument : l'url du flux.
- méthode parse() : Retourne les news.
- getType() : qui retourne le type de flux
- getUrl & setUrl($url) : getter et setter pour l'url du flux

Le fichier de la classe :
MAJ 06/10/2010 14h00: remplacement du regex de test d'url par un filter_var
MAJ 06/10/2010 14h30: mise en place du de la constante qui permet de checker le http://
MAJ 06/10/2010 15h20: retourne les résultats sous la forme de tableau ET d'objet ( au lieu de ou )
MAJ 06/10/2010 15h30: suppression de cUrl; tout le chargement se fait avec SimpleXMLIterator + define() remplacé par des const
MAJ 06/10/2010 16h15: centralisation des fonction de parsing RSS et ATOM, elles étaient identique à un détail près
MAJ 06/10/2010 17h15: ajout d'un getter pour qui retourne le type de flux
MAJ 07/10/2010 13h15: Remplacement du tableau de retour par un ArrayIterator
class NewsFeedReader
{
        protected $url=null;
        protected $xml_doc=null;
       
	   	const FEED_TYPE_NO = 0;
		const FEED_TYPE_RSS = 1;
		const FEED_TYPE_ATOM = 2;
	   
        protected $feed_type=self::FEED_TYPE_NO;
       
       
        function __construct($url=null)
        {
       
                if($url!=null)
                        $this->setUrl($url);
        }
       
       
        private function fetchFeed()
        {
                if($this->getUrl() == null)
                        throw new Exception('Aucune URL.');
                       
                $this->xml_doc = new SimpleXMLIterator($this->url, LIBXML_NOCDATA, true);
               
                if(isset($this->xml_doc->channel))
                        $this->feed_type=self::FEED_TYPE_RSS;
                elseif(isset($this->xml_doc->entry))
                        $this->feed_type=self::FEED_TYPE_ATOM;
                else
                        $this->feed_type=self::FEED_TYPE_NO;
        }
       
        public function parse()
        {
                if($this->xml_doc==null)
                        $this->fetchFeed();
                       
       
                switch($this->feed_type)
                {
                        case self::FEED_TYPE_RSS:
                        case self::FEED_TYPE_ATOM:
                                return $this->parseRSSATOM();
                        break;
                        default:
                                throw new Exception('Rien à parser');
                }
        }
       
        /* PARSERS */
        protected function parseRSSATOM()
        {
            $retour = new ArrayIterator();
            $newsList=null;
           
            if($this->feed_type==self::FEED_TYPE_RSS)
                $newsList=$this->xml_doc->channel->item;
            elseif($this->feed_type==self::FEED_TYPE_ATOM)
                $newsList=$this->xml_doc->entry;

             foreach($newsList as $item)
             {
                 $retour->append(new ArrayObject((array) $item, ArrayObject::ARRAY_AS_PROPS));
             }

            return $retour;
        }
       
       
        /* GETTER / SETTER */
        public function setUrl($url)
        {
                 if(filter_var($url, FILTER_VALIDATE_URL,FILTER_FLAG_SCHEME_REQUIRED)===$url)
                {
                        $this->url=$url;
                        return true;
                }
                throw new Exception('URL invalide');
        }
   
        public function getUrl()
        {
                return ((strlen($this->url)>0)?$this->url:null);
        }

       public function getType()
	{
		return $this->feed_type;
	}
}
?>
Exemple d'utilisation
<?php
require("NewsFeedReader.class.php");
if(!isset($_GET['atom']))
	$rss = new NewsFeedReader("http://feeds.feedburner.com/Ao6-labs?format=xml");
else
	$rss = new NewsFeedReader("http://www.atomenabled.org/atom.xml");

$news = $rss->parse();

?>

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="utf-8" />
    <title>Exemple</title>
</head>
<body>

    <div>
                <?php
                        foreach($news as $actu)
                        {
                                //print_r($actu);
                                echo '<h1><a href='.$actu->link.'>'.$actu->title.'</a></h1>';
								if( $rss->getType() == NewsFeedReader::FEED_TYPE_RSS)
									echo '<p>'.$actu->description.'</p>';
								elseif($rss->getType() == NewsFeedReader::FEED_TYPE_ATOM)
									echo '<p>'.$actu->content.'</p>';
                        }
                ?>
    </div>
 
</body>
</html>
J'ai très peu souvent à développer des classes génériques à utilisation multiple, je bosse surtout sur des points spécifique en général, alors n'hésitez pas à me donner votre avis et à me conseiller !

Bisous :P

Re: Une petit classe qui lit les newsfeed ( rss/atom )

Posté : 06 oct. 2010, 13:08
par stealth35
pas mal :wink:
pourquoi cURL ?
sinon pour valider ton url tu peux utiliser FILTER_VALIDATE_URL avec filter_var ?

tu peux aussi mettre tes constants dans ta class :wink:

Re: Une petit classe qui lit les newsfeed ( rss/atom )

Posté : 06 oct. 2010, 13:16
par Nours312
en amont de la classe, et égalamenet par
et également par
#-o à pas compris ^^

Sinon, il serait pas mal de pouvoir indexer un tableau d'url, (cela pourrait etre issu d'une BDD rapidement), et ta classe rangerais les items par dateTime, ainsi elle pourrait avoir une plus grande utilité ;)

Tu pourrais aussi envisager différentes méthodes de sorties avec des tri par date ASC / DESC par nom, par sujet, par sites (en cas de multiples url), ...

Quitte faire une belle classe multi utilisation, autant faire en sorte de la doté d'un maximum d'outils non ?

Re: Une petit classe qui lit les newsfeed ( rss/atom )

Posté : 06 oct. 2010, 14:07
par AoSiX
Merci, de vos réponses,
pourquoi cURL ?
J'ai consulter pas mal de benchmark m'indiquant que cUrl est plus rapide que file_get_contents(), ça m'a suffit... ( http://stackoverflow.com/questions/5555 ... erformance )

j'implémente le filter_var, je l'utilise régulièrement pour les e-mail en plus, et j'ai zappé le fait qu'il filtre aussi les URL ;)
tu peux aussi mettre tes constants dans ta class :wink:
Mes define dans le constructeur tu veux dire ?
en amont de la classe, et égalamenet par
et également par
#-o à pas compris ^^
Moi non plus :shock: cafouillage corrigé :)
Sinon, il serait pas mal de pouvoir indexer un tableau d'url, (cela pourrait etre issu d'une BDD rapidement), et ta classe rangerais les items par dateTime, ainsi elle pourrait avoir une plus grande utilité ;)

Tu pourrais aussi envisager différentes méthodes de sorties avec des tri par date ASC / DESC par nom, par sujet, par sites (en cas de multiples url), ...
Je pense que c'est pas donné, et peut-être même un peu trop poussé pour moi (je me perd assez vite dans les logiques de tri de tableaux multidimensionnels) ;) Étant donné que je développe ça au boulot pour le boulot, je n'ai pas le possibilité de consacré un temps énorme là dessus... Mais si un jour ma chérie me laisse tomber et que je n'ai plus que ça à faire de mes soirées, je m'y pencherai pour l'améliorer :lol:

Re: Une petit classe qui lit les newsfeed ( rss/atom )

Posté : 06 oct. 2010, 14:13
par stealth35
J'ai consulter pas mal de benchmark m'indiquant que cUrl est plus rapide que file_get_contents(), ça m'a suffit... ( http://stackoverflow.com/questions/5555 ... erformance
ni curl, ni file_get_contents SimpleXmlElement accepte les url :wink:
pour ton switch array/object tu peux aussi utiliser la class ArrayObject tu pourra faire direct :
$news[0]['title']
//ou
$news[0]->title
:wink:

par contre faut faire gaffe avec FILTER_VALIDATE_URL, il verifie une URL mais un URL c'est pas forcement http:// , faut donc verifier le protocole aussi :wink:
Mes define dans le constructeur tu veux dire ?
non dans la class
const FEED_TYPE_NO = 0;
const FEED_TYPE_RSS = 1;
const FEED_TYPE_ATOM = 2;
tu y accède avec self
private $feed_type = self::FEED_TYPE_NO;

Re: Une petit classe qui lit les newsfeed ( rss/atom )

Posté : 06 oct. 2010, 14:22
par stealth35
tu peux aussi utiliser SimpleXMLIterator qui beaucoup rapide que SimpleXMLElement pour les boucles :wink:

Re: Une petit classe qui lit les newsfeed ( rss/atom )

Posté : 06 oct. 2010, 14:33
par AoSiX
pour ton switch array/object tu peux aussi utiliser la class ArrayObject tu pourra faire direct :
$news[0]['title']
//ou
$news[0]->title
:wink:
En fait l'objet n'est pas un object generique, c'est un SimpleXMLElement, incompatible avec ArrayObject. Le fait que ce soit un SimpleXMLElement ou un object, c'est quasiment pareil pour un développeur (pas pour un chippoteur), pas pour ArrayObject..
par contre faut faire gaffe avec FILTER_VALIDATE_URL, il verifie une URL mais un URL c'est pas forcement http:// , faut donc verifier le protocole aussi :wink:
J'ai googler, à priori FILTER_FLAG_SCHEME_REQUIRED est la solution ;)

Mes define dans le constructeur tu veux dire ?
non dans la class
const FEED_TYPE_NO = 0;
const FEED_TYPE_RSS = 1;
const FEED_TYPE_ATOM = 2;
tu y accède avec self
private $feed_type = self::FEED_TYPE_NO;
La raison pour laquelle je n'ai pas fait cela, c'est qu'ainsi je peux les utilise également dans mon code en dehors de la classe
$news = $rss->parse(PARSE_OBJECT);

Re: Une petit classe qui lit les newsfeed ( rss/atom )

Posté : 06 oct. 2010, 14:43
par stealth35
En fait l'objet n'est pas un object generique, c'est un SimpleXMLElement, incompatible avec ArrayObject. Le fait que ce soit un SimpleXMLElement ou un object, c'est quasiment pareil pour un développeur (pas pour un chippoteur), pas pour ArrayObject..
faut faire comme pour ton code le caster en array :wink:
J'ai googler, à priori FILTER_FLAG_SCHEME_REQUIRED est la solution ;)
t'es sur :wink:
La raison pour laquelle je n'ai pas fait cela, c'est qu'ainsi je peux les utilise également dans mon code en dehors de la classe
$news = $rss->parse(PARSE_OBJECT);
c'est comme pour les autres class
$rss->parse(NewsFeedReader::PARSE_OBJECT); 
:wink:
mais t'en aurai pas besoin avec le ArrayObject


sinon j'ai tester sur plusieur lien j'ai pas eu de soucis, les rdf passe pas par contre mais c'est normal

Re: Une petit classe qui lit les newsfeed ( rss/atom )

Posté : 06 oct. 2010, 15:09
par AoSiX
Alors je me suis occupé de regarder ArrayObject, et je tombe sur un os, les méthodes sont accessible en mode array, mais pas en mode objet c'est à dire que :
$news = $rss->parse();

foreach($news as $actu)
{
        echo '<h1><a href='.$actu['link'].'>'.$actu['title'].'</a></h1>';
	echo '<h1><a href='.$actu->link.'>'.$actu->title.'</a></h1>';
}
Le première ligne marche super, la seconde me notice Undefined property: ArrayObject::$link et $title aussi. J'ai print_ré tout ça, et je vois que mes objets sont de type "storage:ArrayObject:private"; je pense que le private joue... une idée pour le rendre public ?

Re: Une petite classe qui lit les newsfeed ( rss/atom )

Posté : 06 oct. 2010, 15:15
par stealth35
ta mis l'option ArrayObject::ARRAY_AS_PROPS ?

Re: Une petite classe qui lit les newsfeed ( rss/atom )

Posté : 06 oct. 2010, 15:19
par AoSiX
ta mis l'option ArrayObject::ARRAY_AS_PROPS ?
C'est fou comme on peut se sentir bête parfois...merci :)

Re: Une petite classe qui lit les newsfeed ( rss/atom )

Posté : 06 oct. 2010, 15:21
par stealth35
pour ton simplexml tu peu direct faire
$this->xml_doc = new SimpleXMLIterator($this->url, LIBXML_NOCDATA, true);

Re: Une petite classe qui lit les newsfeed ( rss/atom )

Posté : 06 oct. 2010, 15:36
par AoSiX
Merci encore pour ces petites astuces qui me serviront sans doute bien des fois ;) On a quasiment recodé tout ma classe xD

Re: Une petite classe qui lit les newsfeed ( rss/atom )

Posté : 06 oct. 2010, 15:37
par stealth35
Merci encore pour ces petites astuces qui me serviront sans doute bien des fois ;) On a quasiment recodé tout ma classe xD
ca donee quoi maintenant ?

Re: Une petite classe qui lit les newsfeed ( rss/atom )

Posté : 06 oct. 2010, 15:45
par AoSiX
J'ai mis régulièrement à jour le message inital, donc tu peux le reprendre là haut ;)

J'ai ajouter en dernier les const, à la place des define();

avec SimpleXMLIterator, on démarre obligatoirement à php5.1 non ?