Skip to content

Instantly share code, notes, and snippets.

@hissy
Last active June 5, 2018 01:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hissy/bd6d21a080072d48891d107b267e603c to your computer and use it in GitHub Desktop.
Save hissy/bd6d21a080072d48891d107b267e603c to your computer and use it in GitHub Desktop.
#concrete5 SmartFormat RSS (An example to customize Zend Feed with Extension)
<?php
// application/bootstrap/app.php
$app->make('Concrete\Core\Routing\RouterInterface')->register('/feed/smartnews', function() use ($app) {
/**
* Registering Extension for Zend Feed
*/
/** @var \Zend\ServiceManager\AbstractPluginManager $manager */
$manager = \Zend\Feed\Writer\Writer::getExtensionManager();
$manager->setInvokableClass(
'SmartNewsRendererFeed',
'Application\Src\Feed\Writer\Extension\SmartNews\Renderer\Feed'
);
$manager->setInvokableClass(
'SmartNewsEntry',
'Application\Src\Feed\Writer\Extension\SmartNews\Entry'
);
$manager->setInvokableClass(
'SmartNewsRendererEntry',
'Application\Src\Feed\Writer\Extension\SmartNews\Renderer\Entry'
);
\Zend\Feed\Writer\Writer::registerExtension('SmartNews');
/**
* Get pages
*/
$pl = new \Concrete\Core\Page\PageList();
$pl->sortByPublicDateDescending();
$vp = \Concrete\Core\Permission\Key\Key::getByHandle('view_page');
$guest = \Concrete\Core\User\Group\Group::getByID(GUEST_GROUP_ID);
$access = \Concrete\Core\Permission\Access\Entity\GroupEntity::getOrCreate($guest);
// we set page permissions to be Guest group only, because
// authentication won't work with RSS feeds
$pl->setPermissionsChecker(function($page) use ($vp, $access) {
$vp->setPermissionObject($page);
$pa = $vp->getPermissionAccessObject($page);
if (!is_object($pa)) {
return false;
}
return $pa->validateAccessEntities(array($access));
});
// Filter By Page Type
$pl->filterByPageTypeHandle('article');
$pagination = $pl->getPagination();
if ($pagination->getTotalResults() > 0) {
$request = \Concrete\Core\Http\Request::getInstance();
/**
* Retrieve site information
*/
$site = $app->make('site')->getSite();
$home = $site->getSiteHomePageObject('ACTIVE');
$description = ($site->getAttribute('description')) ? $site->getAttribute('description') : t('No Description');
$thumbnail = $site->getAttribute('thumbnail');
/**
* Setup Feed Object
*/
$writer = new \Zend\Feed\Writer\Feed();
$writer->setTitle($site->getSiteName());
$writer->setLink($site->getSiteCanonicalURL());
$writer->setDescription($description);
if (is_object($thumbnail) {
$writer->setImage(array(
'uri' => $thumbnail->getURL(),
'title' => $site->getSiteName(),
'link' => $site->getSiteCanonicalURL()
));
}
$writer->setDateCreated(new DateTime());
/** @var \Concrete\Core\Page\Page|\Concrete\Core\Page\Collection\Collection|\Page $p */
foreach($pagination->getCurrentPageResults() as $p) {
$entry = $writer->createEntry();
$entry->setTitle($p->getCollectionName());
if ($description = $p->getCollectionDescription()) {
$entry->setDescription($description);
}
$entry->setDateCreated(strtotime($p->getCollectionDatePublic()));
$entry->setLink($p->getCollectionLink(true));
$uid = $p->getCollectionUserID();
/** @var \Concrete\Core\User\UserInfo $ui */
$ui = $app->make('Concrete\Core\User\UserInfoFactory')->getByID($uid);
if ($ui !== null) {
$entry->addAuthor(array(
'name' => $ui->getUserDisplayName(),
'uri' => (string) $ui->getUserPublicProfileUrl()
));
}
$thumbnail = $p->getAttribute('thumbnail');
if (is_object($thumbnail)) {
$entry->setSmartNewsThumbnail((string) $thumbnail->getURL());
}
if ($tracking_id = $site->getAttribute('tracking_id'))
$entry->setSmartNewsAnalytics(array(
'trackingid' => $tracking_id,
'uri' => $p->getCollectionLink(true)
));
}
$a = \Concrete\Core\Area\Area::get($p, 'Main');
$blocks = $a->getAreaBlocksArray();
$request->setCurrentPage($p);
ob_start();
foreach($blocks as $b) {
$bv = new \Concrete\Core\Block\View\BlockView($b);
$bv->render('view');
}
$content = ob_get_contents();
ob_end_clean();
if (!$content) {
$content = t('No Content.');
}
$entry->setContent($content);
$writer->addEntry($entry);
}
return \Concrete\Core\Http\Response::create(
$writer->export('rss'),
200,
array('Content-Type' => 'text/xml')
);
}
}
<?php
// application/src/Feed/Writer/Extension/SmartNews/Entry.php
namespace Application\Src\Feed\Writer\Extension\SmartNews;
use Zend\Feed\Exception\InvalidArgumentException;
use Zend\Feed\Uri;
use Zend\Feed\Writer\Exception\BadMethodCallException;
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 = array();
/**
* 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 thumbnail of this entry
*
* @param string $url
* @throws InvalidArgumentException
* @return $this
*/
public function setSmartNewsThumbnail($url)
{
if (empty($url) || !is_string($url) || !Uri::factory($url)->isValid()) {
throw new InvalidArgumentException('Invalid parameter: parameter must be a non-empty string and valid URI/IRI');
}
$this->data['thumbnail'] = $url;
return $this;
}
/**
* Set the analytics code
*
* @param array $data
* @throws InvalidArgumentException
* @return $this
*/
public function setSmartNewsAnalytics(array $data)
{
if (!array_key_exists('trackingid', $data)
|| empty($data['trackingid'])
|| !is_string($data['trackingid'])
) {
throw new InvalidArgumentException('Invalid parameter: Tracking ID must be a non-empty string');
}
if (!array_key_exists('uri', $data)
|| empty($data['uri'])
|| !is_string($data['uri'])
|| !Uri::factory($data['uri'])->isValid()
) {
throw new InvalidArgumentException('Invalid parameter: path must be a non-empty string and valid URI');
}
$this->data['analytics'] = $data;
return $this;
}
/**
* Overloading to SmartNews specific setters
*
* @param string $method
* @param array $params
* @throws BadMethodCallException
* @return mixed
*/
public function __call($method, array $params)
{
$point = lcfirst(substr($method, 12));
if (!method_exists($this, 'setSmartNews' . ucfirst($point))
&& !method_exists($this, 'addSmartNews' . ucfirst($point))
) {
throw new BadMethodCallException(
'invalid method: ' . $method
);
}
if (!array_key_exists($point, $this->data)
|| empty($this->data[$point])
) {
return null;
}
return $this->data[$point];
}
}
<?php
// application/src/Feed/Writer/Extension/SmartNews/Renderer/Entry.php
namespace Application\Src\Feed\Writer\Extension\SmartNews\Renderer;
use Zend\Feed\Uri;
use Zend\Feed\Writer\Extension\AbstractRenderer;
class Entry extends 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;
/**
* @inheritDoc
*/
public function render()
{
$this->_setThumbnail($this->dom, $this->base);
$this->_setAnalytics($this->dom, $this->base);
if ($this->called) {
$this->_appendNamespaces();
}
}
protected function _setThumbnail(\DOMDocument $dom, \DOMElement $root)
{
$url = $this->getDataContainer()->getSmartNewsThumbnail();
if (!$url) {
return;
}
$thumbnail = $dom->createElement('media:thumbnail');
$thumbnail->setAttribute('url', $url);
$root->appendChild($thumbnail);
$this->called = true;
}
protected function _setAnalytics(\DOMDocument $dom, \DOMElement $root)
{
$data = $this->getDataContainer()->getSmartNewsAnalytics();
if (!is_array($data)) {
return;
}
$uri = Uri::factory($data['uri']);
$code = sprintf("<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', '%s', '%s');
ga('require', 'displayfeatures');
ga('set', 'referrer', 'http://www.smartnews.com/');
ga('send', 'pageview', '%s');
</script>", $data['trackingid'], $uri->getHost(), $uri->getPath());
$analytics = $dom->createElement('snf:analytics');
$root->appendChild($analytics);
$cdata = $dom->createCDATASection($code);
$analytics->appendChild($cdata);
$this->called = true;
}
/**
* @inheritDoc
*/
protected function _appendNamespaces()
{
$this->getRootElement()->setAttribute('xmlns:media',
'http://search.yahoo.com/mrss/');
$this->getRootElement()->setAttribute('xmlns:snf',
'http://www.smartnews.be/snf');
}
}
<?php
// application/src/Feed/Writer/Extension/SmartNews/Renderer/Feed.php
namespace Application\Src\Feed\Writer\Extension\SmartNews\Renderer;
use Zend\Feed\Writer\Extension\AbstractRenderer;
class Feed extends 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;
/**
* @inheritDoc
*/
public function render()
{
$this->_setFeedLogo($this->dom, $this->base);
if ($this->called) {
$this->_appendNamespaces();
}
}
protected function _setFeedLogo(\DOMDocument $dom, \DOMElement $root)
{
$image = $this->getDataContainer()->getImage();
if (!$image) {
return;
}
$logo = $dom->createElement('snf:logo');
$url = $dom->createElement('url');
$text = $dom->createTextNode($image['uri']);
$url->appendChild($text);
$logo->appendChild($url);
$root->appendChild($logo);
$this->called = true;
}
/**
* @inheritDoc
*/
protected function _appendNamespaces()
{
$this->getRootElement()->setAttribute('xmlns:snf',
'http://www.smartnews.be/snf');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment