Procházet zdrojové kódy

Configuration to change breadcrumb uri for child admin (#4034)

Default object link at child admin in breadcrumb is to edit action. The idea is give a possibility to change it to other route.
Cassiano před 8 roky
rodič
revize
6b970e6e3b

+ 1 - 1
Admin/AbstractAdmin.php

@@ -2045,7 +2045,7 @@ EOT;
             E_USER_DEPRECATED
             E_USER_DEPRECATED
         );
         );
         if ($this->breadcrumbsBuilder === null) {
         if ($this->breadcrumbsBuilder === null) {
-            $this->breadcrumbsBuilder = new BreadcrumbsBuilder();
+            $this->breadcrumbsBuilder = new BreadcrumbsBuilder($this->getConfigurationPool()->getContainer()->getParameter('sonata.admin.configuration.breadcrumbs'));
         }
         }
 
 
         return $this->breadcrumbsBuilder;
         return $this->breadcrumbsBuilder;

+ 29 - 2
Admin/BreadcrumbsBuilder.php

@@ -12,6 +12,7 @@
 namespace Sonata\AdminBundle\Admin;
 namespace Sonata\AdminBundle\Admin;
 
 
 use Knp\Menu\ItemInterface;
 use Knp\Menu\ItemInterface;
+use Symfony\Component\OptionsResolver\OptionsResolver;
 
 
 /**
 /**
  * Stateless breadcrumbs builder (each method needs an Admin object).
  * Stateless breadcrumbs builder (each method needs an Admin object).
@@ -20,6 +21,32 @@ use Knp\Menu\ItemInterface;
  */
  */
 final class BreadcrumbsBuilder implements BreadcrumbsBuilderInterface
 final class BreadcrumbsBuilder implements BreadcrumbsBuilderInterface
 {
 {
+    /**
+     * @var string[]
+     */
+    protected $config = array();
+
+    /**
+     * @param string[] $config
+     */
+    public function __construct(array $config = array())
+    {
+        $resolver = new OptionsResolver();
+        $this->configureOptions($resolver);
+
+        $this->config = $resolver->resolve($config);
+    }
+
+    /**
+     * @param OptionsResolver $resolver
+     */
+    public function configureOptions(OptionsResolver $resolver)
+    {
+        $resolver->setDefaults(array(
+            'child_admin_route' => 'edit',
+        ));
+    }
+
     /**
     /**
      * {@inheritdoc}
      * {@inheritdoc}
      */
      */
@@ -82,8 +109,8 @@ final class BreadcrumbsBuilder implements BreadcrumbsBuilderInterface
             $menu = $menu->addChild(
             $menu = $menu->addChild(
                 $admin->toString($admin->getSubject()),
                 $admin->toString($admin->getSubject()),
                 array(
                 array(
-                    'uri' => $admin->hasRoute('edit') && $admin->isGranted('EDIT') ?
-                    $admin->generateUrl('edit', array('id' => $id)) :
+                    'uri' => $admin->hasRoute($this->config['child_admin_route']) && $admin->hasAccess($this->config['child_admin_route'], $admin->getSubject()) ?
+                    $admin->generateUrl($this->config['child_admin_route'], array('id' => $id)) :
                     null,
                     null,
                 )
                 )
             );
             );

+ 9 - 0
DependencyInjection/Configuration.php

@@ -73,6 +73,15 @@ class Configuration implements ConfigurationInterface
 
 
                 ->scalarNode('title')->defaultValue('Sonata Admin')->cannotBeEmpty()->end()
                 ->scalarNode('title')->defaultValue('Sonata Admin')->cannotBeEmpty()->end()
                 ->scalarNode('title_logo')->defaultValue('bundles/sonataadmin/logo_title.png')->cannotBeEmpty()->end()
                 ->scalarNode('title_logo')->defaultValue('bundles/sonataadmin/logo_title.png')->cannotBeEmpty()->end()
+                ->arrayNode('breadcrumbs')
+                    ->addDefaultsIfNotSet()
+                    ->children()
+                        ->scalarNode('child_admin_route')
+                            ->defaultValue('edit')
+                            ->info('Change the default route used to generate the link to the parent object, when in a child admin')
+                        ->end()
+                    ->end()
+                ->end()
                 ->arrayNode('options')
                 ->arrayNode('options')
                     ->addDefaultsIfNotSet()
                     ->addDefaultsIfNotSet()
                     ->children()
                     ->children()

+ 1 - 0
DependencyInjection/SonataAdminExtension.php

@@ -91,6 +91,7 @@ class SonataAdminExtension extends Extension implements PrependExtensionInterfac
         $container->setParameter('sonata.admin.configuration.dashboard_groups', $config['dashboard']['groups']);
         $container->setParameter('sonata.admin.configuration.dashboard_groups', $config['dashboard']['groups']);
         $container->setParameter('sonata.admin.configuration.dashboard_blocks', $config['dashboard']['blocks']);
         $container->setParameter('sonata.admin.configuration.dashboard_blocks', $config['dashboard']['blocks']);
         $container->setParameter('sonata.admin.configuration.sort_admins', $config['options']['sort_admins']);
         $container->setParameter('sonata.admin.configuration.sort_admins', $config['options']['sort_admins']);
+        $container->setParameter('sonata.admin.configuration.breadcrumbs', $config['breadcrumbs']);
 
 
         if (null === $config['security']['acl_user_manager'] && isset($bundles['FOSUserBundle'])) {
         if (null === $config['security']['acl_user_manager'] && isset($bundles['FOSUserBundle'])) {
             $container->setParameter('sonata.admin.security.acl_user_manager', 'fos_user.user_manager');
             $container->setParameter('sonata.admin.security.acl_user_manager', 'fos_user.user_manager');

+ 3 - 1
Resources/config/core.xml

@@ -24,7 +24,9 @@
             <argument type="service" id="service_container"/>
             <argument type="service" id="service_container"/>
             <argument/>
             <argument/>
         </service>
         </service>
-        <service id="sonata.admin.breadcrumbs_builder" class="Sonata\AdminBundle\Admin\BreadcrumbsBuilder"/>
+        <service id="sonata.admin.breadcrumbs_builder" class="Sonata\AdminBundle\Admin\BreadcrumbsBuilder">
+            <argument>%sonata.admin.configuration.breadcrumbs%</argument>
+        </service>
         <!-- Services used to format the label, default is sonata.admin.label.strategy.noop -->
         <!-- Services used to format the label, default is sonata.admin.label.strategy.noop -->
         <service id="sonata.admin.label.strategy.bc" class="Sonata\AdminBundle\Translator\BCLabelTranslatorStrategy"/>
         <service id="sonata.admin.label.strategy.bc" class="Sonata\AdminBundle\Translator\BCLabelTranslatorStrategy"/>
         <service id="sonata.admin.label.strategy.native" class="Sonata\AdminBundle\Translator\NativeLabelTranslatorStrategy"/>
         <service id="sonata.admin.label.strategy.native" class="Sonata\AdminBundle\Translator\NativeLabelTranslatorStrategy"/>

+ 13 - 0
Resources/doc/reference/breadcrumbs.rst

@@ -13,3 +13,16 @@ Getting the breadcrumbs for a given action of a given admin is done like this:
 
 
    <?php
    <?php
    $this->get('sonata.admin.breadcrumbs_builder')->getBreadcrumbs($admin, $action);
    $this->get('sonata.admin.breadcrumbs_builder')->getBreadcrumbs($admin, $action);
+
+Configuration
+-------------
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # app/config/config.yml
+
+        sonata_admin:
+            breadcrumbs:
+               # use this to change the default route used to generate the link to the parent object inside a breadcrumb, when in a child admin
+               child_admin_route: edit

+ 18 - 1
Tests/Admin/AdminTest.php

@@ -1768,9 +1768,26 @@ class AdminTest extends \PHPUnit_Framework_TestCase
      */
      */
     public function testDefaultBreadcrumbsBuilder()
     public function testDefaultBreadcrumbsBuilder()
     {
     {
+        $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
+        $container->expects($this->once())
+            ->method('getParameter')
+            ->with('sonata.admin.configuration.breadcrumbs')
+            ->will($this->returnValue(array()));
+
+        $pool = $this->getMockBuilder('Sonata\AdminBundle\Admin\Pool')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $pool->expects($this->once())
+            ->method('getContainer')
+            ->will($this->returnValue($container));
+
         $admin = $this->getMockForAbstractClass('Sonata\AdminBundle\Admin\AbstractAdmin', array(
         $admin = $this->getMockForAbstractClass('Sonata\AdminBundle\Admin\AbstractAdmin', array(
             'admin.my_code', 'My\Class', 'MyBundle:ClassAdmin',
             'admin.my_code', 'My\Class', 'MyBundle:ClassAdmin',
-        ));
+        ), '', true, true, true, array('getConfigurationPool'));
+        $admin->expects($this->once())
+            ->method('getConfigurationPool')
+            ->will($this->returnValue($pool));
+
         $this->assertInstanceOf(
         $this->assertInstanceOf(
             'Sonata\AdminBundle\Admin\BreadcrumbsBuilder',
             'Sonata\AdminBundle\Admin\BreadcrumbsBuilder',
             $admin->getBreadcrumbsBuilder()
             $admin->getBreadcrumbsBuilder()

+ 34 - 1
Tests/Admin/BreadcrumbsBuilderTest.php

@@ -64,6 +64,19 @@ class BreadcrumbsBuilderTest extends \PHPUnit_Framework_TestCase
             'Sonata\AdminBundle\Model\ModelManagerInterface'
             'Sonata\AdminBundle\Model\ModelManagerInterface'
         );
         );
 
 
+        $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
+        $container->expects($this->any())
+            ->method('getParameter')
+            ->with('sonata.admin.configuration.breadcrumbs')
+            ->will($this->returnValue(array()));
+        $pool = $this->getMockBuilder('Sonata\AdminBundle\Admin\Pool')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $pool->expects($this->any())
+            ->method('getContainer')
+            ->will($this->returnValue($container));
+
+        $admin->setConfigurationPool($pool);
         $admin->setMenuFactory($menuFactory);
         $admin->setMenuFactory($menuFactory);
         $admin->setLabelTranslatorStrategy($translatorStrategy);
         $admin->setLabelTranslatorStrategy($translatorStrategy);
         $admin->setRouteGenerator($routeGenerator);
         $admin->setRouteGenerator($routeGenerator);
@@ -184,6 +197,7 @@ class BreadcrumbsBuilderTest extends \PHPUnit_Framework_TestCase
         $admin->setSubject(new DummySubject());
         $admin->setSubject(new DummySubject());
         $admin->getBreadcrumbs('flag');
         $admin->getBreadcrumbs('flag');
 
 
+        $commentAdmin->setConfigurationPool($pool);
         $commentAdmin->getBreadcrumbs('edit');
         $commentAdmin->getBreadcrumbs('edit');
 
 
         $commentAdmin->getBreadcrumbs('list');
         $commentAdmin->getBreadcrumbs('list');
@@ -260,6 +274,20 @@ class BreadcrumbsBuilderTest extends \PHPUnit_Framework_TestCase
             )
             )
             ->will($this->returnValue($menu));
             ->will($this->returnValue($menu));
 
 
+        $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
+        $container->expects($this->any())
+            ->method('getParameter')
+            ->with('sonata.admin.configuration.breadcrumbs')
+            ->will($this->returnValue(array()));
+        $pool = $this->getMockBuilder('Sonata\AdminBundle\Admin\Pool')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $pool->expects($this->any())
+            ->method('getContainer')
+            ->will($this->returnValue($container));
+
+        $admin->setConfigurationPool($pool);
+
         $admin->getBreadcrumbs('repost');
         $admin->getBreadcrumbs('repost');
         $admin->setSubject(new DummySubject());
         $admin->setSubject(new DummySubject());
         $flagBreadcrumb = $admin->getBreadcrumbs('flag');
         $flagBreadcrumb = $admin->getBreadcrumbs('flag');
@@ -287,7 +315,7 @@ class BreadcrumbsBuilderTest extends \PHPUnit_Framework_TestCase
         $leafMenu->getParent()->willReturn($childMenu);
         $leafMenu->getParent()->willReturn($childMenu);
 
 
         $action = 'my_action';
         $action = 'my_action';
-        $breadcrumbsBuilder = new BreadcrumbsBuilder();
+        $breadcrumbsBuilder = new BreadcrumbsBuilder(array('child_admin_route' => 'show'));
         $admin = $this->prophesize('Sonata\AdminBundle\Admin\AbstractAdmin');
         $admin = $this->prophesize('Sonata\AdminBundle\Admin\AbstractAdmin');
         $admin->isChild()->willReturn(false);
         $admin->isChild()->willReturn(false);
 
 
@@ -341,6 +369,11 @@ class BreadcrumbsBuilderTest extends \PHPUnit_Framework_TestCase
         $childAdmin->getSubject()->willReturn('my subject');
         $childAdmin->getSubject()->willReturn('my subject');
         $childAdmin->toString('my subject')->willReturn('My subject');
         $childAdmin->toString('my subject')->willReturn('My subject');
 
 
+        $admin->hasAccess('show', 'my subject')->willReturn(true)->shouldBeCalled();
+        $admin->hasRoute('show')->willReturn(true);
+        $admin->generateUrl('show', array('id' => 'my-object'))->willReturn('/myadmin/my-object');
+
+        $admin->trans('My class', array(), null)->willReturn('Ma classe');
         $admin->hasRoute('list')->willReturn(true);
         $admin->hasRoute('list')->willReturn(true);
         $admin->isGranted('LIST')->willReturn(true);
         $admin->isGranted('LIST')->willReturn(true);
         $admin->generateUrl('list')->willReturn('/myadmin/list');
         $admin->generateUrl('list')->willReturn('/myadmin/list');

+ 7 - 0
Tests/DependencyInjection/ConfigurationTest.php

@@ -26,6 +26,13 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
         $this->assertTrue($config['options']['use_icheck']);
         $this->assertTrue($config['options']['use_icheck']);
     }
     }
 
 
+    public function testBreadcrumbsChildRouteDefaultsToEdit()
+    {
+        $config = $this->process(array());
+
+        $this->assertSame('edit', $config['breadcrumbs']['child_admin_route']);
+    }
+
     public function testOptionsWithInvalidFormat()
     public function testOptionsWithInvalidFormat()
     {
     {
         $this->setExpectedException('Symfony\Component\Config\Definition\Exception\InvalidTypeException');
         $this->setExpectedException('Symfony\Component\Config\Definition\Exception\InvalidTypeException');