Skip to content
This repository was archived by the owner on Jan 31, 2025. It is now read-only.

Commit 4e20f48

Browse files
committed
Add extension support
1 parent afaf06c commit 4e20f48

File tree

8 files changed

+171
-1
lines changed

8 files changed

+171
-1
lines changed

doc/render-feed.md

+7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ $item = new Item('2347259');
1818
$item->setUrl('https://example.org/2347259');
1919
$item->setDatePublished(new DateTime('2016-02-09 14:22:00', new DateTimeZone('+0200')));
2020
$item->setContentText('Cats are neat. https://example.org/cats');
21+
$item->addExtension('blue_shed', [
22+
'about' => 'https://blueshed-podcasts.com/json-feed-extension-docs',
23+
'explicit': false,
24+
'copyright' => '1948 by George Orwell',
25+
'owner' => 'Big Brother and the Holding Company',
26+
'subtitle' => 'All shouting, all the time. Double. Plus. Good.'
27+
]);
2128

2229
$feed = new Feed('Brent Simmons’s Microblog');
2330
$feed->setUserComment('This is a microblog feed. You can add this to your feed reader using the following URL: https://example.org/feed.json');

src/Item.php

+48
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace JDecool\JsonFeed;
44

55
use DateTime;
6+
use InvalidArgumentException;
67

78
class Item
89
{
@@ -48,6 +49,9 @@ class Item
4849
/** @var Attachment[] */
4950
private $attachments;
5051

52+
/** @var array */
53+
private $extensions;
54+
5155
/**
5256
* Constructor
5357
*
@@ -59,6 +63,7 @@ public function __construct($id)
5963

6064
$this->tags = [];
6165
$this->attachments = [];
66+
$this->extensions = [];
6267
}
6368

6469
/**
@@ -398,4 +403,47 @@ public function setAttachments(array $attachments)
398403

399404
return $this;
400405
}
406+
407+
/**
408+
* Add an extension to the item
409+
*
410+
* @param string $key
411+
* @param array $value
412+
* @return Item
413+
*/
414+
public function addExtension($key, array $value)
415+
{
416+
if (!is_string($key)) {
417+
throw new InvalidArgumentException('Extension key must be a string');
418+
}
419+
420+
$this->extensions[$key] = $value;
421+
422+
return $this;
423+
}
424+
425+
/**
426+
* Get all extensions
427+
*
428+
* @return array
429+
*/
430+
public function getExtensions()
431+
{
432+
return $this->extensions;
433+
}
434+
435+
/**
436+
* Get an extension
437+
*
438+
* @param string $key
439+
* @return array|null
440+
*/
441+
public function getExtension($key)
442+
{
443+
if (!isset($this->extensions[$key])) {
444+
return null;
445+
}
446+
447+
return $this->extensions[$key];
448+
}
401449
}

src/Reader/Version1/FeedReader.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,17 @@ private function readItemNode(array $content)
141141

142142
default:
143143
try {
144-
$this->accessor->setValue($item, $key, $value);
144+
if ('_' === $key[0]) {
145+
$item->addExtension(substr($key, 1), $value);
146+
} else {
147+
$this->accessor->setValue($item, $key, $value);
148+
}
145149
} catch (NoSuchPropertyException $e) {
146150
if ($this->isErrorEnabled) {
147151
throw InvalidFeedException::invalidItemProperty($key);
148152
}
149153
}
154+
break;
150155
}
151156
}
152157

src/Writer/Version1/Renderer.php

+6
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,12 @@ private function renderItem(Item $item)
136136
}, $attachments);
137137
}
138138

139+
if ($extensions = $item->getExtensions()) {
140+
foreach ($extensions as $key => $extension) {
141+
$result['_'.$key] = $extension;
142+
}
143+
}
144+
139145
return $result;
140146
}
141147

test/Fixtures/extension.json

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"version": "https://jsonfeed.org/version/1",
3+
"title": "My Example Feed",
4+
"items": [
5+
{
6+
"id": "2",
7+
"content_text": "This is a second item.",
8+
"url": "https://example.org/second-item",
9+
"_extItem2": {
10+
"foo": "value",
11+
"bar": "value"
12+
},
13+
"_extAuthor": {
14+
"john": "doe",
15+
"jane": "doe"
16+
}
17+
},
18+
{
19+
"id": "1",
20+
"content_html": "<p>Hello, world!</p>",
21+
"url": "https://example.org/initial-post",
22+
"_extAuthor": {
23+
"john": "doe",
24+
"jane": "doe"
25+
}
26+
}
27+
]
28+
}

test/ItemTest.php

+27
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,31 @@ public function testSetAttachments()
117117
$this->assertEquals(2, count($item->getAttachments()));
118118
$this->assertEquals($attachments, $item->getAttachments());
119119
}
120+
121+
public function testAddExtension()
122+
{
123+
$extension1 = [
124+
'about' => 'https://blueshed-podcasts.com/json-feed-extension-docs',
125+
'explicit' => false,
126+
'copyright' => '1948 by George Orwell',
127+
'owner' => 'Big Brother and the Holding Company',
128+
'subtitle' => 'All shouting, all the time. Double. Plus. Good.'
129+
];
130+
131+
$item = new Item('myid');
132+
$item->addExtension('blue_shed', $extension1);
133+
134+
$this->assertEquals(1, count($item->getExtensions()));
135+
$this->assertEquals($extension1, $item->getExtension('blue_shed'));
136+
137+
$extension2 = [
138+
'foo1' => 'bar1',
139+
'foo2' => 'bar2',
140+
];
141+
$item->addExtension('blue_shed2', $extension2);
142+
143+
$this->assertEquals(2, count($item->getExtensions()));
144+
$this->assertEquals($extension1, $item->getExtension('blue_shed'));
145+
$this->assertEquals($extension2, $item->getExtension('blue_shed2'));
146+
}
120147
}

test/Reader/Version1/FeedReaderTest.php

+26
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,32 @@ public function testReaderWithInvalidPropertyWithErrorEnabled()
193193
$this->assertEquals('Brent Simmons’s Microblog', $feed->getTitle());
194194
}
195195

196+
public function testReadExtensions()
197+
{
198+
$input = $this->getFixtures('extension');
199+
$reader = FeedReader::create();
200+
201+
$feed = $reader->readFromJson($input);
202+
$this->assertInstanceOf('JDecool\JsonFeed\Feed', $feed);
203+
$this->assertEquals('My Example Feed', $feed->getTitle());
204+
205+
$items = $feed->getItems();
206+
$this->assertCount(2, $items);
207+
208+
$item = new Item('2');
209+
$item->setContentText('This is a second item.');
210+
$item->setUrl('https://example.org/second-item');
211+
$item->addExtension('extItem2', ['foo' => 'value', 'bar' => 'value']);
212+
$item->addExtension('extAuthor', ['john' => 'doe', 'jane' => 'doe']);
213+
$this->assertEquals($item, $items[0]);
214+
215+
$item = new Item('1');
216+
$item->setContentHtml('<p>Hello, world!</p>');
217+
$item->setUrl('https://example.org/initial-post');
218+
$item->addExtension('extAuthor', ['john' => 'doe', 'jane' => 'doe']);
219+
$this->assertEquals($item, $items[1]);
220+
}
221+
196222
private function getFixtures($name)
197223
{
198224
return file_get_contents(self::$fixturesPath.'/'.$name.'.json');

test/Writer/Version1/RendererTest.php

+23
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,29 @@ public function testMicroblogFeed()
9393
$this->assertJsonStringEqualsJsonString($expected, $render->render($feed));
9494
}
9595

96+
public function testRenderExtension()
97+
{
98+
$feed = new Feed('My Example Feed');
99+
100+
$item2 = new Item('2');
101+
$item2->setContentText('This is a second item.');
102+
$item2->setUrl('https://example.org/second-item');
103+
$item2->addExtension('extItem2', ['foo' => 'value', 'bar' => 'value']);
104+
$item2->addExtension('extAuthor', ['john' => 'doe', 'jane' => 'doe']);
105+
$feed->addItem($item2);
106+
107+
$item1 = new Item('1');
108+
$item1->setContentHtml('<p>Hello, world!</p>');
109+
$item1->setUrl('https://example.org/initial-post');
110+
$item1->addExtension('extAuthor', ['john' => 'doe', 'jane' => 'doe']);
111+
$feed->addItem($item1);
112+
113+
$expected = $this->getFixtures('extension');
114+
115+
$render = new Renderer();
116+
$this->assertJsonStringEqualsJsonString($expected, $render->render($feed));
117+
}
118+
96119
private function getFixtures($name)
97120
{
98121
return file_get_contents(self::$fixturesPath.'/'.$name.'.json');

0 commit comments

Comments
 (0)