Skip to content
This repository has been archived by the owner on Jan 30, 2020. It is now read-only.

Make StandaloneExtensionManagers configurable #55

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions doc/book/reader.md
Original file line number Diff line number Diff line change
Expand Up @@ -532,9 +532,9 @@ manager". Extension managers must implement `Zend\Feed\Reader\ExtensionManagerIn
Three implementations exist:

- `Zend\Feed\Reader\StandaloneExtensionManager` is a hard-coded implementation
seeded with all feed and entry implementations. You can extend it to add
extensions, though it's likely easier to copy and paste it, adding your
changes.
seeded with all feed and entry implementations. You can add simple extensions
from it using `add` and `remove` methods. `ExtensionPluginManager` is
recommended for more complex needs.
- `Zend\Feed\Reader\ExtensionPluginManager` is a `Zend\ServiceManager\AbstractPluginManager`
implementation, `Zend\Feed\Reader\ExtensionManager`; as such, you can extend
it to add more extensions, use a `Zend\ServiceManager\ConfigInterface` instance
Expand Down Expand Up @@ -727,7 +727,8 @@ your extension manager knows about it, and then register the extension with

The following example uses `Zend\Feed\Reader\ExtensionPluginManager` to manage
extensions, as it provides the ability to register new extensions without
requiring extension of the plugin manager itself. To use it, first intall
requiring extension of the plugin manager itself (note that this example works
with ServiceManager v2, but not v3). To use it, first install
zend-servicemanager:

```bash
Expand Down
62 changes: 49 additions & 13 deletions src/Reader/StandaloneExtensionManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,24 @@

namespace Zend\Feed\Reader;

use Zend\Feed\Reader\Exception\InvalidArgumentException;

class StandaloneExtensionManager implements ExtensionManagerInterface
{
private $extensions = [
'Atom\Entry' => 'Zend\Feed\Reader\Extension\Atom\Entry',
'Atom\Feed' => 'Zend\Feed\Reader\Extension\Atom\Feed',
'Content\Entry' => 'Zend\Feed\Reader\Extension\Content\Entry',
'CreativeCommons\Entry' => 'Zend\Feed\Reader\Extension\CreativeCommons\Entry',
'CreativeCommons\Feed' => 'Zend\Feed\Reader\Extension\CreativeCommons\Feed',
'DublinCore\Entry' => 'Zend\Feed\Reader\Extension\DublinCore\Entry',
'DublinCore\Feed' => 'Zend\Feed\Reader\Extension\DublinCore\Feed',
'Podcast\Entry' => 'Zend\Feed\Reader\Extension\Podcast\Entry',
'Podcast\Feed' => 'Zend\Feed\Reader\Extension\Podcast\Feed',
'Slash\Entry' => 'Zend\Feed\Reader\Extension\Slash\Entry',
'Syndication\Feed' => 'Zend\Feed\Reader\Extension\Syndication\Feed',
'Thread\Entry' => 'Zend\Feed\Reader\Extension\Thread\Entry',
'WellFormedWeb\Entry' => 'Zend\Feed\Reader\Extension\WellFormedWeb\Entry',
'Atom\Entry' => Extension\Atom\Entry::class,
'Atom\Feed' => Extension\Atom\Feed::class,
'Content\Entry' => Extension\Content\Entry::class,
'CreativeCommons\Entry' => Extension\CreativeCommons\Entry::class,
'CreativeCommons\Feed' => Extension\CreativeCommons\Feed::class,
'DublinCore\Entry' => Extension\DublinCore\Entry::class,
'DublinCore\Feed' => Extension\DublinCore\Feed::class,
'Podcast\Entry' => Extension\Podcast\Entry::class,
'Podcast\Feed' => Extension\Podcast\Feed::class,
'Slash\Entry' => Extension\Slash\Entry::class,
'Syndication\Feed' => Extension\Syndication\Feed::class,
'Thread\Entry' => Extension\Thread\Entry::class,
'WellFormedWeb\Entry' => Extension\WellFormedWeb\Entry::class,
];

/**
Expand All @@ -49,4 +51,38 @@ public function get($extension)
$class = $this->extensions[$extension];
return new $class();
}

/**
* Add an extension.
*
* @param string $name
* @param string $class
*/
public function add($name, $class)
{
if (is_string($class) && (
is_a($class, Extension\AbstractEntry::class, true) ||
is_a($class, Extension\AbstractFeed::class, true))
) {
$this->extensions[$name] = $class;
return;
}

throw new InvalidArgumentException(sprintf(
'Plugin of type %s is invalid; must implement %2$s\Extension\AbstractFeed '
. 'or %2$s\Extension\AbstractEntry',
$class,
__NAMESPACE__
));
}

/**
* Remove an extension.
*
* @param string $name
*/
public function remove($name)
{
unset($this->extensions[$name]);
}
}
38 changes: 38 additions & 0 deletions src/Writer/StandaloneExtensionManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

namespace Zend\Feed\Writer;

use Zend\Feed\Writer\Exception\InvalidArgumentException;

class StandaloneExtensionManager implements ExtensionManagerInterface
{
private $extensions = [
Expand Down Expand Up @@ -47,4 +49,40 @@ public function get($extension)
$class = $this->extensions[$extension];
return new $class();
}

/**
* Add an extension.
*
* @param string $name
* @param string $class
*/
public function add($name, $class)
{
if (is_string($class) && ((
is_a($class, Extension\AbstractRenderer::class, true) ||
'Feed' === substr($class, -4) ||
'Entry' === substr($class, -5)
))) {
$this->extensions[$name] = $class;

return;
}

throw new InvalidArgumentException(sprintf(
'Plugin of type %s is invalid; must implement %s\Extension\RendererInterface '
. 'or the classname must end in "Feed" or "Entry"',
$class,
__NAMESPACE__
));
}

/**
* Remove an extension.
*
* @param string $name
*/
public function remove($name)
{
unset($this->extensions[$name]);
}
}
30 changes: 30 additions & 0 deletions test/Reader/StandaloneExtensionManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@

class StandaloneExtensionManagerTest extends TestCase
{
/**
* @var StandaloneExtensionManager
*/
private $extensions;

public function setUp()
{
$this->extensions = new StandaloneExtensionManager();
Expand Down Expand Up @@ -80,4 +85,29 @@ public function testEachPluginRetrievalReturnsNewInstance($pluginName, $pluginCl
$this->assertInstanceOf($pluginClass, $test);
$this->assertNotSame($extension, $test);
}

public function testAddAcceptsValidExtensionClasses()
{
$ext = $this->createMock(\Zend\Feed\Reader\Extension\AbstractEntry::class);
$this->extensions->add('Test/Entry', get_class($ext));
$this->assertTrue($this->extensions->has('Test/Entry'));
$ext = $this->createMock(\Zend\Feed\Reader\Extension\AbstractFeed::class);
$this->extensions->add('Test/Feed', get_class($ext));
$this->assertTrue($this->extensions->has('Test/Feed'));
}

public function testAddRejectsInvalidExtensions()
{
$this->expectException(\Zend\Feed\Reader\Exception\InvalidArgumentException::class);
$this->extensions->add('Test/Entry', 'blah');
}

public function testExtensionRemoval()
{
$ext = $this->createMock(\Zend\Feed\Reader\Extension\AbstractEntry::class);
$this->extensions->add('Test/Entry', get_class($ext));
$this->assertTrue($this->extensions->has('Test/Entry'));
$this->extensions->remove('Test/Entry');
$this->assertFalse($this->extensions->has('Test/Entry'));
}
}
123 changes: 123 additions & 0 deletions test/Writer/StandaloneExtensionManagerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace ZendTest\Feed\Writer;

use PHPUnit\Framework\TestCase;
use Zend\Feed\Writer\StandaloneExtensionManager;
use Zend\Feed\Writer\ExtensionManagerInterface;

class StandaloneExtensionManagerTest extends TestCase
{
/**
* @var StandaloneExtensionManager
*/
private $extensions;

public function setUp()
{
$this->extensions = new StandaloneExtensionManager();
}

public function testIsAnExtensionManagerImplementation()
{
$this->assertInstanceOf(ExtensionManagerInterface::class, $this->extensions);
}

public function defaultPlugins()
{
return [
'Atom\Renderer\Feed' => [
'Atom\Renderer\Feed', \Zend\Feed\Writer\Extension\Atom\Renderer\Feed::class
],
'Content\Renderer\Entry' => [
'Content\Renderer\Entry', \Zend\Feed\Writer\Extension\Content\Renderer\Entry::class
],
'DublinCore\Renderer\Entry' => [
'DublinCore\Renderer\Entry', \Zend\Feed\Writer\Extension\DublinCore\Renderer\Entry::class
],
'DublinCore\Renderer\Feed' => [
'DublinCore\Renderer\Feed', \Zend\Feed\Writer\Extension\DublinCore\Renderer\Feed::class
],
'ITunes\Entry' => ['ITunes\Entry', \Zend\Feed\Writer\Extension\ITunes\Entry::class],
'ITunes\Feed' => ['ITunes\Feed', \Zend\Feed\Writer\Extension\ITunes\Feed::class],
'ITunes\Renderer\Entry' => [
'ITunes\Renderer\Entry', \Zend\Feed\Writer\Extension\ITunes\Renderer\Entry::class
],
'ITunes\Renderer\Feed' => [
'ITunes\Renderer\Feed', \Zend\Feed\Writer\Extension\ITunes\Renderer\Feed::class
],
'Slash\Renderer\Entry' => [
'Slash\Renderer\Entry', \Zend\Feed\Writer\Extension\Slash\Renderer\Entry::class
],
'Threading\Renderer\Entry' => [
'Threading\Renderer\Entry', \Zend\Feed\Writer\Extension\Threading\Renderer\Entry::class
],
'WellFormedWeb\Renderer\Entry' => [
'WellFormedWeb\Renderer\Entry', \Zend\Feed\Writer\Extension\WellFormedWeb\Renderer\Entry::class
],
];
}

/**
* @dataProvider defaultPlugins
*/
public function testHasAllDefaultPlugins($pluginName, $pluginClass)
{
$this->assertTrue($this->extensions->has($pluginName));
}

/**
* @dataProvider defaultPlugins
*/
public function testCanRetrieveDefaultPluginInstances($pluginName, $pluginClass)
{
$extension = $this->extensions->get($pluginName);
$this->assertInstanceOf($pluginClass, $extension);
}

/**
* @dataProvider defaultPlugins
*/
public function testEachPluginRetrievalReturnsNewInstance($pluginName, $pluginClass)
{
$extension = $this->extensions->get($pluginName);
$this->assertInstanceOf($pluginClass, $extension);

$test = $this->extensions->get($pluginName);
$this->assertInstanceOf($pluginClass, $test);
$this->assertNotSame($extension, $test);
}

public function testAddAcceptsValidExtensionClasses()
{
$this->extensions->add('Test/Feed', 'MyTestExtension_Feed');
$this->assertTrue($this->extensions->has('Test/Feed'));

$this->extensions->add('Test/Entry', 'MyTestExtension_Entry');
$this->assertTrue($this->extensions->has('Test/Entry'));

$ext = $this->createMock(\Zend\Feed\Writer\Extension\AbstractRenderer::class);
$this->extensions->add('Test/Thing', get_class($ext));
$this->assertTrue($this->extensions->has('Test/Thing'));
}

public function testAddRejectsInvalidExtensions()
{
$this->expectException(\Zend\Feed\Writer\Exception\InvalidArgumentException::class);
$this->extensions->add('Test/Feed', 'blah');
}

public function testExtensionRemoval()
{
$this->extensions->add('Test/Entry', 'MyTestExtension_Entry');
$this->assertTrue($this->extensions->has('Test/Entry'));
$this->extensions->remove('Test/Entry');
$this->assertFalse($this->extensions->has('Test/Entry'));
}
}