{"id":13519437,"url":"https://github.com/alexdebril/rss-atom-bundle","last_synced_at":"2025-09-08T12:08:41.319Z","repository":{"id":6676239,"uuid":"7921121","full_name":"alexdebril/rss-atom-bundle","owner":"alexdebril","description":"RSS and Atom Bundle for Symfony","archived":false,"fork":false,"pushed_at":"2024-01-30T13:37:49.000Z","size":1131,"stargazers_count":138,"open_issues_count":4,"forks_count":49,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-31T12:39:25.347Z","etag":null,"topics":["atom","atom-feed","feed","feed-io","feed-reading","jsonfeed","rss","rss-atom-bundle","symfony"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alexdebril.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-01-30T18:42:39.000Z","updated_at":"2024-12-17T12:51:24.000Z","dependencies_parsed_at":"2024-06-18T12:24:53.795Z","dependency_job_id":null,"html_url":"https://github.com/alexdebril/rss-atom-bundle","commit_stats":{"total_commits":551,"total_committers":41,"mean_commits":"13.439024390243903","dds":"0.22867513611615242","last_synced_commit":"29e624c428d4284726e5da5e0d245cbc93d1f17a"},"previous_names":[],"tags_count":75,"template":false,"template_full_name":null,"purl":"pkg:github/alexdebril/rss-atom-bundle","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexdebril%2Frss-atom-bundle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexdebril%2Frss-atom-bundle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexdebril%2Frss-atom-bundle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexdebril%2Frss-atom-bundle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alexdebril","download_url":"https://codeload.github.com/alexdebril/rss-atom-bundle/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexdebril%2Frss-atom-bundle/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274181741,"owners_count":25236552,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-08T02:00:09.813Z","response_time":121,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["atom","atom-feed","feed","feed-io","feed-reading","jsonfeed","rss","rss-atom-bundle","symfony"],"created_at":"2024-08-01T05:01:59.081Z","updated_at":"2025-09-08T12:08:41.295Z","avatar_url":"https://github.com/alexdebril.png","language":"PHP","funding_links":[],"categories":["PHP","Miscellaneous"],"sub_categories":[],"readme":"# RssAtomBundle - Read and Build Atom/RSS feeds\n\n[![SensioLabsInsight](https://insight.sensiolabs.com/projects/9e0b1301-d7a5-49fd-916b-49da544389ac/big.png)](https://insight.sensiolabs.com/projects/9e0b1301-d7a5-49fd-916b-49da544389ac)\n[![Latest Stable Version](https://poser.pugx.org/debril/rss-atom-bundle/v/stable.png)](https://packagist.org/packages/debril/rss-atom-bundle)\n[![Download Count](https://poser.pugx.org/debril/rss-atom-bundle/d/total)](https://packagist.org/packages/debril/rss-atom-bundle)\n[![Build Status](https://secure.travis-ci.org/alexdebril/rss-atom-bundle.png?branch=master)](http://travis-ci.org/alexdebril/rss-atom-bundle)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/alexdebril/rss-atom-bundle/badges/quality-score.png?s=6e4cc3b9368ddbf14b1066114b6af6d9011894d9)](https://scrutinizer-ci.com/g/alexdebril/rss-atom-bundle/)\n[![Code Coverage](https://scrutinizer-ci.com/g/alexdebril/rss-atom-bundle/badges/coverage.png?s=5bbd191f3b9364b8c31d8f1881f4c1fd06829fc3)](https://scrutinizer-ci.com/g/alexdebril/rss-atom-bundle/)\n\nRssAtomBundle is a Bundle for Symfony made to easily access and deliver JSON / RSS / Atom feeds. It is built on top of [feed-io](https://github.com/alexdebril/feed-io) and features:\n\n- Detection of the feed format (JSON / RSS / Atom)\n- enclosures support\n- A generic StreamController built to write all your feeds. This controller is able to send a 304 HTTP Code if the feed didn't change since the last visit\n- HTTP Headers support when reading feeds in order to save network traffic\n- Content filtering to fetch only the newest items\n- multiple feeds writing\n- Ability to use doctrine as a data source\n- PSR compliant logging\n- DateTime detection and conversion\n- Guzzle Client integration\n\nKeep informed about new releases and incoming features : http://debril.org/category/rss-atom-bundle\n\nYou can try rss-atom-bundle through its [Demo](https://rss-atom-demo.herokuapp.com/).\n\n## Installation\n\n### Dependencies\n\nAs a Symfony Bundle, RssAtomBundle must be installed using Composer. If you do not know Composer, please refer to its website: http://getcomposer.org/\n\n### Your application uses Symfony 3.3 or later\n\nActivate Symfony's [contrib recipes](https://github.com/symfony/recipes-contrib) and use Composer to require the bundle :\n\n```shell\ncomposer config extra.symfony.allow-contrib true\ncomposer require debril/rss-atom-bundle\n```\n\nThat's it. To check the installation, you can start your application and hit http://localhost:8000/rss in your browser. You should see a mock RSS stream.\n\n### If your application uses Symfony \u003c 3.3\n\nInstall the bundle using Composer :\n\n```shell\ncomposer require debril/rss-atom-bundle\n```\n\nAdd the bundle's routing configuration in app/config/routing.yml :\n\n```yaml\nrssatom:\n    resource: \"@DebrilRssAtomBundle/Resources/config/routing.yml\"\n\n```\n\nEdit your app/AppKernel.php to register the bundle in the registerBundles() method as above:\n\n```php\nclass AppKernel extends Kernel\n{\n\n    public function registerBundles()\n    {\n        $bundles = array(\n            new Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle(),\n            // ...\n            // register the bundle here\n            new Debril\\RssAtomBundle\\DebrilRssAtomBundle(),\n```\n\n## Usage\n\nrss-atom-bundle is designed to read feeds across the internet and to publish your own using [feed-io](https://github.com/alexdebril/feed-io)\nfeed-io provides two interfaces, each one being dedicated to feed's consuming and publishing :\n\n- [FeedInterface](https://github.com/alexdebril/feed-io/blob/master/src/FeedIo/FeedInterface.php) to handle the feed\n- [ItemInterface](https://github.com/alexdebril/feed-io/blob/master/src/FeedIo/Feed/ItemInterface.php) to handle feed's items\n\n### Getting a FeedIo instance\n\nYou can fetch a `FeedIo\\FeedIo` instance through dependency injection or the service container.\n\n#### Dependency injection (highly recommended)\n\n```php\n\nnamespace App\\Feed;\n\nclass Consumer\n{\n\n    /**\n     * @type \\FeedIo\\FeedIo\n     */\n    private $feedIo;\n\n    public function __construct(FeedIo $feedIo)\n    {\n        $this-\u003efeedIo = $feedIo;\n    }\n}\n\n```\n\n#### Service Container\n\nWherever you have access to the service container :\n\n```php\n\u003c?php\n    // get feedio\n    $feedIo = $this-\u003econtainer-\u003eget('feedio');\n```\n\n### Feed Reading\n\nTo read a feed you need to use the `feedio` service which provides two methods for that : `read()` and `readSince()`. This service is based upon [FeedIo](https://github.com/alexdebril/feed-io/blob/master/src/FeedIo/FeedIo.php).\n\n#### using read()\n\n`read()` is designed to give a brand new Feed instance or any object of your own, as long as it implements the [FeedInterface](https://github.com/alexdebril/feed-io/blob/master/src/FeedIo/FeedInterface.php) interface. It takes three arguments :\n\n- `$url` : URL of the RSS/Atom feed you want to read (eg: http://php.net/feed.atom)\n- `$feed` (optional) : a FeedInterface instance. The default is a new `\\FeedIo\\Feed` instance\n- `$modifiedSince` (optional) : the last time you read this feed. This is useful to fetch only the articles which were published after your last hit.\n\nWith a `\\FeedIo\\FeedIo` instance called `$feedIo` :\n```php\n\u003c?php\n    // this date is used to fetch only the latest items\n    $modifiedSince = new \\DateTime($date);\n\n    // the feed you want to read\n    $url = 'http://host.tld/feed';\n\n    // now fetch its (fresh) content\n    $feed = $feedIo-\u003eread($url, new \\Acme\\Entity\\Feed, $modifiedSince)-\u003egetFeed();\n\n    foreach ( $feed as $item ) {\n        echo \"item title : {$item-\u003egetTitle()} \\n \";\n        // getMedias() returns enclosures if any\n        $medias = $item-\u003egetMedias();\n    }\n\n?\u003e\n```\n`read()` fetches the feed hosted at `$url` and removes items prior to `$modifiedSince`. If it is the first time you read this feed, then you must specify a date far enough in the past to keep all the items. This method does not loop until the `$modifiedSince` is reached, it justs performs one hit and filters the response to keep only the fresh articles.\n\n#### using readSince()\n\n`readSince()` helps you get a `\\FeedIo\\Feed` without creating its instance :\n\n ```php\n \u003c?php\n     // get feedio\n     $feedIo = $this-\u003econtainer-\u003eget('feedio');\n\n     // this date is used to fetch only the latest items\n     $modifiedSince = new \\DateTime($date);\n\n     // the feed you want to read\n     $url = 'http://host.tld/feed';\n\n     // now fetch its (fresh) content\n     $feed = $feedIo-\u003ereadSince($url, $modifiedSince)-\u003egetFeed();\n ?\u003e\n ```\n\n### Providing feeds\n\nRssAtomBundle offers the ability to provide JSON/RSS/Atom feeds. The route will match the following pattern : /{format}/{contentId}\n\n- {format} must be \"rss\" or \"atom\" (or whatever you want if you add the good routing rule in routing.yml)\n- {contentId} is an optional argument. Use it you have several feeds\n\nThe request will be handled by `StreamController`, according to the following steps :\n\n- 1 : grabs the ModifiedSince header if it exists\n- 2 : creates an `Options` instance holding the request's parameters (contentId if it exists)\n- 3 : gets the provider defined in services.yml and calls the `getFeedContent(Options $options)` method\n- 4 : compare the feed's LastModified property with the ModifiedSince header\n- 5 : if LastModified is prior or equal to ModifiedSince then the response contains only a \"NotModified\" header and the 304 code. Otherwise, the stream is built and sent to the client\n\n#### Defining you own provider\n\nYou must give to RssAtomBundle the content you want it to display in the feed. For that, two steps :\n\n- write a class that implements `FeedProviderInterface`. This class that we call a 'provider' will be in charge of building the feed.\n- configure the dependency injection to make RssAtomBundle use it\n\n##### FeedContentProviderInterface implementation\n\nYour class just needs to implement the `Debril\\RssAtomBundle\\Provider\\FeedProviderInterface` interface, for instance :\n\n```php\n\u003c?php\n# src/Feed/Provider.php\nnamespace App\\Feed;\n\nuse FeedIo\\Feed;\nuse FeedIo\\FeedInterface;\nuse FeedIo\\Feed\\Item;\nuse Debril\\RssAtomBundle\\Provider\\FeedContentProviderInterface;\n\nclass Provider implements FeedProviderInterface\n{\n    /**\n     * @param array $options\n     * @return \\FeedIo\\FeedInterface\n     * @throws \\Debril\\RssAtomBundle\\Exception\\FeedNotFoundException\n     */\n    public function getFeed(Request $request) : FeedInterface\n    {\n        // build the feed the way you want\n        $feed = new Feed();\n        $feed-\u003esetTitle('your title');\n        foreach($this-\u003egetItems() as $item ) {\n            $feed-\u003eadd($item);\n        }\n\n        return $feed;\n    }\n\n    protected function getItems()\n    {\n        foreach($this-\u003efetchFromStorage() as $storedItem) {\n            $item = new Item;\n            $item-\u003esetTitle($storedItem-\u003egetTitle());\n            // ...\n            yield $item;\n        }\n    }\n    protected function fetchFromStorage()\n    {\n        // query the database to fetch items\n    }\n}\n```\n\nStreamController expects the getFeed()'s return value to be a `FeedIo\\FeedInterface` instance. It can be a `FeedIo\\Feed` or a class of your own and if so, your class MUST implement `\\FeedIo\\FeedInterface`.\n\nYou can also start from this class to save some time : [App\\Feed\\Provider.php](/Resources/sample/Provider.php)\n\n```php\n\u003c?php\ninterface FeedInterface extends \\Iterator, NodeInterface\n{\n    /**\n     * This method MUST return the feed's full URL\n     * @return string\n     */\n    public function getUrl();\n\n    /**\n     * @param string $url\n     * @return FeedInterface\n     */\n    public function setUrl($url);\n\n    // Full source can be read in the repository .......\n?\u003e\n```\n##### configuration\n\nNow, you need to configure the `debril.rss_atom.provider` service with the provider's class in your project's services.yml :\n\n```yml\n# config/services.yaml\nparameters:\n  debril.rss_atom.provider.class: 'App\\Feed\\Provider'\n```\n\nOr, if you need to build it with arguments, you can override `debril.rss_atom.provider`'s declaration :\n\n```yml\n# config/services.yaml\nservices:\n  debril.rss_atom.provider:\n    class: App\\Feed\\Provider\n    arguments: [\"@logger\", \"@doctrine\"]\n```\n\nThat's it. Go to http://localhost:8000/atom, it should display your feed.\n\n##### Make the StreamController answer with a 404\n\nIf the reclaimed feed does not exist, you just need to throw a FeedNotFoundException to make the StreamController answer with a 404 error. Otherwise, `getFeedContent(Options $options)` must return a `\\FeedIo\\FeedInterface` instance. Then, the controller properly turns the object into a XML stream.\n\nMore information on the FeedContentProviderInterface interface and how to interface rss-atom-bundle directly with doctrine can be found in the [Providing Feeds section](https://github.com/alexdebril/rss-atom-bundle/wiki/Providing-feeds)\n\n\n## Useful Tips\n\n### Skipping 304 HTTP Code\n\nThe HTTP cache handling can be annoying during development process, you can skip it through configuration in your app/config/config.yml file :\n\n```yml\n# config/packages/rss_atom.yaml\ndebril_rss_atom:\n    force_refresh: true\n```\n\nThis way, the `StreamController` will always display your feed's content and return a 200 HTTP code.\n\n### Private feeds\n\nYou may have private feeds, user-specific or behind some authentication.  \nIn that case, you don't want to `Cache-Control: public` header to be added, not to have your feed cached by a reverse-proxy (such as Symfony AppCache or Varnish).  \nYou can do so by setting `private` parameter to `true` in config:\n\n```yml\n# config/packages/rss_atom.yaml\ndebril_rss_atom:\n    private: true\n```\n\n### Adding non-standard date formats\n\nSome feeds use date formats which are not compliant with the specifications. You can fix this by adding the format in your configuration\n\n```yml\n# config/packages/rss_atom.yaml\ndebril_rss_atom:\n    date_formats:\n      - 'Y/M/d'\n```\n\n### Using custom Content Type header for feed generation\n\nIf you need to customize the Content-Type header of your feed you can specify the value in your configuration\n\n```yml\n# config/packages/rss_atom.yaml\ndebril_rss_atom:\n    content_type_json: application/json\n    content_type_xml: application/xhtml+xml\n```\n\n### Going back to feed-io 3.0\n\nStarting from version 4.1 rss-atom-bundle comes with feed-io 4 if your application depends on PHP 7.1+. If you need to use feed-io 3 instead for some reason, you can do it in `composer.json` :\n\n```yml\n    \"debril/rss-atom-bundle\": \"^4.1\",\n    \"debril/feed-io\": \"~3.0\",\n```\n\n### Override tip\nIt could happen that according to the order of the bundles registered in `AppKernel`, this override procedures do not work properly. This happens when a bundle is registered before `rss-atom-bundle`.\nIn this case, you should use the Symfony `CompilerPass` as reported in the [documentation](http://symfony.com/doc/current/bundles/override.html#services-configuration).\n\n`Vendor/Bundle/VendorBundle.php`:\n```php\nuse Vendor\\Bundle\\DependencyInjection\\Compiler\\OverrideRssAtomBundleProviderCompilerPass;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\HttpKernel\\Bundle\\Bundle;\n\nclass VendorBundle extends Bundle\n{\n    public function build(ContainerBuilder $container)\n    {\n        parent::build($container);\n        $container-\u003eaddCompilerPass(new OverrideRssAtomBundleProviderCompilerPass());\n    }\n}\n```\n\nand `Vendor/Bundle/DependencyInjection/Compiler/OverrideRssAtomBundleProviderCompilerPass.php`:\n```php\nuse Vendor\\Bundle\\Provider\\FeedProvider;\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Reference;\n\nclass OverrideRssAtomBundleProviderCompilerPass implements CompilerPassInterface\n{\n    public function process(ContainerBuilder $container)\n    {\n        $definition = $container-\u003egetDefinition('debril.rss_atom.provider');\n        $definition-\u003esetClass(FeedProvider::class);\n        $definition-\u003eaddArgument(new Reference('my.service1'));\n        $definition-\u003eaddArgument(new Reference('my.service2'));\n    }\n}\n```\n\nYou can follow either `services.xml` or `CompilerPass` but with services, you have to pay attention to bundles registration order.\n\n\n## Fetching the repository\n\nDo this if you want to contribute (and you're welcome to do so):\n\n    git clone https://github.com/alexdebril/rss-atom-bundle.git\n\n    composer.phar install --dev\n\n## Unit Testing\n\nYou can run the unit test suites using the following command in the Bundle's source director:\n\n    bin/phpunit\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexdebril%2Frss-atom-bundle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falexdebril%2Frss-atom-bundle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexdebril%2Frss-atom-bundle/lists"}