Browse Source

#4036 Add priority support for admin extensions (#4298)

Sam Van der Borght 8 years ago
parent
commit
aaf5cb1a65

+ 42 - 9
DependencyInjection/Compiler/ExtensionCompilerPass.php

@@ -27,6 +27,7 @@ class ExtensionCompilerPass implements CompilerPassInterface
     public function process(ContainerBuilder $container)
     public function process(ContainerBuilder $container)
     {
     {
         $universalExtensions = array();
         $universalExtensions = array();
+        $targets = array();
 
 
         foreach ($container->findTaggedServiceIds('sonata.admin.extension') as $id => $tags) {
         foreach ($container->findTaggedServiceIds('sonata.admin.extension') as $id => $tags) {
             foreach ($tags as $attributes) {
             foreach ($tags as $attributes) {
@@ -37,17 +38,14 @@ class ExtensionCompilerPass implements CompilerPassInterface
                 }
                 }
 
 
                 if (isset($attributes['global']) && $attributes['global']) {
                 if (isset($attributes['global']) && $attributes['global']) {
-                    $universalExtensions[] = $id;
+                    $universalExtensions[$id] = $attributes;
                 }
                 }
 
 
                 if (!$target || !$container->hasDefinition($target)) {
                 if (!$target || !$container->hasDefinition($target)) {
                     continue;
                     continue;
                 }
                 }
 
 
-                $container
-                    ->getDefinition($target)
-                    ->addMethodCall('addExtension', array(new Reference($id)))
-                ;
+                $this->addExtension($targets, $target, $id, $attributes);
             }
             }
         }
         }
 
 
@@ -57,17 +55,34 @@ class ExtensionCompilerPass implements CompilerPassInterface
         foreach ($container->findTaggedServiceIds('sonata.admin') as $id => $attributes) {
         foreach ($container->findTaggedServiceIds('sonata.admin') as $id => $attributes) {
             $admin = $container->getDefinition($id);
             $admin = $container->getDefinition($id);
 
 
-            foreach ($universalExtensions as $extension) {
-                $admin->addMethodCall('addExtension', array(new Reference($extension)));
+            if (!isset($targets[$id])) {
+                $targets[$id] = new \SplPriorityQueue();
+            }
+
+            foreach ($universalExtensions as $extension => $extensionAttributes) {
+                $this->addExtension($targets, $id, $extension, $extensionAttributes);
             }
             }
 
 
             $extensions = $this->getExtensionsForAdmin($id, $admin, $container, $extensionMap);
             $extensions = $this->getExtensionsForAdmin($id, $admin, $container, $extensionMap);
 
 
             foreach ($extensions as $extension) {
             foreach ($extensions as $extension) {
                 if (!$container->has($extension)) {
                 if (!$container->has($extension)) {
-                    throw new \InvalidArgumentException(sprintf('Unable to find extension service for id %s', $extension));
+                    throw new \InvalidArgumentException(
+                        sprintf('Unable to find extension service for id %s', $extension)
+                    );
                 }
                 }
-                $admin->addMethodCall('addExtension', array(new Reference($extension)));
+
+                $this->addExtension($targets, $id, $extension, $attributes);
+            }
+        }
+
+        foreach ($targets as $target => $extensions) {
+            $extensions = iterator_to_array($extensions);
+            krsort($extensions);
+            $admin = $container->getDefinition($target);
+
+            foreach (array_values($extensions) as $extension) {
+                $admin->addMethodCall('addExtension', array($extension));
             }
             }
         }
         }
     }
     }
@@ -197,4 +212,22 @@ class ExtensionCompilerPass implements CompilerPassInterface
 
 
         return $this->hasTrait($parentClass, $traitName);
         return $this->hasTrait($parentClass, $traitName);
     }
     }
+
+    /**
+     * Add extension configuration to the targets array.
+     *
+     * @param array  $targets
+     * @param string $target
+     * @param string $extension
+     * @param array  $attributes
+     */
+    private function addExtension(array &$targets, $target, $extension, $attributes)
+    {
+        if (!isset($targets[$target])) {
+            $targets[$target] = new \SplPriorityQueue();
+        }
+
+        $priority = isset($attributes['priority']) ? $attributes['priority'] : 0;
+        $targets[$target]->insert(new Reference($extension), $priority);
+    }
 }
 }

+ 7 - 0
Resources/doc/reference/extensions.rst

@@ -35,6 +35,8 @@ You can include this information in the service definition of your extension.
 Add the tag *sonata.admin.extension* and use the *target* attribute to point to
 Add the tag *sonata.admin.extension* and use the *target* attribute to point to
 the admin you want to modify. Please note you can specify as many tags you want.
 the admin you want to modify. Please note you can specify as many tags you want.
 Set the *global* attribute to *true* and the extension will be added to all admins.
 Set the *global* attribute to *true* and the extension will be added to all admins.
+The *priority* attribute is *0* by default and can be a positive or negative integer.
+The higher the priority, the earlier it's executed.
 
 
 .. configuration-block::
 .. configuration-block::
 
 
@@ -52,6 +54,11 @@ Set the *global* attribute to *true* and the extension will be added to all admi
                 tags:
                 tags:
                     - { name: sonata.admin.extension, global: true }
                     - { name: sonata.admin.extension, global: true }
 
 
+            app.important.extension:
+                class: AppBundle\Admin\Extension\ImportantAdminExtension
+                tags:
+                    - { name: sonata.admin.extension, priority: 5 }
+
 The second option is to add it to your config.yml file.
 The second option is to add it to your config.yml file.
 
 
 .. configuration-block::
 .. configuration-block::

+ 4 - 4
Tests/DependencyInjection/Compiler/ExtensionCompilerPassTest.php

@@ -251,8 +251,8 @@ class ExtensionCompilerPassTest extends PHPUnit_Framework_TestCase
         $this->assertCount(4, $extensions);
         $this->assertCount(4, $extensions);
 
 
         $this->assertInstanceOf(get_class($this->securityExtension), $extensions[0]);
         $this->assertInstanceOf(get_class($this->securityExtension), $extensions[0]);
-        $this->assertInstanceOf(get_class($this->publishExtension), $extensions[2]);
-        $this->assertInstanceOf(get_class($this->historyExtension), $extensions[3]);
+        $this->assertInstanceOf(get_class($this->publishExtension), $extensions[1]);
+        $this->assertInstanceOf(get_class($this->historyExtension), $extensions[2]);
 
 
         $def = $container->get('sonata_article_admin');
         $def = $container->get('sonata_article_admin');
         $extensions = $def->getExtensions();
         $extensions = $def->getExtensions();
@@ -260,7 +260,7 @@ class ExtensionCompilerPassTest extends PHPUnit_Framework_TestCase
 
 
         $this->assertInstanceOf(get_class($this->securityExtension), $extensions[0]);
         $this->assertInstanceOf(get_class($this->securityExtension), $extensions[0]);
         $this->assertInstanceOf(get_class($this->publishExtension), $extensions[1]);
         $this->assertInstanceOf(get_class($this->publishExtension), $extensions[1]);
-        $this->assertInstanceOf(get_class($this->orderExtension), $extensions[3]);
+        $this->assertInstanceOf(get_class($this->orderExtension), $extensions[2]);
         $this->assertInstanceOf(get_class($this->filterExtension), $extensions[4]);
         $this->assertInstanceOf(get_class($this->filterExtension), $extensions[4]);
 
 
         $def = $container->get('sonata_news_admin');
         $def = $container->get('sonata_news_admin');
@@ -268,7 +268,7 @@ class ExtensionCompilerPassTest extends PHPUnit_Framework_TestCase
         $this->assertCount(5, $extensions);
         $this->assertCount(5, $extensions);
         $this->assertInstanceOf(get_class($this->securityExtension), $extensions[0]);
         $this->assertInstanceOf(get_class($this->securityExtension), $extensions[0]);
         $this->assertInstanceOf(get_class($this->orderExtension), $extensions[1]);
         $this->assertInstanceOf(get_class($this->orderExtension), $extensions[1]);
-        $this->assertInstanceOf(get_class($this->historyExtension), $extensions[3]);
+        $this->assertInstanceOf(get_class($this->historyExtension), $extensions[2]);
         $this->assertInstanceOf(get_class($this->filterExtension), $extensions[4]);
         $this->assertInstanceOf(get_class($this->filterExtension), $extensions[4]);
     }
     }