Skip to content

Commit

Permalink
Merge pull request #162 from alexdebril/release/4.1
Browse files Browse the repository at this point in the history
Release/4.1
  • Loading branch information
alexdebril authored Jan 10, 2018
2 parents 6617762 + 8b36cbf commit 95adebe
Show file tree
Hide file tree
Showing 10 changed files with 666 additions and 752 deletions.
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ matrix:

before_script:
- composer config --global repo.packagist composer https://packagist.org
- composer install
- composer update

script : $PHPUNIT_BIN -c $PHPUNIT_CONFIG $PHPUNIT_FLAGS

Expand All @@ -34,4 +34,3 @@ after_script:
php ocular.phar code-coverage:upload --format=php-clover coverage.xml
echo 'done'
fi
41 changes: 14 additions & 27 deletions Controller/StreamController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Debril\RssAtomBundle\Controller;

use FeedIo\FeedIo;
use FeedIo\FeedInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
Expand All @@ -14,10 +15,6 @@
*/
class StreamController extends Controller
{
/**
* default provider.
*/
const DEFAULT_SOURCE = 'debril.provider.default';

/**
* @var \DateTime
Expand All @@ -26,10 +23,12 @@ class StreamController extends Controller

/**
* @param Request $request
*
* @param FeedContentProviderInterface $provider
* @param FeedIo $feedIo
* @return Response
* @throws \Exception
*/
public function indexAction(Request $request)
public function indexAction(Request $request, FeedContentProviderInterface $provider, FeedIo $feedIo)
{
$options = $request->attributes->get('_route_params');
$this->setModifiedSince($request);
Expand All @@ -38,7 +37,8 @@ public function indexAction(Request $request)
return $this->createStreamResponse(
$options,
$request->get('format', 'rss'),
$request->get('source', self::DEFAULT_SOURCE)
$provider,
$feedIo
);
}

Expand Down Expand Up @@ -81,18 +81,19 @@ protected function setModifiedSince(Request $request)
*
* @param array $options
* @param $format
* @param string $source
* @param FeedContentProviderInterface $provider
* @param FeedIo $feedIo
*
* @return Response
*
* @throws \Exception
*/
protected function createStreamResponse(array $options, $format, $source = self::DEFAULT_SOURCE)
protected function createStreamResponse(array $options, $format, FeedContentProviderInterface $provider, FeedIo $feedIo)
{
$content = $this->getContent($options, $source);
$content = $this->getContent($options, $provider);

if ($this->mustForceRefresh() || $content->getLastModified() > $this->getModifiedSince()) {
$response = new Response($this->getFeedIo()->format($content, $format));
$response = new Response($feedIo->format($content, $format));
$this->setFeedHeaders($response, $content, $format);

} else {
Expand Down Expand Up @@ -129,20 +130,14 @@ protected function setFeedHeaders(Response $response, FeedInterface $feed, $form
* default : debril.provider.service.
*
* @param array $options
* @param string $source
* @param FeedContentProviderInterface $provider
*
* @return FeedInterface
*
* @throws \Exception
*/
protected function getContent(array $options, $source)
protected function getContent(array $options, $provider)
{
$provider = $this->get($source);

if (!$provider instanceof FeedContentProviderInterface) {
throw new \Exception('Provider is not a FeedContentProviderInterface instance');
}

try {
return $provider->getFeedContent($options);
} catch (FeedNotFoundException $e) {
Expand All @@ -168,12 +163,4 @@ protected function isPrivate()
return $this->container->getParameter('debril_rss_atom.private_feeds');
}

/**
* @return \FeedIo\FeedIo
*/
protected function getFeedIo()
{
return $this->container->get('feedio');
}

}
176 changes: 105 additions & 71 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ rssatom:

Edit your app/AppKernel.php to register the bundle in the registerBundles() method as above:


```php
class AppKernel extends Kernel
{
Expand Down Expand Up @@ -153,7 +152,63 @@ The request will be handled by `StreamController`, according to the following st
- 4 : compare the feed's LastModified property with the ModifiedSince header
- 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

StreamController expects the getFeedContent()'s return value to be a FeedInterface instance. It can be a `FeedIo\Feed` or a class you wrote and if so, your class MUST implement `\FeedIo\FeedInterface`.
#### Defining you own provider

You must give to RssAtomBundle the content you want it to display in the feed. For that, two steps :

- write a class that implements `FeedContentProviderInterface`. This class that we call a 'provider' will be in charge of building the feed.
- configure the dependency injection to make RssAtomBundle use it

##### FeedContentProviderInterface implementation

Your class just needs to implement the `Debril\RssAtomBundle\Provider\FeedContentProviderInterface` interface, for instance :

```php
<?php
# src/Feed/Provider.php
namespace App\Feed;

use FeedIo\Feed;
use FeedIo\Feed\Item;
use Debril\RssAtomBundle\Provider\FeedContentProviderInterface;

class Provider implements FeedContentProviderInterface
{

/**
* @param \Symfony\Component\OptionsResolver $params
* @return \FeedIo\FeedInterface
* @throws \Debril\RssAtomBundle\Exception\FeedNotFoundException
*/
public function getFeedContent(Options $options)
{
// build the feed the way you want
$feed = new Feed();
$feed->setTitle('your title');
foreach($this->getItems() as $item ) {
$feed->add($item);
}

return $feed;
}

protected function getItems()
{
foreach($this->fetchFromStorage() as $storedItem) {
$item = new Item;
$item->setTitle($storedItem->getTitle());
// ...
yield $item;
}
}
protected function fetchFromStorage()
{
// query the database to fetch items
}
}
```

StreamController expects the getFeedContent()'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`.

```php
<?php
Expand All @@ -174,83 +229,33 @@ interface FeedInterface extends \Iterator, NodeInterface
// Full source can be read in the repository .......
?>
```
##### configuration

Now, how to plug the `StreamController` with the provider of your choice ? The easiest way is to override the `debril.provider.default` service with your own in services.xml :
Now, you need to configure the `debril.rss_atom.provider` service with the provider's class in your project's services.yml :

```xml
<service id="debril.provider.default" class="Namespace\Of\Your\Class">
<argument type="service" id="doctrine" />
</service>
```yml
# config/services.yaml
parameters:
debril.rss_atom.provider.class: 'App\Feed\Provider'
```
Your class just needs to implement the `FeedContentProviderInterface` interface :
That's it. Go to http://localhost:8000/atom, it should display your feed.
```php
interface FeedContentProviderInterface
{
/**
* @param \Symfony\Component\OptionsResolver $params
* @return \FeedIo\FeedInterface
* @throws \Debril\RssAtomBundle\Exception\FeedNotFoundException
*/
public function getFeedContent(Options $options);
}
```
##### Make the StreamController answer with a 404
If 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.

More 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)

## Override tip
It 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`.
In this case, you should use the Symfony `CompilerPass` as reported in the [documentation](http://symfony.com/doc/current/bundles/override.html#services-configuration).

`Vendor/Bundle/VendorBundle.php`:
```php
use Vendor\Bundle\DependencyInjection\Compiler\OverrideRssAtomBundleProviderCompilerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

class VendorBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new OverrideRssAtomBundleProviderCompilerPass());
}
}
```

and `Vendor/Bundle/DependencyInjection/Compiler/OverrideRssAtomBundleProviderCompilerPass.php`:
```php
use Vendor\Bundle\Provider\FeedProvider;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

class OverrideRssAtomBundleProviderCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$definition = $container->getDefinition('debril.provider.default');
$definition->setClass(FeedProvider::class);
$definition->addArgument(new Reference('my.service1'));
$definition->addArgument(new Reference('my.service2'));
}
}
```

You can follow either `services.xml` or `CompilerPass` but with services, you have to pay attention to bundles registration order.


## Useful Tips

### Skipping 304 HTTP Code


The HTTP cache handling can be annoying during development process, you can skip it through configuration in your app/config/config.yml file :

```yml
# config/packages/rss_atom.yaml
debril_rss_atom:
force_refresh: true
```
Expand All @@ -264,6 +269,7 @@ In that case, you don't want to `Cache-Control: public` header to be added, not
You can do so by setting `private` parameter to `true` in config:

```yml
# config/packages/rss_atom.yaml
debril_rss_atom:
private: true
```
Expand All @@ -273,25 +279,53 @@ debril_rss_atom:
Some feeds use date formats which are not compliant with the specifications. You can fix this by adding the format in your configuration

```yml
# app/config/config.yml
# config/packages/rss_atom.yaml
debril_rss_atom:
date_formats:
- 'Y/M/d'
```

### Choosing your own provider
### Override tip
It 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`.
In this case, you should use the Symfony `CompilerPass` as reported in the [documentation](http://symfony.com/doc/current/bundles/override.html#services-configuration).

`Vendor/Bundle/VendorBundle.php`:
```php
use Vendor\Bundle\DependencyInjection\Compiler\OverrideRssAtomBundleProviderCompilerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class VendorBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new OverrideRssAtomBundleProviderCompilerPass());
}
}
```

Need to keep the existing routes and add one mapped to a different FeedProvider ? add it own in your routing file :
and `Vendor/Bundle/DependencyInjection/Compiler/OverrideRssAtomBundleProviderCompilerPass.php`:
```php
use Vendor\Bundle\Provider\FeedProvider;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
```xml
<route id="your_route_name" pattern="/your/route/{contentId}">
<default key="_controller">DebrilRssAtomBundle:Stream:index</default>
<default key="format">rss</default>
<default key="source">your.provider.service</default>
</route>
class OverrideRssAtomBundleProviderCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$definition = $container->getDefinition('debril.rss_atom.provider');
$definition->setClass(FeedProvider::class);
$definition->addArgument(new Reference('my.service1'));
$definition->addArgument(new Reference('my.service2'));
}
}
```

The `source` parameter must contain a valid service name defined in your application.
You can follow either `services.xml` or `CompilerPass` but with services, you have to pay attention to bundles registration order.


## Fetching the repository

Expand Down
36 changes: 0 additions & 36 deletions Resources/config/routing.xml

This file was deleted.

Loading

0 comments on commit 95adebe

Please sign in to comment.