Update to drupal 8.0.0-rc1. For more information, see https://www.drupal.org/node/2582663

This commit is contained in:
Greg Anderson 2015-10-08 11:40:12 -07:00
parent eb34d130a8
commit f32e58e4b1
8476 changed files with 211648 additions and 170042 deletions

View file

@ -0,0 +1,846 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer;
use DateTime;
use Zend\Feed\Uri;
use Zend\Validator;
class AbstractFeed
{
/**
* Contains all Feed level date to append in feed output
*
* @var array
*/
protected $data = [];
/**
* Holds the value "atom" or "rss" depending on the feed type set when
* when last exported.
*
* @var string
*/
protected $type = null;
/**
* @var $extensions
*/
protected $extensions;
/**
* Constructor: Primarily triggers the registration of core extensions and
* loads those appropriate to this data container.
*
*/
public function __construct()
{
Writer::registerCoreExtensions();
$this->_loadExtensions();
}
/**
* Set a single author
*
* The following option keys are supported:
* 'name' => (string) The name
* 'email' => (string) An optional email
* 'uri' => (string) An optional and valid URI
*
* @param array $author
* @throws Exception\InvalidArgumentException If any value of $author not follow the format.
* @return AbstractFeed
*/
public function addAuthor(array $author)
{
// Check array values
if (!array_key_exists('name', $author)
|| empty($author['name'])
|| !is_string($author['name'])
) {
throw new Exception\InvalidArgumentException(
'Invalid parameter: author array must include a "name" key with a non-empty string value');
}
if (isset($author['email'])) {
if (empty($author['email']) || !is_string($author['email'])) {
throw new Exception\InvalidArgumentException(
'Invalid parameter: "email" array value must be a non-empty string');
}
}
if (isset($author['uri'])) {
if (empty($author['uri']) || !is_string($author['uri']) ||
!Uri::factory($author['uri'])->isValid()
) {
throw new Exception\InvalidArgumentException(
'Invalid parameter: "uri" array value must be a non-empty string and valid URI/IRI');
}
}
$this->data['authors'][] = $author;
return $this;
}
/**
* Set an array with feed authors
*
* @see addAuthor
* @param array $authors
* @return AbstractFeed
*/
public function addAuthors(array $authors)
{
foreach ($authors as $author) {
$this->addAuthor($author);
}
return $this;
}
/**
* Set the copyright entry
*
* @param string $copyright
* @throws Exception\InvalidArgumentException
* @return AbstractFeed
*/
public function setCopyright($copyright)
{
if (empty($copyright) || !is_string($copyright)) {
throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
}
$this->data['copyright'] = $copyright;
return $this;
}
/**
* Set the feed creation date
*
* @param null|int|DateTime
* @throws Exception\InvalidArgumentException
* @return AbstractFeed
*/
public function setDateCreated($date = null)
{
if ($date === null) {
$date = new DateTime();
} elseif (is_int($date)) {
$date = new DateTime('@' . $date);
} elseif (!$date instanceof DateTime) {
throw new Exception\InvalidArgumentException('Invalid DateTime object or UNIX Timestamp'
. ' passed as parameter');
}
$this->data['dateCreated'] = $date;
return $this;
}
/**
* Set the feed modification date
*
* @param null|int|DateTime
* @throws Exception\InvalidArgumentException
* @return AbstractFeed
*/
public function setDateModified($date = null)
{
if ($date === null) {
$date = new DateTime();
} elseif (is_int($date)) {
$date = new DateTime('@' . $date);
} elseif (!$date instanceof DateTime) {
throw new Exception\InvalidArgumentException('Invalid DateTime object or UNIX Timestamp'
. ' passed as parameter');
}
$this->data['dateModified'] = $date;
return $this;
}
/**
* Set the feed last-build date. Ignored for Atom 1.0.
*
* @param null|int|DateTime
* @throws Exception\InvalidArgumentException
* @return AbstractFeed
*/
public function setLastBuildDate($date = null)
{
if ($date === null) {
$date = new DateTime();
} elseif (is_int($date)) {
$date = new DateTime('@' . $date);
} elseif (!$date instanceof DateTime) {
throw new Exception\InvalidArgumentException('Invalid DateTime object or UNIX Timestamp'
. ' passed as parameter');
}
$this->data['lastBuildDate'] = $date;
return $this;
}
/**
* Set the feed description
*
* @param string $description
* @throws Exception\InvalidArgumentException
* @return AbstractFeed
*/
public function setDescription($description)
{
if (empty($description) || !is_string($description)) {
throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
}
$this->data['description'] = $description;
return $this;
}
/**
* Set the feed generator entry
*
* @param array|string $name
* @param null|string $version
* @param null|string $uri
* @throws Exception\InvalidArgumentException
* @return AbstractFeed
*/
public function setGenerator($name, $version = null, $uri = null)
{
if (is_array($name)) {
$data = $name;
if (empty($data['name']) || !is_string($data['name'])) {
throw new Exception\InvalidArgumentException('Invalid parameter: "name" must be a non-empty string');
}
$generator = ['name' => $data['name']];
if (isset($data['version'])) {
if (empty($data['version']) || !is_string($data['version'])) {
throw new Exception\InvalidArgumentException('Invalid parameter: "version" must be a non-empty string');
}
$generator['version'] = $data['version'];
}
if (isset($data['uri'])) {
if (empty($data['uri']) || !is_string($data['uri']) || !Uri::factory($data['uri'])->isValid()) {
throw new Exception\InvalidArgumentException('Invalid parameter: "uri" must be a non-empty string and a valid URI/IRI');
}
$generator['uri'] = $data['uri'];
}
} else {
if (empty($name) || !is_string($name)) {
throw new Exception\InvalidArgumentException('Invalid parameter: "name" must be a non-empty string');
}
$generator = ['name' => $name];
if (isset($version)) {
if (empty($version) || !is_string($version)) {
throw new Exception\InvalidArgumentException('Invalid parameter: "version" must be a non-empty string');
}
$generator['version'] = $version;
}
if (isset($uri)) {
if (empty($uri) || !is_string($uri) || !Uri::factory($uri)->isValid()) {
throw new Exception\InvalidArgumentException('Invalid parameter: "uri" must be a non-empty string and a valid URI/IRI');
}
$generator['uri'] = $uri;
}
}
$this->data['generator'] = $generator;
return $this;
}
/**
* Set the feed ID - URI or URN (via PCRE pattern) supported
*
* @param string $id
* @throws Exception\InvalidArgumentException
* @return AbstractFeed
*/
public function setId($id)
{
if ((empty($id) || !is_string($id) || !Uri::factory($id)->isValid())
&& !preg_match("#^urn:[a-zA-Z0-9][a-zA-Z0-9\-]{1,31}:([a-zA-Z0-9\(\)\+\,\.\:\=\@\;\$\_\!\*\-]|%[0-9a-fA-F]{2})*#", $id)
&& !$this->_validateTagUri($id)
) {
throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string and valid URI/IRI');
}
$this->data['id'] = $id;
return $this;
}
/**
* Validate a URI using the tag scheme (RFC 4151)
*
* @param string $id
* @return bool
*/
protected function _validateTagUri($id)
{
if (preg_match('/^tag:(?P<name>.*),(?P<date>\d{4}-?\d{0,2}-?\d{0,2}):(?P<specific>.*)(.*:)*$/', $id, $matches)) {
$dvalid = false;
$date = $matches['date'];
$d6 = strtotime($date);
if ((strlen($date) == 4) && $date <= date('Y')) {
$dvalid = true;
} elseif ((strlen($date) == 7) && ($d6 < strtotime("now"))) {
$dvalid = true;
} elseif ((strlen($date) == 10) && ($d6 < strtotime("now"))) {
$dvalid = true;
}
$validator = new Validator\EmailAddress;
if ($validator->isValid($matches['name'])) {
$nvalid = true;
} else {
$nvalid = $validator->isValid('info@' . $matches['name']);
}
return $dvalid && $nvalid;
}
return false;
}
/**
* Set a feed image (URI at minimum). Parameter is a single array with the
* required key 'uri'. When rendering as RSS, the required keys are 'uri',
* 'title' and 'link'. RSS also specifies three optional parameters 'width',
* 'height' and 'description'. Only 'uri' is required and used for Atom rendering.
*
* @param array $data
* @throws Exception\InvalidArgumentException
* @return AbstractFeed
*/
public function setImage(array $data)
{
if (empty($data['uri']) || !is_string($data['uri'])
|| !Uri::factory($data['uri'])->isValid()
) {
throw new Exception\InvalidArgumentException('Invalid parameter: parameter \'uri\''
. ' must be a non-empty string and valid URI/IRI');
}
$this->data['image'] = $data;
return $this;
}
/**
* Set the feed language
*
* @param string $language
* @throws Exception\InvalidArgumentException
* @return AbstractFeed
*/
public function setLanguage($language)
{
if (empty($language) || !is_string($language)) {
throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
}
$this->data['language'] = $language;
return $this;
}
/**
* Set a link to the HTML source
*
* @param string $link
* @throws Exception\InvalidArgumentException
* @return AbstractFeed
*/
public function setLink($link)
{
if (empty($link) || !is_string($link) || !Uri::factory($link)->isValid()) {
throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string and valid URI/IRI');
}
$this->data['link'] = $link;
return $this;
}
/**
* Set a link to an XML feed for any feed type/version
*
* @param string $link
* @param string $type
* @throws Exception\InvalidArgumentException
* @return AbstractFeed
*/
public function setFeedLink($link, $type)
{
if (empty($link) || !is_string($link) || !Uri::factory($link)->isValid()) {
throw new Exception\InvalidArgumentException('Invalid parameter: "link"" must be a non-empty string and valid URI/IRI');
}
if (!in_array(strtolower($type), ['rss', 'rdf', 'atom'])) {
throw new Exception\InvalidArgumentException('Invalid parameter: "type"; You must declare the type of feed the link points to, i.e. RSS, RDF or Atom');
}
$this->data['feedLinks'][strtolower($type)] = $link;
return $this;
}
/**
* Set the feed title
*
* @param string $title
* @throws Exception\InvalidArgumentException
* @return AbstractFeed
*/
public function setTitle($title)
{
if (empty($title) || !is_string($title)) {
throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
}
$this->data['title'] = $title;
return $this;
}
/**
* Set the feed character encoding
*
* @param string $encoding
* @throws Exception\InvalidArgumentException
* @return AbstractFeed
*/
public function setEncoding($encoding)
{
if (empty($encoding) || !is_string($encoding)) {
throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
}
$this->data['encoding'] = $encoding;
return $this;
}
/**
* Set the feed's base URL
*
* @param string $url
* @throws Exception\InvalidArgumentException
* @return AbstractFeed
*/
public function setBaseUrl($url)
{
if (empty($url) || !is_string($url) || !Uri::factory($url)->isValid()) {
throw new Exception\InvalidArgumentException('Invalid parameter: "url" array value'
. ' must be a non-empty string and valid URI/IRI');
}
$this->data['baseUrl'] = $url;
return $this;
}
/**
* Add a Pubsubhubbub hub endpoint URL
*
* @param string $url
* @throws Exception\InvalidArgumentException
* @return AbstractFeed
*/
public function addHub($url)
{
if (empty($url) || !is_string($url) || !Uri::factory($url)->isValid()) {
throw new Exception\InvalidArgumentException('Invalid parameter: "url" array value'
. ' must be a non-empty string and valid URI/IRI');
}
if (!isset($this->data['hubs'])) {
$this->data['hubs'] = [];
}
$this->data['hubs'][] = $url;
return $this;
}
/**
* Add Pubsubhubbub hub endpoint URLs
*
* @param array $urls
* @return AbstractFeed
*/
public function addHubs(array $urls)
{
foreach ($urls as $url) {
$this->addHub($url);
}
return $this;
}
/**
* Add a feed category
*
* @param array $category
* @throws Exception\InvalidArgumentException
* @return AbstractFeed
*/
public function addCategory(array $category)
{
if (!isset($category['term'])) {
throw new Exception\InvalidArgumentException('Each category must be an array and '
. 'contain at least a "term" element containing the machine '
. ' readable category name');
}
if (isset($category['scheme'])) {
if (empty($category['scheme'])
|| !is_string($category['scheme'])
|| !Uri::factory($category['scheme'])->isValid()
) {
throw new Exception\InvalidArgumentException('The Atom scheme or RSS domain of'
. ' a category must be a valid URI');
}
}
if (!isset($this->data['categories'])) {
$this->data['categories'] = [];
}
$this->data['categories'][] = $category;
return $this;
}
/**
* Set an array of feed categories
*
* @param array $categories
* @return AbstractFeed
*/
public function addCategories(array $categories)
{
foreach ($categories as $category) {
$this->addCategory($category);
}
return $this;
}
/**
* Get a single author
*
* @param int $index
* @return string|null
*/
public function getAuthor($index = 0)
{
if (isset($this->data['authors'][$index])) {
return $this->data['authors'][$index];
}
return;
}
/**
* Get an array with feed authors
*
* @return array
*/
public function getAuthors()
{
if (!array_key_exists('authors', $this->data)) {
return;
}
return $this->data['authors'];
}
/**
* Get the copyright entry
*
* @return string|null
*/
public function getCopyright()
{
if (!array_key_exists('copyright', $this->data)) {
return;
}
return $this->data['copyright'];
}
/**
* Get the feed creation date
*
* @return string|null
*/
public function getDateCreated()
{
if (!array_key_exists('dateCreated', $this->data)) {
return;
}
return $this->data['dateCreated'];
}
/**
* Get the feed modification date
*
* @return string|null
*/
public function getDateModified()
{
if (!array_key_exists('dateModified', $this->data)) {
return;
}
return $this->data['dateModified'];
}
/**
* Get the feed last-build date
*
* @return string|null
*/
public function getLastBuildDate()
{
if (!array_key_exists('lastBuildDate', $this->data)) {
return;
}
return $this->data['lastBuildDate'];
}
/**
* Get the feed description
*
* @return string|null
*/
public function getDescription()
{
if (!array_key_exists('description', $this->data)) {
return;
}
return $this->data['description'];
}
/**
* Get the feed generator entry
*
* @return string|null
*/
public function getGenerator()
{
if (!array_key_exists('generator', $this->data)) {
return;
}
return $this->data['generator'];
}
/**
* Get the feed ID
*
* @return string|null
*/
public function getId()
{
if (!array_key_exists('id', $this->data)) {
return;
}
return $this->data['id'];
}
/**
* Get the feed image URI
*
* @return array
*/
public function getImage()
{
if (!array_key_exists('image', $this->data)) {
return;
}
return $this->data['image'];
}
/**
* Get the feed language
*
* @return string|null
*/
public function getLanguage()
{
if (!array_key_exists('language', $this->data)) {
return;
}
return $this->data['language'];
}
/**
* Get a link to the HTML source
*
* @return string|null
*/
public function getLink()
{
if (!array_key_exists('link', $this->data)) {
return;
}
return $this->data['link'];
}
/**
* Get a link to the XML feed
*
* @return string|null
*/
public function getFeedLinks()
{
if (!array_key_exists('feedLinks', $this->data)) {
return;
}
return $this->data['feedLinks'];
}
/**
* Get the feed title
*
* @return string|null
*/
public function getTitle()
{
if (!array_key_exists('title', $this->data)) {
return;
}
return $this->data['title'];
}
/**
* Get the feed character encoding
*
* @return string|null
*/
public function getEncoding()
{
if (!array_key_exists('encoding', $this->data)) {
return 'UTF-8';
}
return $this->data['encoding'];
}
/**
* Get the feed's base url
*
* @return string|null
*/
public function getBaseUrl()
{
if (!array_key_exists('baseUrl', $this->data)) {
return;
}
return $this->data['baseUrl'];
}
/**
* Get the URLs used as Pubsubhubbub hubs endpoints
*
* @return string|null
*/
public function getHubs()
{
if (!array_key_exists('hubs', $this->data)) {
return;
}
return $this->data['hubs'];
}
/**
* Get the feed categories
*
* @return string|null
*/
public function getCategories()
{
if (!array_key_exists('categories', $this->data)) {
return;
}
return $this->data['categories'];
}
/**
* Resets the instance and deletes all data
*
* @return void
*/
public function reset()
{
$this->data = [];
}
/**
* Set the current feed type being exported to "rss" or "atom". This allows
* other objects to gracefully choose whether to execute or not, depending
* on their appropriateness for the current type, e.g. renderers.
*
* @param string $type
* @return AbstractFeed
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* Retrieve the current or last feed type exported.
*
* @return string Value will be "rss" or "atom"
*/
public function getType()
{
return $this->type;
}
/**
* Unset a specific data point
*
* @param string $name
* @return AbstractFeed
*/
public function remove($name)
{
if (isset($this->data[$name])) {
unset($this->data[$name]);
}
return $this;
}
/**
* Method overloading: call given method on first extension implementing it
*
* @param string $method
* @param array $args
* @return mixed
* @throws Exception\BadMethodCallException if no extensions implements the method
*/
public function __call($method, $args)
{
foreach ($this->extensions as $extension) {
try {
return call_user_func_array([$extension, $method], $args);
} catch (Exception\BadMethodCallException $e) {
}
}
throw new Exception\BadMethodCallException(
'Method: ' . $method . ' does not exist and could not be located on a registered Extension'
);
}
/**
* Load extensions from Zend\Feed\Writer\Writer
*
* @throws Exception\RuntimeException
* @return void
*/
protected function _loadExtensions()
{
$all = Writer::getExtensions();
$manager = Writer::getExtensionManager();
$exts = $all['feed'];
foreach ($exts as $ext) {
if (!$manager->has($ext)) {
throw new Exception\RuntimeException(sprintf('Unable to load extension "%s"; could not resolve to class', $ext));
}
$this->extensions[$ext] = $manager->get($ext);
$this->extensions[$ext]->setEncoding($this->getEncoding());
}
}
}

View file

@ -0,0 +1,236 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer;
use DateTime;
use Zend\Feed\Uri;
/**
*/
class Deleted
{
/**
* Internal array containing all data associated with this entry or item.
*
* @var array
*/
protected $data = [];
/**
* Holds the value "atom" or "rss" depending on the feed type set when
* when last exported.
*
* @var string
*/
protected $type = null;
/**
* Set the feed character encoding
*
* @param $encoding
* @throws Exception\InvalidArgumentException
* @return string|null
* @return Deleted
*/
public function setEncoding($encoding)
{
if (empty($encoding) || !is_string($encoding)) {
throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
}
$this->data['encoding'] = $encoding;
return $this;
}
/**
* Get the feed character encoding
*
* @return string|null
*/
public function getEncoding()
{
if (!array_key_exists('encoding', $this->data)) {
return 'UTF-8';
}
return $this->data['encoding'];
}
/**
* Unset a specific data point
*
* @param string $name
* @return Deleted
*/
public function remove($name)
{
if (isset($this->data[$name])) {
unset($this->data[$name]);
}
return $this;
}
/**
* Set the current feed type being exported to "rss" or "atom". This allows
* other objects to gracefully choose whether to execute or not, depending
* on their appropriateness for the current type, e.g. renderers.
*
* @param string $type
* @return Deleted
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* Retrieve the current or last feed type exported.
*
* @return string Value will be "rss" or "atom"
*/
public function getType()
{
return $this->type;
}
/**
* Set reference
*
* @param $reference
* @throws Exception\InvalidArgumentException
* @return Deleted
*/
public function setReference($reference)
{
if (empty($reference) || !is_string($reference)) {
throw new Exception\InvalidArgumentException('Invalid parameter: reference must be a non-empty string');
}
$this->data['reference'] = $reference;
return $this;
}
/**
* @return string
*/
public function getReference()
{
if (!array_key_exists('reference', $this->data)) {
return;
}
return $this->data['reference'];
}
/**
* Set when
*
* @param null|string|DateTime $date
* @throws Exception\InvalidArgumentException
* @return Deleted
*/
public function setWhen($date = null)
{
if ($date === null) {
$date = new DateTime();
} elseif (is_int($date)) {
$date = new DateTime('@' . $date);
} elseif (!$date instanceof DateTime) {
throw new Exception\InvalidArgumentException('Invalid DateTime object or UNIX Timestamp'
. ' passed as parameter');
}
$this->data['when'] = $date;
return $this;
}
/**
* @return DateTime
*/
public function getWhen()
{
if (!array_key_exists('when', $this->data)) {
return;
}
return $this->data['when'];
}
/**
* Set by
*
* @param array $by
* @throws Exception\InvalidArgumentException
* @return Deleted
*/
public function setBy(array $by)
{
$author = [];
if (!array_key_exists('name', $by)
|| empty($by['name'])
|| !is_string($by['name'])
) {
throw new Exception\InvalidArgumentException('Invalid parameter: author array must include a'
. ' "name" key with a non-empty string value');
}
$author['name'] = $by['name'];
if (isset($by['email'])) {
if (empty($by['email']) || !is_string($by['email'])) {
throw new Exception\InvalidArgumentException('Invalid parameter: "email" array'
. ' value must be a non-empty string');
}
$author['email'] = $by['email'];
}
if (isset($by['uri'])) {
if (empty($by['uri'])
|| !is_string($by['uri'])
|| !Uri::factory($by['uri'])->isValid()
) {
throw new Exception\InvalidArgumentException('Invalid parameter: "uri" array value must'
. ' be a non-empty string and valid URI/IRI');
}
$author['uri'] = $by['uri'];
}
$this->data['by'] = $author;
return $this;
}
/**
* @return string
*/
public function getBy()
{
if (!array_key_exists('by', $this->data)) {
return;
}
return $this->data['by'];
}
/**
* @param string $comment
* @return Deleted
*/
public function setComment($comment)
{
$this->data['comment'] = $comment;
return $this;
}
/**
* @return string
*/
public function getComment()
{
if (!array_key_exists('comment', $this->data)) {
return;
}
return $this->data['comment'];
}
}

View file

@ -0,0 +1,765 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer;
use DateTime;
use Zend\Feed\Uri;
/**
*/
class Entry
{
/**
* Internal array containing all data associated with this entry or item.
*
* @var array
*/
protected $data = [];
/**
* Registered extensions
*
* @var array
*/
protected $extensions = [];
/**
* Holds the value "atom" or "rss" depending on the feed type set when
* when last exported.
*
* @var string
*/
protected $type = null;
/**
* Constructor: Primarily triggers the registration of core extensions and
* loads those appropriate to this data container.
*
*/
public function __construct()
{
Writer::registerCoreExtensions();
$this->_loadExtensions();
}
/**
* Set a single author
*
* The following option keys are supported:
* 'name' => (string) The name
* 'email' => (string) An optional email
* 'uri' => (string) An optional and valid URI
*
* @param array $author
* @throws Exception\InvalidArgumentException If any value of $author not follow the format.
* @return Entry
*/
public function addAuthor(array $author)
{
// Check array values
if (!array_key_exists('name', $author)
|| empty($author['name'])
|| !is_string($author['name'])
) {
throw new Exception\InvalidArgumentException(
'Invalid parameter: author array must include a "name" key with a non-empty string value');
}
if (isset($author['email'])) {
if (empty($author['email']) || !is_string($author['email'])) {
throw new Exception\InvalidArgumentException(
'Invalid parameter: "email" array value must be a non-empty string');
}
}
if (isset($author['uri'])) {
if (empty($author['uri']) || !is_string($author['uri']) ||
!Uri::factory($author['uri'])->isValid()
) {
throw new Exception\InvalidArgumentException(
'Invalid parameter: "uri" array value must be a non-empty string and valid URI/IRI');
}
}
$this->data['authors'][] = $author;
return $this;
}
/**
* Set an array with feed authors
*
* @see addAuthor
* @param array $authors
* @return Entry
*/
public function addAuthors(array $authors)
{
foreach ($authors as $author) {
$this->addAuthor($author);
}
return $this;
}
/**
* Set the feed character encoding
*
* @param string $encoding
* @throws Exception\InvalidArgumentException
* @return Entry
*/
public function setEncoding($encoding)
{
if (empty($encoding) || !is_string($encoding)) {
throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
}
$this->data['encoding'] = $encoding;
return $this;
}
/**
* Get the feed character encoding
*
* @return string|null
*/
public function getEncoding()
{
if (!array_key_exists('encoding', $this->data)) {
return 'UTF-8';
}
return $this->data['encoding'];
}
/**
* Set the copyright entry
*
* @param string $copyright
* @throws Exception\InvalidArgumentException
* @return Entry
*/
public function setCopyright($copyright)
{
if (empty($copyright) || !is_string($copyright)) {
throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
}
$this->data['copyright'] = $copyright;
return $this;
}
/**
* Set the entry's content
*
* @param string $content
* @throws Exception\InvalidArgumentException
* @return Entry
*/
public function setContent($content)
{
if (empty($content) || !is_string($content)) {
throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
}
$this->data['content'] = $content;
return $this;
}
/**
* Set the feed creation date
*
* @param null|int|DateTime $date
* @throws Exception\InvalidArgumentException
* @return Entry
*/
public function setDateCreated($date = null)
{
if ($date === null) {
$date = new DateTime();
} elseif (is_int($date)) {
$date = new DateTime('@' . $date);
} elseif (!$date instanceof DateTime) {
throw new Exception\InvalidArgumentException('Invalid DateTime object or UNIX Timestamp passed as parameter');
}
$this->data['dateCreated'] = $date;
return $this;
}
/**
* Set the feed modification date
*
* @param null|int|DateTime $date
* @throws Exception\InvalidArgumentException
* @return Entry
*/
public function setDateModified($date = null)
{
if ($date === null) {
$date = new DateTime();
} elseif (is_int($date)) {
$date = new DateTime('@' . $date);
} elseif (!$date instanceof DateTime) {
throw new Exception\InvalidArgumentException('Invalid DateTime object or UNIX Timestamp passed as parameter');
}
$this->data['dateModified'] = $date;
return $this;
}
/**
* Set the feed description
*
* @param string $description
* @throws Exception\InvalidArgumentException
* @return Entry
*/
public function setDescription($description)
{
if (empty($description) || !is_string($description)) {
throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
}
$this->data['description'] = $description;
return $this;
}
/**
* Set the feed ID
*
* @param string $id
* @throws Exception\InvalidArgumentException
* @return Entry
*/
public function setId($id)
{
if (empty($id) || !is_string($id)) {
throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
}
$this->data['id'] = $id;
return $this;
}
/**
* Set a link to the HTML source of this entry
*
* @param string $link
* @throws Exception\InvalidArgumentException
* @return Entry
*/
public function setLink($link)
{
if (empty($link) || !is_string($link) || !Uri::factory($link)->isValid()) {
throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string and valid URI/IRI');
}
$this->data['link'] = $link;
return $this;
}
/**
* Set the number of comments associated with this entry
*
* @param int $count
* @throws Exception\InvalidArgumentException
* @return Entry
*/
public function setCommentCount($count)
{
if (!is_numeric($count) || (int) $count != $count || (int) $count < 0) {
throw new Exception\InvalidArgumentException('Invalid parameter: "count" must be a positive integer number or zero');
}
$this->data['commentCount'] = (int) $count;
return $this;
}
/**
* Set a link to a HTML page containing comments associated with this entry
*
* @param string $link
* @throws Exception\InvalidArgumentException
* @return Entry
*/
public function setCommentLink($link)
{
if (empty($link) || !is_string($link) || !Uri::factory($link)->isValid()) {
throw new Exception\InvalidArgumentException('Invalid parameter: "link" must be a non-empty string and valid URI/IRI');
}
$this->data['commentLink'] = $link;
return $this;
}
/**
* Set a link to an XML feed for any comments associated with this entry
*
* @param array $link
* @throws Exception\InvalidArgumentException
* @return Entry
*/
public function setCommentFeedLink(array $link)
{
if (!isset($link['uri']) || !is_string($link['uri']) || !Uri::factory($link['uri'])->isValid()) {
throw new Exception\InvalidArgumentException('Invalid parameter: "link" must be a non-empty string and valid URI/IRI');
}
if (!isset($link['type']) || !in_array($link['type'], ['atom', 'rss', 'rdf'])) {
throw new Exception\InvalidArgumentException('Invalid parameter: "type" must be one'
. ' of "atom", "rss" or "rdf"');
}
if (!isset($this->data['commentFeedLinks'])) {
$this->data['commentFeedLinks'] = [];
}
$this->data['commentFeedLinks'][] = $link;
return $this;
}
/**
* Set a links to an XML feed for any comments associated with this entry.
* Each link is an array with keys "uri" and "type", where type is one of:
* "atom", "rss" or "rdf".
*
* @param array $links
* @return Entry
*/
public function setCommentFeedLinks(array $links)
{
foreach ($links as $link) {
$this->setCommentFeedLink($link);
}
return $this;
}
/**
* Set the feed title
*
* @param string $title
* @throws Exception\InvalidArgumentException
* @return Entry
*/
public function setTitle($title)
{
if (empty($title) || !is_string($title)) {
throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
}
$this->data['title'] = $title;
return $this;
}
/**
* Get an array with feed authors
*
* @return array
*/
public function getAuthors()
{
if (!array_key_exists('authors', $this->data)) {
return;
}
return $this->data['authors'];
}
/**
* Get the entry content
*
* @return string
*/
public function getContent()
{
if (!array_key_exists('content', $this->data)) {
return;
}
return $this->data['content'];
}
/**
* Get the entry copyright information
*
* @return string
*/
public function getCopyright()
{
if (!array_key_exists('copyright', $this->data)) {
return;
}
return $this->data['copyright'];
}
/**
* Get the entry creation date
*
* @return string
*/
public function getDateCreated()
{
if (!array_key_exists('dateCreated', $this->data)) {
return;
}
return $this->data['dateCreated'];
}
/**
* Get the entry modification date
*
* @return string
*/
public function getDateModified()
{
if (!array_key_exists('dateModified', $this->data)) {
return;
}
return $this->data['dateModified'];
}
/**
* Get the entry description
*
* @return string
*/
public function getDescription()
{
if (!array_key_exists('description', $this->data)) {
return;
}
return $this->data['description'];
}
/**
* Get the entry ID
*
* @return string
*/
public function getId()
{
if (!array_key_exists('id', $this->data)) {
return;
}
return $this->data['id'];
}
/**
* Get a link to the HTML source
*
* @return string|null
*/
public function getLink()
{
if (!array_key_exists('link', $this->data)) {
return;
}
return $this->data['link'];
}
/**
* Get all links
*
* @return array
*/
public function getLinks()
{
if (!array_key_exists('links', $this->data)) {
return;
}
return $this->data['links'];
}
/**
* Get the entry title
*
* @return string
*/
public function getTitle()
{
if (!array_key_exists('title', $this->data)) {
return;
}
return $this->data['title'];
}
/**
* Get the number of comments/replies for current entry
*
* @return int
*/
public function getCommentCount()
{
if (!array_key_exists('commentCount', $this->data)) {
return;
}
return $this->data['commentCount'];
}
/**
* Returns a URI pointing to the HTML page where comments can be made on this entry
*
* @return string
*/
public function getCommentLink()
{
if (!array_key_exists('commentLink', $this->data)) {
return;
}
return $this->data['commentLink'];
}
/**
* Returns an array of URIs pointing to a feed of all comments for this entry
* where the array keys indicate the feed type (atom, rss or rdf).
*
* @return string
*/
public function getCommentFeedLinks()
{
if (!array_key_exists('commentFeedLinks', $this->data)) {
return;
}
return $this->data['commentFeedLinks'];
}
/**
* Add an entry category
*
* @param array $category
* @throws Exception\InvalidArgumentException
* @return Entry
*/
public function addCategory(array $category)
{
if (!isset($category['term'])) {
throw new Exception\InvalidArgumentException('Each category must be an array and '
. 'contain at least a "term" element containing the machine '
. ' readable category name');
}
if (isset($category['scheme'])) {
if (empty($category['scheme'])
|| !is_string($category['scheme'])
|| !Uri::factory($category['scheme'])->isValid()
) {
throw new Exception\InvalidArgumentException('The Atom scheme or RSS domain of'
. ' a category must be a valid URI');
}
}
if (!isset($this->data['categories'])) {
$this->data['categories'] = [];
}
$this->data['categories'][] = $category;
return $this;
}
/**
* Set an array of entry categories
*
* @param array $categories
* @return Entry
*/
public function addCategories(array $categories)
{
foreach ($categories as $category) {
$this->addCategory($category);
}
return $this;
}
/**
* Get the entry categories
*
* @return string|null
*/
public function getCategories()
{
if (!array_key_exists('categories', $this->data)) {
return;
}
return $this->data['categories'];
}
/**
* Adds an enclosure to the entry. The array parameter may contain the
* keys 'uri', 'type' and 'length'. Only 'uri' is required for Atom, though the
* others must also be provided or RSS rendering (where they are required)
* will throw an Exception.
*
* @param array $enclosure
* @throws Exception\InvalidArgumentException
* @return Entry
*/
public function setEnclosure(array $enclosure)
{
if (!isset($enclosure['uri'])) {
throw new Exception\InvalidArgumentException('Enclosure "uri" is not set');
}
if (!Uri::factory($enclosure['uri'])->isValid()) {
throw new Exception\InvalidArgumentException('Enclosure "uri" is not a valid URI/IRI');
}
$this->data['enclosure'] = $enclosure;
return $this;
}
/**
* Retrieve an array of all enclosures to be added to entry.
*
* @return array
*/
public function getEnclosure()
{
if (!array_key_exists('enclosure', $this->data)) {
return;
}
return $this->data['enclosure'];
}
/**
* Unset a specific data point
*
* @param string $name
* @return Entry
*/
public function remove($name)
{
if (isset($this->data[$name])) {
unset($this->data[$name]);
}
return $this;
}
/**
* Get registered extensions
*
* @return array
*/
public function getExtensions()
{
return $this->extensions;
}
/**
* Return an Extension object with the matching name (postfixed with _Entry)
*
* @param string $name
* @return object
*/
public function getExtension($name)
{
if (array_key_exists($name . '\\Entry', $this->extensions)) {
return $this->extensions[$name . '\\Entry'];
}
return;
}
/**
* Set the current feed type being exported to "rss" or "atom". This allows
* other objects to gracefully choose whether to execute or not, depending
* on their appropriateness for the current type, e.g. renderers.
*
* @param string $type
* @return Entry
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* Retrieve the current or last feed type exported.
*
* @return string Value will be "rss" or "atom"
*/
public function getType()
{
return $this->type;
}
/**
* Method overloading: call given method on first extension implementing it
*
* @param string $method
* @param array $args
* @return mixed
* @throws Exception\BadMethodCallException if no extensions implements the method
*/
public function __call($method, $args)
{
foreach ($this->extensions as $extension) {
try {
return call_user_func_array([$extension, $method], $args);
} catch (\BadMethodCallException $e) {
}
}
throw new Exception\BadMethodCallException('Method: ' . $method
. ' does not exist and could not be located on a registered Extension');
}
/**
* Creates a new Zend\Feed\Writer\Source data container for use. This is NOT
* added to the current feed automatically, but is necessary to create a
* container with some initial values preset based on the current feed data.
*
* @return Source
*/
public function createSource()
{
$source = new Source;
if ($this->getEncoding()) {
$source->setEncoding($this->getEncoding());
}
$source->setType($this->getType());
return $source;
}
/**
* Appends a Zend\Feed\Writer\Entry object representing a new entry/item
* the feed data container's internal group of entries.
*
* @param Source $source
* @return Entry
*/
public function setSource(Source $source)
{
$this->data['source'] = $source;
return $this;
}
/**
* @return Source
*/
public function getSource()
{
if (isset($this->data['source'])) {
return $this->data['source'];
}
return;
}
/**
* Load extensions from Zend\Feed\Writer\Writer
*
* @return void
*/
protected function _loadExtensions()
{
$all = Writer::getExtensions();
$manager = Writer::getExtensionManager();
$exts = $all['entry'];
foreach ($exts as $ext) {
$this->extensions[$ext] = $manager->get($ext);
$this->extensions[$ext]->setEncoding($this->getEncoding());
}
}
}

View file

@ -0,0 +1,21 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Exception;
use Zend\Feed\Exception;
/**
* Feed exceptions
*
* Class to represent exceptions that occur during Feed operations.
*/
class BadMethodCallException extends Exception\BadMethodCallException implements ExceptionInterface
{
}

View file

@ -0,0 +1,19 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Exception;
/**
* Feed exceptions
*
* Interface to represent exceptions that occur during Feed operations.
*/
interface ExceptionInterface
{
}

View file

@ -0,0 +1,21 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Exception;
use Zend\Feed\Exception;
/**
* Feed exceptions
*
* Class to represent exceptions that occur during Feed operations.
*/
class InvalidArgumentException extends Exception\InvalidArgumentException implements ExceptionInterface
{
}

View file

@ -0,0 +1,16 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Exception;
use Zend\Feed\Exception;
class RuntimeException extends Exception\RuntimeException implements ExceptionInterface
{
}

View file

@ -0,0 +1,164 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Extension;
use DOMDocument;
use DOMElement;
/**
*/
abstract class AbstractRenderer implements RendererInterface
{
/**
* @var DOMDocument
*/
protected $dom = null;
/**
* @var mixed
*/
protected $entry = null;
/**
* @var DOMElement
*/
protected $base = null;
/**
* @var mixed
*/
protected $container = null;
/**
* @var string
*/
protected $type = null;
/**
* @var DOMElement
*/
protected $rootElement = null;
/**
* Encoding of all text values
*
* @var string
*/
protected $encoding = 'UTF-8';
/**
* Set the data container
*
* @param mixed $container
* @return AbstractRenderer
*/
public function setDataContainer($container)
{
$this->container = $container;
return $this;
}
/**
* Set feed encoding
*
* @param string $enc
* @return AbstractRenderer
*/
public function setEncoding($enc)
{
$this->encoding = $enc;
return $this;
}
/**
* Get feed encoding
*
* @return string
*/
public function getEncoding()
{
return $this->encoding;
}
/**
* Set DOMDocument and DOMElement on which to operate
*
* @param DOMDocument $dom
* @param DOMElement $base
* @return AbstractRenderer
*/
public function setDomDocument(DOMDocument $dom, DOMElement $base)
{
$this->dom = $dom;
$this->base = $base;
return $this;
}
/**
* Get data container being rendered
*
* @return mixed
*/
public function getDataContainer()
{
return $this->container;
}
/**
* Set feed type
*
* @param string $type
* @return AbstractRenderer
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* Get feedtype
*
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* Set root element of document
*
* @param DOMElement $root
* @return AbstractRenderer
*/
public function setRootElement(DOMElement $root)
{
$this->rootElement = $root;
return $this;
}
/**
* Get root element
*
* @return DOMElement
*/
public function getRootElement()
{
return $this->rootElement;
}
/**
* Append namespaces to feed
*
* @return void
*/
abstract protected function _appendNamespaces();
}

View file

@ -0,0 +1,108 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Extension\Atom\Renderer;
use DOMDocument;
use DOMElement;
use Zend\Feed\Writer\Extension;
/**
*/
class Feed extends Extension\AbstractRenderer
{
/**
* Set to TRUE if a rendering method actually renders something. This
* is used to prevent premature appending of a XML namespace declaration
* until an element which requires it is actually appended.
*
* @var bool
*/
protected $called = false;
/**
* Render feed
*
* @return void
*/
public function render()
{
/**
* RSS 2.0 only. Used mainly to include Atom links and
* Pubsubhubbub Hub endpoint URIs under the Atom namespace
*/
if (strtolower($this->getType()) == 'atom') {
return;
}
$this->_setFeedLinks($this->dom, $this->base);
$this->_setHubs($this->dom, $this->base);
if ($this->called) {
$this->_appendNamespaces();
}
}
/**
* Append namespaces to root element of feed
*
* @return void
*/
protected function _appendNamespaces()
{
$this->getRootElement()->setAttribute('xmlns:atom',
'http://www.w3.org/2005/Atom');
}
/**
* Set feed link elements
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setFeedLinks(DOMDocument $dom, DOMElement $root)
{
$flinks = $this->getDataContainer()->getFeedLinks();
if (!$flinks || empty($flinks)) {
return;
}
foreach ($flinks as $type => $href) {
if (strtolower($type) == $this->getType()) { // issue 2605
$mime = 'application/' . strtolower($type) . '+xml';
$flink = $dom->createElement('atom:link');
$root->appendChild($flink);
$flink->setAttribute('rel', 'self');
$flink->setAttribute('type', $mime);
$flink->setAttribute('href', $href);
}
}
$this->called = true;
}
/**
* Set PuSH hubs
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setHubs(DOMDocument $dom, DOMElement $root)
{
$hubs = $this->getDataContainer()->getHubs();
if (!$hubs || empty($hubs)) {
return;
}
foreach ($hubs as $hubUrl) {
$hub = $dom->createElement('atom:link');
$hub->setAttribute('rel', 'hub');
$hub->setAttribute('href', $hubUrl);
$root->appendChild($hub);
}
$this->called = true;
}
}

View file

@ -0,0 +1,75 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Extension\Content\Renderer;
use DOMDocument;
use DOMElement;
use Zend\Feed\Writer\Extension;
/**
*/
class Entry extends Extension\AbstractRenderer
{
/**
* Set to TRUE if a rendering method actually renders something. This
* is used to prevent premature appending of a XML namespace declaration
* until an element which requires it is actually appended.
*
* @var bool
*/
protected $called = false;
/**
* Render entry
*
* @return void
*/
public function render()
{
if (strtolower($this->getType()) == 'atom') {
return;
}
$this->_setContent($this->dom, $this->base);
if ($this->called) {
$this->_appendNamespaces();
}
}
/**
* Append namespaces to root element
*
* @return void
*/
protected function _appendNamespaces()
{
$this->getRootElement()->setAttribute('xmlns:content',
'http://purl.org/rss/1.0/modules/content/');
}
/**
* Set entry content
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setContent(DOMDocument $dom, DOMElement $root)
{
$content = $this->getDataContainer()->getContent();
if (!$content) {
return;
}
$element = $dom->createElement('content:encoded');
$root->appendChild($element);
$cdata = $dom->createCDATASection($content);
$element->appendChild($cdata);
$this->called = true;
}
}

View file

@ -0,0 +1,79 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Extension\DublinCore\Renderer;
use DOMDocument;
use DOMElement;
use Zend\Feed\Writer\Extension;
/**
*/
class Entry extends Extension\AbstractRenderer
{
/**
* Set to TRUE if a rendering method actually renders something. This
* is used to prevent premature appending of a XML namespace declaration
* until an element which requires it is actually appended.
*
* @var bool
*/
protected $called = false;
/**
* Render entry
*
* @return void
*/
public function render()
{
if (strtolower($this->getType()) == 'atom') {
return;
}
$this->_setAuthors($this->dom, $this->base);
if ($this->called) {
$this->_appendNamespaces();
}
}
/**
* Append namespaces to entry
*
* @return void
*/
protected function _appendNamespaces()
{
$this->getRootElement()->setAttribute('xmlns:dc',
'http://purl.org/dc/elements/1.1/');
}
/**
* Set entry author elements
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setAuthors(DOMDocument $dom, DOMElement $root)
{
$authors = $this->getDataContainer()->getAuthors();
if (!$authors || empty($authors)) {
return;
}
foreach ($authors as $data) {
$author = $this->dom->createElement('dc:creator');
if (array_key_exists('name', $data)) {
$text = $dom->createTextNode($data['name']);
$author->appendChild($text);
$root->appendChild($author);
}
}
$this->called = true;
}
}

View file

@ -0,0 +1,79 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Extension\DublinCore\Renderer;
use DOMDocument;
use DOMElement;
use Zend\Feed\Writer\Extension;
/**
*/
class Feed extends Extension\AbstractRenderer
{
/**
* Set to TRUE if a rendering method actually renders something. This
* is used to prevent premature appending of a XML namespace declaration
* until an element which requires it is actually appended.
*
* @var bool
*/
protected $called = false;
/**
* Render feed
*
* @return void
*/
public function render()
{
if (strtolower($this->getType()) == 'atom') {
return;
}
$this->_setAuthors($this->dom, $this->base);
if ($this->called) {
$this->_appendNamespaces();
}
}
/**
* Append namespaces to feed element
*
* @return void
*/
protected function _appendNamespaces()
{
$this->getRootElement()->setAttribute('xmlns:dc',
'http://purl.org/dc/elements/1.1/');
}
/**
* Set feed authors
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setAuthors(DOMDocument $dom, DOMElement $root)
{
$authors = $this->getDataContainer()->getAuthors();
if (!$authors || empty($authors)) {
return;
}
foreach ($authors as $data) {
$author = $this->dom->createElement('dc:creator');
if (array_key_exists('name', $data)) {
$text = $dom->createTextNode($data['name']);
$author->appendChild($text);
$root->appendChild($author);
}
}
$this->called = true;
}
}

View file

@ -0,0 +1,246 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Extension\ITunes;
use Zend\Feed\Writer;
use Zend\Feed\Writer\Extension;
use Zend\Stdlib\StringUtils;
use Zend\Stdlib\StringWrapper\StringWrapperInterface;
/**
*/
class Entry
{
/**
* Array of Feed data for rendering by Extension's renderers
*
* @var array
*/
protected $data = [];
/**
* Encoding of all text values
*
* @var string
*/
protected $encoding = 'UTF-8';
/**
* The used string wrapper supporting encoding
*
* @var StringWrapperInterface
*/
protected $stringWrapper;
public function __construct()
{
$this->stringWrapper = StringUtils::getWrapper($this->encoding);
}
/**
* Set feed encoding
*
* @param string $enc
* @return Entry
*/
public function setEncoding($enc)
{
$this->stringWrapper = StringUtils::getWrapper($enc);
$this->encoding = $enc;
return $this;
}
/**
* Get feed encoding
*
* @return string
*/
public function getEncoding()
{
return $this->encoding;
}
/**
* Set a block value of "yes" or "no". You may also set an empty string.
*
* @param string
* @return Entry
* @throws Writer\Exception\InvalidArgumentException
*/
public function setItunesBlock($value)
{
if (!ctype_alpha($value) && strlen($value) > 0) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "block" may only'
. ' contain alphabetic characters');
}
if ($this->stringWrapper->strlen($value) > 255) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "block" may only'
. ' contain a maximum of 255 characters');
}
$this->data['block'] = $value;
}
/**
* Add authors to itunes entry
*
* @param array $values
* @return Entry
*/
public function addItunesAuthors(array $values)
{
foreach ($values as $value) {
$this->addItunesAuthor($value);
}
return $this;
}
/**
* Add author to itunes entry
*
* @param string $value
* @return Entry
* @throws Writer\Exception\InvalidArgumentException
*/
public function addItunesAuthor($value)
{
if ($this->stringWrapper->strlen($value) > 255) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: any "author" may only'
. ' contain a maximum of 255 characters each');
}
if (!isset($this->data['authors'])) {
$this->data['authors'] = [];
}
$this->data['authors'][] = $value;
return $this;
}
/**
* Set duration
*
* @param int $value
* @return Entry
* @throws Writer\Exception\InvalidArgumentException
*/
public function setItunesDuration($value)
{
$value = (string) $value;
if (!ctype_digit($value)
&& !preg_match("/^\d+:[0-5]{1}[0-9]{1}$/", $value)
&& !preg_match("/^\d+:[0-5]{1}[0-9]{1}:[0-5]{1}[0-9]{1}$/", $value)
) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "duration" may only'
. ' be of a specified [[HH:]MM:]SS format');
}
$this->data['duration'] = $value;
return $this;
}
/**
* Set "explicit" flag
*
* @param bool $value
* @return Entry
* @throws Writer\Exception\InvalidArgumentException
*/
public function setItunesExplicit($value)
{
if (!in_array($value, ['yes', 'no', 'clean'])) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "explicit" may only'
. ' be one of "yes", "no" or "clean"');
}
$this->data['explicit'] = $value;
return $this;
}
/**
* Set keywords
*
* @param array $value
* @return Entry
* @throws Writer\Exception\InvalidArgumentException
*/
public function setItunesKeywords(array $value)
{
if (count($value) > 12) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "keywords" may only'
. ' contain a maximum of 12 terms');
}
$concat = implode(',', $value);
if ($this->stringWrapper->strlen($concat) > 255) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "keywords" may only'
. ' have a concatenated length of 255 chars where terms are delimited'
. ' by a comma');
}
$this->data['keywords'] = $value;
return $this;
}
/**
* Set subtitle
*
* @param string $value
* @return Entry
* @throws Writer\Exception\InvalidArgumentException
*/
public function setItunesSubtitle($value)
{
if ($this->stringWrapper->strlen($value) > 255) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "subtitle" may only'
. ' contain a maximum of 255 characters');
}
$this->data['subtitle'] = $value;
return $this;
}
/**
* Set summary
*
* @param string $value
* @return Entry
* @throws Writer\Exception\InvalidArgumentException
*/
public function setItunesSummary($value)
{
if ($this->stringWrapper->strlen($value) > 4000) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "summary" may only'
. ' contain a maximum of 4000 characters');
}
$this->data['summary'] = $value;
return $this;
}
/**
* Overloading to itunes specific setters
*
* @param string $method
* @param array $params
* @throws Writer\Exception\BadMethodCallException
* @return mixed
*/
public function __call($method, array $params)
{
$point = lcfirst(substr($method, 9));
if (!method_exists($this, 'setItunes' . ucfirst($point))
&& !method_exists($this, 'addItunes' . ucfirst($point))
) {
throw new Writer\Exception\BadMethodCallException(
'invalid method: ' . $method
);
}
if (!array_key_exists($point, $this->data)
|| empty($this->data[$point])
) {
return;
}
return $this->data[$point];
}
}

View file

@ -0,0 +1,362 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Extension\ITunes;
use Zend\Feed\Uri;
use Zend\Feed\Writer;
use Zend\Stdlib\StringUtils;
use Zend\Stdlib\StringWrapper\StringWrapperInterface;
/**
*/
class Feed
{
/**
* Array of Feed data for rendering by Extension's renderers
*
* @var array
*/
protected $data = [];
/**
* Encoding of all text values
*
* @var string
*/
protected $encoding = 'UTF-8';
/**
* The used string wrapper supporting encoding
*
* @var StringWrapperInterface
*/
protected $stringWrapper;
/**
* Constructor
*/
public function __construct()
{
$this->stringWrapper = StringUtils::getWrapper($this->encoding);
}
/**
* Set feed encoding
*
* @param string $enc
* @return Feed
*/
public function setEncoding($enc)
{
$this->stringWrapper = StringUtils::getWrapper($enc);
$this->encoding = $enc;
return $this;
}
/**
* Get feed encoding
*
* @return string
*/
public function getEncoding()
{
return $this->encoding;
}
/**
* Set a block value of "yes" or "no". You may also set an empty string.
*
* @param string
* @return Feed
* @throws Writer\Exception\InvalidArgumentException
*/
public function setItunesBlock($value)
{
if (!ctype_alpha($value) && strlen($value) > 0) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "block" may only'
. ' contain alphabetic characters');
}
if ($this->stringWrapper->strlen($value) > 255) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "block" may only'
. ' contain a maximum of 255 characters');
}
$this->data['block'] = $value;
return $this;
}
/**
* Add feed authors
*
* @param array $values
* @return Feed
*/
public function addItunesAuthors(array $values)
{
foreach ($values as $value) {
$this->addItunesAuthor($value);
}
return $this;
}
/**
* Add feed author
*
* @param string $value
* @return Feed
* @throws Writer\Exception\InvalidArgumentException
*/
public function addItunesAuthor($value)
{
if ($this->stringWrapper->strlen($value) > 255) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: any "author" may only'
. ' contain a maximum of 255 characters each');
}
if (!isset($this->data['authors'])) {
$this->data['authors'] = [];
}
$this->data['authors'][] = $value;
return $this;
}
/**
* Set feed categories
*
* @param array $values
* @return Feed
* @throws Writer\Exception\InvalidArgumentException
*/
public function setItunesCategories(array $values)
{
if (!isset($this->data['categories'])) {
$this->data['categories'] = [];
}
foreach ($values as $key => $value) {
if (!is_array($value)) {
if ($this->stringWrapper->strlen($value) > 255) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: any "category" may only'
. ' contain a maximum of 255 characters each');
}
$this->data['categories'][] = $value;
} else {
if ($this->stringWrapper->strlen($key) > 255) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: any "category" may only'
. ' contain a maximum of 255 characters each');
}
$this->data['categories'][$key] = [];
foreach ($value as $val) {
if ($this->stringWrapper->strlen($val) > 255) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: any "category" may only'
. ' contain a maximum of 255 characters each');
}
$this->data['categories'][$key][] = $val;
}
}
}
return $this;
}
/**
* Set feed image (icon)
*
* @param string $value
* @return Feed
* @throws Writer\Exception\InvalidArgumentException
*/
public function setItunesImage($value)
{
if (!Uri::factory($value)->isValid()) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "image" may only'
. ' be a valid URI/IRI');
}
if (!in_array(substr($value, -3), ['jpg', 'png'])) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "image" may only'
. ' use file extension "jpg" or "png" which must be the last three'
. ' characters of the URI (i.e. no query string or fragment)');
}
$this->data['image'] = $value;
return $this;
}
/**
* Set feed cumulative duration
*
* @param string $value
* @return Feed
* @throws Writer\Exception\InvalidArgumentException
*/
public function setItunesDuration($value)
{
$value = (string) $value;
if (!ctype_digit($value)
&& !preg_match("/^\d+:[0-5]{1}[0-9]{1}$/", $value)
&& !preg_match("/^\d+:[0-5]{1}[0-9]{1}:[0-5]{1}[0-9]{1}$/", $value)
) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "duration" may only'
. ' be of a specified [[HH:]MM:]SS format');
}
$this->data['duration'] = $value;
return $this;
}
/**
* Set "explicit" flag
*
* @param bool $value
* @return Feed
* @throws Writer\Exception\InvalidArgumentException
*/
public function setItunesExplicit($value)
{
if (!in_array($value, ['yes', 'no', 'clean'])) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "explicit" may only'
. ' be one of "yes", "no" or "clean"');
}
$this->data['explicit'] = $value;
return $this;
}
/**
* Set feed keywords
*
* @param array $value
* @return Feed
* @throws Writer\Exception\InvalidArgumentException
*/
public function setItunesKeywords(array $value)
{
if (count($value) > 12) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "keywords" may only'
. ' contain a maximum of 12 terms');
}
$concat = implode(',', $value);
if ($this->stringWrapper->strlen($concat) > 255) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "keywords" may only'
. ' have a concatenated length of 255 chars where terms are delimited'
. ' by a comma');
}
$this->data['keywords'] = $value;
return $this;
}
/**
* Set new feed URL
*
* @param string $value
* @return Feed
* @throws Writer\Exception\InvalidArgumentException
*/
public function setItunesNewFeedUrl($value)
{
if (!Uri::factory($value)->isValid()) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "newFeedUrl" may only'
. ' be a valid URI/IRI');
}
$this->data['newFeedUrl'] = $value;
return $this;
}
/**
* Add feed owners
*
* @param array $values
* @return Feed
*/
public function addItunesOwners(array $values)
{
foreach ($values as $value) {
$this->addItunesOwner($value);
}
return $this;
}
/**
* Add feed owner
*
* @param array $value
* @return Feed
* @throws Writer\Exception\InvalidArgumentException
*/
public function addItunesOwner(array $value)
{
if (!isset($value['name']) || !isset($value['email'])) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: any "owner" must'
. ' be an array containing keys "name" and "email"');
}
if ($this->stringWrapper->strlen($value['name']) > 255
|| $this->stringWrapper->strlen($value['email']) > 255
) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: any "owner" may only'
. ' contain a maximum of 255 characters each for "name" and "email"');
}
if (!isset($this->data['owners'])) {
$this->data['owners'] = [];
}
$this->data['owners'][] = $value;
return $this;
}
/**
* Set feed subtitle
*
* @param string $value
* @return Feed
* @throws Writer\Exception\InvalidArgumentException
*/
public function setItunesSubtitle($value)
{
if ($this->stringWrapper->strlen($value) > 255) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "subtitle" may only'
. ' contain a maximum of 255 characters');
}
$this->data['subtitle'] = $value;
return $this;
}
/**
* Set feed summary
*
* @param string $value
* @return Feed
* @throws Writer\Exception\InvalidArgumentException
*/
public function setItunesSummary($value)
{
if ($this->stringWrapper->strlen($value) > 4000) {
throw new Writer\Exception\InvalidArgumentException('invalid parameter: "summary" may only'
. ' contain a maximum of 4000 characters');
}
$this->data['summary'] = $value;
return $this;
}
/**
* Overloading: proxy to internal setters
*
* @param string $method
* @param array $params
* @return mixed
* @throws Writer\Exception\BadMethodCallException
*/
public function __call($method, array $params)
{
$point = lcfirst(substr($method, 9));
if (!method_exists($this, 'setItunes' . ucfirst($point))
&& !method_exists($this, 'addItunes' . ucfirst($point))
) {
throw new Writer\Exception\BadMethodCallException(
'invalid method: ' . $method
);
}
if (!array_key_exists($point, $this->data) || empty($this->data[$point])) {
return;
}
return $this->data[$point];
}
}

View file

@ -0,0 +1,200 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Extension\ITunes\Renderer;
use DOMDocument;
use DOMElement;
use Zend\Feed\Writer\Extension;
/**
*/
class Entry extends Extension\AbstractRenderer
{
/**
* Set to TRUE if a rendering method actually renders something. This
* is used to prevent premature appending of a XML namespace declaration
* until an element which requires it is actually appended.
*
* @var bool
*/
protected $called = false;
/**
* Render entry
*
* @return void
*/
public function render()
{
$this->_setAuthors($this->dom, $this->base);
$this->_setBlock($this->dom, $this->base);
$this->_setDuration($this->dom, $this->base);
$this->_setExplicit($this->dom, $this->base);
$this->_setKeywords($this->dom, $this->base);
$this->_setSubtitle($this->dom, $this->base);
$this->_setSummary($this->dom, $this->base);
if ($this->called) {
$this->_appendNamespaces();
}
}
/**
* Append namespaces to entry root
*
* @return void
*/
protected function _appendNamespaces()
{
$this->getRootElement()->setAttribute('xmlns:itunes',
'http://www.itunes.com/dtds/podcast-1.0.dtd');
}
/**
* Set entry authors
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setAuthors(DOMDocument $dom, DOMElement $root)
{
$authors = $this->getDataContainer()->getItunesAuthors();
if (!$authors || empty($authors)) {
return;
}
foreach ($authors as $author) {
$el = $dom->createElement('itunes:author');
$text = $dom->createTextNode($author);
$el->appendChild($text);
$root->appendChild($el);
$this->called = true;
}
}
/**
* Set itunes block
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setBlock(DOMDocument $dom, DOMElement $root)
{
$block = $this->getDataContainer()->getItunesBlock();
if ($block === null) {
return;
}
$el = $dom->createElement('itunes:block');
$text = $dom->createTextNode($block);
$el->appendChild($text);
$root->appendChild($el);
$this->called = true;
}
/**
* Set entry duration
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setDuration(DOMDocument $dom, DOMElement $root)
{
$duration = $this->getDataContainer()->getItunesDuration();
if (!$duration) {
return;
}
$el = $dom->createElement('itunes:duration');
$text = $dom->createTextNode($duration);
$el->appendChild($text);
$root->appendChild($el);
$this->called = true;
}
/**
* Set explicit flag
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setExplicit(DOMDocument $dom, DOMElement $root)
{
$explicit = $this->getDataContainer()->getItunesExplicit();
if ($explicit === null) {
return;
}
$el = $dom->createElement('itunes:explicit');
$text = $dom->createTextNode($explicit);
$el->appendChild($text);
$root->appendChild($el);
$this->called = true;
}
/**
* Set entry keywords
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setKeywords(DOMDocument $dom, DOMElement $root)
{
$keywords = $this->getDataContainer()->getItunesKeywords();
if (!$keywords || empty($keywords)) {
return;
}
$el = $dom->createElement('itunes:keywords');
$text = $dom->createTextNode(implode(',', $keywords));
$el->appendChild($text);
$root->appendChild($el);
$this->called = true;
}
/**
* Set entry subtitle
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setSubtitle(DOMDocument $dom, DOMElement $root)
{
$subtitle = $this->getDataContainer()->getItunesSubtitle();
if (!$subtitle) {
return;
}
$el = $dom->createElement('itunes:subtitle');
$text = $dom->createTextNode($subtitle);
$el->appendChild($text);
$root->appendChild($el);
$this->called = true;
}
/**
* Set entry summary
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setSummary(DOMDocument $dom, DOMElement $root)
{
$summary = $this->getDataContainer()->getItunesSummary();
if (!$summary) {
return;
}
$el = $dom->createElement('itunes:summary');
$text = $dom->createTextNode($summary);
$el->appendChild($text);
$root->appendChild($el);
$this->called = true;
}
}

View file

@ -0,0 +1,303 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Extension\ITunes\Renderer;
use DOMDocument;
use DOMElement;
use Zend\Feed\Writer\Extension;
/**
*/
class Feed extends Extension\AbstractRenderer
{
/**
* Set to TRUE if a rendering method actually renders something. This
* is used to prevent premature appending of a XML namespace declaration
* until an element which requires it is actually appended.
*
* @var bool
*/
protected $called = false;
/**
* Render feed
*
* @return void
*/
public function render()
{
$this->_setAuthors($this->dom, $this->base);
$this->_setBlock($this->dom, $this->base);
$this->_setCategories($this->dom, $this->base);
$this->_setImage($this->dom, $this->base);
$this->_setDuration($this->dom, $this->base);
$this->_setExplicit($this->dom, $this->base);
$this->_setKeywords($this->dom, $this->base);
$this->_setNewFeedUrl($this->dom, $this->base);
$this->_setOwners($this->dom, $this->base);
$this->_setSubtitle($this->dom, $this->base);
$this->_setSummary($this->dom, $this->base);
if ($this->called) {
$this->_appendNamespaces();
}
}
/**
* Append feed namespaces
*
* @return void
*/
protected function _appendNamespaces()
{
$this->getRootElement()->setAttribute('xmlns:itunes',
'http://www.itunes.com/dtds/podcast-1.0.dtd');
}
/**
* Set feed authors
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setAuthors(DOMDocument $dom, DOMElement $root)
{
$authors = $this->getDataContainer()->getItunesAuthors();
if (!$authors || empty($authors)) {
return;
}
foreach ($authors as $author) {
$el = $dom->createElement('itunes:author');
$text = $dom->createTextNode($author);
$el->appendChild($text);
$root->appendChild($el);
}
$this->called = true;
}
/**
* Set feed itunes block
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setBlock(DOMDocument $dom, DOMElement $root)
{
$block = $this->getDataContainer()->getItunesBlock();
if ($block === null) {
return;
}
$el = $dom->createElement('itunes:block');
$text = $dom->createTextNode($block);
$el->appendChild($text);
$root->appendChild($el);
$this->called = true;
}
/**
* Set feed categories
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setCategories(DOMDocument $dom, DOMElement $root)
{
$cats = $this->getDataContainer()->getItunesCategories();
if (!$cats || empty($cats)) {
return;
}
foreach ($cats as $key => $cat) {
if (!is_array($cat)) {
$el = $dom->createElement('itunes:category');
$el->setAttribute('text', $cat);
$root->appendChild($el);
} else {
$el = $dom->createElement('itunes:category');
$el->setAttribute('text', $key);
$root->appendChild($el);
foreach ($cat as $subcat) {
$el2 = $dom->createElement('itunes:category');
$el2->setAttribute('text', $subcat);
$el->appendChild($el2);
}
}
}
$this->called = true;
}
/**
* Set feed image (icon)
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setImage(DOMDocument $dom, DOMElement $root)
{
$image = $this->getDataContainer()->getItunesImage();
if (!$image) {
return;
}
$el = $dom->createElement('itunes:image');
$el->setAttribute('href', $image);
$root->appendChild($el);
$this->called = true;
}
/**
* Set feed cumulative duration
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setDuration(DOMDocument $dom, DOMElement $root)
{
$duration = $this->getDataContainer()->getItunesDuration();
if (!$duration) {
return;
}
$el = $dom->createElement('itunes:duration');
$text = $dom->createTextNode($duration);
$el->appendChild($text);
$root->appendChild($el);
$this->called = true;
}
/**
* Set explicit flag
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setExplicit(DOMDocument $dom, DOMElement $root)
{
$explicit = $this->getDataContainer()->getItunesExplicit();
if ($explicit === null) {
return;
}
$el = $dom->createElement('itunes:explicit');
$text = $dom->createTextNode($explicit);
$el->appendChild($text);
$root->appendChild($el);
$this->called = true;
}
/**
* Set feed keywords
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setKeywords(DOMDocument $dom, DOMElement $root)
{
$keywords = $this->getDataContainer()->getItunesKeywords();
if (!$keywords || empty($keywords)) {
return;
}
$el = $dom->createElement('itunes:keywords');
$text = $dom->createTextNode(implode(',', $keywords));
$el->appendChild($text);
$root->appendChild($el);
$this->called = true;
}
/**
* Set feed's new URL
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setNewFeedUrl(DOMDocument $dom, DOMElement $root)
{
$url = $this->getDataContainer()->getItunesNewFeedUrl();
if (!$url) {
return;
}
$el = $dom->createElement('itunes:new-feed-url');
$text = $dom->createTextNode($url);
$el->appendChild($text);
$root->appendChild($el);
$this->called = true;
}
/**
* Set feed owners
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setOwners(DOMDocument $dom, DOMElement $root)
{
$owners = $this->getDataContainer()->getItunesOwners();
if (!$owners || empty($owners)) {
return;
}
foreach ($owners as $owner) {
$el = $dom->createElement('itunes:owner');
$name = $dom->createElement('itunes:name');
$text = $dom->createTextNode($owner['name']);
$name->appendChild($text);
$email = $dom->createElement('itunes:email');
$text = $dom->createTextNode($owner['email']);
$email->appendChild($text);
$root->appendChild($el);
$el->appendChild($name);
$el->appendChild($email);
}
$this->called = true;
}
/**
* Set feed subtitle
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setSubtitle(DOMDocument $dom, DOMElement $root)
{
$subtitle = $this->getDataContainer()->getItunesSubtitle();
if (!$subtitle) {
return;
}
$el = $dom->createElement('itunes:subtitle');
$text = $dom->createTextNode($subtitle);
$el->appendChild($text);
$root->appendChild($el);
$this->called = true;
}
/**
* Set feed summary
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setSummary(DOMDocument $dom, DOMElement $root)
{
$summary = $this->getDataContainer()->getItunesSummary();
if (!$summary) {
return;
}
$el = $dom->createElement('itunes:summary');
$text = $dom->createTextNode($summary);
$el->appendChild($text);
$root->appendChild($el);
$this->called = true;
}
}

View file

@ -0,0 +1,49 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Extension;
use DOMDocument;
use DOMElement;
/**
*/
interface RendererInterface
{
/**
* Set the data container
*
* @param mixed $container
* @return void
*/
public function setDataContainer($container);
/**
* Retrieve container
*
* @return mixed
*/
public function getDataContainer();
/**
* Set DOMDocument and DOMElement on which to operate
*
* @param DOMDocument $dom
* @param DOMElement $base
* @return void
*/
public function setDomDocument(DOMDocument $dom, DOMElement $base);
/**
* Render
*
* @return void
*/
public function render();
}

View file

@ -0,0 +1,74 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Extension\Slash\Renderer;
use DOMDocument;
use DOMElement;
use Zend\Feed\Writer\Extension;
/**
*/
class Entry extends Extension\AbstractRenderer
{
/**
* Set to TRUE if a rendering method actually renders something. This
* is used to prevent premature appending of a XML namespace declaration
* until an element which requires it is actually appended.
*
* @var bool
*/
protected $called = false;
/**
* Render entry
*
* @return void
*/
public function render()
{
if (strtolower($this->getType()) == 'atom') {
return; // RSS 2.0 only
}
$this->_setCommentCount($this->dom, $this->base);
if ($this->called) {
$this->_appendNamespaces();
}
}
/**
* Append entry namespaces
*
* @return void
*/
protected function _appendNamespaces()
{
$this->getRootElement()->setAttribute('xmlns:slash',
'http://purl.org/rss/1.0/modules/slash/');
}
/**
* Set entry comment count
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setCommentCount(DOMDocument $dom, DOMElement $root)
{
$count = $this->getDataContainer()->getCommentCount();
if (!$count) {
$count = 0;
}
$tcount = $this->dom->createElement('slash:comments');
$tcount->nodeValue = $count;
$root->appendChild($tcount);
$this->called = true;
}
}

View file

@ -0,0 +1,128 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Extension\Threading\Renderer;
use DOMDocument;
use DOMElement;
use Zend\Feed\Writer\Extension;
/**
*/
class Entry extends Extension\AbstractRenderer
{
/**
* Set to TRUE if a rendering method actually renders something. This
* is used to prevent premature appending of a XML namespace declaration
* until an element which requires it is actually appended.
*
* @var bool
*/
protected $called = false;
/**
* Render entry
*
* @return void
*/
public function render()
{
if (strtolower($this->getType()) == 'rss') {
return; // Atom 1.0 only
}
$this->_setCommentLink($this->dom, $this->base);
$this->_setCommentFeedLinks($this->dom, $this->base);
$this->_setCommentCount($this->dom, $this->base);
if ($this->called) {
$this->_appendNamespaces();
}
}
/**
* Append entry namespaces
*
* @return void
*/
protected function _appendNamespaces()
{
$this->getRootElement()->setAttribute('xmlns:thr',
'http://purl.org/syndication/thread/1.0');
}
/**
* Set comment link
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setCommentLink(DOMDocument $dom, DOMElement $root)
{
$link = $this->getDataContainer()->getCommentLink();
if (!$link) {
return;
}
$clink = $this->dom->createElement('link');
$clink->setAttribute('rel', 'replies');
$clink->setAttribute('type', 'text/html');
$clink->setAttribute('href', $link);
$count = $this->getDataContainer()->getCommentCount();
if ($count !== null) {
$clink->setAttribute('thr:count', $count);
}
$root->appendChild($clink);
$this->called = true;
}
/**
* Set comment feed links
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setCommentFeedLinks(DOMDocument $dom, DOMElement $root)
{
$links = $this->getDataContainer()->getCommentFeedLinks();
if (!$links || empty($links)) {
return;
}
foreach ($links as $link) {
$flink = $this->dom->createElement('link');
$flink->setAttribute('rel', 'replies');
$flink->setAttribute('type', 'application/' . $link['type'] . '+xml');
$flink->setAttribute('href', $link['uri']);
$count = $this->getDataContainer()->getCommentCount();
if ($count !== null) {
$flink->setAttribute('thr:count', $count);
}
$root->appendChild($flink);
$this->called = true;
}
}
/**
* Set entry comment count
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setCommentCount(DOMDocument $dom, DOMElement $root)
{
$count = $this->getDataContainer()->getCommentCount();
if ($count === null) {
return;
}
$tcount = $this->dom->createElement('thr:total');
$tcount->nodeValue = $count;
$root->appendChild($tcount);
$this->called = true;
}
}

View file

@ -0,0 +1,79 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Extension\WellFormedWeb\Renderer;
use DOMDocument;
use DOMElement;
use Zend\Feed\Writer\Extension;
/**
*/
class Entry extends Extension\AbstractRenderer
{
/**
* Set to TRUE if a rendering method actually renders something. This
* is used to prevent premature appending of a XML namespace declaration
* until an element which requires it is actually appended.
*
* @var bool
*/
protected $called = false;
/**
* Render entry
*
* @return void
*/
public function render()
{
if (strtolower($this->getType()) == 'atom') {
return; // RSS 2.0 only
}
$this->_setCommentFeedLinks($this->dom, $this->base);
if ($this->called) {
$this->_appendNamespaces();
}
}
/**
* Append entry namespaces
*
* @return void
*/
protected function _appendNamespaces()
{
$this->getRootElement()->setAttribute('xmlns:wfw',
'http://wellformedweb.org/CommentAPI/');
}
/**
* Set entry comment feed links
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setCommentFeedLinks(DOMDocument $dom, DOMElement $root)
{
$links = $this->getDataContainer()->getCommentFeedLinks();
if (!$links || empty($links)) {
return;
}
foreach ($links as $link) {
if ($link['type'] == 'rss') {
$flink = $this->dom->createElement('wfw:commentRss');
$text = $dom->createTextNode($link['uri']);
$flink->appendChild($text);
$root->appendChild($flink);
}
}
$this->called = true;
}
}

View file

@ -0,0 +1,80 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer;
/**
* Default implementation of ExtensionManagerInterface
*
* Decorator of ExtensionPluginManager.
*/
class ExtensionManager implements ExtensionManagerInterface
{
protected $pluginManager;
/**
* Constructor
*
* Seeds the extension manager with a plugin manager; if none provided,
* creates an instance.
*
* @param null|ExtensionPluginManager $pluginManager
*/
public function __construct(ExtensionPluginManager $pluginManager = null)
{
if (null === $pluginManager) {
$pluginManager = new ExtensionPluginManager();
}
$this->pluginManager = $pluginManager;
}
/**
* Method overloading
*
* Proxy to composed ExtensionPluginManager instance.
*
* @param string $method
* @param array $args
* @return mixed
* @throws Exception\BadMethodCallException
*/
public function __call($method, $args)
{
if (!method_exists($this->pluginManager, $method)) {
throw new Exception\BadMethodCallException(sprintf(
'Method by name of %s does not exist in %s',
$method,
__CLASS__
));
}
return call_user_func_array([$this->pluginManager, $method], $args);
}
/**
* Get the named extension
*
* @param string $name
* @return Extension\AbstractRenderer
*/
public function get($name)
{
return $this->pluginManager->get($name);
}
/**
* Do we have the named extension?
*
* @param string $name
* @return bool
*/
public function has($name)
{
return $this->pluginManager->has($name);
}
}

View file

@ -0,0 +1,29 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer;
interface ExtensionManagerInterface
{
/**
* Do we have the extension?
*
* @param string $extension
* @return bool
*/
public function has($extension);
/**
* Retrieve the extension
*
* @param string $extension
* @return mixed
*/
public function get($extension);
}

View file

@ -0,0 +1,80 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer;
use Zend\ServiceManager\AbstractPluginManager;
/**
* Plugin manager implementation for feed writer extensions
*
* Validation checks that we have an Entry, Feed, or Extension\AbstractRenderer.
*/
class ExtensionPluginManager extends AbstractPluginManager
{
/**
* Default set of extension classes
*
* @var array
*/
protected $invokableClasses = [
'atomrendererfeed' => 'Zend\Feed\Writer\Extension\Atom\Renderer\Feed',
'contentrendererentry' => 'Zend\Feed\Writer\Extension\Content\Renderer\Entry',
'dublincorerendererentry' => 'Zend\Feed\Writer\Extension\DublinCore\Renderer\Entry',
'dublincorerendererfeed' => 'Zend\Feed\Writer\Extension\DublinCore\Renderer\Feed',
'itunesentry' => 'Zend\Feed\Writer\Extension\ITunes\Entry',
'itunesfeed' => 'Zend\Feed\Writer\Extension\ITunes\Feed',
'itunesrendererentry' => 'Zend\Feed\Writer\Extension\ITunes\Renderer\Entry',
'itunesrendererfeed' => 'Zend\Feed\Writer\Extension\ITunes\Renderer\Feed',
'slashrendererentry' => 'Zend\Feed\Writer\Extension\Slash\Renderer\Entry',
'threadingrendererentry' => 'Zend\Feed\Writer\Extension\Threading\Renderer\Entry',
'wellformedwebrendererentry' => 'Zend\Feed\Writer\Extension\WellFormedWeb\Renderer\Entry',
];
/**
* Do not share instances
*
* @var bool
*/
protected $shareByDefault = false;
/**
* Validate the plugin
*
* Checks that the extension loaded is of a valid type.
*
* @param mixed $plugin
* @return void
* @throws Exception\InvalidArgumentException if invalid
*/
public function validatePlugin($plugin)
{
if ($plugin instanceof Extension\AbstractRenderer) {
// we're okay
return;
}
if ('Feed' == substr(get_class($plugin), -4)) {
// we're okay
return;
}
if ('Entry' == substr(get_class($plugin), -5)) {
// we're okay
return;
}
throw new Exception\InvalidArgumentException(sprintf(
'Plugin of type %s is invalid; must implement %s\Extension\RendererInterface '
. 'or the classname must end in "Feed" or "Entry"',
(is_object($plugin) ? get_class($plugin) : gettype($plugin)),
__NAMESPACE__
));
}
}

View file

@ -0,0 +1,239 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer;
use Countable;
use Iterator;
/**
*/
class Feed extends AbstractFeed implements Iterator, Countable
{
/**
* Contains all entry objects
*
* @var array
*/
protected $entries = [];
/**
* A pointer for the iterator to keep track of the entries array
*
* @var int
*/
protected $entriesKey = 0;
/**
* Creates a new Zend\Feed\Writer\Entry data container for use. This is NOT
* added to the current feed automatically, but is necessary to create a
* container with some initial values preset based on the current feed data.
*
* @return \Zend\Feed\Writer\Entry
*/
public function createEntry()
{
$entry = new Entry;
if ($this->getEncoding()) {
$entry->setEncoding($this->getEncoding());
}
$entry->setType($this->getType());
return $entry;
}
/**
* Appends a Zend\Feed\Writer\Deleted object representing a new entry tombstone
* to the feed data container's internal group of entries.
*
* @param Deleted $deleted
* @return void
*/
public function addTombstone(Deleted $deleted)
{
$this->entries[] = $deleted;
}
/**
* Creates a new Zend\Feed\Writer\Deleted data container for use. This is NOT
* added to the current feed automatically, but is necessary to create a
* container with some initial values preset based on the current feed data.
*
* @return Deleted
*/
public function createTombstone()
{
$deleted = new Deleted;
if ($this->getEncoding()) {
$deleted->setEncoding($this->getEncoding());
}
$deleted->setType($this->getType());
return $deleted;
}
/**
* Appends a Zend\Feed\Writer\Entry object representing a new entry/item
* the feed data container's internal group of entries.
*
* @param Entry $entry
* @return Feed
*/
public function addEntry(Entry $entry)
{
$this->entries[] = $entry;
return $this;
}
/**
* Removes a specific indexed entry from the internal queue. Entries must be
* added to a feed container in order to be indexed.
*
* @param int $index
* @throws Exception\InvalidArgumentException
* @return Feed
*/
public function removeEntry($index)
{
if (!isset($this->entries[$index])) {
throw new Exception\InvalidArgumentException('Undefined index: ' . $index . '. Entry does not exist.');
}
unset($this->entries[$index]);
return $this;
}
/**
* Retrieve a specific indexed entry from the internal queue. Entries must be
* added to a feed container in order to be indexed.
*
* @param int $index
* @throws Exception\InvalidArgumentException
*/
public function getEntry($index = 0)
{
if (isset($this->entries[$index])) {
return $this->entries[$index];
}
throw new Exception\InvalidArgumentException('Undefined index: ' . $index . '. Entry does not exist.');
}
/**
* Orders all indexed entries by date, thus offering date ordered readable
* content where a parser (or Homo Sapien) ignores the generic rule that
* XML element order is irrelevant and has no intrinsic meaning.
*
* Using this method will alter the original indexation.
*
* @return Feed
*/
public function orderByDate()
{
/**
* Could do with some improvement for performance perhaps
*/
$timestamp = time();
$entries = [];
foreach ($this->entries as $entry) {
if ($entry->getDateModified()) {
$timestamp = (int) $entry->getDateModified()->getTimestamp();
} elseif ($entry->getDateCreated()) {
$timestamp = (int) $entry->getDateCreated()->getTimestamp();
}
$entries[$timestamp] = $entry;
}
krsort($entries, SORT_NUMERIC);
$this->entries = array_values($entries);
return $this;
}
/**
* Get the number of feed entries.
* Required by the Iterator interface.
*
* @return int
*/
public function count()
{
return count($this->entries);
}
/**
* Return the current entry
*
* @return Entry
*/
public function current()
{
return $this->entries[$this->key()];
}
/**
* Return the current feed key
*
* @return mixed
*/
public function key()
{
return $this->entriesKey;
}
/**
* Move the feed pointer forward
*
* @return void
*/
public function next()
{
++$this->entriesKey;
}
/**
* Reset the pointer in the feed object
*
* @return void
*/
public function rewind()
{
$this->entriesKey = 0;
}
/**
* Check to see if the iterator is still valid
*
* @return bool
*/
public function valid()
{
return 0 <= $this->entriesKey && $this->entriesKey < $this->count();
}
/**
* Attempt to build and return the feed resulting from the data set
*
* @param string $type The feed type "rss" or "atom" to export as
* @param bool $ignoreExceptions
* @throws Exception\InvalidArgumentException
* @return string
*/
public function export($type, $ignoreExceptions = false)
{
$this->setType(strtolower($type));
$type = ucfirst($this->getType());
if ($type !== 'Rss' && $type !== 'Atom') {
throw new Exception\InvalidArgumentException('Invalid feed type specified: ' . $type . '.'
. ' Should be one of "rss" or "atom".');
}
$renderClass = 'Zend\\Feed\\Writer\\Renderer\\Feed\\' . $type;
$renderer = new $renderClass($this);
if ($ignoreExceptions) {
$renderer->ignoreExceptions();
}
return $renderer->render()->saveXml();
}
}

View file

@ -0,0 +1,127 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer;
use Traversable;
abstract class FeedFactory
{
/**
* Create and return a Feed based on data provided.
*
* @param array|Traversable $data
* @throws Exception\InvalidArgumentException
* @return Feed
*/
public static function factory($data)
{
if (!is_array($data) && !$data instanceof Traversable) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects an array or Traversable argument; received "%s"',
__METHOD__,
(is_object($data) ? get_class($data) : gettype($data))
));
}
$feed = new Feed();
foreach ($data as $key => $value) {
// Setters
$key = static::convertKey($key);
$method = 'set' . $key;
if (method_exists($feed, $method)) {
switch ($method) {
case 'setfeedlink':
if (!is_array($value)) {
// Need an array
break;
}
if (!array_key_exists('link', $value) || !array_key_exists('type', $value)) {
// Need both keys to set this correctly
break;
}
$feed->setFeedLink($value['link'], $value['type']);
break;
default:
$feed->$method($value);
break;
}
continue;
}
// Entries
if ('entries' == $key) {
static::createEntries($value, $feed);
continue;
}
}
return $feed;
}
/**
* Normalize a key
*
* @param string $key
* @return string
*/
protected static function convertKey($key)
{
$key = str_replace('_', '', strtolower($key));
return $key;
}
/**
* Create and attach entries to a feed
*
* @param array|Traversable $entries
* @param Feed $feed
* @throws Exception\InvalidArgumentException
* @return void
*/
protected static function createEntries($entries, Feed $feed)
{
if (!is_array($entries) && !$entries instanceof Traversable) {
throw new Exception\InvalidArgumentException(sprintf(
'%s::factory expects the "entries" value to be an array or Traversable; received "%s"',
get_called_class(),
(is_object($entries) ? get_class($entries) : gettype($entries))
));
}
foreach ($entries as $data) {
if (!is_array($data) && !$data instanceof Traversable && !$data instanceof Entry) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects an array, Traversable, or Zend\Feed\Writer\Entry argument; received "%s"',
__METHOD__,
(is_object($data) ? get_class($data) : gettype($data))
));
}
// Use case 1: Entry item
if ($data instanceof Entry) {
$feed->addEntry($data);
continue;
}
// Use case 2: iterate item and populate entry
$entry = $feed->createEntry();
foreach ($data as $key => $value) {
$key = static::convertKey($key);
$method = 'set' . $key;
if (!method_exists($entry, $method)) {
continue;
}
$entry->$method($value);
}
$feed->addEntry($entry);
}
}
}

View file

@ -0,0 +1,233 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Renderer;
use DOMDocument;
use DOMElement;
use Zend\Feed\Writer;
/**
*/
class AbstractRenderer
{
/**
* Extensions
* @var array
*/
protected $extensions = [];
/**
* @var Writer\AbstractFeed
*/
protected $container = null;
/**
* @var DOMDocument
*/
protected $dom = null;
/**
* @var bool
*/
protected $ignoreExceptions = false;
/**
* @var array
*/
protected $exceptions = [];
/**
* Encoding of all text values
*
* @var string
*/
protected $encoding = 'UTF-8';
/**
* Holds the value "atom" or "rss" depending on the feed type set when
* when last exported.
*
* @var string
*/
protected $type = null;
/**
* @var DOMElement
*/
protected $rootElement = null;
/**
* Constructor
*
* @param Writer\AbstractFeed $container
*/
public function __construct($container)
{
$this->container = $container;
$this->setType($container->getType());
$this->_loadExtensions();
}
/**
* Save XML to string
*
* @return string
*/
public function saveXml()
{
return $this->getDomDocument()->saveXml();
}
/**
* Get DOM document
*
* @return DOMDocument
*/
public function getDomDocument()
{
return $this->dom;
}
/**
* Get document element from DOM
*
* @return DOMElement
*/
public function getElement()
{
return $this->getDomDocument()->documentElement;
}
/**
* Get data container of items being rendered
*
* @return Writer\AbstractFeed
*/
public function getDataContainer()
{
return $this->container;
}
/**
* Set feed encoding
*
* @param string $enc
* @return AbstractRenderer
*/
public function setEncoding($enc)
{
$this->encoding = $enc;
return $this;
}
/**
* Get feed encoding
*
* @return string
*/
public function getEncoding()
{
return $this->encoding;
}
/**
* Indicate whether or not to ignore exceptions
*
* @param bool $bool
* @return AbstractRenderer
* @throws Writer\Exception\InvalidArgumentException
*/
public function ignoreExceptions($bool = true)
{
if (!is_bool($bool)) {
throw new Writer\Exception\InvalidArgumentException('Invalid parameter: $bool. Should be TRUE or FALSE (defaults to TRUE if null)');
}
$this->ignoreExceptions = $bool;
return $this;
}
/**
* Get exception list
*
* @return array
*/
public function getExceptions()
{
return $this->exceptions;
}
/**
* Set the current feed type being exported to "rss" or "atom". This allows
* other objects to gracefully choose whether to execute or not, depending
* on their appropriateness for the current type, e.g. renderers.
*
* @param string $type
*/
public function setType($type)
{
$this->type = $type;
}
/**
* Retrieve the current or last feed type exported.
*
* @return string Value will be "rss" or "atom"
*/
public function getType()
{
return $this->type;
}
/**
* Sets the absolute root element for the XML feed being generated. This
* helps simplify the appending of namespace declarations, but also ensures
* namespaces are added to the root element - not scattered across the entire
* XML file - may assist namespace unsafe parsers and looks pretty ;).
*
* @param DOMElement $root
*/
public function setRootElement(DOMElement $root)
{
$this->rootElement = $root;
}
/**
* Retrieve the absolute root element for the XML feed being generated.
*
* @return DOMElement
*/
public function getRootElement()
{
return $this->rootElement;
}
/**
* Load extensions from Zend\Feed\Writer\Writer
*
* @return void
*/
protected function _loadExtensions()
{
Writer\Writer::registerCoreExtensions();
$manager = Writer\Writer::getExtensionManager();
$all = Writer\Writer::getExtensions();
if (stripos(get_class($this), 'entry')) {
$exts = $all['entryRenderer'];
} else {
$exts = $all['feedRenderer'];
}
foreach ($exts as $extension) {
$plugin = $manager->get($extension);
$plugin->setDataContainer($this->getDataContainer());
$plugin->setEncoding($this->getEncoding());
$this->extensions[$extension] = $plugin;
}
}
}

View file

@ -0,0 +1,434 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Renderer\Entry;
use DateTime;
use DOMDocument;
use DOMElement;
use Zend\Feed\Uri;
use Zend\Feed\Writer;
use Zend\Feed\Writer\Renderer;
use Zend\Validator;
class Atom extends Renderer\AbstractRenderer implements Renderer\RendererInterface
{
/**
* Constructor
*
* @param Writer\Entry $container
*/
public function __construct(Writer\Entry $container)
{
parent::__construct($container);
}
/**
* Render atom entry
*
* @return Atom
*/
public function render()
{
$this->dom = new DOMDocument('1.0', $this->container->getEncoding());
$this->dom->formatOutput = true;
$entry = $this->dom->createElementNS(Writer\Writer::NAMESPACE_ATOM_10, 'entry');
$this->dom->appendChild($entry);
$this->_setSource($this->dom, $entry);
$this->_setTitle($this->dom, $entry);
$this->_setDescription($this->dom, $entry);
$this->_setDateCreated($this->dom, $entry);
$this->_setDateModified($this->dom, $entry);
$this->_setLink($this->dom, $entry);
$this->_setId($this->dom, $entry);
$this->_setAuthors($this->dom, $entry);
$this->_setEnclosure($this->dom, $entry);
$this->_setContent($this->dom, $entry);
$this->_setCategories($this->dom, $entry);
foreach ($this->extensions as $ext) {
$ext->setType($this->getType());
$ext->setRootElement($this->getRootElement());
$ext->setDOMDocument($this->getDOMDocument(), $entry);
$ext->render();
}
return $this;
}
/**
* Set entry title
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Writer\Exception\InvalidArgumentException
*/
protected function _setTitle(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getTitle()) {
$message = 'Atom 1.0 entry elements MUST contain exactly one'
. ' atom:title element but a title has not been set';
$exception = new Writer\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
$title = $dom->createElement('title');
$root->appendChild($title);
$title->setAttribute('type', 'html');
$cdata = $dom->createCDATASection($this->getDataContainer()->getTitle());
$title->appendChild($cdata);
}
/**
* Set entry description
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setDescription(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getDescription()) {
return; // unless src content or base64
}
$subtitle = $dom->createElement('summary');
$root->appendChild($subtitle);
$subtitle->setAttribute('type', 'html');
$cdata = $dom->createCDATASection(
$this->getDataContainer()->getDescription()
);
$subtitle->appendChild($cdata);
}
/**
* Set date entry was modified
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Writer\Exception\InvalidArgumentException
*/
protected function _setDateModified(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getDateModified()) {
$message = 'Atom 1.0 entry elements MUST contain exactly one'
. ' atom:updated element but a modification date has not been set';
$exception = new Writer\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
$updated = $dom->createElement('updated');
$root->appendChild($updated);
$text = $dom->createTextNode(
$this->getDataContainer()->getDateModified()->format(DateTime::ATOM)
);
$updated->appendChild($text);
}
/**
* Set date entry was created
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setDateCreated(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getDateCreated()) {
return;
}
$el = $dom->createElement('published');
$root->appendChild($el);
$text = $dom->createTextNode(
$this->getDataContainer()->getDateCreated()->format(DateTime::ATOM)
);
$el->appendChild($text);
}
/**
* Set entry authors
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setAuthors(DOMDocument $dom, DOMElement $root)
{
$authors = $this->container->getAuthors();
if ((!$authors || empty($authors))) {
/**
* This will actually trigger an Exception at the feed level if
* a feed level author is not set.
*/
return;
}
foreach ($authors as $data) {
$author = $this->dom->createElement('author');
$name = $this->dom->createElement('name');
$author->appendChild($name);
$root->appendChild($author);
$text = $dom->createTextNode($data['name']);
$name->appendChild($text);
if (array_key_exists('email', $data)) {
$email = $this->dom->createElement('email');
$author->appendChild($email);
$text = $dom->createTextNode($data['email']);
$email->appendChild($text);
}
if (array_key_exists('uri', $data)) {
$uri = $this->dom->createElement('uri');
$author->appendChild($uri);
$text = $dom->createTextNode($data['uri']);
$uri->appendChild($text);
}
}
}
/**
* Set entry enclosure
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setEnclosure(DOMDocument $dom, DOMElement $root)
{
$data = $this->container->getEnclosure();
if ((!$data || empty($data))) {
return;
}
$enclosure = $this->dom->createElement('link');
$enclosure->setAttribute('rel', 'enclosure');
if (isset($data['type'])) {
$enclosure->setAttribute('type', $data['type']);
}
if (isset($data['length'])) {
$enclosure->setAttribute('length', $data['length']);
}
$enclosure->setAttribute('href', $data['uri']);
$root->appendChild($enclosure);
}
protected function _setLink(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getLink()) {
return;
}
$link = $dom->createElement('link');
$root->appendChild($link);
$link->setAttribute('rel', 'alternate');
$link->setAttribute('type', 'text/html');
$link->setAttribute('href', $this->getDataContainer()->getLink());
}
/**
* Set entry identifier
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Writer\Exception\InvalidArgumentException
*/
protected function _setId(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getId()
&& !$this->getDataContainer()->getLink()) {
$message = 'Atom 1.0 entry elements MUST contain exactly one '
. 'atom:id element, or as an alternative, we can use the same '
. 'value as atom:link however neither a suitable link nor an '
. 'id have been set';
$exception = new Writer\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
if (!$this->getDataContainer()->getId()) {
$this->getDataContainer()->setId(
$this->getDataContainer()->getLink()
);
}
if (!Uri::factory($this->getDataContainer()->getId())->isValid()
&& !preg_match(
"#^urn:[a-zA-Z0-9][a-zA-Z0-9\-]{1,31}:([a-zA-Z0-9\(\)\+\,\.\:\=\@\;\$\_\!\*\-]|%[0-9a-fA-F]{2})*#",
$this->getDataContainer()->getId()
)
&& !$this->_validateTagUri($this->getDataContainer()->getId())
) {
throw new Writer\Exception\InvalidArgumentException('Atom 1.0 IDs must be a valid URI/IRI');
}
$id = $dom->createElement('id');
$root->appendChild($id);
$text = $dom->createTextNode($this->getDataContainer()->getId());
$id->appendChild($text);
}
/**
* Validate a URI using the tag scheme (RFC 4151)
*
* @param string $id
* @return bool
*/
protected function _validateTagUri($id)
{
if (preg_match(
'/^tag:(?P<name>.*),(?P<date>\d{4}-?\d{0,2}-?\d{0,2}):(?P<specific>.*)(.*:)*$/',
$id,
$matches
)) {
$dvalid = false;
$date = $matches['date'];
$d6 = strtotime($date);
if ((strlen($date) == 4) && $date <= date('Y')) {
$dvalid = true;
} elseif ((strlen($date) == 7) && ($d6 < strtotime("now"))) {
$dvalid = true;
} elseif ((strlen($date) == 10) && ($d6 < strtotime("now"))) {
$dvalid = true;
}
$validator = new Validator\EmailAddress;
if ($validator->isValid($matches['name'])) {
$nvalid = true;
} else {
$nvalid = $validator->isValid('info@' . $matches['name']);
}
return $dvalid && $nvalid;
}
return false;
}
/**
* Set entry content
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Writer\Exception\InvalidArgumentException
*/
protected function _setContent(DOMDocument $dom, DOMElement $root)
{
$content = $this->getDataContainer()->getContent();
if (!$content && !$this->getDataContainer()->getLink()) {
$message = 'Atom 1.0 entry elements MUST contain exactly one '
. 'atom:content element, or as an alternative, at least one link '
. 'with a rel attribute of "alternate" to indicate an alternate '
. 'method to consume the content.';
$exception = new Writer\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
if (!$content) {
return;
}
$element = $dom->createElement('content');
$element->setAttribute('type', 'xhtml');
$xhtmlElement = $this->_loadXhtml($content);
$deep = version_compare(PHP_VERSION, '7', 'ge') ? 1 : true;
$xhtml = $dom->importNode($xhtmlElement, $deep);
$element->appendChild($xhtml);
$root->appendChild($element);
}
/**
* Load a HTML string and attempt to normalise to XML
*/
protected function _loadXhtml($content)
{
if (class_exists('tidy', false)) {
$tidy = new \tidy;
$config = [
'output-xhtml' => true,
'show-body-only' => true,
'quote-nbsp' => false
];
$encoding = str_replace('-', '', $this->getEncoding());
$tidy->parseString($content, $config, $encoding);
$tidy->cleanRepair();
$xhtml = (string) $tidy;
} else {
$xhtml = $content;
}
$xhtml = preg_replace([
"/(<[\/]?)([a-zA-Z]+)/"
], '$1xhtml:$2', $xhtml);
$dom = new DOMDocument('1.0', $this->getEncoding());
$dom->loadXML(
'<xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml">'
. $xhtml
. '</xhtml:div>'
);
return $dom->documentElement;
}
/**
* Set entry categories
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setCategories(DOMDocument $dom, DOMElement $root)
{
$categories = $this->getDataContainer()->getCategories();
if (!$categories) {
return;
}
foreach ($categories as $cat) {
$category = $dom->createElement('category');
$category->setAttribute('term', $cat['term']);
if (isset($cat['label'])) {
$category->setAttribute('label', $cat['label']);
} else {
$category->setAttribute('label', $cat['term']);
}
if (isset($cat['scheme'])) {
$category->setAttribute('scheme', $cat['scheme']);
}
$root->appendChild($category);
}
}
/**
* Append Source element (Atom 1.0 Feed Metadata)
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setSource(DOMDocument $dom, DOMElement $root)
{
$source = $this->getDataContainer()->getSource();
if (!$source) {
return;
}
$renderer = new Renderer\Feed\AtomSource($source);
$renderer->setType($this->getType());
$element = $renderer->render()->getElement();
$imported = $dom->importNode($element, true);
$root->appendChild($imported);
}
}

View file

@ -0,0 +1,102 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Renderer\Entry\Atom;
use DateTime;
use DOMDocument;
use DOMElement;
use Zend\Feed\Writer;
use Zend\Feed\Writer\Renderer;
class Deleted extends Renderer\AbstractRenderer implements Renderer\RendererInterface
{
/**
* Constructor
*
* @param Writer\Deleted $container
*/
public function __construct(Writer\Deleted $container)
{
parent::__construct($container);
}
/**
* Render atom entry
*
* @return Writer\Renderer\Entry\Atom
*/
public function render()
{
$this->dom = new DOMDocument('1.0', $this->container->getEncoding());
$this->dom->formatOutput = true;
$entry = $this->dom->createElement('at:deleted-entry');
$this->dom->appendChild($entry);
$entry->setAttribute('ref', $this->container->getReference());
$entry->setAttribute('when', $this->container->getWhen()->format(DateTime::ATOM));
$this->_setBy($this->dom, $entry);
$this->_setComment($this->dom, $entry);
return $this;
}
/**
* Set tombstone comment
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setComment(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getComment()) {
return;
}
$c = $dom->createElement('at:comment');
$root->appendChild($c);
$c->setAttribute('type', 'html');
$cdata = $dom->createCDATASection($this->getDataContainer()->getComment());
$c->appendChild($cdata);
}
/**
* Set entry authors
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setBy(DOMDocument $dom, DOMElement $root)
{
$data = $this->container->getBy();
if ((!$data || empty($data))) {
return;
}
$author = $this->dom->createElement('at:by');
$name = $this->dom->createElement('name');
$author->appendChild($name);
$root->appendChild($author);
$text = $dom->createTextNode($data['name']);
$name->appendChild($text);
if (array_key_exists('email', $data)) {
$email = $this->dom->createElement('email');
$author->appendChild($email);
$text = $dom->createTextNode($data['email']);
$email->appendChild($text);
}
if (array_key_exists('uri', $data)) {
$uri = $this->dom->createElement('uri');
$author->appendChild($uri);
$text = $dom->createTextNode($data['uri']);
$uri->appendChild($text);
}
}
}

View file

@ -0,0 +1,104 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Renderer\Entry;
use DateTime;
use DOMDocument;
use DOMElement;
use Zend\Feed\Writer;
use Zend\Feed\Writer\Renderer;
/**
*/
class AtomDeleted extends Renderer\AbstractRenderer implements Renderer\RendererInterface
{
/**
* Constructor
*
* @param Writer\Deleted $container
*/
public function __construct(Writer\Deleted $container)
{
parent::__construct($container);
}
/**
* Render atom entry
*
* @return \Zend\Feed\Writer\Renderer\Entry\Atom
*/
public function render()
{
$this->dom = new DOMDocument('1.0', $this->container->getEncoding());
$this->dom->formatOutput = true;
$entry = $this->dom->createElement('at:deleted-entry');
$this->dom->appendChild($entry);
$entry->setAttribute('ref', $this->container->getReference());
$entry->setAttribute('when', $this->container->getWhen()->format(DateTime::ATOM));
$this->_setBy($this->dom, $entry);
$this->_setComment($this->dom, $entry);
return $this;
}
/**
* Set tombstone comment
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setComment(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getComment()) {
return;
}
$c = $dom->createElement('at:comment');
$root->appendChild($c);
$c->setAttribute('type', 'html');
$cdata = $dom->createCDATASection($this->getDataContainer()->getComment());
$c->appendChild($cdata);
}
/**
* Set entry authors
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setBy(DOMDocument $dom, DOMElement $root)
{
$data = $this->container->getBy();
if ((!$data || empty($data))) {
return;
}
$author = $this->dom->createElement('at:by');
$name = $this->dom->createElement('name');
$author->appendChild($name);
$root->appendChild($author);
$text = $dom->createTextNode($data['name']);
$name->appendChild($text);
if (array_key_exists('email', $data)) {
$email = $this->dom->createElement('email');
$author->appendChild($email);
$text = $dom->createTextNode($data['email']);
$email->appendChild($text);
}
if (array_key_exists('uri', $data)) {
$uri = $this->dom->createElement('uri');
$author->appendChild($uri);
$text = $dom->createTextNode($data['uri']);
$uri->appendChild($text);
}
}
}

View file

@ -0,0 +1,329 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Renderer\Entry;
use DateTime;
use DOMDocument;
use DOMElement;
use Zend\Feed\Uri;
use Zend\Feed\Writer;
use Zend\Feed\Writer\Renderer;
/**
*/
class Rss extends Renderer\AbstractRenderer implements Renderer\RendererInterface
{
/**
* Constructor
*
* @param Writer\Entry $container
*/
public function __construct(Writer\Entry $container)
{
parent::__construct($container);
}
/**
* Render RSS entry
*
* @return Rss
*/
public function render()
{
$this->dom = new DOMDocument('1.0', $this->container->getEncoding());
$this->dom->formatOutput = true;
$this->dom->substituteEntities = false;
$entry = $this->dom->createElement('item');
$this->dom->appendChild($entry);
$this->_setTitle($this->dom, $entry);
$this->_setDescription($this->dom, $entry);
$this->_setDateCreated($this->dom, $entry);
$this->_setDateModified($this->dom, $entry);
$this->_setLink($this->dom, $entry);
$this->_setId($this->dom, $entry);
$this->_setAuthors($this->dom, $entry);
$this->_setEnclosure($this->dom, $entry);
$this->_setCommentLink($this->dom, $entry);
$this->_setCategories($this->dom, $entry);
foreach ($this->extensions as $ext) {
$ext->setType($this->getType());
$ext->setRootElement($this->getRootElement());
$ext->setDOMDocument($this->getDOMDocument(), $entry);
$ext->render();
}
return $this;
}
/**
* Set entry title
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Writer\Exception\InvalidArgumentException
*/
protected function _setTitle(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getDescription()
&& !$this->getDataContainer()->getTitle()) {
$message = 'RSS 2.0 entry elements SHOULD contain exactly one'
. ' title element but a title has not been set. In addition, there'
. ' is no description as required in the absence of a title.';
$exception = new Writer\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
$title = $dom->createElement('title');
$root->appendChild($title);
$text = $dom->createTextNode($this->getDataContainer()->getTitle());
$title->appendChild($text);
}
/**
* Set entry description
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Writer\Exception\InvalidArgumentException
*/
protected function _setDescription(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getDescription()
&& !$this->getDataContainer()->getTitle()) {
$message = 'RSS 2.0 entry elements SHOULD contain exactly one'
. ' description element but a description has not been set. In'
. ' addition, there is no title element as required in the absence'
. ' of a description.';
$exception = new Writer\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
if (!$this->getDataContainer()->getDescription()) {
return;
}
$subtitle = $dom->createElement('description');
$root->appendChild($subtitle);
$text = $dom->createCDATASection($this->getDataContainer()->getDescription());
$subtitle->appendChild($text);
}
/**
* Set date entry was last modified
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setDateModified(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getDateModified()) {
return;
}
$updated = $dom->createElement('pubDate');
$root->appendChild($updated);
$text = $dom->createTextNode(
$this->getDataContainer()->getDateModified()->format(DateTime::RSS)
);
$updated->appendChild($text);
}
/**
* Set date entry was created
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setDateCreated(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getDateCreated()) {
return;
}
if (!$this->getDataContainer()->getDateModified()) {
$this->getDataContainer()->setDateModified(
$this->getDataContainer()->getDateCreated()
);
}
}
/**
* Set entry authors
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setAuthors(DOMDocument $dom, DOMElement $root)
{
$authors = $this->container->getAuthors();
if ((!$authors || empty($authors))) {
return;
}
foreach ($authors as $data) {
$author = $this->dom->createElement('author');
$name = $data['name'];
if (array_key_exists('email', $data)) {
$name = $data['email'] . ' (' . $data['name'] . ')';
}
$text = $dom->createTextNode($name);
$author->appendChild($text);
$root->appendChild($author);
}
}
/**
* Set entry enclosure
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Writer\Exception\InvalidArgumentException
*/
protected function _setEnclosure(DOMDocument $dom, DOMElement $root)
{
$data = $this->container->getEnclosure();
if ((!$data || empty($data))) {
return;
}
if (!isset($data['type'])) {
$exception = new Writer\Exception\InvalidArgumentException('Enclosure "type" is not set');
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
if (!isset($data['length'])) {
$exception = new Writer\Exception\InvalidArgumentException('Enclosure "length" is not set');
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
if ((int) $data['length'] < 0 || !ctype_digit((string) $data['length'])) {
$exception = new Writer\Exception\InvalidArgumentException('Enclosure "length" must be an integer'
. ' indicating the content\'s length in bytes');
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
$enclosure = $this->dom->createElement('enclosure');
$enclosure->setAttribute('type', $data['type']);
$enclosure->setAttribute('length', $data['length']);
$enclosure->setAttribute('url', $data['uri']);
$root->appendChild($enclosure);
}
/**
* Set link to entry
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setLink(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getLink()) {
return;
}
$link = $dom->createElement('link');
$root->appendChild($link);
$text = $dom->createTextNode($this->getDataContainer()->getLink());
$link->appendChild($text);
}
/**
* Set entry identifier
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setId(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getId()
&& !$this->getDataContainer()->getLink()) {
return;
}
$id = $dom->createElement('guid');
$root->appendChild($id);
if (!$this->getDataContainer()->getId()) {
$this->getDataContainer()->setId(
$this->getDataContainer()->getLink());
}
$text = $dom->createTextNode($this->getDataContainer()->getId());
$id->appendChild($text);
if (!Uri::factory($this->getDataContainer()->getId())->isValid()) {
$id->setAttribute('isPermaLink', 'false');
}
}
/**
* Set link to entry comments
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setCommentLink(DOMDocument $dom, DOMElement $root)
{
$link = $this->getDataContainer()->getCommentLink();
if (!$link) {
return;
}
$clink = $this->dom->createElement('comments');
$text = $dom->createTextNode($link);
$clink->appendChild($text);
$root->appendChild($clink);
}
/**
* Set entry categories
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setCategories(DOMDocument $dom, DOMElement $root)
{
$categories = $this->getDataContainer()->getCategories();
if (!$categories) {
return;
}
foreach ($categories as $cat) {
$category = $dom->createElement('category');
if (isset($cat['scheme'])) {
$category->setAttribute('domain', $cat['scheme']);
}
$text = $dom->createCDATASection($cat['term']);
$category->appendChild($text);
$root->appendChild($category);
}
}
}

View file

@ -0,0 +1,403 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Renderer\Feed;
use DateTime;
use DOMDocument;
use DOMElement;
use Zend\Feed\Writer;
use Zend\Feed\Writer\Renderer;
use Zend\Feed\Writer\Version;
/**
*/
class AbstractAtom extends Renderer\AbstractRenderer
{
/**
* Constructor
*
* @param Writer\AbstractFeed $container
*/
public function __construct($container)
{
parent::__construct($container);
}
/**
* Set feed language
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setLanguage(DOMDocument $dom, DOMElement $root)
{
if ($this->getDataContainer()->getLanguage()) {
$root->setAttribute('xml:lang', $this->getDataContainer()
->getLanguage());
}
}
/**
* Set feed title
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Writer\Exception\InvalidArgumentException
*/
protected function _setTitle(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getTitle()) {
$message = 'Atom 1.0 feed elements MUST contain exactly one'
. ' atom:title element but a title has not been set';
$exception = new Writer\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
$title = $dom->createElement('title');
$root->appendChild($title);
$title->setAttribute('type', 'text');
$text = $dom->createTextNode($this->getDataContainer()->getTitle());
$title->appendChild($text);
}
/**
* Set feed description
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setDescription(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getDescription()) {
return;
}
$subtitle = $dom->createElement('subtitle');
$root->appendChild($subtitle);
$subtitle->setAttribute('type', 'text');
$text = $dom->createTextNode($this->getDataContainer()->getDescription());
$subtitle->appendChild($text);
}
/**
* Set date feed was last modified
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Writer\Exception\InvalidArgumentException
*/
protected function _setDateModified(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getDateModified()) {
$message = 'Atom 1.0 feed elements MUST contain exactly one'
. ' atom:updated element but a modification date has not been set';
$exception = new Writer\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
$updated = $dom->createElement('updated');
$root->appendChild($updated);
$text = $dom->createTextNode(
$this->getDataContainer()->getDateModified()->format(DateTime::ATOM)
);
$updated->appendChild($text);
}
/**
* Set feed generator string
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setGenerator(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getGenerator()) {
$this->getDataContainer()->setGenerator('Zend_Feed_Writer',
Version::VERSION, 'http://framework.zend.com');
}
$gdata = $this->getDataContainer()->getGenerator();
$generator = $dom->createElement('generator');
$root->appendChild($generator);
$text = $dom->createTextNode($gdata['name']);
$generator->appendChild($text);
if (array_key_exists('uri', $gdata)) {
$generator->setAttribute('uri', $gdata['uri']);
}
if (array_key_exists('version', $gdata)) {
$generator->setAttribute('version', $gdata['version']);
}
}
/**
* Set link to feed
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setLink(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getLink()) {
return;
}
$link = $dom->createElement('link');
$root->appendChild($link);
$link->setAttribute('rel', 'alternate');
$link->setAttribute('type', 'text/html');
$link->setAttribute('href', $this->getDataContainer()->getLink());
}
/**
* Set feed links
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Writer\Exception\InvalidArgumentException
*/
protected function _setFeedLinks(DOMDocument $dom, DOMElement $root)
{
$flinks = $this->getDataContainer()->getFeedLinks();
if (!$flinks || !array_key_exists('atom', $flinks)) {
$message = 'Atom 1.0 feed elements SHOULD contain one atom:link '
. 'element with a rel attribute value of "self". This is the '
. 'preferred URI for retrieving Atom Feed Documents representing '
. 'this Atom feed but a feed link has not been set';
$exception = new Writer\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
foreach ($flinks as $type => $href) {
$mime = 'application/' . strtolower($type) . '+xml';
$flink = $dom->createElement('link');
$root->appendChild($flink);
$flink->setAttribute('rel', 'self');
$flink->setAttribute('type', $mime);
$flink->setAttribute('href', $href);
}
}
/**
* Set feed authors
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setAuthors(DOMDocument $dom, DOMElement $root)
{
$authors = $this->container->getAuthors();
if (!$authors || empty($authors)) {
/**
* Technically we should defer an exception until we can check
* that all entries contain an author. If any entry is missing
* an author, then a missing feed author element is invalid
*/
return;
}
foreach ($authors as $data) {
$author = $this->dom->createElement('author');
$name = $this->dom->createElement('name');
$author->appendChild($name);
$root->appendChild($author);
$text = $dom->createTextNode($data['name']);
$name->appendChild($text);
if (array_key_exists('email', $data)) {
$email = $this->dom->createElement('email');
$author->appendChild($email);
$text = $dom->createTextNode($data['email']);
$email->appendChild($text);
}
if (array_key_exists('uri', $data)) {
$uri = $this->dom->createElement('uri');
$author->appendChild($uri);
$text = $dom->createTextNode($data['uri']);
$uri->appendChild($text);
}
}
}
/**
* Set feed identifier
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Writer\Exception\InvalidArgumentException
*/
protected function _setId(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getId()
&& !$this->getDataContainer()->getLink()) {
$message = 'Atom 1.0 feed elements MUST contain exactly one '
. 'atom:id element, or as an alternative, we can use the same '
. 'value as atom:link however neither a suitable link nor an '
. 'id have been set';
$exception = new Writer\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
if (!$this->getDataContainer()->getId()) {
$this->getDataContainer()->setId(
$this->getDataContainer()->getLink());
}
$id = $dom->createElement('id');
$root->appendChild($id);
$text = $dom->createTextNode($this->getDataContainer()->getId());
$id->appendChild($text);
}
/**
* Set feed copyright
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setCopyright(DOMDocument $dom, DOMElement $root)
{
$copyright = $this->getDataContainer()->getCopyright();
if (!$copyright) {
return;
}
$copy = $dom->createElement('rights');
$root->appendChild($copy);
$text = $dom->createTextNode($copyright);
$copy->appendChild($text);
}
/**
* Set feed level logo (image)
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setImage(DOMDocument $dom, DOMElement $root)
{
$image = $this->getDataContainer()->getImage();
if (!$image) {
return;
}
$img = $dom->createElement('logo');
$root->appendChild($img);
$text = $dom->createTextNode($image['uri']);
$img->appendChild($text);
}
/**
* Set date feed was created
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setDateCreated(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getDateCreated()) {
return;
}
if (!$this->getDataContainer()->getDateModified()) {
$this->getDataContainer()->setDateModified(
$this->getDataContainer()->getDateCreated()
);
}
}
/**
* Set base URL to feed links
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setBaseUrl(DOMDocument $dom, DOMElement $root)
{
$baseUrl = $this->getDataContainer()->getBaseUrl();
if (!$baseUrl) {
return;
}
$root->setAttribute('xml:base', $baseUrl);
}
/**
* Set hubs to which this feed pushes
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setHubs(DOMDocument $dom, DOMElement $root)
{
$hubs = $this->getDataContainer()->getHubs();
if (!$hubs) {
return;
}
foreach ($hubs as $hubUrl) {
$hub = $dom->createElement('link');
$hub->setAttribute('rel', 'hub');
$hub->setAttribute('href', $hubUrl);
$root->appendChild($hub);
}
}
/**
* Set feed categories
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setCategories(DOMDocument $dom, DOMElement $root)
{
$categories = $this->getDataContainer()->getCategories();
if (!$categories) {
return;
}
foreach ($categories as $cat) {
$category = $dom->createElement('category');
$category->setAttribute('term', $cat['term']);
if (isset($cat['label'])) {
$category->setAttribute('label', $cat['label']);
} else {
$category->setAttribute('label', $cat['term']);
}
if (isset($cat['scheme'])) {
$category->setAttribute('scheme', $cat['scheme']);
}
$root->appendChild($category);
}
}
}

View file

@ -0,0 +1,99 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Renderer\Feed;
use DOMDocument;
use Zend\Feed\Writer;
use Zend\Feed\Writer\Renderer;
/**
*/
class Atom extends AbstractAtom implements Renderer\RendererInterface
{
/**
* Constructor
*
* @param Writer\Feed $container
*/
public function __construct(Writer\Feed $container)
{
parent::__construct($container);
}
/**
* Render Atom feed
*
* @return Atom
*/
public function render()
{
if (!$this->container->getEncoding()) {
$this->container->setEncoding('UTF-8');
}
$this->dom = new DOMDocument('1.0', $this->container->getEncoding());
$this->dom->formatOutput = true;
$root = $this->dom->createElementNS(
Writer\Writer::NAMESPACE_ATOM_10,
'feed'
);
$this->setRootElement($root);
$this->dom->appendChild($root);
$this->_setLanguage($this->dom, $root);
$this->_setBaseUrl($this->dom, $root);
$this->_setTitle($this->dom, $root);
$this->_setDescription($this->dom, $root);
$this->_setImage($this->dom, $root);
$this->_setDateCreated($this->dom, $root);
$this->_setDateModified($this->dom, $root);
$this->_setGenerator($this->dom, $root);
$this->_setLink($this->dom, $root);
$this->_setFeedLinks($this->dom, $root);
$this->_setId($this->dom, $root);
$this->_setAuthors($this->dom, $root);
$this->_setCopyright($this->dom, $root);
$this->_setCategories($this->dom, $root);
$this->_setHubs($this->dom, $root);
foreach ($this->extensions as $ext) {
$ext->setType($this->getType());
$ext->setRootElement($this->getRootElement());
$ext->setDOMDocument($this->getDOMDocument(), $root);
$ext->render();
}
foreach ($this->container as $entry) {
if ($this->getDataContainer()->getEncoding()) {
$entry->setEncoding($this->getDataContainer()->getEncoding());
}
if ($entry instanceof Writer\Entry) {
$renderer = new Renderer\Entry\Atom($entry);
} else {
if (!$this->dom->documentElement->hasAttribute('xmlns:at')) {
$this->dom->documentElement->setAttribute(
'xmlns:at',
'http://purl.org/atompub/tombstones/1.0'
);
}
$renderer = new Renderer\Entry\AtomDeleted($entry);
}
if ($this->ignoreExceptions === true) {
$renderer->ignoreExceptions();
}
$renderer->setType($this->getType());
$renderer->setRootElement($this->dom->documentElement);
$renderer->render();
$element = $renderer->getElement();
$deep = version_compare(PHP_VERSION, '7', 'ge') ? 1 : true;
$imported = $this->dom->importNode($element, $deep);
$root->appendChild($imported);
}
return $this;
}
}

View file

@ -0,0 +1,399 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Renderer\Feed\Atom;
use Datetime;
use DOMDocument;
use DOMElement;
use Zend\Feed;
use Zend\Feed\Writer\Version;
class AbstractAtom extends Feed\Writer\Renderer\AbstractRenderer
{
/**
* Constructor
*
* @param \Zend\Feed\Writer\Feed $container
*/
public function __construct($container)
{
parent::__construct($container);
}
/**
* Set feed language
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setLanguage(DOMDocument $dom, DOMElement $root)
{
if ($this->getDataContainer()->getLanguage()) {
$root->setAttribute('xml:lang', $this->getDataContainer()
->getLanguage());
}
}
/**
* Set feed title
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Feed\Exception\InvalidArgumentException
*/
protected function _setTitle(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getTitle()) {
$message = 'Atom 1.0 feed elements MUST contain exactly one'
. ' atom:title element but a title has not been set';
$exception = new Feed\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
$title = $dom->createElement('title');
$root->appendChild($title);
$title->setAttribute('type', 'text');
$text = $dom->createTextNode($this->getDataContainer()->getTitle());
$title->appendChild($text);
}
/**
* Set feed description
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setDescription(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getDescription()) {
return;
}
$subtitle = $dom->createElement('subtitle');
$root->appendChild($subtitle);
$subtitle->setAttribute('type', 'text');
$text = $dom->createTextNode($this->getDataContainer()->getDescription());
$subtitle->appendChild($text);
}
/**
* Set date feed was last modified
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Feed\Exception\InvalidArgumentException
*/
protected function _setDateModified(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getDateModified()) {
$message = 'Atom 1.0 feed elements MUST contain exactly one'
. ' atom:updated element but a modification date has not been set';
$exception = new Feed\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
$updated = $dom->createElement('updated');
$root->appendChild($updated);
$text = $dom->createTextNode(
$this->getDataContainer()->getDateModified()->format(DateTime::ATOM)
);
$updated->appendChild($text);
}
/**
* Set feed generator string
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setGenerator(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getGenerator()) {
$this->getDataContainer()->setGenerator('Zend_Feed_Writer',
Version::VERSION, 'http://framework.zend.com');
}
$gdata = $this->getDataContainer()->getGenerator();
$generator = $dom->createElement('generator');
$root->appendChild($generator);
$text = $dom->createTextNode($gdata['name']);
$generator->appendChild($text);
if (array_key_exists('uri', $gdata)) {
$generator->setAttribute('uri', $gdata['uri']);
}
if (array_key_exists('version', $gdata)) {
$generator->setAttribute('version', $gdata['version']);
}
}
/**
* Set link to feed
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setLink(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getLink()) {
return;
}
$link = $dom->createElement('link');
$root->appendChild($link);
$link->setAttribute('rel', 'alternate');
$link->setAttribute('type', 'text/html');
$link->setAttribute('href', $this->getDataContainer()->getLink());
}
/**
* Set feed links
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Feed\Exception\InvalidArgumentException
*/
protected function _setFeedLinks(DOMDocument $dom, DOMElement $root)
{
$flinks = $this->getDataContainer()->getFeedLinks();
if (!$flinks || !array_key_exists('atom', $flinks)) {
$message = 'Atom 1.0 feed elements SHOULD contain one atom:link '
. 'element with a rel attribute value of "self". This is the '
. 'preferred URI for retrieving Atom Feed Documents representing '
. 'this Atom feed but a feed link has not been set';
$exception = new Feed\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
foreach ($flinks as $type => $href) {
$mime = 'application/' . strtolower($type) . '+xml';
$flink = $dom->createElement('link');
$root->appendChild($flink);
$flink->setAttribute('rel', 'self');
$flink->setAttribute('type', $mime);
$flink->setAttribute('href', $href);
}
}
/**
* Set feed authors
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setAuthors(DOMDocument $dom, DOMElement $root)
{
$authors = $this->container->getAuthors();
if (!$authors || empty($authors)) {
/**
* Technically we should defer an exception until we can check
* that all entries contain an author. If any entry is missing
* an author, then a missing feed author element is invalid
*/
return;
}
foreach ($authors as $data) {
$author = $this->dom->createElement('author');
$name = $this->dom->createElement('name');
$author->appendChild($name);
$root->appendChild($author);
$text = $dom->createTextNode($data['name']);
$name->appendChild($text);
if (array_key_exists('email', $data)) {
$email = $this->dom->createElement('email');
$author->appendChild($email);
$text = $dom->createTextNode($data['email']);
$email->appendChild($text);
}
if (array_key_exists('uri', $data)) {
$uri = $this->dom->createElement('uri');
$author->appendChild($uri);
$text = $dom->createTextNode($data['uri']);
$uri->appendChild($text);
}
}
}
/**
* Set feed identifier
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Feed\Exception\InvalidArgumentException
*/
protected function _setId(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getId()
&& !$this->getDataContainer()->getLink()) {
$message = 'Atom 1.0 feed elements MUST contain exactly one '
. 'atom:id element, or as an alternative, we can use the same '
. 'value as atom:link however neither a suitable link nor an '
. 'id have been set';
$exception = new Feed\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
if (!$this->getDataContainer()->getId()) {
$this->getDataContainer()->setId(
$this->getDataContainer()->getLink());
}
$id = $dom->createElement('id');
$root->appendChild($id);
$text = $dom->createTextNode($this->getDataContainer()->getId());
$id->appendChild($text);
}
/**
* Set feed copyright
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setCopyright(DOMDocument $dom, DOMElement $root)
{
$copyright = $this->getDataContainer()->getCopyright();
if (!$copyright) {
return;
}
$copy = $dom->createElement('rights');
$root->appendChild($copy);
$text = $dom->createTextNode($copyright);
$copy->appendChild($text);
}
/**
* Set feed level logo (image)
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setImage(DOMDocument $dom, DOMElement $root)
{
$image = $this->getDataContainer()->getImage();
if (!$image) {
return;
}
$img = $dom->createElement('logo');
$root->appendChild($img);
$text = $dom->createTextNode($image['uri']);
$img->appendChild($text);
}
/**
* Set date feed was created
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setDateCreated(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getDateCreated()) {
return;
}
if (!$this->getDataContainer()->getDateModified()) {
$this->getDataContainer()->setDateModified(
$this->getDataContainer()->getDateCreated()
);
}
}
/**
* Set base URL to feed links
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setBaseUrl(DOMDocument $dom, DOMElement $root)
{
$baseUrl = $this->getDataContainer()->getBaseUrl();
if (!$baseUrl) {
return;
}
$root->setAttribute('xml:base', $baseUrl);
}
/**
* Set hubs to which this feed pushes
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setHubs(DOMDocument $dom, DOMElement $root)
{
$hubs = $this->getDataContainer()->getHubs();
if (!$hubs) {
return;
}
foreach ($hubs as $hubUrl) {
$hub = $dom->createElement('link');
$hub->setAttribute('rel', 'hub');
$hub->setAttribute('href', $hubUrl);
$root->appendChild($hub);
}
}
/**
* Set feed categories
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setCategories(DOMDocument $dom, DOMElement $root)
{
$categories = $this->getDataContainer()->getCategories();
if (!$categories) {
return;
}
foreach ($categories as $cat) {
$category = $dom->createElement('category');
$category->setAttribute('term', $cat['term']);
if (isset($cat['label'])) {
$category->setAttribute('label', $cat['label']);
} else {
$category->setAttribute('label', $cat['term']);
}
if (isset($cat['scheme'])) {
$category->setAttribute('scheme', $cat['scheme']);
}
$root->appendChild($category);
}
}
}

View file

@ -0,0 +1,92 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Renderer\Feed\Atom;
use DOMDocument;
use DOMElement;
use Zend\Feed\Writer;
use Zend\Feed\Writer\Renderer;
class Source extends AbstractAtom implements Renderer\RendererInterface
{
/**
* Constructor
*
* @param Writer\Source $container
*/
public function __construct(Writer\Source $container)
{
parent::__construct($container);
}
/**
* Render Atom Feed Metadata (Source element)
*
* @return Writer\Renderer\Feed\Atom
*/
public function render()
{
if (!$this->container->getEncoding()) {
$this->container->setEncoding('UTF-8');
}
$this->dom = new DOMDocument('1.0', $this->container->getEncoding());
$this->dom->formatOutput = true;
$root = $this->dom->createElement('source');
$this->setRootElement($root);
$this->dom->appendChild($root);
$this->_setLanguage($this->dom, $root);
$this->_setBaseUrl($this->dom, $root);
$this->_setTitle($this->dom, $root);
$this->_setDescription($this->dom, $root);
$this->_setDateCreated($this->dom, $root);
$this->_setDateModified($this->dom, $root);
$this->_setGenerator($this->dom, $root);
$this->_setLink($this->dom, $root);
$this->_setFeedLinks($this->dom, $root);
$this->_setId($this->dom, $root);
$this->_setAuthors($this->dom, $root);
$this->_setCopyright($this->dom, $root);
$this->_setCategories($this->dom, $root);
foreach ($this->extensions as $ext) {
$ext->setType($this->getType());
$ext->setRootElement($this->getRootElement());
$ext->setDomDocument($this->getDomDocument(), $root);
$ext->render();
}
return $this;
}
/**
* Set feed generator string
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setGenerator(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getGenerator()) {
return;
}
$gdata = $this->getDataContainer()->getGenerator();
$generator = $dom->createElement('generator');
$root->appendChild($generator);
$text = $dom->createTextNode($gdata['name']);
$generator->appendChild($text);
if (array_key_exists('uri', $gdata)) {
$generator->setAttribute('uri', $gdata['uri']);
}
if (array_key_exists('version', $gdata)) {
$generator->setAttribute('version', $gdata['version']);
}
}
}

View file

@ -0,0 +1,94 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Renderer\Feed;
use DOMDocument;
use DOMElement;
use Zend\Feed\Writer;
use Zend\Feed\Writer\Renderer;
/**
*/
class AtomSource extends AbstractAtom implements Renderer\RendererInterface
{
/**
* Constructor
*
* @param Writer\Source $container
*/
public function __construct(Writer\Source $container)
{
parent::__construct($container);
}
/**
* Render Atom Feed Metadata (Source element)
*
* @return \Zend\Feed\Writer\Renderer\Feed\Atom
*/
public function render()
{
if (!$this->container->getEncoding()) {
$this->container->setEncoding('UTF-8');
}
$this->dom = new DOMDocument('1.0', $this->container->getEncoding());
$this->dom->formatOutput = true;
$root = $this->dom->createElement('source');
$this->setRootElement($root);
$this->dom->appendChild($root);
$this->_setLanguage($this->dom, $root);
$this->_setBaseUrl($this->dom, $root);
$this->_setTitle($this->dom, $root);
$this->_setDescription($this->dom, $root);
$this->_setDateCreated($this->dom, $root);
$this->_setDateModified($this->dom, $root);
$this->_setGenerator($this->dom, $root);
$this->_setLink($this->dom, $root);
$this->_setFeedLinks($this->dom, $root);
$this->_setId($this->dom, $root);
$this->_setAuthors($this->dom, $root);
$this->_setCopyright($this->dom, $root);
$this->_setCategories($this->dom, $root);
foreach ($this->extensions as $ext) {
$ext->setType($this->getType());
$ext->setRootElement($this->getRootElement());
$ext->setDOMDocument($this->getDOMDocument(), $root);
$ext->render();
}
return $this;
}
/**
* Set feed generator string
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setGenerator(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getGenerator()) {
return;
}
$gdata = $this->getDataContainer()->getGenerator();
$generator = $dom->createElement('generator');
$root->appendChild($generator);
$text = $dom->createTextNode($gdata['name']);
$generator->appendChild($text);
if (array_key_exists('uri', $gdata)) {
$generator->setAttribute('uri', $gdata['uri']);
}
if (array_key_exists('version', $gdata)) {
$generator->setAttribute('version', $gdata['version']);
}
}
}

View file

@ -0,0 +1,488 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Renderer\Feed;
use DateTime;
use DOMDocument;
use DOMElement;
use Zend\Feed\Uri;
use Zend\Feed\Writer;
use Zend\Feed\Writer\Renderer;
use Zend\Feed\Writer\Version;
/**
*/
class Rss extends Renderer\AbstractRenderer implements Renderer\RendererInterface
{
/**
* Constructor
*
* @param Writer\Feed $container
*/
public function __construct(Writer\Feed $container)
{
parent::__construct($container);
}
/**
* Render RSS feed
*
* @return self
*/
public function render()
{
$this->dom = new DOMDocument('1.0', $this->container->getEncoding());
$this->dom->formatOutput = true;
$this->dom->substituteEntities = false;
$rss = $this->dom->createElement('rss');
$this->setRootElement($rss);
$rss->setAttribute('version', '2.0');
$channel = $this->dom->createElement('channel');
$rss->appendChild($channel);
$this->dom->appendChild($rss);
$this->_setLanguage($this->dom, $channel);
$this->_setBaseUrl($this->dom, $channel);
$this->_setTitle($this->dom, $channel);
$this->_setDescription($this->dom, $channel);
$this->_setImage($this->dom, $channel);
$this->_setDateCreated($this->dom, $channel);
$this->_setDateModified($this->dom, $channel);
$this->_setLastBuildDate($this->dom, $channel);
$this->_setGenerator($this->dom, $channel);
$this->_setLink($this->dom, $channel);
$this->_setAuthors($this->dom, $channel);
$this->_setCopyright($this->dom, $channel);
$this->_setCategories($this->dom, $channel);
foreach ($this->extensions as $ext) {
$ext->setType($this->getType());
$ext->setRootElement($this->getRootElement());
$ext->setDOMDocument($this->getDOMDocument(), $channel);
$ext->render();
}
foreach ($this->container as $entry) {
if ($this->getDataContainer()->getEncoding()) {
$entry->setEncoding($this->getDataContainer()->getEncoding());
}
if ($entry instanceof Writer\Entry) {
$renderer = new Renderer\Entry\Rss($entry);
} else {
continue;
}
if ($this->ignoreExceptions === true) {
$renderer->ignoreExceptions();
}
$renderer->setType($this->getType());
$renderer->setRootElement($this->dom->documentElement);
$renderer->render();
$element = $renderer->getElement();
$deep = version_compare(PHP_VERSION, '7', 'ge') ? 1 : true;
$imported = $this->dom->importNode($element, $deep);
$channel->appendChild($imported);
}
return $this;
}
/**
* Set feed language
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setLanguage(DOMDocument $dom, DOMElement $root)
{
$lang = $this->getDataContainer()->getLanguage();
if (!$lang) {
return;
}
$language = $dom->createElement('language');
$root->appendChild($language);
$language->nodeValue = $lang;
}
/**
* Set feed title
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Writer\Exception\InvalidArgumentException
*/
protected function _setTitle(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getTitle()) {
$message = 'RSS 2.0 feed elements MUST contain exactly one'
. ' title element but a title has not been set';
$exception = new Writer\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
$title = $dom->createElement('title');
$root->appendChild($title);
$text = $dom->createTextNode($this->getDataContainer()->getTitle());
$title->appendChild($text);
}
/**
* Set feed description
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Writer\Exception\InvalidArgumentException
*/
protected function _setDescription(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getDescription()) {
$message = 'RSS 2.0 feed elements MUST contain exactly one'
. ' description element but one has not been set';
$exception = new Writer\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
$subtitle = $dom->createElement('description');
$root->appendChild($subtitle);
$text = $dom->createTextNode($this->getDataContainer()->getDescription());
$subtitle->appendChild($text);
}
/**
* Set date feed was last modified
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setDateModified(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getDateModified()) {
return;
}
$updated = $dom->createElement('pubDate');
$root->appendChild($updated);
$text = $dom->createTextNode(
$this->getDataContainer()->getDateModified()->format(DateTime::RSS)
);
$updated->appendChild($text);
}
/**
* Set feed generator string
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setGenerator(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getGenerator()) {
$this->getDataContainer()->setGenerator(
'Zend_Feed_Writer',
Version::VERSION,
'http://framework.zend.com'
);
}
$gdata = $this->getDataContainer()->getGenerator();
$generator = $dom->createElement('generator');
$root->appendChild($generator);
$name = $gdata['name'];
if (array_key_exists('version', $gdata)) {
$name .= ' ' . $gdata['version'];
}
if (array_key_exists('uri', $gdata)) {
$name .= ' (' . $gdata['uri'] . ')';
}
$text = $dom->createTextNode($name);
$generator->appendChild($text);
}
/**
* Set link to feed
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Writer\Exception\InvalidArgumentException
*/
protected function _setLink(DOMDocument $dom, DOMElement $root)
{
$value = $this->getDataContainer()->getLink();
if (!$value) {
$message = 'RSS 2.0 feed elements MUST contain exactly one'
. ' link element but one has not been set';
$exception = new Writer\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
$link = $dom->createElement('link');
$root->appendChild($link);
$text = $dom->createTextNode($value);
$link->appendChild($text);
if (!Uri::factory($value)->isValid()) {
$link->setAttribute('isPermaLink', 'false');
}
}
/**
* Set feed authors
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setAuthors(DOMDocument $dom, DOMElement $root)
{
$authors = $this->getDataContainer()->getAuthors();
if (!$authors || empty($authors)) {
return;
}
foreach ($authors as $data) {
$author = $this->dom->createElement('author');
$name = $data['name'];
if (array_key_exists('email', $data)) {
$name = $data['email'] . ' (' . $data['name'] . ')';
}
$text = $dom->createTextNode($name);
$author->appendChild($text);
$root->appendChild($author);
}
}
/**
* Set feed copyright
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setCopyright(DOMDocument $dom, DOMElement $root)
{
$copyright = $this->getDataContainer()->getCopyright();
if (!$copyright) {
return;
}
$copy = $dom->createElement('copyright');
$root->appendChild($copy);
$text = $dom->createTextNode($copyright);
$copy->appendChild($text);
}
/**
* Set feed channel image
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
* @throws Writer\Exception\InvalidArgumentException
*/
protected function _setImage(DOMDocument $dom, DOMElement $root)
{
$image = $this->getDataContainer()->getImage();
if (!$image) {
return;
}
if (!isset($image['title']) || empty($image['title'])
|| !is_string($image['title'])
) {
$message = 'RSS 2.0 feed images must include a title';
$exception = new Writer\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
if (empty($image['link']) || !is_string($image['link'])
|| !Uri::factory($image['link'])->isValid()
) {
$message = 'Invalid parameter: parameter \'link\''
. ' must be a non-empty string and valid URI/IRI';
$exception = new Writer\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
$img = $dom->createElement('image');
$root->appendChild($img);
$url = $dom->createElement('url');
$text = $dom->createTextNode($image['uri']);
$url->appendChild($text);
$title = $dom->createElement('title');
$text = $dom->createTextNode($image['title']);
$title->appendChild($text);
$link = $dom->createElement('link');
$text = $dom->createTextNode($image['link']);
$link->appendChild($text);
$img->appendChild($url);
$img->appendChild($title);
$img->appendChild($link);
if (isset($image['height'])) {
if (!ctype_digit((string) $image['height']) || $image['height'] > 400) {
$message = 'Invalid parameter: parameter \'height\''
. ' must be an integer not exceeding 400';
$exception = new Writer\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
$height = $dom->createElement('height');
$text = $dom->createTextNode($image['height']);
$height->appendChild($text);
$img->appendChild($height);
}
if (isset($image['width'])) {
if (!ctype_digit((string) $image['width']) || $image['width'] > 144) {
$message = 'Invalid parameter: parameter \'width\''
. ' must be an integer not exceeding 144';
$exception = new Writer\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
$width = $dom->createElement('width');
$text = $dom->createTextNode($image['width']);
$width->appendChild($text);
$img->appendChild($width);
}
if (isset($image['description'])) {
if (empty($image['description']) || !is_string($image['description'])) {
$message = 'Invalid parameter: parameter \'description\''
. ' must be a non-empty string';
$exception = new Writer\Exception\InvalidArgumentException($message);
if (!$this->ignoreExceptions) {
throw $exception;
} else {
$this->exceptions[] = $exception;
return;
}
}
$desc = $dom->createElement('description');
$text = $dom->createTextNode($image['description']);
$desc->appendChild($text);
$img->appendChild($desc);
}
}
/**
* Set date feed was created
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setDateCreated(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getDateCreated()) {
return;
}
if (!$this->getDataContainer()->getDateModified()) {
$this->getDataContainer()->setDateModified(
$this->getDataContainer()->getDateCreated()
);
}
}
/**
* Set date feed last build date
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setLastBuildDate(DOMDocument $dom, DOMElement $root)
{
if (!$this->getDataContainer()->getLastBuildDate()) {
return;
}
$lastBuildDate = $dom->createElement('lastBuildDate');
$root->appendChild($lastBuildDate);
$text = $dom->createTextNode(
$this->getDataContainer()->getLastBuildDate()->format(DateTime::RSS)
);
$lastBuildDate->appendChild($text);
}
/**
* Set base URL to feed links
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setBaseUrl(DOMDocument $dom, DOMElement $root)
{
$baseUrl = $this->getDataContainer()->getBaseUrl();
if (!$baseUrl) {
return;
}
$root->setAttribute('xml:base', $baseUrl);
}
/**
* Set feed categories
*
* @param DOMDocument $dom
* @param DOMElement $root
* @return void
*/
protected function _setCategories(DOMDocument $dom, DOMElement $root)
{
$categories = $this->getDataContainer()->getCategories();
if (!$categories) {
return;
}
foreach ($categories as $cat) {
$category = $dom->createElement('category');
if (isset($cat['scheme'])) {
$category->setAttribute('domain', $cat['scheme']);
}
$text = $dom->createTextNode($cat['term']);
$category->appendChild($text);
$root->appendChild($category);
}
}
}

View file

@ -0,0 +1,100 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer\Renderer;
use DOMDocument;
use DOMElement;
/**
*/
interface RendererInterface
{
/**
* Render feed/entry
*
* @return void
*/
public function render();
/**
* Save feed and/or entry to XML and return string
*
* @return string
*/
public function saveXml();
/**
* Get DOM document
*
* @return DOMDocument
*/
public function getDomDocument();
/**
* Get document element from DOM
*
* @return DOMElement
*/
public function getElement();
/**
* Get data container containing feed items
*
* @return mixed
*/
public function getDataContainer();
/**
* Should exceptions be ignored?
*
* @return mixed
*/
public function ignoreExceptions();
/**
* Get list of thrown exceptions
*
* @return array
*/
public function getExceptions();
/**
* Set the current feed type being exported to "rss" or "atom". This allows
* other objects to gracefully choose whether to execute or not, depending
* on their appropriateness for the current type, e.g. renderers.
*
* @param string $type
*/
public function setType($type);
/**
* Retrieve the current or last feed type exported.
*
* @return string Value will be "rss" or "atom"
*/
public function getType();
/**
* Sets the absolute root element for the XML feed being generated. This
* helps simplify the appending of namespace declarations, but also ensures
* namespaces are added to the root element - not scattered across the entire
* XML file - may assist namespace unsafe parsers and looks pretty ;).
*
* @param DOMElement $root
*/
public function setRootElement(DOMElement $root);
/**
* Retrieve the absolute root element for the XML feed being generated.
*
* @return DOMElement
*/
public function getRootElement();
}

View file

@ -0,0 +1,16 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer;
/**
*/
class Source extends AbstractFeed
{
}

View file

@ -0,0 +1,15 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer;
abstract class Version
{
const VERSION = '2';
}

View file

@ -0,0 +1,199 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Feed\Writer;
/**
*/
class Writer
{
/**
* Namespace constants
*/
const NAMESPACE_ATOM_03 = 'http://purl.org/atom/ns#';
const NAMESPACE_ATOM_10 = 'http://www.w3.org/2005/Atom';
const NAMESPACE_RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
const NAMESPACE_RSS_090 = 'http://my.netscape.com/rdf/simple/0.9/';
const NAMESPACE_RSS_10 = 'http://purl.org/rss/1.0/';
/**
* Feed type constants
*/
const TYPE_ANY = 'any';
const TYPE_ATOM_03 = 'atom-03';
const TYPE_ATOM_10 = 'atom-10';
const TYPE_ATOM_ANY = 'atom';
const TYPE_RSS_090 = 'rss-090';
const TYPE_RSS_091 = 'rss-091';
const TYPE_RSS_091_NETSCAPE = 'rss-091n';
const TYPE_RSS_091_USERLAND = 'rss-091u';
const TYPE_RSS_092 = 'rss-092';
const TYPE_RSS_093 = 'rss-093';
const TYPE_RSS_094 = 'rss-094';
const TYPE_RSS_10 = 'rss-10';
const TYPE_RSS_20 = 'rss-20';
const TYPE_RSS_ANY = 'rss';
/**
* @var ExtensionManagerInterface
*/
protected static $extensionManager = null;
/**
* Array of registered extensions by class postfix (after the base class
* name) across four categories - data containers and renderers for entry
* and feed levels.
*
* @var array
*/
protected static $extensions = [
'entry' => [],
'feed' => [],
'entryRenderer' => [],
'feedRenderer' => [],
];
/**
* Set plugin loader for use with Extensions
*
* @param ExtensionManagerInterface
*/
public static function setExtensionManager(ExtensionManagerInterface $extensionManager)
{
static::$extensionManager = $extensionManager;
}
/**
* Get plugin manager for use with Extensions
*
* @return ExtensionManagerInterface
*/
public static function getExtensionManager()
{
if (!isset(static::$extensionManager)) {
static::setExtensionManager(new ExtensionManager());
}
return static::$extensionManager;
}
/**
* Register an Extension by name
*
* @param string $name
* @return void
* @throws Exception\RuntimeException if unable to resolve Extension class
*/
public static function registerExtension($name)
{
$feedName = $name . '\Feed';
$entryName = $name . '\Entry';
$feedRendererName = $name . '\Renderer\Feed';
$entryRendererName = $name . '\Renderer\Entry';
$manager = static::getExtensionManager();
if (static::isRegistered($name)) {
if ($manager->has($feedName)
|| $manager->has($entryName)
|| $manager->has($feedRendererName)
|| $manager->has($entryRendererName)
) {
return;
}
}
if (!$manager->has($feedName)
&& !$manager->has($entryName)
&& !$manager->has($feedRendererName)
&& !$manager->has($entryRendererName)
) {
throw new Exception\RuntimeException('Could not load extension: ' . $name
. 'using Plugin Loader. Check prefix paths are configured and extension exists.');
}
if ($manager->has($feedName)) {
static::$extensions['feed'][] = $feedName;
}
if ($manager->has($entryName)) {
static::$extensions['entry'][] = $entryName;
}
if ($manager->has($feedRendererName)) {
static::$extensions['feedRenderer'][] = $feedRendererName;
}
if ($manager->has($entryRendererName)) {
static::$extensions['entryRenderer'][] = $entryRendererName;
}
}
/**
* Is a given named Extension registered?
*
* @param string $extensionName
* @return bool
*/
public static function isRegistered($extensionName)
{
$feedName = $extensionName . '\Feed';
$entryName = $extensionName . '\Entry';
$feedRendererName = $extensionName . '\Renderer\Feed';
$entryRendererName = $extensionName . '\Renderer\Entry';
if (in_array($feedName, static::$extensions['feed'])
|| in_array($entryName, static::$extensions['entry'])
|| in_array($feedRendererName, static::$extensions['feedRenderer'])
|| in_array($entryRendererName, static::$extensions['entryRenderer'])
) {
return true;
}
return false;
}
/**
* Get a list of extensions
*
* @return array
*/
public static function getExtensions()
{
return static::$extensions;
}
/**
* Reset class state to defaults
*
* @return void
*/
public static function reset()
{
static::$extensionManager = null;
static::$extensions = [
'entry' => [],
'feed' => [],
'entryRenderer' => [],
'feedRenderer' => [],
];
}
/**
* Register core (default) extensions
*
* @return void
*/
public static function registerCoreExtensions()
{
static::registerExtension('DublinCore');
static::registerExtension('Content');
static::registerExtension('Atom');
static::registerExtension('Slash');
static::registerExtension('WellFormedWeb');
static::registerExtension('Threading');
static::registerExtension('ITunes');
}
public static function lcfirst($str)
{
$str[0] = strtolower($str[0]);
return $str;
}
}