Use this bundle to generate rss feeds inside your Symfony application.
❤ Many thanks to @eko (Vincent Composieux) for giving me the inspiration to program this bundle. https://github.com/eko/FeedBundle.
composer require markocupic/rss-feed-generator-bundle
Option A: Add this to your config/bundles.php.
<?php
return [
// ...
Markocupic\RssFeedGeneratorBundle\MarkocupicRssFeedGeneratorBundle::class => ['all' => true],
];
Option B: In a Contao ❤ environment register the rss feed generator bundle in the Contao Manager Plugin class of your bundle.
<?php
declare(strict_types=1);
namespace Contao\CoreBundle\ContaoManager;
use Contao\CoreBundle\ContaoCoreBundle;
use Contao\ManagerPlugin\Bundle\BundlePluginInterface;
use Contao\ManagerPlugin\Bundle\Config\BundleConfig;
use Contao\ManagerPlugin\Bundle\Parser\ParserInterface;
use Contao\ManagerPlugin\Config\ConfigPluginInterface;
use Contao\ManagerPlugin\Routing\RoutingPluginInterface;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Config\Loader\LoaderResolverInterface;
use Symfony\Component\HttpKernel\KernelInterface;
use Markocupic\RssFeedGeneratorBundle\MarkocupicRssFeedGeneratorBundle;
use Acme\MyBundle\AcmeMyBundleBundle;
class Plugin implements BundlePluginInterface, RoutingPluginInterface, ConfigPluginInterface
{
/**
* {@inheritdoc}
*/
public function getBundles(ParserInterface $parser)
{
return [
// Register RSS feed generator bundle
BundleConfig::create(MarkocupicRssFeedGeneratorBundle::class),
// register other bundles
BundleConfig::create(AcmeMyBundle::class)
->setLoadAfter(MarkocupicRssFeedGeneratorBundle::class)
->setLoadAfter(ContaoCoreBundle::class)
];
}
Use dependency injection to require the feed factory in your controller.
# config/services.yml
services:
Markocupic\DemoBundle\Controller\Feed\FeedController:
arguments:
- '@Markocupic\RssFeedGeneratorBundle\Feed\FeedFactory'
- '@database_connection'
- '%kernel.project_dir%'
public: true
// Use the feed factory to generate the feed object
$rss = $this->feedFactory->createFeed(\Markocupic\RssFeedGeneratorBundle\Feed\Feed::ENCODING_UTF8);
// Add one or more attributes to the root element
$rss->setRootAttributes([
'xmlns:tourdb' => 'https://acme.com/schema/tourdbrss/1.0',
'xmlns:atom'=>'http://www.w3.org/2005/Atom',
]);
// Add one or more attributes to the channel element
$rss->setChannelAttributes([
'foo' => 'bar',
]);
Use the Item class inside the feed factory method FeedFactory::addChannelField().
The Item::__constructor($elementName, $strValue, $arrOptions, $arrAttributes) takes four arguments:
- (string) element name
- (string) content
- optional: (array) options (at the moment cdata, and filters)
- optional: (array) with attributes
$rss->addChannelField(
new Item('title', 'Demo feed')
);
$rss->addChannelField(
new Item('link', 'https://foobar.ch')
);
Make cdata elements and insert attributes:
// Add CDATA element and an attribute
$rss->addChannelField(
new Item('description', 'Check our news feed and have fun!', ['cdata' => true], ['attrName' => 'Here comes the attribute value'])
);
// filter or replace values
$arrFilter = ['Ferrari' => 'Italia', 'car' => 'country'] ;
$rss->addChannelField(
new Item('description', 'Ferrari is my favourite car!', ['filter' => $arrFilter])
);
// Will result in:
// <description>Italia is my favourite country!</description>
Use FeedFactory::addChannelItemField(), ItemGroup() and Item() to generate channel items.
The ItemGroup::__constructor($elementName, $arrItemObjects, $arrAttributes) takes three arguments:
- (string) element name
- (array) with Item objects
- optional: (array) with attributes
// Retrieve data from database and add items
$results = $this->getEvents($section);
if (null !== $results) {
while (false !== ($arrEvent = $results->fetch())) {
// Use a new instance of ItemGroup to add a collection of items all of the same level.
$rss->addChannelItemField(
new ItemGroup('item', [
new Item('title', $arrEvent['title']),
new Item('link', $arrEvent['link']),
new Item('description', $arrEvent['description'], ['cdata' => true]),
new Item('pubDate', date('r',(int) $arrEvent['tstamp'])),
new Item('author', $arrEvent['author']),
new Item('guid', $arrEvent['uuid']),
new Item('tourdb:startdate', date('Y-m-d', (int) $arrEvent['startDate'])),
new Item('tourdb:enddate', date('Y-m-d', (int) $arrEvent['endDate'])),
])
);
}
}
// Append nested items with ItemGroup.
$rss->addChannelItemField(
new ItemGroup('item', [
new Item('title', 'Title'),
new Item('link', 'https://foo.bar'),
new ItemGroup('nestedItems', [
new Item('subitem', 'Some content'),
new Item('subitem', 'Some content'),
], ['foo'=> 'bar']),
])
);
Result:
<item>
<title>Title</title>
<link>https://foo.bar</link>
<nestedItem foo="bar">
<subitem>Some content</subitem>
<subitem>Some content</subitem>
</nestedItem>
</item>
return $rss->render();
return $rss->render('public/share/myfeed.xml);
<?php
declare(strict_types=1);
namespace Acme\DemoBundle\Controller\Feed;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Query\QueryBuilder;
use Markocupic\RssFeedGeneratorBundle\Feed\FeedFactory;
use Markocupic\RssFeedGeneratorBundle\Item\Item;
use Markocupic\RssFeedGeneratorBundle\Feed\ItemGroup;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class FeedController extends AbstractController
{
/**
* @var FeedFactory
*/
private $feedFactory;
/**
* @var Connection
*/
private $connection;
/**
* @var string
*/
private $projectDir;
/**
* @Route("/_rssfeed", name="rss_feed")
*/
public function printLatestEvents(): Response
{
$rss = $this->feedFactory->createFeed('utf-8');
$rss->addChannelField(
new Item('title', 'Acme news')
);
$rss->addChannelField(
new Item('description', 'Enjoj our news.')
);
$rss->addChannelField(
new Item('link', 'https://acme.com')
);
$rss->addChannelField(
new Item('language', 'de')
);
$rss->addChannelField(
new Item('pubDate', date('r', (time() - 3600)))
);
// Retrieve data from db
$results = $this->getEvents($section);
// Add some channel items
if (null !== $results) {
while (false !== ($arrEvent = $results->fetch())) {
$eventsModel = $calendarEventsModelAdapter->findByPk($arrEvent['id']);
$rss->addChannelItemField(
new ItemGroup('item', [
new Item('title', $arrEvent['title']),
new Item('link', $arrEvent['link']),
new Item('description', $arrEvent['description'], ['cdata' => true]),
new Item('pubDate', date('r', (int) $eventsModel->tstamp)),
])
);
}
}
return $rss->render($this->projectDir.'/public/share/rss.xml');
}
}
The extension will filter by default some characters. Linebreaks will be replaced with a whitespace, etc. Please have a look at the Plugin Configuration.
Overriding these defaults is pretty easy and can be done in config/parameters.yml. Please use regular expressions for the search patterns.
# config/parameters.yml
markocupic_rss_feed_generator:
filter:
'/</': '<'
'/[\n\r]+/': ' '
'/(/': '('
'/)/': ')'
'/\[-\]/': ''
'/\­/': ''
'/\[nbsp\]/': ' '
'/ /': ' '
'/&/': '&'