* $feed = new ezcFeed( 'rss2' );
*
* - by parsing an existing XML file or URI. The feed type of the resulting
* ezcFeed object will be autodetected. Example:
*
* $feed = ezcFeed::parse( 'http://www.example.com/rss2.xml' );
*
* - by parsing an XML document stored in a string variable. The feed type of
* the resulting ezcFeed object will be autodetected. Example:
*
* $feed = ezcFeed::parseContent( $xmlString );
*
*
* Operations possible upon ezcFeed objects (in the following examples $feed is
* an existing {@link ezcFeed} object):
* - set a value to the feed object. Example:
*
* $feed->title = 'News';
*
* - get a value from the feed object. Example:
*
* $title = $feed->title;
*
* - iterate over the items in the feed. Example:
*
* // retrieve the titles from the feed items
* foreach ( $feed->items as $item )
* {
* $titles[] = $item->title;
* }
*
* - add a new item to the feed. Example:
*
* $item = $feed->add( 'item' );
* $item->title = 'Item title';
*
* - add a new module to the feed item. Example:
*
* $item = $feed->add( 'item' );
* $module = $item->addModule( 'Content' );
* $content->encoded = 'text content which will be encoded';
*
* - iterate over the loaded modules in a feed item. Example:
*
* // display the namespaces of the modules loaded in the feed item $item
* foreach ( $item->getModules() as $moduleName => $module )
* {
* echo $module->getNamespace();
* }
*
* - generate an XML document from the {@link ezcFeed} object. The result
* string should be saved to a file, and a link to a file made accessible to
* users of the application. Example:
*
* $xml = $feed->generate();
*
*
* @property ezcFeedElement $author
* One author of the feed.
* ATOM-author (required, multiple),
* RSS1-none,
* RSS2-managingEditor (optional, recommended, single).
* @property array(ezcFeedElement) $authors
* Access to the multiple $author values. Example:
*
* foreach ( $feed->authors as $author )
* {
* //use the ezcFeedElement $author
* }
*
* @property ezcFeedElement $category
* A category for the feed.
* ATOM-category (optional, multiple),
* RSS1-none,
* RSS2-category (optional, multiple).
* @property array(ezcFeedElement) $categories
* Access to the multiple $category values. Example:
*
* foreach ( $feed->categories as $category )
* {
* //use the ezcFeedElement $category
* }
*
* @property ezcFeedElement $cloud
* Allows processes to register with a cloud to be notified of updates
* to the channel, implementing a lightweight publish-subscribe
* protocol for RSS feeds.
* ATOM-none,
* RSS1-none,
* RSS2-cloud (optional, not recommended, single).
* @property ezcFeedElement $contributor
* One contributor for the feed.
* ATOM-contributor (optional, not recommended, multiple),
* RSS1-none,
* RSS2-none.
* @property array(ezcFeedElement) $contributors
* Access to the multiple $contributor values. Example:
*
* foreach ( $feed->contributors as $contributor )
* {
* //use the ezcFeedElement $contributor
* }
*
* @property ezcFeedElement $copyright
* Copyright information for the feed.
* ATOM-rights (optional, single),
* RSS1-none,
* RSS2-copyright (optional, single).
* @property ezcFeedElement $description
* A short description of the feed.
* ATOM-subtitle (required, single),
* RSS1-description (required, single),
* RSS2-description (required, single).
* @property ezcFeedElement $docs
* An URL that points to the documentation for the format used in the
* feed file.
* ATOM-none,
* RSS1-none,
* RSS2-docs (optional, not recommended, single) - usual value is
* {@link http://www.rssboard.org/rss-specification}.
* @property ezcFeedElement $generator
* Indicates the software used to generate the feed.
* ATOM-generator (optional, single),
* RSS1-none,
* RSS2-generator (optional, single).
* @property ezcFeedElement $icon
* An icon for a feed, similar with favicon.ico for websites.
* ATOM-icon (optional, not recommended, single),
* RSS1-none,
* RSS2-none.
* @property ezcFeedElement $id
* A universally unique and permanent identifier for a feed. For
* example, it can be an Internet domain name.
* ATOM-id (required, single),
* RSS1-about (required, single),
* RSS2-none.
* @property ezcFeedElement $image
* An image associated with the feed
* ATOM-logo (optional, single),
* RSS1-image (optional, single),
* RSS2-image (optional, single).
* @property-read ezcFeedItem $item
* A feed item.
* ATOM-entry (optional, recommended, multiple),
* RSS1-item (required, multiple),
* RSS2-item (required, multiple).
* @property-read array(ezcFeedItem) $items
* The items contained in the feed. Example:
*
* foreach ( $feed->items as $item )
* {
* //use the ezcFeedItem $item
* }
*
* @property ezcFeedElement $language
* The language for the feed.
* ATOM-xml:lang attribute for title, description, copyright, content,
* comments (optional, single) - accessed as language through ezcFeed,
* RSS1-none,
* RSS2-language (optional, single).
* @property ezcFeedElement $link
* An URL to the HTML website corresponding to the channel.
* ATOM-link (required one link with rel='self', multiple),
* RSS1-link (required, single),
* RSS2-link (required, single).
* @property array(ezcFeedElement) $links
* Access to the multiple $link values. Example:
*
* foreach ( $feed->links as $link )
* {
* //use the ezcFeedElement $link
* }
*
* @property ezcFeedElement $published
* The time the feed was published.
* ATOM-none,
* RSS1-none,
* RSS2-pubDate (optional, not recommended, single).
* @property ezcFeedElement $rating
* The {@link http://www.w3.org/PICS/ PICS} rating for the channel.
* ATOM-none,
* RSS1-none,
* RSS2-rating (optional, not recommended, single).
* @property ezcFeedElement $skipDays
* A hint for aggregators telling them which days they can skip when
* reading the feed.
* ATOM-none,
* RSS1-none,
* RSS2-skipDays (optional, not recommended, single).
* @property ezcFeedElement $skipHours
* A hint for aggregators telling them which hours they can skip when
* reading the feed.
* ATOM-none,
* RSS1-none,
* RSS2-skipHours (optional, not recommended, single).
* @property ezcFeedElement $textInput
* Specifies a text input box that can be displayed with the feed.
* ATOM-none,
* RSS1-textinput (optional, not recommended, single),
* RSS2-textInput (optional, not recommended, single).
* @property ezcFeedElement $title
* Human readable title for the feed. For example, it can be the same
* as the website title.
* ATOM-title (required, single),
* RSS1-title (required, single),
* RSS2-title (required, single).
* @property ezcFeedElement $ttl
* Number of minutes that indicates how long a channel can be cached
* before refreshing from the source.
* ATOM-none,
* RSS1-none,
* RSS2-ttl (optional, not recommended, single).
* @property ezcFeedElement $updated
* The last time the feed was updated.
* ATOM-updated (required, single),
* RSS1-none,
* RSS2-lastBuildDate (optional, recommended, single).
* @property ezcFeedElement $webMaster
* The email address of the webmaster responsible for the feed.
* ATOM-none,
* RSS1-none,
* RSS2-webMaster (optional, not recommended, single).
*
* @todo parse() and parseContent() should(?) handle common broken XML files
* (for example if the first line is not )
*
* @package Feed
* @version 1.1alpha1
* @mainclass
*/
class ezcFeed
{
/**
* The version of the feed generator, to be included in the generated feeds.
*/
const GENERATOR_VERSION = '1.1alpha1';
/**
* The uri of the feed generator, to be included in the generated feeds.
*/
const GENERATOR_URI = 'http://ezcomponents.org/docs/tutorials/Feed';
/**
* Holds a list of all supported feed types.
*
* @var array(string=>string)
*/
protected static $supportedFeedTypes = array(
'rss1' => 'ezcFeedRss1',
'rss2' => 'ezcFeedRss2',
'atom' => 'ezcFeedAtom',
);
/**
* Holds a list of all supported modules.
*
* @var array(string=>string)
*/
protected static $supportedModules = array(
'Content' => 'ezcFeedContentModule',
'CreativeCommons' => 'ezcFeedCreativeCommonsModule',
'DublinCore' => 'ezcFeedDublinCoreModule',
'Geo' => 'ezcFeedGeoModule',
'iTunes' => 'ezcFeedITunesModule',
);
/**
* Holds a list of all supported modules prefixes.
*
* @var array(string=>string)
*/
protected static $supportedModulesPrefixes = array(
'content' => 'Content',
'creativeCommons' => 'CreativeCommons',
'dc' => 'DublinCore',
'geo' => 'Geo',
'itunes' => 'iTunes',
);
/**
* Holds the feed processor.
*
* @var ezcFeedProcessor
* @ignore
*/
protected $feedProcessor;
/**
* Holds the feed type (eg. 'rss2').
*
* @var string
* @ignore
*/
protected $feedType;
/**
* Holds the feed content type (eg. 'application/rss+xml').
*
* @var string
* @ignore
*/
protected $contentType;
/**
* Creates a new feed of type $type.
*
* The $type value is one of {@link self::$supportedFeedTypes}.
*
* Example:
*
* // create an RSS2 feed
* $feed = new ezcFeed( 'rss2' );
*
*
* @throws ezcFeedUnsupportedTypeException
* If the passed $type is an unsupported feed type.
*
* @param string $type The feed type. See {@link self::$supportedFeedTypes} for possible values
*/
public function __construct( $type )
{
$type = strtolower( $type );
if ( !isset( self::$supportedFeedTypes[$type] ) )
{
throw new ezcFeedUnsupportedTypeException( $type );
}
$this->feedType = $type;
$this->feedProcessor = new self::$supportedFeedTypes[$type];
$this->contentType = $this->feedProcessor->getContentType();
}
/**
* Sets the property $property to $value.
*
* @param string $property The property name
* @param mixed $value The property value
* @ignore
*/
public function __set( $property, $value )
{
switch ( $property )
{
case 'author':
case 'authors':
case 'category':
case 'categories':
case 'cloud':
case 'contributor':
case 'contributors':
case 'copyright':
case 'description':
case 'docs':
case 'generator':
case 'icon':
case 'id':
case 'image':
case 'language':
case 'link':
case 'links':
case 'published':
case 'rating':
case 'skipDays':
case 'skipHours':
case 'textInput':
case 'title':
case 'ttl':
case 'updated':
case 'webMaster':
$this->feedProcessor->set( $property, $value );
break;
default:
$supportedModules = ezcFeed::getSupportedModules();
if ( isset( $supportedModules[$property] ) )
{
$this->feedProcessor->setModule( $property, $value );
return;
}
}
}
/**
* Returns the value of property $property.
*
* @throws ezcBasePropertyNotFoundException
* If the property $property does not exist.
*
* @param string $property The property name
* @return mixed
* @ignore
*/
public function __get( $property )
{
switch ( $property )
{
case 'author':
case 'authors':
case 'category':
case 'categories':
case 'cloud':
case 'contributor':
case 'contributors':
case 'copyright':
case 'description':
case 'docs':
case 'generator':
case 'icon':
case 'id':
case 'image':
case 'item':
case 'items':
case 'language':
case 'link':
case 'links':
case 'published':
case 'rating':
case 'skipDays':
case 'skipHours':
case 'textInput':
case 'title':
case 'ttl':
case 'updated':
case 'webMaster':
$value = $this->feedProcessor->get( $property );
return $value;
default:
$supportedModules = ezcFeed::getSupportedModules();
if ( isset( $supportedModules[$property] ) )
{
if ( isset( $this->$property ) )
{
return $this->feedProcessor->getModule( $property );
}
else
{
throw new ezcFeedUndefinedModuleException( $property );
}
}
}
throw new ezcFeedUnsupportedModuleException( $property );
}
/**
* Returns if the property $name is set.
*
* @param string $name The property name
* @return bool
* @ignore
*/
public function __isset( $name )
{
switch ( $name )
{
case 'author':
case 'authors':
case 'category':
case 'categories':
case 'cloud':
case 'contributor':
case 'contributors':
case 'copyright':
case 'description':
case 'docs':
case 'generator':
case 'icon':
case 'id':
case 'image':
case 'item':
case 'items':
case 'language':
case 'link':
case 'links':
case 'published':
case 'rating':
case 'skipDays':
case 'skipHours':
case 'textInput':
case 'title':
case 'ttl':
case 'updated':
case 'webMaster':
$value = $this->feedProcessor->get( $name );
return ( $value !== null );
default:
$supportedModules = ezcFeed::getSupportedModules();
if ( isset( $supportedModules[$name] ) )
{
return $this->hasModule( $name );;
}
}
return false;
}
/**
* Adds a new module to this item and returns it.
*
* @todo check if module is already added, maybe return the existing module
*
* @param string $name The name of the module to add
* @return ezcFeedModule
*/
public function addModule( $name )
{
$this->$name = ezcFeedModule::create( $name, 'feed' );
return $this->$name;
}
/**
* Returns true if the module $name is loaded, false otherwise.
*
* @param string $name The name of the module to check if loaded for this item
* @return bool
*/
public function hasModule( $name )
{
return $this->feedProcessor->hasModule( $name );
}
/**
* Returns an array with all the modules loaded at feed-level.
*
* @return array(ezcFeedModule)
*/
public function getModules()
{
return $this->feedProcessor->getModules();
}
/**
* Adds a new element with name $name to the feed and returns it.
*
* Example:
*
* // $feed is an ezcFeed object
* $item = $feed->add( 'item' );
* $item->title = 'Item title';
*
*
* @param string $name The name of the element to add
* @return ezcFeedElement
*/
public function add( $name )
{
return $this->feedProcessor->add( $name );
}
/**
* Generates and returns an XML document from the current object.
*
* @return string
*/
public function generate()
{
return $this->feedProcessor->generate();
}
/**
* Parses the XML document in the $uri and returns an ezcFeed object with
* the type autodetected from the XML document.
*
* Example of parsing an XML document stored in an URI:
*
* $feed = ezcFeed::parse( 'http://www.example.com/rss2.xml' );
*
*
* @throws ezcBaseFileNotFoundException
* If the XML file at $uri could not be found.
* @throws ezcFeedCanNotParseException
* If the content at $uri is not a valid XML document.
*
* @param string $uri An URI which stores an XML document
* @return ezcFeed
*/
public static function parse( $uri )
{
if ( !file_exists( $uri ) )
{
$headers = @get_headers( $uri );
if ( preg_match( "|200|", $headers[0] ) === 0 )
{
throw new ezcBaseFileNotFoundException( $uri );
}
}
$xml = new DOMDocument();
$retval = @$xml->load( $uri );
if ( $retval === false )
{
throw new ezcFeedCanNotParseException( $uri, "{$uri} is not a valid XML file" );
}
return self::dispatchXml( $xml );
}
/**
* Parses the XML document stored in $content and returns an ezcFeed object
* with the type autodetected from the XML document.
*
* Example of parsing an XML document stored in a string:
*
* // $xmlString contains a valid XML string
* $feed = ezcFeed::parseContent( $xmlString );
*
*
* @throws ezcFeedParseErrorException
* If $content is not a valid XML document.
*
* @param string $content A string variable which stores an XML document
* @return ezcFeed
*/
public static function parseContent( $content )
{
$xml = new DOMDocument();
$retval = @$xml->loadXML( $content );
if ( $retval === false )
{
throw new ezcFeedParseErrorException( "Content is no valid XML" );
}
return self::dispatchXml( $xml );
}
/**
* Parses the $xml object by dispatching it to the processor that can
* handle it.
*
* @throws ezcFeedCanNotParseException
* If the $xml object could not be parsed by any available processor.
*
* @param DOMDocument $xml The XML object to parse
* @return ezcFeed
* @ignore
*/
protected static function dispatchXml( DOMDocument $xml )
{
foreach ( self::$supportedFeedTypes as $feedType => $feedClass )
{
$canParse = call_user_func( array( $feedClass, 'canParse' ), $xml );
if ( $canParse === true )
{
$processor = new $feedClass;
return $processor->parse( $xml );
}
}
throw new ezcFeedCanNotParseException( $xml->documentURI, 'Feed type not recognized' );
}
/**
* Returns the supported feed types (the keys of the
* {@link self::$supportedFeedTypes} array).
*
* @return array(string)
*/
public static function getSupportedTypes()
{
return array_keys( self::$supportedFeedTypes );
}
/**
* Returns the supported feed modules ({@link self::$supportedModules}
* array).
*
* @return array(string)
*/
public static function getSupportedModules()
{
return self::$supportedModules;
}
/**
* Returns the supported feed modules prefixes
* ({@link self::$supportedModulesPrefixes} array).
*
* @return array(string)
*/
public static function getSupportedModulesPrefixes()
{
return self::$supportedModulesPrefixes;
}
/**
* Returns the feed type of this feed object (eg. 'rss2').
*
* @return string
*/
public function getFeedType()
{
return $this->feedType;
}
/**
* Returns the feed content type of this feed object
* (eg. 'application/rss+xml').
*
* @return string
*/
public function getContentType()
{
return $this->contentType;
}
}
?>