Skip to content

Commit

Permalink
Merge pull request #186 from alexdebril/issue/refactoring
Browse files Browse the repository at this point in the history
4.3 release candidate
  • Loading branch information
alexdebril authored Aug 9, 2019
2 parents 1ce655e + b19d837 commit 5c0ef9b
Show file tree
Hide file tree
Showing 19 changed files with 1,023 additions and 706 deletions.
167 changes: 31 additions & 136 deletions Controller/StreamController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,169 +2,64 @@

namespace Debril\RssAtomBundle\Controller;

use FeedIo\FeedIo;
use FeedIo\FeedInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Debril\RssAtomBundle\Provider\FeedProviderInterface;
use Debril\RssAtomBundle\Request\ModifiedSince;
use Debril\RssAtomBundle\Provider\FeedContentProviderInterface;
use Debril\RssAtomBundle\Exception\FeedException\FeedNotFoundException;
use Debril\RssAtomBundle\Response\FeedBuilder;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
* Class StreamController.
*/
class StreamController extends AbstractController
class StreamController
{

/**
* @var \DateTime
* @var FeedBuilder
*/
protected $since;
private $feedBuilder;

/**
* @param Request $request
* @param FeedContentProviderInterface $provider
* @param FeedIo $feedIo
* @return Response
* @throws \Exception
* @var ModifiedSince
*/
public function indexAction(Request $request, FeedContentProviderInterface $provider, FeedIo $feedIo) : Response
{
$options = $request->attributes->get('_route_params');
$this->setModifiedSince($request);
$options['Since'] = $this->getModifiedSince();

return $this->createStreamResponse(
$options,
$request->get('format', 'rss'),
$provider,
$feedIo
);
}
private $modifiedSince;

/**
* Extract the 'If-Modified-Since' value from the headers.
*
* @return \DateTime
* @param FeedBuilder $feedBuilder
* @param ModifiedSince $modifiedSince
*/
protected function getModifiedSince() : \DateTime
public function __construct(FeedBuilder $feedBuilder, ModifiedSince $modifiedSince)
{
if (is_null($this->since)) {
$this->since = new \DateTime('@0');
}

return $this->since;
$this->feedBuilder = $feedBuilder;
$this->modifiedSince = $modifiedSince;
}

/**
* @param Request $request
*
* @return $this
*/
protected function setModifiedSince(Request $request) : self
{
$this->since = new \DateTime();
if ($request->headers->has('If-Modified-Since')) {
$string = $request->headers->get('If-Modified-Since');
$this->since = \DateTime::createFromFormat(\DateTime::RSS, $string);
} else {
$this->since->setTimestamp(1);
}

return $this;
}

/**
* Generate the HTTP response
* 200 : a full body containing the stream
* 304 : Not modified.
*
* @param array $options
* @param $format
* @param FeedContentProviderInterface $provider
* @param FeedIo $feedIo
*
* @param FeedProviderInterface $provider
* @param LoggerInterface $logger
* @return Response
*
* @throws \Exception
*/
protected function createStreamResponse(array $options, string $format, FeedContentProviderInterface $provider, FeedIo $feedIo) : Response
{
$content = $this->getContent($options, $provider);

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

} else {
$response = new Response();
$response->setNotModified();
}

return $response;
}

/**
* @param Response $response
* @param FeedInterface $feed
* @param string $format
* @return $this
*/
protected function setFeedHeaders(Response $response, FeedInterface $feed, string $format) : self
{
$contentType =
'json' == $format ?
$this->getParameter('debril_rss_atom.content_type_json') :
$this->getParameter('debril_rss_atom.content_type_xml')
;
$response->headers->set('Content-Type', $contentType);
if (! $this->isPrivate() ) {
$response->setPublic();
}

$response->setMaxAge(3600);
$response->setLastModified($feed->getLastModified());

return $this;
}

/**
* Get the Stream's content using a FeedContentProviderInterface
* The FeedContentProviderInterface instance is provided as a service
* default : debril.provider.service.
*
* @param array $options
* @param FeedContentProviderInterface $provider
*
* @return FeedInterface
*
* @throws \Exception
*/
protected function getContent(array $options, FeedContentProviderInterface $provider) : FeedInterface
public function indexAction(Request $request, FeedProviderInterface $provider, LoggerInterface $logger) : Response
{
try {
return $provider->getFeedContent($options);
if ($provider instanceof FeedContentProviderInterface) {
$logger->info('The \\Debril\\RssAtomBundle\\Provider\\FeedContentProviderInterface is deprecated since rss-atom-bundle 4.3, use FeedProviderInterface instead');
$options = $request->attributes->get('_route_params');
$options['Since'] = $this->modifiedSince->getValue();
$feed = $provider->getFeedContent($options);
} else {
$feed = $provider->getFeed($request);
}

return $this->feedBuilder->getResponse($request->get('format', 'rss'), $feed);
} catch (FeedNotFoundException $e) {
throw $this->createNotFoundException('feed not found');
throw new NotFoundHttpException('feed not found');
}
}

/**
* Returns true if the controller must ignore the last modified date.
*
* @return bool
*/
protected function mustForceRefresh() : bool
{
return $this->getParameter('debril_rss_atom.force_refresh');
}

/**
* @return boolean true if the feed must be private
*/
protected function isPrivate() : bool
{
return $this->getParameter('debril_rss_atom.private_feeds');
}

}
2 changes: 1 addition & 1 deletion DependencyInjection/DebrilRssAtomExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public function load(array $configs, ContainerBuilder $container) : void
$loader->load('services.yml');

$this->setDateFormats($container, $config);
$container->setParameter('debril_rss_atom.private_feeds', $config['private']);
$container->setParameter('debril_rss_atom.public_feeds', !$config['private']);
$container->setParameter('debril_rss_atom.force_refresh', $config['force_refresh']);
$container->setParameter('debril_rss_atom.content_type_json', $config['content_type_json']);
$container->setParameter('debril_rss_atom.content_type_xml', $config['content_type_xml']);
Expand Down
18 changes: 17 additions & 1 deletion Provider/DoctrineFeedContentProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
use FeedIo\FeedInterface;
use Doctrine\Bundle\DoctrineBundle\Registry;
use Debril\RssAtomBundle\Exception\FeedException\FeedNotFoundException;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
* @deprecated since 4.3, will be dropped in 5.0
* @codeCoverageIgnore
*/
class DoctrineFeedContentProvider implements FeedContentProviderInterface
Expand All @@ -30,10 +33,13 @@ class DoctrineFeedContentProvider implements FeedContentProviderInterface
protected $repositoryName;

/**
* DoctrineFeedContentProvider constructor.
* @param Registry $doctrine
* @param LoggerInterface $logger
*/
public function __construct(Registry $doctrine)
public function __construct(Registry $doctrine, LoggerInterface $logger)
{
$logger->info('The \\Debril\\RssAtomBundle\\Provider\\DoctrineFeedContentProvider is deprecated since rss-atom-bundle 4.3, will be removed in 5.0');
$this->doctrine = $doctrine;
}

Expand Down Expand Up @@ -107,4 +113,14 @@ public function getIdFromOptions(array $options) : string

return $options['id'];
}

/**
* @param Request $request
* @return FeedInterface
* @throws FeedNotFoundException
*/
public function getFeed(Request $request): FeedInterface
{
return $request->get('id');
}
}
3 changes: 2 additions & 1 deletion Provider/FeedContentProviderInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
use FeedIo\FeedInterface;

/**
* @deprecated since 4.3 you MUST use `FeedProviderInterface` instead
* Interface FeedContentProviderInterface.
*/
interface FeedContentProviderInterface
interface FeedContentProviderInterface extends FeedProviderInterface
{
/**
* @param array $options
Expand Down
19 changes: 19 additions & 0 deletions Provider/FeedProviderInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php declare(strict_types=1);

namespace Debril\RssAtomBundle\Provider;

use Debril\RssAtomBundle\Exception\FeedException\FeedNotFoundException;
use FeedIo\FeedInterface;
use Symfony\Component\HttpFoundation\Request;

interface FeedProviderInterface
{

/**
* @param Request $request
* @return FeedInterface
* @throws FeedNotFoundException
*/
public function getFeed(Request $request): FeedInterface;

}
34 changes: 28 additions & 6 deletions Provider/MockProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,52 @@
use FeedIo\Feed\Item;
use Debril\RssAtomBundle\Exception\FeedException\FeedNotFoundException;
use FeedIo\FeedInterface;
use Symfony\Component\HttpFoundation\Request;

/**
* Class MockProvider.
*/
class MockProvider implements FeedContentProviderInterface
{

/**
* @param Request $request
* @return FeedInterface
* @throws FeedNotFoundException
*/
public function getFeed(Request $request): FeedInterface
{
$id = $request->get('id');

return $this->buildFeed($id);
}

/**
* @param array $options
*
* @return FeedInterface
*
* @throws FeedNotFoundException
*/
public function getFeedContent(array $options) : FeedInterface
{
$feed = new Feed();
$id = array_key_exists('id', $options) ? $options['id'] : '';

$id = array_key_exists('id', $options) ? $options['id'] : null;
return $this->buildFeed($id);
}

/**
* @param string $id
* @return FeedInterface
* @throws FeedNotFoundException
*/
protected function buildFeed(string $id): FeedInterface
{
if ($id === 'not-found') {
throw new FeedNotFoundException();
}

$feed->setPublicId($id);
$feed = new Feed();

$feed->setPublicId($id);
$feed->setTitle('thank you for using RssAtomBundle');
$feed->setDescription('this is the mock FeedContent');
$feed->setLink('https://raw.github.com/alexdebril/rss-atom-bundle/');
Expand All @@ -50,7 +71,8 @@ public function getFeedContent(array $options) : FeedInterface

/**
* @param Feed $feed
* @return Feed
* @return FeedInterface
* @throws \Exception
*/
protected function addItem(Feed $feed) : FeedInterface
{
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,12 +189,12 @@ The request will be handled by `StreamController`, according to the following st

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.
- write a class that implements `FeedProviderInterface`. 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 :
Your class just needs to implement the `Debril\RssAtomBundle\Provider\FeedProviderInterface` interface, for instance :

```php
<?php
Expand All @@ -206,14 +206,14 @@ use FeedIo\FeedInterface;
use FeedIo\Feed\Item;
use Debril\RssAtomBundle\Provider\FeedContentProviderInterface;

class Provider implements FeedContentProviderInterface
class Provider implements FeedProviderInterface
{
/**
* @param array $options
* @return \FeedIo\FeedInterface
* @throws \Debril\RssAtomBundle\Exception\FeedNotFoundException
*/
public function getFeedContent(array $options) : FeedInterface
public function getFeed(Request $request) : FeedInterface
{
// build the feed the way you want
$feed = new Feed();
Expand Down Expand Up @@ -241,7 +241,7 @@ class Provider implements FeedContentProviderInterface
}
```

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`.
StreamController 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`.

You can also start from this class to save some time : [App\Feed\Provider.php](/Resources/sample/Provider.php)

Expand Down
Loading

0 comments on commit 5c0ef9b

Please sign in to comment.