Chris@0: get('DublinCore\Feed'); Chris@0: $feed->setDomDocument($dom); Chris@0: $feed->setType($this->data['type']); Chris@0: $feed->setXpath($this->xpath); Chris@0: $this->extensions['DublinCore\Feed'] = $feed; Chris@0: Chris@0: $feed = $manager->get('Atom\Feed'); Chris@0: $feed->setDomDocument($dom); Chris@0: $feed->setType($this->data['type']); Chris@0: $feed->setXpath($this->xpath); Chris@0: $this->extensions['Atom\Feed'] = $feed; Chris@0: Chris@0: if ($this->getType() !== Reader\Reader::TYPE_RSS_10 Chris@0: && $this->getType() !== Reader\Reader::TYPE_RSS_090 Chris@0: ) { Chris@0: $xpathPrefix = '/rss/channel'; Chris@0: } else { Chris@0: $xpathPrefix = '/rdf:RDF/rss:channel'; Chris@0: } Chris@0: foreach ($this->extensions as $extension) { Chris@0: $extension->setXpathPrefix($xpathPrefix); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get a single author Chris@0: * Chris@0: * @param int $index Chris@0: * @return string|null Chris@0: */ Chris@0: public function getAuthor($index = 0) Chris@0: { Chris@0: $authors = $this->getAuthors(); Chris@0: Chris@0: if (isset($authors[$index])) { Chris@0: return $authors[$index]; Chris@0: } Chris@0: Chris@0: return; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get an array with feed authors Chris@0: * Chris@0: * @return array Chris@0: */ Chris@0: public function getAuthors() Chris@0: { Chris@0: if (array_key_exists('authors', $this->data)) { Chris@0: return $this->data['authors']; Chris@0: } Chris@0: Chris@0: $authors = []; Chris@0: $authorsDc = $this->getExtension('DublinCore')->getAuthors(); Chris@12: if (! empty($authorsDc)) { Chris@0: foreach ($authorsDc as $author) { Chris@0: $authors[] = [ Chris@0: 'name' => $author['name'] Chris@0: ]; Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Technically RSS doesn't specific author element use at the feed level Chris@0: * but it's supported on a "just in case" basis. Chris@0: */ Chris@0: if ($this->getType() !== Reader\Reader::TYPE_RSS_10 Chris@0: && $this->getType() !== Reader\Reader::TYPE_RSS_090) { Chris@0: $list = $this->xpath->query('//author'); Chris@0: } else { Chris@0: $list = $this->xpath->query('//rss:author'); Chris@0: } Chris@0: if ($list->length) { Chris@0: foreach ($list as $author) { Chris@0: $string = trim($author->nodeValue); Chris@0: $data = []; Chris@0: // Pretty rough parsing - but it's a catchall Chris@0: if (preg_match("/^.*@[^ ]*/", $string, $matches)) { Chris@0: $data['email'] = trim($matches[0]); Chris@0: if (preg_match("/\((.*)\)$/", $string, $matches)) { Chris@0: $data['name'] = $matches[1]; Chris@0: } Chris@0: $authors[] = $data; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: if (count($authors) == 0) { Chris@0: $authors = $this->getExtension('Atom')->getAuthors(); Chris@0: } else { Chris@0: $authors = new Reader\Collection\Author( Chris@0: Reader\Reader::arrayUnique($authors) Chris@0: ); Chris@0: } Chris@0: Chris@0: if (count($authors) == 0) { Chris@0: $authors = null; Chris@0: } Chris@0: Chris@0: $this->data['authors'] = $authors; Chris@0: Chris@0: return $this->data['authors']; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get the copyright entry Chris@0: * Chris@0: * @return string|null Chris@0: */ Chris@0: public function getCopyright() Chris@0: { Chris@0: if (array_key_exists('copyright', $this->data)) { Chris@0: return $this->data['copyright']; Chris@0: } Chris@0: Chris@0: $copyright = null; Chris@0: Chris@0: if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && Chris@0: $this->getType() !== Reader\Reader::TYPE_RSS_090) { Chris@0: $copyright = $this->xpath->evaluate('string(/rss/channel/copyright)'); Chris@0: } Chris@0: Chris@12: if (! $copyright && $this->getExtension('DublinCore') !== null) { Chris@0: $copyright = $this->getExtension('DublinCore')->getCopyright(); Chris@0: } Chris@0: Chris@0: if (empty($copyright)) { Chris@0: $copyright = $this->getExtension('Atom')->getCopyright(); Chris@0: } Chris@0: Chris@12: if (! $copyright) { Chris@0: $copyright = null; Chris@0: } Chris@0: Chris@0: $this->data['copyright'] = $copyright; Chris@0: Chris@0: return $this->data['copyright']; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get the feed creation date Chris@0: * Chris@12: * @return DateTime|null Chris@0: */ Chris@0: public function getDateCreated() Chris@0: { Chris@0: return $this->getDateModified(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get the feed modification date Chris@0: * Chris@0: * @return DateTime Chris@0: * @throws Exception\RuntimeException Chris@0: */ Chris@0: public function getDateModified() Chris@0: { Chris@0: if (array_key_exists('datemodified', $this->data)) { Chris@0: return $this->data['datemodified']; Chris@0: } Chris@0: Chris@0: $date = null; Chris@0: Chris@0: if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && Chris@0: $this->getType() !== Reader\Reader::TYPE_RSS_090) { Chris@0: $dateModified = $this->xpath->evaluate('string(/rss/channel/pubDate)'); Chris@12: if (! $dateModified) { Chris@0: $dateModified = $this->xpath->evaluate('string(/rss/channel/lastBuildDate)'); Chris@0: } Chris@0: if ($dateModified) { Chris@0: $dateModifiedParsed = strtotime($dateModified); Chris@0: if ($dateModifiedParsed) { Chris@0: $date = new DateTime('@' . $dateModifiedParsed); Chris@0: } else { Chris@0: $dateStandards = [DateTime::RSS, DateTime::RFC822, Chris@0: DateTime::RFC2822, null]; Chris@0: foreach ($dateStandards as $standard) { Chris@0: try { Chris@0: $date = DateTime::createFromFormat($standard, $dateModified); Chris@0: break; Chris@0: } catch (\Exception $e) { Chris@0: if ($standard === null) { Chris@0: throw new Exception\RuntimeException( Chris@0: 'Could not load date due to unrecognised' Chris@0: .' format (should follow RFC 822 or 2822):' Chris@0: . $e->getMessage(), Chris@12: 0, Chris@12: $e Chris@0: ); Chris@0: } Chris@0: } Chris@0: } Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@12: if (! $date) { Chris@0: $date = $this->getExtension('DublinCore')->getDate(); Chris@0: } Chris@0: Chris@12: if (! $date) { Chris@0: $date = $this->getExtension('Atom')->getDateModified(); Chris@0: } Chris@0: Chris@12: if (! $date) { Chris@0: $date = null; Chris@0: } Chris@0: Chris@0: $this->data['datemodified'] = $date; Chris@0: Chris@0: return $this->data['datemodified']; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get the feed lastBuild date Chris@0: * Chris@0: * @throws Exception\RuntimeException Chris@0: * @return DateTime Chris@0: */ Chris@0: public function getLastBuildDate() Chris@0: { Chris@0: if (array_key_exists('lastBuildDate', $this->data)) { Chris@0: return $this->data['lastBuildDate']; Chris@0: } Chris@0: Chris@0: $date = null; Chris@0: Chris@0: if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && Chris@0: $this->getType() !== Reader\Reader::TYPE_RSS_090) { Chris@0: $lastBuildDate = $this->xpath->evaluate('string(/rss/channel/lastBuildDate)'); Chris@0: if ($lastBuildDate) { Chris@0: $lastBuildDateParsed = strtotime($lastBuildDate); Chris@0: if ($lastBuildDateParsed) { Chris@0: $date = new DateTime('@' . $lastBuildDateParsed); Chris@0: } else { Chris@0: $dateStandards = [DateTime::RSS, DateTime::RFC822, Chris@0: DateTime::RFC2822, null]; Chris@0: foreach ($dateStandards as $standard) { Chris@0: try { Chris@0: $date = DateTime::createFromFormat($standard, $lastBuildDateParsed); Chris@0: break; Chris@0: } catch (\Exception $e) { Chris@0: if ($standard === null) { Chris@0: throw new Exception\RuntimeException( Chris@0: 'Could not load date due to unrecognised' Chris@0: .' format (should follow RFC 822 or 2822):' Chris@0: . $e->getMessage(), Chris@12: 0, Chris@12: $e Chris@0: ); Chris@0: } Chris@0: } Chris@0: } Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@12: if (! $date) { Chris@0: $date = null; Chris@0: } Chris@0: Chris@0: $this->data['lastBuildDate'] = $date; Chris@0: Chris@0: return $this->data['lastBuildDate']; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get the feed description Chris@0: * Chris@0: * @return string|null Chris@0: */ Chris@0: public function getDescription() Chris@0: { Chris@0: if (array_key_exists('description', $this->data)) { Chris@0: return $this->data['description']; Chris@0: } Chris@0: Chris@0: if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && Chris@0: $this->getType() !== Reader\Reader::TYPE_RSS_090) { Chris@0: $description = $this->xpath->evaluate('string(/rss/channel/description)'); Chris@0: } else { Chris@0: $description = $this->xpath->evaluate('string(/rdf:RDF/rss:channel/rss:description)'); Chris@0: } Chris@0: Chris@12: if (! $description && $this->getExtension('DublinCore') !== null) { Chris@0: $description = $this->getExtension('DublinCore')->getDescription(); Chris@0: } Chris@0: Chris@0: if (empty($description)) { Chris@0: $description = $this->getExtension('Atom')->getDescription(); Chris@0: } Chris@0: Chris@12: if (! $description) { Chris@0: $description = null; Chris@0: } Chris@0: Chris@0: $this->data['description'] = $description; Chris@0: Chris@0: return $this->data['description']; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get the feed ID Chris@0: * Chris@0: * @return string|null Chris@0: */ Chris@0: public function getId() Chris@0: { Chris@0: if (array_key_exists('id', $this->data)) { Chris@0: return $this->data['id']; Chris@0: } Chris@0: Chris@0: $id = null; Chris@0: Chris@0: if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && Chris@0: $this->getType() !== Reader\Reader::TYPE_RSS_090) { Chris@0: $id = $this->xpath->evaluate('string(/rss/channel/guid)'); Chris@0: } Chris@0: Chris@12: if (! $id && $this->getExtension('DublinCore') !== null) { Chris@0: $id = $this->getExtension('DublinCore')->getId(); Chris@0: } Chris@0: Chris@0: if (empty($id)) { Chris@0: $id = $this->getExtension('Atom')->getId(); Chris@0: } Chris@0: Chris@12: if (! $id) { Chris@0: if ($this->getLink()) { Chris@0: $id = $this->getLink(); Chris@0: } elseif ($this->getTitle()) { Chris@0: $id = $this->getTitle(); Chris@0: } else { Chris@0: $id = null; Chris@0: } Chris@0: } Chris@0: Chris@0: $this->data['id'] = $id; Chris@0: Chris@0: return $this->data['id']; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get the feed image data Chris@0: * Chris@0: * @return array|null Chris@0: */ Chris@0: public function getImage() Chris@0: { Chris@0: if (array_key_exists('image', $this->data)) { Chris@0: return $this->data['image']; Chris@0: } Chris@0: Chris@0: if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && Chris@0: $this->getType() !== Reader\Reader::TYPE_RSS_090) { Chris@0: $list = $this->xpath->query('/rss/channel/image'); Chris@0: $prefix = '/rss/channel/image[1]'; Chris@0: } else { Chris@0: $list = $this->xpath->query('/rdf:RDF/rss:channel/rss:image'); Chris@0: $prefix = '/rdf:RDF/rss:channel/rss:image[1]'; Chris@0: } Chris@0: if ($list->length > 0) { Chris@0: $image = []; Chris@0: $value = $this->xpath->evaluate('string(' . $prefix . '/url)'); Chris@0: if ($value) { Chris@0: $image['uri'] = $value; Chris@0: } Chris@0: $value = $this->xpath->evaluate('string(' . $prefix . '/link)'); Chris@0: if ($value) { Chris@0: $image['link'] = $value; Chris@0: } Chris@0: $value = $this->xpath->evaluate('string(' . $prefix . '/title)'); Chris@0: if ($value) { Chris@0: $image['title'] = $value; Chris@0: } Chris@0: $value = $this->xpath->evaluate('string(' . $prefix . '/height)'); Chris@0: if ($value) { Chris@0: $image['height'] = $value; Chris@0: } Chris@0: $value = $this->xpath->evaluate('string(' . $prefix . '/width)'); Chris@0: if ($value) { Chris@0: $image['width'] = $value; Chris@0: } Chris@0: $value = $this->xpath->evaluate('string(' . $prefix . '/description)'); Chris@0: if ($value) { Chris@0: $image['description'] = $value; Chris@0: } Chris@0: } else { Chris@0: $image = null; Chris@0: } Chris@0: Chris@0: $this->data['image'] = $image; Chris@0: Chris@0: return $this->data['image']; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get the feed language Chris@0: * Chris@0: * @return string|null Chris@0: */ Chris@0: public function getLanguage() Chris@0: { Chris@0: if (array_key_exists('language', $this->data)) { Chris@0: return $this->data['language']; Chris@0: } Chris@0: Chris@0: $language = null; Chris@0: Chris@0: if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && Chris@0: $this->getType() !== Reader\Reader::TYPE_RSS_090) { Chris@0: $language = $this->xpath->evaluate('string(/rss/channel/language)'); Chris@0: } Chris@0: Chris@12: if (! $language && $this->getExtension('DublinCore') !== null) { Chris@0: $language = $this->getExtension('DublinCore')->getLanguage(); Chris@0: } Chris@0: Chris@0: if (empty($language)) { Chris@0: $language = $this->getExtension('Atom')->getLanguage(); Chris@0: } Chris@0: Chris@12: if (! $language) { Chris@0: $language = $this->xpath->evaluate('string(//@xml:lang[1])'); Chris@0: } Chris@0: Chris@12: if (! $language) { Chris@0: $language = null; Chris@0: } Chris@0: Chris@0: $this->data['language'] = $language; Chris@0: Chris@0: return $this->data['language']; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get a link to the feed Chris@0: * Chris@0: * @return string|null Chris@0: */ Chris@0: public function getLink() Chris@0: { Chris@0: if (array_key_exists('link', $this->data)) { Chris@0: return $this->data['link']; Chris@0: } Chris@0: Chris@0: if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && Chris@0: $this->getType() !== Reader\Reader::TYPE_RSS_090) { Chris@0: $link = $this->xpath->evaluate('string(/rss/channel/link)'); Chris@0: } else { Chris@0: $link = $this->xpath->evaluate('string(/rdf:RDF/rss:channel/rss:link)'); Chris@0: } Chris@0: Chris@0: if (empty($link)) { Chris@0: $link = $this->getExtension('Atom')->getLink(); Chris@0: } Chris@0: Chris@12: if (! $link) { Chris@0: $link = null; Chris@0: } Chris@0: Chris@0: $this->data['link'] = $link; Chris@0: Chris@0: return $this->data['link']; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get a link to the feed XML Chris@0: * Chris@0: * @return string|null Chris@0: */ Chris@0: public function getFeedLink() Chris@0: { Chris@0: if (array_key_exists('feedlink', $this->data)) { Chris@0: return $this->data['feedlink']; Chris@0: } Chris@0: Chris@0: $link = $this->getExtension('Atom')->getFeedLink(); Chris@0: Chris@0: if ($link === null || empty($link)) { Chris@0: $link = $this->getOriginalSourceUri(); Chris@0: } Chris@0: Chris@0: $this->data['feedlink'] = $link; Chris@0: Chris@0: return $this->data['feedlink']; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get the feed generator entry Chris@0: * Chris@0: * @return string|null Chris@0: */ Chris@0: public function getGenerator() Chris@0: { Chris@0: if (array_key_exists('generator', $this->data)) { Chris@0: return $this->data['generator']; Chris@0: } Chris@0: Chris@0: $generator = null; Chris@0: Chris@0: if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && Chris@0: $this->getType() !== Reader\Reader::TYPE_RSS_090) { Chris@0: $generator = $this->xpath->evaluate('string(/rss/channel/generator)'); Chris@0: } Chris@0: Chris@12: if (! $generator) { Chris@0: if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && Chris@0: $this->getType() !== Reader\Reader::TYPE_RSS_090) { Chris@0: $generator = $this->xpath->evaluate('string(/rss/channel/atom:generator)'); Chris@0: } else { Chris@0: $generator = $this->xpath->evaluate('string(/rdf:RDF/rss:channel/atom:generator)'); Chris@0: } Chris@0: } Chris@0: Chris@0: if (empty($generator)) { Chris@0: $generator = $this->getExtension('Atom')->getGenerator(); Chris@0: } Chris@0: Chris@12: if (! $generator) { Chris@0: $generator = null; Chris@0: } Chris@0: Chris@0: $this->data['generator'] = $generator; Chris@0: Chris@0: return $this->data['generator']; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get the feed title Chris@0: * Chris@0: * @return string|null Chris@0: */ Chris@0: public function getTitle() Chris@0: { Chris@0: if (array_key_exists('title', $this->data)) { Chris@0: return $this->data['title']; Chris@0: } Chris@0: Chris@0: if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && Chris@0: $this->getType() !== Reader\Reader::TYPE_RSS_090) { Chris@0: $title = $this->xpath->evaluate('string(/rss/channel/title)'); Chris@0: } else { Chris@0: $title = $this->xpath->evaluate('string(/rdf:RDF/rss:channel/rss:title)'); Chris@0: } Chris@0: Chris@12: if (! $title && $this->getExtension('DublinCore') !== null) { Chris@0: $title = $this->getExtension('DublinCore')->getTitle(); Chris@0: } Chris@0: Chris@12: if (! $title) { Chris@0: $title = $this->getExtension('Atom')->getTitle(); Chris@0: } Chris@0: Chris@12: if (! $title) { Chris@0: $title = null; Chris@0: } Chris@0: Chris@0: $this->data['title'] = $title; Chris@0: Chris@0: return $this->data['title']; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get an array of any supported Pusubhubbub endpoints Chris@0: * Chris@0: * @return array|null Chris@0: */ Chris@0: public function getHubs() Chris@0: { Chris@0: if (array_key_exists('hubs', $this->data)) { Chris@0: return $this->data['hubs']; Chris@0: } Chris@0: Chris@0: $hubs = $this->getExtension('Atom')->getHubs(); Chris@0: Chris@0: if (empty($hubs)) { Chris@0: $hubs = null; Chris@0: } else { Chris@0: $hubs = array_unique($hubs); Chris@0: } Chris@0: Chris@0: $this->data['hubs'] = $hubs; Chris@0: Chris@0: return $this->data['hubs']; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get all categories Chris@0: * Chris@0: * @return Reader\Collection\Category Chris@0: */ Chris@0: public function getCategories() Chris@0: { Chris@0: if (array_key_exists('categories', $this->data)) { Chris@0: return $this->data['categories']; Chris@0: } Chris@0: Chris@0: if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && Chris@0: $this->getType() !== Reader\Reader::TYPE_RSS_090) { Chris@0: $list = $this->xpath->query('/rss/channel//category'); Chris@0: } else { Chris@0: $list = $this->xpath->query('/rdf:RDF/rss:channel//rss:category'); Chris@0: } Chris@0: Chris@0: if ($list->length) { Chris@0: $categoryCollection = new Collection\Category; Chris@0: foreach ($list as $category) { Chris@0: $categoryCollection[] = [ Chris@0: 'term' => $category->nodeValue, Chris@0: 'scheme' => $category->getAttribute('domain'), Chris@0: 'label' => $category->nodeValue, Chris@0: ]; Chris@0: } Chris@0: } else { Chris@0: $categoryCollection = $this->getExtension('DublinCore')->getCategories(); Chris@0: } Chris@0: Chris@0: if (count($categoryCollection) == 0) { Chris@0: $categoryCollection = $this->getExtension('Atom')->getCategories(); Chris@0: } Chris@0: Chris@0: $this->data['categories'] = $categoryCollection; Chris@0: Chris@0: return $this->data['categories']; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Read all entries to the internal entries array Chris@0: * Chris@0: */ Chris@0: protected function indexEntries() Chris@0: { Chris@0: if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && $this->getType() !== Reader\Reader::TYPE_RSS_090) { Chris@0: $entries = $this->xpath->evaluate('//item'); Chris@0: } else { Chris@0: $entries = $this->xpath->evaluate('//rss:item'); Chris@0: } Chris@0: Chris@0: foreach ($entries as $index => $entry) { Chris@0: $this->entries[$index] = $entry; Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Register the default namespaces for the current feed format Chris@0: * Chris@0: */ Chris@0: protected function registerNamespaces() Chris@0: { Chris@0: switch ($this->data['type']) { Chris@0: case Reader\Reader::TYPE_RSS_10: Chris@0: $this->xpath->registerNamespace('rdf', Reader\Reader::NAMESPACE_RDF); Chris@0: $this->xpath->registerNamespace('rss', Reader\Reader::NAMESPACE_RSS_10); Chris@0: break; Chris@0: Chris@0: case Reader\Reader::TYPE_RSS_090: Chris@0: $this->xpath->registerNamespace('rdf', Reader\Reader::NAMESPACE_RDF); Chris@0: $this->xpath->registerNamespace('rss', Reader\Reader::NAMESPACE_RSS_090); Chris@0: break; Chris@0: } Chris@0: } Chris@0: }