Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Introduced factory extension to provide better hooks in the factory

  • Loading branch information...
commit 25056422affd0d9f027f9f2cb75c2ccdf34964db 1 parent e02f7fa
@stof stof authored
View
10 CHANGELOG.md
@@ -1,5 +1,9 @@
-## 2.0.0 (2013-XX-XX)
+## 2.0.0 beta 1 (2013-XX-XX)
+* Introduced extension points in the MenuFactory through `Knp\Menu\Factory\ExtensionInterface`
+* [BC break compared to 2.0 alpha 1] The inheritance extension points introduced in alpha1 are
+ deprecated in favor of extensions and will be removed before the stable release.
+* `Knp\Menu\Silex\RouterAwareFactory` is deprecated in favor of `Knp\Menu\Silex\RoutingExtension`.
* [BC break] Deprecated the methods `createFromArray` and `createFromNode` in the MenuFactory and
removed them from `Knp\Menu\FactoryInterface`. Use `Knp\Menu\Loader\ArrayLoader` and
`Knp\Menu\Loader\NodeLoader` instead.
@@ -9,7 +13,7 @@
instead.
* Made the RouterVoter comaptible with SensioFrameworkExtraBundle param converters
* Added the possibility to match routes using a regex on their name in the RouterVoter
-* [BC break] Refactored the RouterVoter to make it more flexible
+* [BC break compared to 2.0 alpha 1] Refactored the RouterVoter to make it more flexible
The way to pass routes in the item extras has changed.
Before:
@@ -36,10 +40,12 @@
## 2.0.0 alpha 1 (2013-06-23)
+* Added protected methods `buildOptions` and `configureItem` in the MenuFactory as extension point by inheritance
* [BC break] Refactored the way to mark items as current
``setCurrentUri``, ``getCurrentUri`` and ``getCurrentItem`` have been removed from the ItemInterface.
Determining the current items is now delegated to a matcher, and the default implementation
uses voters to apply the matching. Getting the current items can be done thanks to the CurrentItemFilterIterator.
+* [BC break] The signature of the CurrentItemFilterIterator constructor changed to accept the item matcher
* [BC break] Changed the format of the breadcrumb array
Instead of storing the elements with the label as key and the uri as value
the array now stores an array of array elements with 3 keys: `label`, `uri` and `item`.
View
59 src/Knp/Menu/Factory/CoreExtension.php
@@ -0,0 +1,59 @@
+<?php
+
+namespace Knp\Menu\Factory;
+
+use Knp\Menu\ItemInterface;
+
+/**
+ * core factory extension with the main logic
+ */
+class CoreExtension implements ExtensionInterface
+{
+ /**
+ * Builds the full option array used to configure the item.
+ *
+ * @param array $options
+ *
+ * @return array
+ */
+ public function buildOptions(array $options)
+ {
+ return array_merge(
+ array(
+ 'uri' => null,
+ 'label' => null,
+ 'attributes' => array(),
+ 'linkAttributes' => array(),
+ 'childrenAttributes' => array(),
+ 'labelAttributes' => array(),
+ 'extras' => array(),
+ 'current' => null,
+ 'display' => true,
+ 'displayChildren' => true,
+ ),
+ $options
+ );
+ }
+
+ /**
+ * Configures the newly created item with the passed options
+ *
+ * @param ItemInterface $item
+ * @param array $options
+ */
+ public function buildItem(ItemInterface $item, array $options)
+ {
+ $item
+ ->setUri($options['uri'])
+ ->setLabel($options['label'])
+ ->setAttributes($options['attributes'])
+ ->setLinkAttributes($options['linkAttributes'])
+ ->setChildrenAttributes($options['childrenAttributes'])
+ ->setLabelAttributes($options['labelAttributes'])
+ ->setExtras($options['extras'])
+ ->setCurrent($options['current'])
+ ->setDisplay($options['display'])
+ ->setDisplayChildren($options['displayChildren'])
+ ;
+ }
+}
View
25 src/Knp/Menu/Factory/ExtensionInterface.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace Knp\Menu\Factory;
+
+use Knp\Menu\ItemInterface;
+
+interface ExtensionInterface
+{
+ /**
+ * Builds the full option array used to configure the item.
+ *
+ * @param array $options The options processed by the previous extensions
+ *
+ * @return array
+ */
+ public function buildOptions(array $options);
+
+ /**
+ * Configures the item with the passed options
+ *
+ * @param ItemInterface $item
+ * @param array $options
+ */
+ public function buildItem(ItemInterface $item, array $options);
+}
View
85 src/Knp/Menu/MenuFactory.php
@@ -2,6 +2,8 @@
namespace Knp\Menu;
+use Knp\Menu\Factory\CoreExtension;
+use Knp\Menu\Factory\ExtensionInterface;
use Knp\Menu\Loader\ArrayLoader;
use Knp\Menu\Loader\NodeLoader;
@@ -10,60 +12,71 @@
*/
class MenuFactory implements FactoryInterface
{
+ /**
+ * @var \SplPriorityQueue|ExtensionInterface[]
+ */
+ private $extensions;
+
+ public function __construct()
+ {
+ $this->extensions = new \SplPriorityQueue();
+
+ $this->addExtension(new CoreExtension(), -10);
+ }
+
public function createItem($name, array $options = array())
{
+ // TODO remove this BC layer before releasing 2.0
+ $processedOptions = $this->buildOptions($options);
+ if ($processedOptions !== $options) {
+ trigger_error(sprintf('Overwriting Knp\Menu\MenuFactory::buildOptions is deprecated. Use a factory extension instead of %s.', get_class($this)), E_USER_DEPRECATED);
+
+ $options = $processedOptions;
+ }
+
+ foreach (clone $this->extensions as $extension) {
+ $options = $extension->buildOptions($options);
+ }
+
$item = new MenuItem($name, $this);
- $options = $this->buildOptions($options);
- $this->configureItem($item, $options);
+ foreach (clone $this->extensions as $extension) {
+ $extension->buildItem($item, $options);
+ }
+
+ // TODO remove this BC layer before releasing 2.0
+ if (method_exists($this, 'configureItem')) {
+ trigger_error(sprintf('Overwriting Knp\Menu\MenuFactory::configureItem is deprecated. Use a factory extension instead of %s.', get_class($this)), E_USER_DEPRECATED);
+
+ $this->configureItem($item, $options);
+ }
return $item;
}
/**
- * Builds the full option array used to configure the item.
- *
- * @param array $options
+ * Adds a factory extension
*
- * @return array
+ * @param ExtensionInterface $extension
+ * @param integer $priority
*/
- protected function buildOptions(array $options)
+ public function addExtension(ExtensionInterface $extension, $priority = 0)
{
- return array_merge(
- array(
- 'uri' => null,
- 'label' => null,
- 'attributes' => array(),
- 'linkAttributes' => array(),
- 'childrenAttributes' => array(),
- 'labelAttributes' => array(),
- 'extras' => array(),
- 'display' => true,
- 'displayChildren' => true,
- ),
- $options
- );
+ $this->extensions->insert($extension, $priority);
}
/**
- * Configures the newly created item with the passed options
+ * Builds the full option array used to configure the item.
*
- * @param ItemInterface $item
- * @param array $options
+ * @deprecated Use a Knp\Menu\Factory\ExtensionInterface instead
+ *
+ * @param array $options
+ *
+ * @return array
*/
- protected function configureItem(ItemInterface $item, array $options)
+ protected function buildOptions(array $options)
{
- $item
- ->setUri($options['uri'])
- ->setLabel($options['label'])
- ->setAttributes($options['attributes'])
- ->setLinkAttributes($options['linkAttributes'])
- ->setChildrenAttributes($options['childrenAttributes'])
- ->setLabelAttributes($options['labelAttributes'])
- ->setExtras($options['extras'])
- ->setDisplay($options['display'])
- ->setDisplayChildren($options['displayChildren'])
- ;
+ return $options;
}
/**
View
6 src/Knp/Menu/Silex/KnpMenuServiceProvider.php
@@ -18,11 +18,13 @@ class KnpMenuServiceProvider implements ServiceProviderInterface
public function register(Application $app)
{
$app['knp_menu.factory'] = $app->share(function () use ($app) {
+ $factory = new MenuFactory();
+
if (isset($app['url_generator'])) {
- return new RouterAwareFactory($app['url_generator']);
+ $factory->addExtension(new RoutingExtension($app['url_generator']));
}
- return new MenuFactory();
+ return $factory;
});
$app['knp_menu.matcher'] = $app->share(function () use ($app) {
View
24 src/Knp/Menu/Silex/RouterAwareFactory.php
@@ -7,30 +7,16 @@
/**
* Factory able to use the Symfony2 Routing component to build the url
+ *
+ * @deprecated Use Knp\Menu\Silex\RoutingExtension instead
*/
class RouterAwareFactory extends MenuFactory
{
- protected $generator;
-
public function __construct(UrlGeneratorInterface $generator)
{
- $this->generator = $generator;
- }
-
- protected function buildOptions(array $options = array())
- {
- if (!empty($options['route'])) {
- $params = isset($options['routeParameters']) ? $options['routeParameters'] : array();
- $absolute = isset($options['routeAbsolute']) ? $options['routeAbsolute'] : false;
- $options['uri'] = $this->generator->generate($options['route'], $params, $absolute);
-
- // adding the item route to the extras under the 'routes' key (for the Silex RouteVoter)
- $options['extras']['routes'][] = array(
- 'route' => $options['route'],
- 'parameters' => $params,
- );
- }
+ trigger_error(__CLASS__ . ' is deprecated. Use Knp\Menu\Silex\RoutingExtension instead.', E_USER_DEPRECATED);
- return parent::buildOptions($options);
+ parent::__construct();
+ $this->addExtension(new RoutingExtension($generator));
}
}
View
41 src/Knp/Menu/Silex/RoutingExtension.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace Knp\Menu\Silex;
+
+use Knp\Menu\Factory\ExtensionInterface;
+use Knp\Menu\ItemInterface;
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+
+/**
+ * Factory able to use the Symfony2 Routing component to build the url
+ */
+class RoutingExtension implements ExtensionInterface
+{
+ private $generator;
+
+ public function __construct(UrlGeneratorInterface $generator)
+ {
+ $this->generator = $generator;
+ }
+
+ public function buildOptions(array $options = array())
+ {
+ if (!empty($options['route'])) {
+ $params = isset($options['routeParameters']) ? $options['routeParameters'] : array();
+ $absolute = isset($options['routeAbsolute']) ? $options['routeAbsolute'] : false;
+ $options['uri'] = $this->generator->generate($options['route'], $params, $absolute);
+
+ // adding the item route to the extras under the 'routes' key (for the Silex RouteVoter)
+ $options['extras']['routes'][] = array(
+ 'route' => $options['route'],
+ 'parameters' => $params,
+ );
+ }
+
+ return $options;
+ }
+
+ public function buildItem(ItemInterface $item, array $options)
+ {
+ }
+}
View
30 tests/Knp/Menu/Tests/MenuFactoryTest.php
@@ -6,6 +6,36 @@
class MenuFactoryTest extends \PHPUnit_Framework_TestCase
{
+ public function testExtensions()
+ {
+ $factory = new MenuFactory();
+
+ $extension1 = $this->getMock('Knp\Menu\Factory\ExtensionInterface');
+ $extension1->expects($this->once())
+ ->method('buildOptions')
+ ->with(array('foo' => 'bar'))
+ ->will($this->returnValue(array('uri' => 'foobar')));
+ $extension1->expects($this->once())
+ ->method('buildItem')
+ ->with($this->isInstanceOf('Knp\Menu\ItemInterface'), $this->contains('foobar'));
+
+ $factory->addExtension($extension1);
+
+ $extension2 = $this->getMock('Knp\Menu\Factory\ExtensionInterface');
+ $extension2->expects($this->once())
+ ->method('buildOptions')
+ ->with(array('foo' => 'baz'))
+ ->will($this->returnValue(array('foo' => 'bar')));
+ $extension1->expects($this->once())
+ ->method('buildItem')
+ ->with($this->isInstanceOf('Knp\Menu\ItemInterface'), $this->contains('foobar'));
+
+ $factory->addExtension($extension2, 10);
+
+ $item = $factory->createItem('test', array('foo' => 'baz'));
+ $this->assertEquals('foobar', $item->getUri());
+ }
+
public function testCreateItem()
{
$factory = new MenuFactory();
View
9 tests/Knp/Menu/Tests/Silex/KnpMenuServiceProviderTest.php
@@ -27,15 +27,6 @@ public function testFactoryWithoutRouter()
$this->assertEquals('Knp\Menu\MenuFactory', get_class($app['knp_menu.factory']));
}
- public function testFactoryWithRouter()
- {
- $app = new Application();
- $app->register(new KnpMenuServiceProvider());
- $app->register(new UrlGeneratorServiceProvider());
-
- $this->assertInstanceOf('Knp\Menu\Silex\RouterAwareFactory', $app['knp_menu.factory']);
- }
-
public function testTwigRendererNotRegistered()
{
$app = new Application();
View
57 tests/Knp/Menu/Tests/Silex/RouterAwareFactoryTest.php
@@ -21,46 +21,29 @@ public function testCreateItemWithRoute()
->with('homepage', array(), false)
->will($this->returnValue('/foobar'))
;
- $factory = new RouterAwareFactory($generator);
- $item = $factory->createItem('test_item', array('uri' => '/hello', 'route' => 'homepage'));
- $this->assertEquals('/foobar', $item->getUri());
- }
-
- public function testCreateItemWithRouteAndParameters()
- {
- $generator = $this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface');
- $generator->expects($this->once())
- ->method('generate')
- ->with('homepage', array('id' => 12), false)
- ->will($this->returnValue('/foobar'))
- ;
- $factory = new RouterAwareFactory($generator);
- $item = $factory->createItem('test_item', array('route' => 'homepage', 'routeParameters' => array('id' => 12)));
- $this->assertEquals('/foobar', $item->getUri());
- }
- public function testCreateItemWithAbsoluteRoute()
- {
- $generator = $this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface');
- $generator->expects($this->once())
- ->method('generate')
- ->with('homepage', array(), true)
- ->will($this->returnValue('http://php.net'))
- ;
- $factory = new RouterAwareFactory($generator);
- $item = $factory->createItem('test_item', array('route' => 'homepage', 'routeAbsolute' => true));
- $this->assertEquals('http://php.net', $item->getUri());
- }
+ $deprecatedErrorCatched = false;
+ set_error_handler(function ($errorNumber, $message, $file, $line) use (&$deprecatedErrorCatched) {
+ if ($errorNumber & E_USER_DEPRECATED) {
+ $deprecatedErrorCatched = true;
+ return true;
+ }
+
+ return \PHPUnit_Util_ErrorHandler::handleError($errorNumber, $message, $file, $line);
+ });
+
+ try {
+ $factory = new RouterAwareFactory($generator);
+ } catch (\Exception $e) {
+ restore_error_handler();
+ throw $e;
+ }
- public function testCreateItemAppendsRouteUnderExtras()
- {
- $generator = $this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface');
- $factory = new RouterAwareFactory($generator);
+ restore_error_handler();
- $item = $factory->createItem('test_item', array('route' => 'homepage'));
- $this->assertEquals(array(array('route' => 'homepage', 'parameters' => array())), $item->getExtra('routes'));
+ $this->assertTrue($deprecatedErrorCatched, 'The RouterAwareFactory throws a E_USER_DEPRECATED when instantiating it.');
- $item = $factory->createItem('test_item', array('route' => 'homepage', 'extras' => array('routes' => array('other_page'))));
- $this->assertContains(array('route' => 'homepage', 'parameters' => array()), $item->getExtra('routes'));
+ $item = $factory->createItem('test_item', array('uri' => '/hello', 'route' => 'homepage'));
+ $this->assertEquals('/foobar', $item->getUri());
}
}
View
82 tests/Knp/Menu/Tests/Silex/RoutingExtensionTest.php
@@ -0,0 +1,82 @@
+<?php
+
+namespace Knp\Menu\Tests\Silex;
+
+use Knp\Menu\Silex\RoutingExtension;
+
+class RoutingExtensionTest extends \PHPUnit_Framework_TestCase
+{
+ public function setUp()
+ {
+ if (!interface_exists('Symfony\Component\Routing\Generator\UrlGeneratorInterface')) {
+ $this->markTestSkipped('The Symfony2 Routing component is not available');
+ }
+ }
+
+ public function testCreateItemWithRoute()
+ {
+ $generator = $this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface');
+ $generator->expects($this->once())
+ ->method('generate')
+ ->with('homepage', array(), false)
+ ->will($this->returnValue('/foobar'))
+ ;
+
+ $extension = new RoutingExtension($generator);
+
+ $processedOptions = $extension->buildOptions(array('uri' => '/hello', 'route' => 'homepage', 'label' => 'foo'));
+
+ $this->assertEquals('/foobar', $processedOptions['uri']);
+ $this->assertEquals('foo', $processedOptions['label']);
+ }
+
+ public function testCreateItemWithRouteAndParameters()
+ {
+ $generator = $this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface');
+ $generator->expects($this->once())
+ ->method('generate')
+ ->with('homepage', array('id' => 12), false)
+ ->will($this->returnValue('/foobar'))
+ ;
+
+ $extension = new RoutingExtension($generator);
+
+ $processedOptions = $extension->buildOptions(array('route' => 'homepage', 'routeParameters' => array('id' => 12)));
+
+ $this->assertEquals('/foobar', $processedOptions['uri']);
+ }
+
+ public function testCreateItemWithAbsoluteRoute()
+ {
+ $generator = $this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface');
+ $generator->expects($this->once())
+ ->method('generate')
+ ->with('homepage', array(), true)
+ ->will($this->returnValue('http://php.net'))
+ ;
+
+ $extension = new RoutingExtension($generator);
+
+ $processedOptions = $extension->buildOptions(array('route' => 'homepage', 'routeAbsolute' => true));
+
+ $this->assertEquals('http://php.net', $processedOptions['uri']);
+ }
+
+ public function testCreateItemAppendsRouteUnderExtras()
+ {
+ $generator = $this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface');
+
+ $extension = new RoutingExtension($generator);
+
+ $processedOptions = $extension->buildOptions( array('route' => 'homepage'));
+ $this->assertEquals(array(array('route' => 'homepage', 'parameters' => array())), $processedOptions['extras']['routes']);
+
+ $processedOptions = $extension->buildOptions( array('route' => 'homepage', 'routeParameters' => array('bar' => 'baz')));
+ $this->assertEquals(array(array('route' => 'homepage', 'parameters' => array('bar' => 'baz'))), $processedOptions['extras']['routes']);
+
+ $processedOptions = $extension->buildOptions( array('route' => 'homepage', 'extras' => array('routes' => array('other_page'))));
+ $this->assertContains(array('route' => 'homepage', 'parameters' => array()), $processedOptions['extras']['routes']);
+ $this->assertContains('other_page', $processedOptions['extras']['routes']);
+ }
+
+}
Please sign in to comment.
Something went wrong with that request. Please try again.