Skip to content

Commit 86e6f3c

Browse files
committed
refactorization, unittest, travis ci, coveralls, readme badges
Signed-off-by: Bruno Meilick <[email protected]>
1 parent 4432c39 commit 86e6f3c

File tree

31 files changed

+6494
-150
lines changed

31 files changed

+6494
-150
lines changed

.coveralls.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# https://github.com/php-coveralls/php-coveralls
2+
service_name: travis-ci
3+
coverage_clover: tests/logs/clover.xml
4+
json_path: tests/logs/coveralls-upload.json

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
/vendor/**/.*
1414
/vendor/**/*.json
1515
/vendor/**/*.txt
16-
/vendor/**/*.md
16+
/vendor/**/*.md``
1717
/vendor/**/*.yml
1818
/vendor/**/*.yaml
1919
/vendor/**/*.xml

.travis.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
language: php
2+
php: 7.2
3+
matrix:
4+
fast_finish: true
5+
install: composer install --no-interaction
6+
script: composer test
7+
after_success: travis_retry php vendor/bin/php-coveralls -v
8+
notifications:
9+
webhooks:
10+
on_success: change
11+
on_failure: always
12+
on_start: never
13+
urls:
14+
- https://webhooks.gitter.im/e/77d9949056dc0462d25d

README.md

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Kirby 3 Feed
22

3-
![GitHub release](https://img.shields.io/github/release/bnomei/kirby3-feed.svg?maxAge=1800) ![License](https://img.shields.io/github/license/mashape/apistatus.svg) ![Kirby Version](https://img.shields.io/badge/Kirby-3%2B-black.svg) ![Kirby 3 Pluginkit](https://img.shields.io/badge/Pluginkit-YES-cca000.svg)
3+
![GitHub release](https://img.shields.io/github/release/bnomei/kirby3-feed.svg?maxAge=1800) ![License](https://img.shields.io/github/license/mashape/apistatus.svg) ![Kirby Version](https://img.shields.io/badge/Kirby-3-black.svg) ![Kirby 3 Pluginkit](https://img.shields.io/badge/Pluginkit-YES-cca000.svg) [![Build Status](https://travis-ci.com/bnomei/kirby3-feed.svg?branch=master)](https://travis-ci.com/bnomei/kirby3-feed) [![Coverage Status](https://coveralls.io/repos/github/bnomei/kirby3-feed/badge.svg?branch=master)](https://coveralls.io/github/bnomei/kirby3-feed?branch=master) [![Gitter](https://badges.gitter.im/bnomei-kirby-3-plugins/community.svg)](https://gitter.im/bnomei-kirby-3-plugins/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
44

55
Generate a RSS/JSON-Feed from a Pages-Collection.
66

@@ -37,16 +37,18 @@ If you use these defaults you need to provide the fields `date (type: date)` and
3737

3838
```php
3939
[
40-
'url' => site()->url(),
41-
'feedurl' => site()->url() . '/feed/',
42-
'title' => 'Feed',
40+
'url' => site()->url(),
41+
'feedurl' => site()->url() . '/feed/',
42+
'title' => 'Feed',
4343
'description' => '',
44-
'link' => site()->url(),
45-
'urlfield' => 'url',
46-
'datefield' => 'date',
47-
'textfield' => 'text',
48-
'modified' => time(),
49-
'snippet' => 'feed/rss', // or 'feed/json
44+
'link' => site()->url(),
45+
'urlfield' => 'url',
46+
'datefield' => 'date',
47+
'textfield' => 'text',
48+
'modified' => time(),
49+
'snippet' => 'feed/rss', // 'feed/json'
50+
'mime' => null,
51+
'sort' => true,
5052
]
5153
```
5254

@@ -83,7 +85,16 @@ or rss json
8385
<link rel="alternate" type="application/json" title="Latest articles" href="<?= site()->url() ?>/feed"/>
8486
```
8587

86-
**Sorting by date**
88+
> TIP: Having multiple feed links is still valid html. So you can have both rss and json if you want and setup the routes properly.
89+
90+
**Sorting**
91+
92+
The Plugin applies a default sorting for the pages by date/modified in descending order (newest first).
93+
94+
- If you do not want this you have to set the `datefield` setting to another Field name or PageMethod name.
95+
- If you want to disable sorting by the plugin and add your own you can set the option `sort` to `false`.
96+
97+
**Pitfalls when presorting by date and limit**
8798

8899
Using `sortBy('date', 'desc')` will **not** yield expected results! In K3 sorting by date needs a callback.
89100
```php

classes/Feed.php

Lines changed: 162 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,198 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace Bnomei;
46

5-
class Feed
7+
final class Feed
68
{
7-
private static $indexname = null;
8-
private static $cache = null;
9-
private static function cache(): \Kirby\Cache\Cache
9+
/**
10+
* @var array
11+
*/
12+
private $options;
13+
14+
/*
15+
* @var string
16+
*/
17+
private $string;
18+
19+
public function __construct(?\Kirby\Cms\Pages $pages = null, array $options = [])
1020
{
11-
if (!static::$cache) {
12-
static::$cache = kirby()->cache('bnomei.feed');
13-
}
14-
return static::$cache;
21+
$this->options = $this->optionsFromDefault($pages, $options);
1522
}
1623

17-
public static function flush()
24+
/**
25+
* @return array
26+
*/
27+
public function getOptions(): array
1828
{
19-
return static::cache()->flush();
29+
return $this->options;
2030
}
2131

22-
public static function isJson($string)
32+
/**
33+
* @return string
34+
*/
35+
public function getString(): string
2336
{
24-
json_decode($string);
25-
return (json_last_error() == JSON_ERROR_NONE);
37+
return $this->string;
2638
}
2739

28-
public static function isXml($content)
40+
/**
41+
* @param null $force
42+
* @return Feed
43+
* @throws \Kirby\Exception\InvalidArgumentException
44+
*/
45+
public function stringFromSnippet($force = null): Feed
2946
{
30-
$content = trim($content);
31-
if (empty($content)) {
32-
return false;
47+
$force = $force ? $force : (option('debug') && option('bnomei.feed.debugforce'));
48+
$key = $this->modifiedHashFromKeys();
49+
50+
$string = null;
51+
if (! $force) {
52+
$string = kirby()->cache('bnomei.feed')->get($key);
3353
}
34-
if (stripos($content, '<!DOCTYPE html>') !== false) {
35-
return false;
54+
if ($string) {
55+
$this->string = $string;
56+
return $this;
3657
}
37-
libxml_use_internal_errors(true);
38-
simplexml_load_string($content);
39-
$errors = libxml_get_errors();
40-
libxml_clear_errors();
41-
return empty($errors);
58+
59+
$string = snippet(
60+
\Kirby\Toolkit\A::get($this->options, 'snippet'),
61+
$this->options,
62+
true
63+
);
64+
65+
kirby()->cache('bnomei.feed')->set(
66+
$key,
67+
$string,
68+
intval(option('bnomei.feed.expires'))
69+
);
70+
71+
$this->string = $string;
72+
return $this;
4273
}
4374

44-
public static function feed($pages, $options = [], $force = null)
75+
/**
76+
* @return string
77+
* @throws \Kirby\Exception\DuplicateException
78+
*/
79+
private function modifiedHashFromKeys(): string
4580
{
46-
if ($force == null && option('debug') && option('bnomei.feed.debugforce')) {
47-
$force = true;
48-
}
49-
$key = [];
50-
foreach ($pages as $p) {
51-
$key[] = $p->modified();
81+
$keys = [
82+
kirby()->language() ? kirby()->language()->code() : '',
83+
str_replace('.', '', kirby()->plugin('bnomei/feed')->version()[0]),
84+
\Kirby\Toolkit\A::get($this->options, 'snippet'),
85+
];
86+
$pages = \Kirby\Toolkit\A::get($this->options, 'items');
87+
foreach ($pages as $page) {
88+
$keys[] = $page->modified();
5289
}
53-
$l = kirby()->language() ? kirby()->language()->code() : '';
54-
$key = md5($l . '_' . \implode(',', $key));
55-
$response = $force ? null : static::cache()->get($key);
56-
if (!$response) {
57-
$snippet = \Kirby\Toolkit\A::get($options, 'snippet', 'feed/rss');
58-
$response = snippet($snippet, static::data($pages, $options), true);
59-
static::cache()->set(
60-
$key,
61-
$response,
62-
option('bnomei.feed.expires')
63-
);
64-
}
65-
return $response;
90+
return sha1(implode(',', $keys));
6691
}
6792

68-
public static function data($pages, $options = [])
93+
/**
94+
* @param \Kirby\Cms\Pages|null $pages
95+
* @param array $options
96+
* @return array
97+
*/
98+
public function optionsFromDefault(?\Kirby\Cms\Pages $pages = null, $options = []): array
6999
{
70-
$defaults = array(
71-
'url' => site()->url(),
72-
'feedurl' => site()->url() . '/feed/',
73-
'title' => 'Feed',
100+
$defaults = [
101+
'url' => site()->url(),
102+
'feedurl' => site()->url() . '/feed/',
103+
'title' => 'Feed',
74104
'description' => '',
75-
'link' => site()->url(),
76-
'urlfield' => 'url',
77-
'datefield' => 'date',
78-
'textfield' => 'text',
79-
'modified' => time(),
80-
);
105+
'link' => site()->url(),
106+
'urlfield' => 'url',
107+
'datefield' => 'date',
108+
'textfield' => 'text',
109+
'modified' => time(),
110+
'snippet' => 'feed/rss',
111+
'mime' => null,
112+
'sort' => true,
113+
];
81114
$options = array_merge($defaults, $options);
82115

83-
$items = $pages->sortBy($options['datefield'], 'desc');
116+
$items = $pages ?? null;
117+
if ($items && $options['sort'] === true) {
118+
$items = $items->sortBy($options['datefield'], 'desc');
119+
}
84120
$options['items'] = $items;
121+
$options['link'] = url($options['link']);
85122

86-
$options['link'] = url($options['link']);
87-
88-
if ($options['datefield'] == 'modified') {
123+
if ($items && $options['datefield'] === 'modified') {
89124
$options['modified'] = $items->first()->modified('r', 'date');
125+
} elseif ($items) {
126+
$datefieldName = $options['datefield'];
127+
$options['modified'] = date('r', $items->first()->{$datefieldName}()->toTimestamp());
90128
} else {
91-
$f = $options['datefield'];
92-
$options['modified'] = date('r', $items->first()->{$f}()->toTimestamp());
129+
$options['modified'] = site()->homePage()->modified();
93130
}
94131

95132
return $options;
96133
}
134+
135+
/**
136+
* @return \Kirby\Http\Response
137+
*/
138+
public function response(): \Kirby\Http\Response
139+
{
140+
$mime = \Kirby\Toolkit\A::get($this->options, 'mime');
141+
$snippet = \Kirby\Toolkit\A::get($this->options, 'snippet');
142+
143+
if ($mime && in_array($mime, array_values(\Kirby\Toolkit\Mime::types()))) {
144+
return new \Kirby\Http\Response($this->string, $mime);
145+
} elseif ($snippet === 'feed/json' || \Bnomei\Feed::isJson($this->string)) {
146+
return new \Kirby\Http\Response($this->string, 'application/json');
147+
} elseif ($snippet === 'feed/rss' || \Bnomei\Feed::isXml($this->string)) {
148+
return new \Kirby\Http\Response($this->string, 'application/rss+xml');
149+
}
150+
return new \Kirby\Http\Response('Error: Feed Response', null, 500);
151+
}
152+
153+
/**
154+
* @param \Kirby\Cms\Pages $pages
155+
* @param array $options
156+
* @param null $force
157+
* @return \Kirby\Http\Response
158+
* @throws \Kirby\Exception\InvalidArgumentException
159+
*/
160+
public static function feed(\Kirby\Cms\Pages $pages, array $options = [], $force = null): \Kirby\Http\Response
161+
{
162+
$feed = new self($pages, $options);
163+
return $feed->stringFromSnippet($force)->response();
164+
}
165+
166+
/**
167+
* @param $string
168+
* @return bool
169+
*/
170+
public static function isJson($string): bool
171+
{
172+
json_decode($string);
173+
$lastError = json_last_error();
174+
return $lastError === JSON_ERROR_NONE;
175+
}
176+
177+
/**
178+
* @param $content
179+
* @return bool
180+
*/
181+
public static function isXml($content): bool
182+
{
183+
if (! $content) {
184+
return false;
185+
}
186+
if (is_string($content) && strlen(trim($content)) === 0) {
187+
return false;
188+
}
189+
if (stripos($content, '<!DOCTYPE html>') !== false) {
190+
return false;
191+
}
192+
libxml_use_internal_errors(true);
193+
simplexml_load_string(trim($content));
194+
$errors = libxml_get_errors();
195+
libxml_clear_errors();
196+
return count($errors) === 0;
197+
}
97198
}

0 commit comments

Comments
 (0)