Skip to content

Commit

Permalink
Issue/390 (#397)
Browse files Browse the repository at this point in the history
* Fiter items through `Result`. Fix #390

* Fix coding style

* remove backslash

* Advertise filtering ability
  • Loading branch information
alexdebril authored May 9, 2022
1 parent f5f06ea commit 9b726b1
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 6 deletions.
45 changes: 39 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- Enclosure support to handle external medias like audio content
- Feed logo support (RSS + Atom)
- PSR compliant logging
- Content filtering to fetch only the newest items
- DateTime detection and conversion
- A generic HTTP ClientInterface
- Guzzle Client integration
Expand Down Expand Up @@ -49,12 +50,6 @@ Let's suppose you installed feed-io using Composer, you can use its command line
./vendor/bin/feedio read http://php.net/feed.atom
```

You can specify the number of items you want to read using the --count option. The instruction below will display the latest item :

```shell
./vendor/bin/feedio read -c 1 http://php.net/feed.atom
```

## reading

feed-io is designed to read feeds across the internet and to publish your own. Its main class is [FeedIo](https://github.com/alexdebril/feed-io/blob/master/src/FeedIo/FeedIo.php) :
Expand All @@ -76,6 +71,44 @@ foreach( $result->getFeed() as $item ) {
}

```

If you need to get only the new items since the last time you've consumed the feed, use the result's `getItemsSince()` method:

```php
// read a feed and specify the `$modifiedSince` limit to fetch only items newer than this date
$result = $feedIo->read($url, $feed, $modifiedSince);

// iterate through new items
foreach( $result->getItemsSince() as $item ) {
echo $item->getTitle();
}

```

You can also mix several filters to exclude items according to your needs:

```php
// read a feed
$result = $feedIo->read($url, $feed, $modifiedSince);

// remove items older than `$modifiedSince`
$since = new FeedIo\Filter\Since($result->getModifiedSince());

// Your own filter
$database = new Acme\Filter\Database();

$chain = new Chain();
$chain
->add($since)
->add($database);

// iterate through new items
foreach( $result->getFilteredItems($chain) as $item ) {
echo $item->getTitle();
}

```

In order to save bandwidth, feed-io estimates the next time it will be relevant to read the feed and get new items from it.

```php
Expand Down
30 changes: 30 additions & 0 deletions src/FeedIo/Filter/Chain.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace FeedIo\Filter;

use FeedIo\FeedInterface;

class Chain
{
private array $filters;

public function add(FilterInterface $filter): void
{
$this->filters[] = $filter;
}

public function filter(FeedInterface $feed): iterable
{
foreach ($feed as $item) {
foreach ($this->filters as $filter) {
if (!$filter->filter($item)) {
continue 2;
}
}

yield $item;
}
}
}
18 changes: 18 additions & 0 deletions src/FeedIo/Filter/FilterInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace FeedIo\Filter;

use FeedIo\Feed\ItemInterface;

interface FilterInterface
{
/**
* Returns `true` if the item is to be returned.
*
* @param ItemInterface $item
* @return bool
*/
public function filter(ItemInterface $item): bool;
}
23 changes: 23 additions & 0 deletions src/FeedIo/Filter/Since.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace FeedIo\Filter;

use DateTime;
use FeedIo\Feed\ItemInterface;

class Since implements FilterInterface
{
private DateTime $date;

public function __construct(DateTime $date)
{
$this->date = $date;
}

public function filter(ItemInterface $item): bool
{
return $item->getLastModified() >= $this->date;
}
}
15 changes: 15 additions & 0 deletions src/FeedIo/Reader/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
use DateTime;
use FeedIo\Adapter\ResponseInterface;
use FeedIo\FeedInterface;
use FeedIo\Filter\Chain;
use FeedIo\Filter\Since;
use FeedIo\Reader\Result\UpdateStats;

/**
Expand Down Expand Up @@ -52,6 +54,19 @@ public function getFeed(): FeedInterface
return $this->feed;
}

public function getItemsSince(DateTime $since = null): iterable
{
$filter = new Chain();
$filter->add(new Since($since ?? $this->modifiedSince));

return $filter->filter($this->getFeed());
}

public function getFilteredItems(Chain $filterChain): iterable
{
return $filterChain->filter($this->feed);
}

public function getModifiedSince(): ?DateTime
{
return $this->modifiedSince;
Expand Down
49 changes: 49 additions & 0 deletions tests/FeedIo/Filter/ChainTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace FeedIo\Filter;

use FeedIo\Feed;
use FeedIo\Feed\Item;
use PHPUnit\Framework\TestCase;

class ChainTest extends TestCase
{
public function testFilter()
{
$chain = new Chain();
$chain->add(new Since(new \DateTime('-1 day')));

$feed = new Feed();
$feed->add((new Item())->setLastModified(new \DateTime('-1 hour')));
$feed->add((new Item())->setLastModified(new \DateTime('-1 day')));
$feed->add((new Item())->setLastModified(new \DateTime('-1 month')));

$filtered = $chain->filter($feed);
$this->assertEquals(2, iterator_count($filtered));
}

public function testFancyFilter()
{
$chain = new Chain();
$fancyFilter = $this->getMockForAbstractClass('\FeedIo\Filter\FilterInterface');
$fancyFilter->expects($this->exactly(2))->method('filter')->will($this->returnCallback(function (Item $item) {
return $item->getTitle() === '1 day ago';
}));

$chain->add(new Since(new \DateTime('-1 day')));
$chain->add($fancyFilter);

$feed = new Feed();
$feed->add((new Item())->setTitle('1 hour ago')->setLastModified(new \DateTime('-1 hour')));
$feed->add((new Item())->setTitle('1 day ago')->setLastModified(new \DateTime('-1 day')));
$feed->add((new Item())->setTitle('1 month ago')->setLastModified(new \DateTime('-1 month')));

$filtered = $chain->filter($feed);
$count = 0;
foreach ($filtered as $item) {
$count++;
}
$this->assertEquals(1, $count);
$this->assertEquals('1 day ago', $item->getTitle());
}
}
17 changes: 17 additions & 0 deletions tests/FeedIo/Filter/SinceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace FeedIo\Filter;

use FeedIo\Feed\Item;
use PHPUnit\Framework\TestCase;

class FilterTest extends TestCase
{
public function testFilter()
{
$filter = new Since(new \DateTime('-1 day'));
$this->assertTrue($filter->filter((new Item())->setLastModified(new \DateTime('-1 hour'))));
$this->assertTrue($filter->filter((new Item())->setLastModified(new \DateTime('-1 day'))));
$this->assertFalse($filter->filter((new Item())->setLastModified(new \DateTime('-2 day'))));
}
}

0 comments on commit 9b726b1

Please sign in to comment.