Browse Source

Added url list type

Andrej Hudec 11 years ago
parent
commit
2ff32cde33

+ 48 - 11
Resources/doc/reference/field_types.rst

@@ -6,18 +6,19 @@ List and Show Actions
 
 There are many field types that can be used in the list action or show action :
 
-* array: display value from an array
-* boolean: display a green or red picture dependant on the boolean value, this type accepts an ``editable``
+* **array**: display value from an array
+* **boolean**: display a green or red picture dependant on the boolean value, this type accepts an ``editable``
   parameter to edit the value from within the list or the show actions
-* date: display a formatted date. Accepts an optional ``format`` parameter
-* datetime: display a formatted date and time. Accepts an optional ``format`` parameter
-* text: display a text
-* trans: translate the value with a provided ``catalogue`` option
-* string: display a text
-* decimal: display a number
-* currency: display a number with a provided ``currency`` option
-* percent: display a percentage
-* choice: uses the given value as index for the ``choices`` array and displays (and optionally translates) the matching value
+* **date**: display a formatted date. Accepts an optional ``format`` parameter
+* **datetime**: display a formatted date and time. Accepts an optional ``format`` parameter
+* **text**: display a text
+* **trans**: translate the value with a provided ``catalogue`` option
+* **string**: display a text
+* **decimal**: display a number
+* **currency**: display a number with a provided ``currency`` option
+* **percent**: display a percentage
+* **choice**: uses the given value as index for the ``choices`` array and displays (and optionally translates) the matching value
+* **url**: display a link
 
 Choice
 ^^^^^^
@@ -34,6 +35,42 @@ Choice
     // For value ``array('r', 'b')`` is displayed `text ``red | blue``.
     $listMapper->add('colors', 'choice', array('multiple'=>true, 'delimiter'=>' | ', 'choices'=>array('r'=>'red', 'g'=>'green', 'b'=>'blue')));
 
+Url
+^^^
+
+Display url link to external website or controller's action.
+
+
+Parameters:
+
+* **hide_protocol**: remove protocol part from the link text
+* **url**: url address (e.g. ``http://example.com``)
+* **route.name**: route name (e.g. ``acme_demo_homepage``)
+* **route.parameters**: array of route parameters (e.g. ``array('type'=>'example', 'display'=>'full')``)
+* **route.absolute**: boolean value, create absolute or relative url address based on ``route.name`` and  ``route.parameters`` (defalut ``false``)
+* **route.identifier_parameter_name**: parameter added to ``route.parameters``, it's value is an object identifier (e.g. 'id') to create dynamic links based on rendered objects.
+
+.. code-block:: php
+
+    // Output for value ``http://example.com``: ``<a href="http://example.com">http://example.com</a>``
+    $listMapper->add('targetUrl', 'url');
+
+    // Output for value ``http://example.com``: ``<a href="http://example.com">example.com</a>``
+    $listMapper->add('targetUrl', 'url', array('hide_protocol' => true));
+
+    // Output for value ``Homepage of example.com`` : ``<a href="http://example.com">Homepage of example.com</a>``
+    $listMapper->add('title', 'url', array('url' => 'http://example.com'));
+
+    // Output for value ``Acme Blog Homepage``: ``<a href="http://blog.example.com">Acme Blog Homepage</a>``
+    $listMapper->add('title', 'url', array('route' => array('name'=>'acme_blog_homepage', 'absolute'=>true)));
+
+    // Output for value ``Sonata is great!`` (related object has identifier ``123``): ``<a href="http://blog.example.com/xml/123">Sonata is great!</a>``
+    $listMapper->add('title', 'url', array('route' => array('name'=>'acme_blog_article', 'absolute'=>true, 'parameters'=>array('format'=>'xml'), 'identifier_parameter_name'=>'id')));
+
+.. note::
+
+    Do not use ``url`` type with ``addIdentifier`` method, because it will create invalid nested urls.
+
 .. note::
 
     If the ``SonataIntlBundle`` is installed in the project some template types

+ 48 - 0
Resources/views/CRUD/list_url.html.twig

@@ -0,0 +1,48 @@
+{#
+
+This file is part of the Sonata package.
+
+(c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
+
+For the full copyright and license information, please view the LICENSE
+file that was distributed with this source code.
+
+#}
+
+{% extends admin.getTemplate('base_list_field') %}
+
+{% block field %}
+{% spaceless %}
+    {% if value is empty %}
+        &nbsp;
+    {% else %}
+        {% if field_description.options.url is defined %}
+            {# target url is string #}
+            {% set url_address = field_description.options.url %}
+        {% elseif field_description.options.route is defined and field_description.options.route.name not in ['edit', 'show'] %}
+            {# target url is Symfony route #}
+            {% set parameters = field_description.options.route.parameters|default([]) %}
+
+            {# route with paramter related to object ID #}
+            {% if field_description.options.route.identifier_parameter_name is defined %}
+                {% set parameters = parameters|merge({(field_description.options.route.identifier_parameter_name):(admin.normalizedidentifier(object))}) %}
+            {% endif %}
+
+            {% if field_description.options.route.absolute|default(false) %}
+                {% set url_address = url(field_description.options.route.name, parameters) %}
+            {% else %}
+                {% set url_address = path(field_description.options.route.name, parameters) %}
+            {% endif %}
+        {% else %}
+            {# value is url #}
+            {% set url_address = value %}
+        {% endif %}
+
+        {% if field_description.options.hide_protocol|default(false) %}
+            {% set value = value|replace({'http://': '', 'https://': ''}) %}
+        {% endif %}
+
+        <a href="{{ url_address }}">{{ value }}</a>
+    {% endif %}
+{% endspaceless %}
+{% endblock %}

+ 54 - 0
Resources/views/CRUD/show_url.html.twig

@@ -0,0 +1,54 @@
+{#
+
+This file is part of the Sonata package.
+
+(c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
+
+For the full copyright and license information, please view the LICENSE
+file that was distributed with this source code.
+
+#}
+
+{% extends 'SonataAdminBundle:CRUD:base_show_field.html.twig' %}
+
+{% block field %}
+{% spaceless %}
+    {% if value is empty %}
+        &nbsp;
+    {% else %}
+        {% if field_description.options.url is defined %}
+            {# target url is string #}
+            {% set url_address = field_description.options.url %}
+        {% elseif field_description.options.route is defined and field_description.options.route.name not in ['edit', 'show'] %}
+            {# target url is Symfony route #}
+            {% set parameters = field_description.options.route.parameters|default([]) %}
+
+            {# route with paramter related to object ID #}
+            {% if field_description.options.route.identifier_parameter_name is defined %}
+                {% set parameters = parameters|merge({(field_description.options.route.identifier_parameter_name):(admin.normalizedidentifier(object))}) %}
+            {% endif %}
+
+            {% if field_description.options.route.absolute|default(false) %}
+                {% set url_address = url(field_description.options.route.name, parameters) %}
+            {% else %}
+                {% set url_address = path(field_description.options.route.name, parameters) %}
+            {% endif %}
+        {% else %}
+            {# value is url #}
+            {% set url_address = value %}
+        {% endif %}
+
+        {% if field_description.options.hide_protocol|default(false) %}
+            {% set value = value|replace({'http://': '', 'https://': ''}) %}
+        {% endif %}
+
+        <a href="{{ url_address }}">
+            {%- if field_description.options.safe -%}
+                {{- value|raw -}}
+            {%- else -%}
+                {{- value -}}
+            {%- endif -%}
+        </a>
+    {% endif %}
+{% endspaceless %}
+{% endblock %}

+ 18 - 0
Tests/Fixtures/Resources/config/routing/routing.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<routes xmlns="http://symfony.com/schema/routing"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
+
+    <route id="sonata_admin_foo" pattern="/foo">
+        <default key="_controller">SonataAdminBundle:RouteAdminController:foo</default>
+    </route>
+
+    <route id="sonata_admin_foo_param" pattern="/foo/{param1}/{param2}">
+        <default key="_controller">SonataAdminBundle:RouteAdminController:fooParam</default>
+    </route>
+
+    <route id="sonata_admin_foo_object" pattern="/foo/obj/{param1}/{barId}/{param2}">
+        <default key="_controller">SonataAdminBundle:RouteAdminController:fooObject</default>
+    </route>
+</routes>

+ 54 - 0
Tests/Twig/Extension/SonataAdminExtensionTest.php

@@ -89,6 +89,11 @@ class SonataAdminExtensionTest extends \PHPUnit_Framework_TestCase
         // routing extension
         $xmlFileLoader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../../../Resources/config/routing')));
         $routeCollection = $xmlFileLoader->load('sonata_admin.xml');
+
+        $xmlFileLoader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../../Fixtures/Resources/config/routing')));
+        $testRouteCollection = $xmlFileLoader->load('routing.xml');
+
+        $routeCollection->addCollection($testRouteCollection);
         $requestContext = new RequestContext();
         $urlGenerator = new UrlGenerator($routeCollection, $requestContext);
         $this->environment->addExtension(new RoutingExtension($urlGenerator));
@@ -114,6 +119,11 @@ class SonataAdminExtensionTest extends \PHPUnit_Framework_TestCase
             ->with($this->equalTo($this->object))
             ->will($this->returnValue(12345));
 
+        $this->admin->expects($this->any())
+            ->method('getNormalizedIdentifier')
+            ->with($this->equalTo($this->object))
+            ->will($this->returnValue(12345));
+
         $this->admin->expects($this->any())
             ->method('trans')
             ->will($this->returnCallback(function($id) {
@@ -204,6 +214,8 @@ class SonataAdminExtensionTest extends \PHPUnit_Framework_TestCase
                         return 'SonataAdminBundle:CRUD:list_array.html.twig';
                     case 'trans':
                         return 'SonataAdminBundle:CRUD:list_trans.html.twig';
+                    case 'url':
+                        return 'SonataAdminBundle:CRUD:list_url.html.twig';
                     case 'nonexistent':
                         // template doesn`t exist
                         return 'SonataAdminBundle:CRUD:list_nonexistent_template.html.twig';
@@ -257,6 +269,7 @@ class SonataAdminExtensionTest extends \PHPUnit_Framework_TestCase
             array('<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> Delete </td>', 'trans', 'action_delete', array('catalogue'=>'SonataAdminBundle')),
             array('<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> </td>', 'trans', null, array('catalogue'=>'SonataAdminBundle')),
             array('<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Status1 </td>', 'choice', 'Status1', array()),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Status1 </td>', 'choice', array('Status1'), array('choices'=>array(), 'multiple'=>true)),
             array('<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1 </td>', 'choice', 'Status1', array('choices'=>array('Status1'=>'Alias1', 'Status2'=>'Alias2', 'Status3'=>'Alias3'))),
             array('<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> </td>', 'choice', null, array('choices'=>array('Status1'=>'Alias1', 'Status2'=>'Alias2', 'Status3'=>'Alias3'))),
             array('<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> NoValidKeyInChoices </td>', 'choice', 'NoValidKeyInChoices', array('choices'=>array('Status1'=>'Alias1', 'Status2'=>'Alias2', 'Status3'=>'Alias3'))),
@@ -268,6 +281,25 @@ class SonataAdminExtensionTest extends \PHPUnit_Framework_TestCase
             array('<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> NoValidKeyInChoices, Alias2 </td>', 'choice', array('NoValidKeyInChoices', 'Status2'), array('choices'=>array('Status1'=>'Alias1', 'Status2'=>'Alias2', 'Status3'=>'Alias3'), 'multiple'=>true)),
             array('<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Delete, Alias3 </td>', 'choice', array('Foo', 'Status3'), array('catalogue'=>'SonataAdminBundle', 'choices'=>array('Foo'=>'action_delete', 'Status2'=>'Alias2', 'Status3'=>'Alias3'), 'multiple'=>true)),
             array('<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> &lt;b&gt;Alias1&lt;/b&gt;, &lt;b&gt;Alias3&lt;/b&gt; </td>', 'choice', array('Status1', 'Status3'), array('choices'=>array('Status1'=>'<b>Alias1</b>', 'Status2'=>'<b>Alias2</b>', 'Status3'=>'<b>Alias3</b>'), 'multiple'=>true)),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>', 'url', null, array()),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>', 'url', null, array('url'=>'http://example.com')),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>', 'url', null, array('route'=>array('name'=>'sonata_admin_foo'))),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> <a href="http://example.com">http://example.com</a> </td>', 'url', 'http://example.com', array()),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> <a href="https://example.com">https://example.com</a> </td>', 'url', 'https://example.com', array()),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> <a href="http://example.com">example.com</a> </td>', 'url', 'http://example.com', array('hide_protocol'=>true)),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> <a href="https://example.com">example.com</a> </td>', 'url', 'https://example.com', array('hide_protocol'=>true)),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> <a href="http://example.com">http://example.com</a> </td>', 'url', 'http://example.com', array('hide_protocol'=>false)),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> <a href="https://example.com">https://example.com</a> </td>', 'url', 'https://example.com', array('hide_protocol'=>false)),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> <a href="http://example.com">Foo</a> </td>', 'url', 'Foo', array('url'=>'http://example.com')),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> <a href="http://example.com">&lt;b&gt;Foo&lt;/b&gt;</a> </td>', 'url', '<b>Foo</b>', array('url'=>'http://example.com')),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> <a href="/foo">Foo</a> </td>', 'url', 'Foo', array('route'=>array('name'=>'sonata_admin_foo'))),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> <a href="http://localhost/foo">Foo</a> </td>', 'url', 'Foo', array('route'=>array('name'=>'sonata_admin_foo', 'absolute'=>true))),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> <a href="/foo">foo/bar?a=b&amp;c=123456789</a> </td>', 'url', 'http://foo/bar?a=b&c=123456789', array('route'=>array('name'=>'sonata_admin_foo'), 'hide_protocol'=>true)),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> <a href="http://localhost/foo">foo/bar?a=b&amp;c=123456789</a> </td>', 'url', 'http://foo/bar?a=b&c=123456789', array('route'=>array('name'=>'sonata_admin_foo', 'absolute'=>true), 'hide_protocol'=>true)),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> <a href="/foo/abcd/efgh?param3=ijkl">Foo</a> </td>', 'url', 'Foo', array('route'=>array('name'=>'sonata_admin_foo_param', 'parameters'=>array('param1'=>'abcd', 'param2'=>'efgh', 'param3'=>'ijkl')))),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> <a href="http://localhost/foo/abcd/efgh?param3=ijkl">Foo</a> </td>', 'url', 'Foo', array('route'=>array('name'=>'sonata_admin_foo_param', 'absolute'=>true, 'parameters'=>array('param1'=>'abcd', 'param2'=>'efgh', 'param3'=>'ijkl')))),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> <a href="/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a> </td>', 'url', 'Foo', array('route'=>array('name'=>'sonata_admin_foo_object', 'parameters'=>array('param1'=>'abcd', 'param2'=>'efgh', 'param3'=>'ijkl'), 'identifier_parameter_name'=>'barId'))),
+            array('<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> <a href="http://localhost/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a> </td>', 'url', 'Foo', array('route'=>array('name'=>'sonata_admin_foo_object', 'absolute'=>true, 'parameters'=>array('param1'=>'abcd', 'param2'=>'efgh', 'param3'=>'ijkl'), 'identifier_parameter_name'=>'barId'))),
         );
     }
 
@@ -320,6 +352,8 @@ class SonataAdminExtensionTest extends \PHPUnit_Framework_TestCase
                         return 'SonataAdminBundle:CRUD:show_array.html.twig';
                     case 'trans':
                         return 'SonataAdminBundle:CRUD:show_trans.html.twig';
+                    case 'url':
+                        return 'SonataAdminBundle:CRUD:show_url.html.twig';
                     default:
                         return false;
                 }
@@ -359,6 +393,23 @@ class SonataAdminExtensionTest extends \PHPUnit_Framework_TestCase
             array('<th>Data</th> <td>Delete, Alias3</td>', 'choice', array('Foo', 'Status3'), array('safe'=>false, 'catalogue'=>'SonataAdminBundle', 'choices'=>array('Foo'=>'action_delete', 'Status2'=>'Alias2', 'Status3'=>'Alias3'), 'multiple'=>true,)),
             array('<th>Data</th> <td><b>Alias1</b>, <b>Alias3</b></td>', 'choice', array('Status1', 'Status3'), array('safe'=>true, 'choices'=>array('Status1'=>'<b>Alias1</b>', 'Status2'=>'<b>Alias2</b>', 'Status3'=>'<b>Alias3</b>'), 'multiple'=>true,)),
             array('<th>Data</th> <td>&lt;b&gt;Alias1&lt;/b&gt;, &lt;b&gt;Alias3&lt;/b&gt;</td>', 'choice', array('Status1', 'Status3'), array('safe'=>false, 'choices'=>array('Status1'=>'<b>Alias1</b>', 'Status2'=>'<b>Alias2</b>', 'Status3'=>'<b>Alias3</b>'), 'multiple'=>true,)),
+            array('<th>Data</th> <td><a href="http://example.com">http://example.com</a></td>', 'url', 'http://example.com', array('safe'=>false)),
+            array('<th>Data</th> <td><a href="https://example.com">https://example.com</a></td>', 'url', 'https://example.com', array('safe'=>false)),
+            array('<th>Data</th> <td><a href="http://example.com">example.com</a></td>', 'url', 'http://example.com', array('safe'=>false, 'hide_protocol'=>true)),
+            array('<th>Data</th> <td><a href="https://example.com">example.com</a></td>', 'url', 'https://example.com', array('safe'=>false, 'hide_protocol'=>true)),
+            array('<th>Data</th> <td><a href="http://example.com">http://example.com</a></td>', 'url', 'http://example.com', array('safe'=>false, 'hide_protocol'=>false)),
+            array('<th>Data</th> <td><a href="https://example.com">https://example.com</a></td>', 'url', 'https://example.com', array('safe'=>false, 'hide_protocol'=>false)),
+            array('<th>Data</th> <td><a href="http://example.com">Foo</a></td>', 'url', 'Foo', array('safe'=>false, 'url'=>'http://example.com')),
+            array('<th>Data</th> <td><a href="http://example.com">&lt;b&gt;Foo&lt;/b&gt;</a></td>', 'url', '<b>Foo</b>', array('safe'=>false, 'url'=>'http://example.com')),
+            array('<th>Data</th> <td><a href="http://example.com"><b>Foo</b></a></td>', 'url', '<b>Foo</b>', array('safe'=>true, 'url'=>'http://example.com')),
+            array('<th>Data</th> <td><a href="/foo">Foo</a></td>', 'url', 'Foo', array('safe'=>false, 'route'=>array('name'=>'sonata_admin_foo'))),
+            array('<th>Data</th> <td><a href="http://localhost/foo">Foo</a></td>', 'url', 'Foo', array('safe'=>false, 'route'=>array('name'=>'sonata_admin_foo', 'absolute'=>true))),
+            array('<th>Data</th> <td><a href="/foo">foo/bar?a=b&amp;c=123456789</a></td>', 'url', 'http://foo/bar?a=b&c=123456789', array('safe'=>false, 'route'=>array('name'=>'sonata_admin_foo'), 'hide_protocol'=>true)),
+            array('<th>Data</th> <td><a href="http://localhost/foo">foo/bar?a=b&amp;c=123456789</a></td>', 'url', 'http://foo/bar?a=b&c=123456789', array('safe'=>false, 'route'=>array('name'=>'sonata_admin_foo', 'absolute'=>true), 'hide_protocol'=>true)),
+            array('<th>Data</th> <td><a href="/foo/abcd/efgh?param3=ijkl">Foo</a></td>', 'url', 'Foo', array('safe'=>false, 'route'=>array('name'=>'sonata_admin_foo_param', 'parameters'=>array('param1'=>'abcd', 'param2'=>'efgh', 'param3'=>'ijkl')))),
+            array('<th>Data</th> <td><a href="http://localhost/foo/abcd/efgh?param3=ijkl">Foo</a></td>', 'url', 'Foo', array('safe'=>false, 'route'=>array('name'=>'sonata_admin_foo_param', 'absolute'=>true, 'parameters'=>array('param1'=>'abcd', 'param2'=>'efgh', 'param3'=>'ijkl')))),
+            array('<th>Data</th> <td><a href="/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a></td>', 'url', 'Foo', array('safe'=>false, 'route'=>array('name'=>'sonata_admin_foo_object', 'parameters'=>array('param1'=>'abcd', 'param2'=>'efgh', 'param3'=>'ijkl'), 'identifier_parameter_name'=>'barId'))),
+            array('<th>Data</th> <td><a href="http://localhost/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a></td>', 'url', 'Foo', array('safe'=>false, 'route'=>array('name'=>'sonata_admin_foo_object', 'absolute'=>true, 'parameters'=>array('param1'=>'abcd', 'param2'=>'efgh', 'param3'=>'ijkl'), 'identifier_parameter_name'=>'barId'))),
 
             // NoValueException
             array('<th>Data</th> <td></td>', 'string', new NoValueException(), array('safe' => false)),
@@ -379,6 +430,9 @@ class SonataAdminExtensionTest extends \PHPUnit_Framework_TestCase
             array('<th>Data</th> <td> </td>', 'trans', new NoValueException(), array('safe'=>false, 'catalogue'=>'SonataAdminBundle')),
             array('<th>Data</th> <td></td>', 'choice', new NoValueException(), array('safe'=>false, 'choices'=>array())),
             array('<th>Data</th> <td></td>', 'choice', new NoValueException(), array('safe'=>false, 'choices'=>array(), 'multiple'=>true)),
+            array('<th>Data</th> <td>&nbsp;</td>', 'url', new NoValueException(), array()),
+            array('<th>Data</th> <td>&nbsp;</td>', 'url', new NoValueException(), array('url'=>'http://example.com')),
+            array('<th>Data</th> <td>&nbsp;</td>', 'url', new NoValueException(), array('route'=>array('name'=>'sonata_admin_foo'))),
         );
     }