Browse Source

changed the bundle name to be the class name of the bundle, not the last part of the namespace

Let's take some examples to explain the change.

First, if you don't use any vendored bundles, this commit does not change anything.

So, let's say you use a FooBundle from Sensio. The files are stored under Bundle\Sensio\FooBundle.
And the Bundle class is Bundle\Sensio\FooBundle\SensioFooBundle.php.

Before the change, the bundle name ($bundle->getName()) would have returned 'FooBundle'.
Now it returns 'SensioFooBundle'.

Why does it matter? Well, it makes template names and controller names easier to read:

Before:

    Template: Sensio\FooBundle:Bar:index.twig.html
    Controller: Sensio\FooBundle:Bar:indexAction

After

    Template: SensioFooBundle:Bar:index.twig.html
    Controller: SensioFooBundle:Bar:indexAction

NB: Even if the change seems simple enough, the implementation is not. As finding
the namespace from the bundle class name is not trivial

NB2: If you don't follow the bundle name best practices, this will probably
leads to unexpected behaviors.
Fabien Potencier 14 years ago
parent
commit
7ac6d59173

+ 1 - 1
src/Symfony/Bundle/DoctrineBundle/Command/DoctrineCommand.php

@@ -134,7 +134,7 @@ abstract class DoctrineCommand extends Command
     protected function getBundleMetadatas(Bundle $bundle)
     {
         $tmp = dirname(str_replace('\\', '/', get_class($bundle)));
-        $namespace = $bundle->getNamespacePrefix().'\\'.$bundle->getName();
+        $namespace = $bundle->getNamespace();
         $class = basename($tmp);
 
         $bundleMetadatas = array();

+ 1 - 1
src/Symfony/Bundle/FrameworkBundle/Command/AssetsInstallCommand.php

@@ -56,7 +56,7 @@ class AssetsInstallCommand extends Command
 
         foreach ($this->container->get('kernel')->getBundles() as $bundle) {
             if (is_dir($originDir = $bundle->getPath().'/Resources/public')) {
-                $output->writeln(sprintf('Installing assets for <comment>%s\\%s</comment>', $bundle->getNamespacePrefix(), $bundle->getName()));
+                $output->writeln(sprintf('Installing assets for <comment>%s\\%s</comment>', $bundle->getNamespace()));
 
                 $targetDir = $input->getArgument('target').'/bundles/'.preg_replace('/bundle$/', '', strtolower($bundle->getName()));
 

+ 16 - 4
src/Symfony/Bundle/FrameworkBundle/Controller/ControllerNameConverter.php

@@ -26,7 +26,6 @@ class ControllerNameConverter
 {
     protected $kernel;
     protected $logger;
-    protected $namespaces;
 
     /**
      * Constructor.
@@ -79,7 +78,7 @@ class ControllerNameConverter
             throw new \InvalidArgumentException(sprintf('The "%s" class does not belong to a known bundle namespace.', $class));
         }
 
-        return $bundle.':'.$controller.':'.$action;
+        return str_replace('\\', '', $bundle).':'.$controller.':'.$action;
     }
 
     /**
@@ -96,11 +95,24 @@ class ControllerNameConverter
         }
 
         list($bundle, $controller, $action) = $parts;
-        $bundle = strtr($bundle, array('/' => '\\'));
         $class = null;
         $logs = array();
+
         foreach ($this->namespaces as $namespace) {
-            $try = $namespace.'\\'.$bundle.'\\Controller\\'.$controller.'Controller';
+            $prefix = null;
+            foreach ($this->kernel->getBundles() as $b) {
+                if ($bundle === $b->getName()) {
+                    $prefix = $b->getNamespaceName();
+
+                    break;
+                }
+            }
+
+            if (null === $prefix) {
+                continue;
+            }
+
+            $try = $prefix.'\\Controller\\'.$controller.'Controller';
             if (!class_exists($try)) {
                 if (null !== $this->logger) {
                     $logs[] = sprintf('Failed finding controller "%s:%s" from namespace "%s" (%s)', $bundle, $controller, $namespace, $try);

+ 3 - 1
src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml

@@ -107,7 +107,9 @@
             <argument type="service" id="templating" />
         </service>
 
-        <service id="templating.name_parser" class="%templating.name_parser.class%" />
+        <service id="templating.name_parser" class="%templating.name_parser.class%">
+            <argument type="service" id="kernel" />
+        </service>
 
         <service id="templating.loader" alias="templating.loader.filesystem" />
 

+ 35 - 1
src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php

@@ -3,6 +3,7 @@
 namespace Symfony\Bundle\FrameworkBundle\Templating;
 
 use Symfony\Component\Templating\TemplateNameParser as BaseTemplateNameParser;
+use Symfony\Component\HttpKernel\Kernel;
 
 /*
  * This file is part of the Symfony package.
@@ -22,6 +23,18 @@ use Symfony\Component\Templating\TemplateNameParser as BaseTemplateNameParser;
  */
 class TemplateNameParser extends BaseTemplateNameParser
 {
+    protected $kernel;
+
+    /**
+     * Constructor.
+     *
+     * @param Kernel $kernel A Kernel instance
+     */
+    public function __construct(Kernel $kernel)
+    {
+        $this->kernel = $kernel;
+    }
+
     /**
      * Parses a template to a template name and an array of options.
      *
@@ -37,13 +50,34 @@ class TemplateNameParser extends BaseTemplateNameParser
             throw new \InvalidArgumentException(sprintf('Template name "%s" is not valid (format is "bundle:section:template.renderer.format").', $name));
         }
 
+        $bundle = null;
+        if ($parts[0]) {
+            foreach ($this->kernel->getBundles() as $b) {
+                if ($parts[0] !== $b->getName()) {
+                    continue;
+                }
+
+                foreach (array_keys($this->kernel->getBundleDirs()) as $prefix) {
+                    if (0 === $pos = strpos($b->getNamespaceName(), $prefix)) {
+                        $bundle = str_replace($prefix.'\\', '', $b->getNamespaceName());
+
+                        break 2;
+                    }
+                }
+            }
+
+            if (null === $bundle) {
+                throw new \InvalidArgumentException(sprintf('Unable to find a valid bundle name for template "%s".', $name));
+            }
+        }
+
         $options = array_replace(
             array(
                 'format' => '',
             ),
             $defaults,
             array(
-                'bundle'     => str_replace('\\', '/', $parts[0]),
+                'bundle'     => $bundle,
                 'controller' => $parts[1],
             )
         );

+ 2 - 3
src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerNameConverterTest.php

@@ -28,7 +28,7 @@ class ControllerNameConverterTest extends TestCase
         $converter = new ControllerNameConverter($kernel);
 
         $this->assertEquals('FooBundle:Default:index', $converter->toShortNotation('TestBundle\FooBundle\Controller\DefaultController::indexAction'), '->toShortNotation() converts a class::method string to the short a:b:c notation');
-        $this->assertEquals('Sensio\\FooBundle:Default:index', $converter->toShortNotation('TestBundle\Sensio\FooBundle\Controller\DefaultController::indexAction'), '->toShortNotation() converts a class::method string to the short a:b:c notation');
+        $this->assertEquals('SensioFooBundle:Default:index', $converter->toShortNotation('TestBundle\Sensio\FooBundle\Controller\DefaultController::indexAction'), '->toShortNotation() converts a class::method string to the short a:b:c notation');
 
         try {
             $converter->toShortNotation('foo');
@@ -67,8 +67,7 @@ class ControllerNameConverterTest extends TestCase
         $converter = new ControllerNameConverter($kernel, $logger);
 
         $this->assertEquals('TestBundle\FooBundle\Controller\DefaultController::indexAction', $converter->fromShortNotation('FooBundle:Default:index'), '->fromShortNotation() converts a short a:b:c notation string to a class::method string');
-        $this->assertEquals('TestBundle\Sensio\FooBundle\Controller\DefaultController::indexAction', $converter->fromShortNotation('Sensio/FooBundle:Default:index'), '->fromShortNotation() converts a short a:b:c notation string to a class::method string');
-        $this->assertEquals('TestBundle\Sensio\FooBundle\Controller\DefaultController::indexAction', $converter->fromShortNotation('Sensio\\FooBundle:Default:index'), '->fromShortNotation() converts a short a:b:c notation string to a class::method string');
+        $this->assertEquals('TestBundle\Sensio\FooBundle\Controller\DefaultController::indexAction', $converter->fromShortNotation('SensioFooBundle:Default:index'), '->fromShortNotation() converts a short a:b:c notation string to a class::method string');
 
         try {
             $converter->fromShortNotation('foo:');

+ 18 - 10
src/Symfony/Bundle/FrameworkBundle/Tests/Templating/TemplateNameParserTest.php

@@ -13,6 +13,7 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Templating;
 
 use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
 use Symfony\Bundle\FrameworkBundle\Templating\TemplateNameParser;
+use Symfony\Bundle\FrameworkBundle\Tests\Kernel;
 
 class TemplateNameParserTest extends TestCase
 {
@@ -21,7 +22,9 @@ class TemplateNameParserTest extends TestCase
      */
     public function testParse($name, $parameters)
     {
-        $converter = new TemplateNameParser();
+        $kernel = new Kernel();
+        $kernel->boot();
+        $converter = new TemplateNameParser($kernel);
 
         $this->assertEquals($parameters, $converter->parse($name));
     }
@@ -29,10 +32,12 @@ class TemplateNameParserTest extends TestCase
     public function getParseTests()
     {
         return array(
-            array('BlogBundle:Post:index.php.html', array('index', array('bundle' => 'BlogBundle', 'controller' => 'Post', 'renderer' => 'php', 'format' => 'html'))),
-            array('BlogBundle:Post:index.twig.html', array('index', array('bundle' => 'BlogBundle', 'controller' => 'Post', 'renderer' => 'twig', 'format' => 'html'))),
-            array('BlogBundle:Post:index.php.xml', array('index', array('bundle' => 'BlogBundle', 'controller' => 'Post', 'renderer' => 'php', 'format' => 'xml'))),
-            array('Sensio\\BlogBundle:Post:index.php.html', array('index', array('bundle' => 'Sensio/BlogBundle', 'controller' => 'Post', 'renderer' => 'php', 'format' => 'html'))),
+            array('FooBundle:Post:index.php.html', array('index', array('bundle' => 'FooBundle', 'controller' => 'Post', 'renderer' => 'php', 'format' => 'html'))),
+            array('FooBundle:Post:index.twig.html', array('index', array('bundle' => 'FooBundle', 'controller' => 'Post', 'renderer' => 'twig', 'format' => 'html'))),
+            array('FooBundle:Post:index.php.xml', array('index', array('bundle' => 'FooBundle', 'controller' => 'Post', 'renderer' => 'php', 'format' => 'xml'))),
+            array('SensioFooBundle:Post:index.php.html', array('index', array('bundle' => 'Sensio\\FooBundle', 'controller' => 'Post', 'renderer' => 'php', 'format' => 'html'))),
+            array(':Post:index.php.html', array('index', array('bundle' => '', 'controller' => 'Post', 'renderer' => 'php', 'format' => 'html'))),
+            array('::index.php.html', array('index', array('bundle' => '', 'controller' => '', 'renderer' => 'php', 'format' => 'html'))),
         );
     }
 
@@ -42,7 +47,9 @@ class TemplateNameParserTest extends TestCase
      */
     public function testParseInvalid($name)
     {
-        $converter = new TemplateNameParser();
+        $kernel = new Kernel();
+        $kernel->boot();
+        $converter = new TemplateNameParser($kernel);
 
         $converter->parse($name);
     }
@@ -50,10 +57,11 @@ class TemplateNameParserTest extends TestCase
     public function getParseInvalidTests()
     {
         return array(
-            array('BlogBundle:Post:index'),
-            array('BlogBundle:Post'),
-            array('BlogBundle:Post:foo:bar'),
-            array('BlogBundle:Post:index.foo.bar.foobar'),
+            array('BarBundle:Post:index.php.html'),
+            array('FooBundle:Post:index'),
+            array('FooBundle:Post'),
+            array('FooBundle:Post:foo:bar'),
+            array('FooBundle:Post:index.foo.bar.foobar'),
         );
     }
 }

+ 9 - 10
src/Symfony/Component/HttpKernel/Bundle/Bundle.php

@@ -26,7 +26,7 @@ use Symfony\Component\Finder\Finder;
 abstract class Bundle extends ContainerAware implements BundleInterface
 {
     protected $name;
-    protected $namespacePrefix;
+    protected $namespace;
     protected $path;
     protected $reflection;
 
@@ -59,17 +59,17 @@ abstract class Bundle extends ContainerAware implements BundleInterface
     }
 
     /**
-     * Gets the Bundle namespace prefix.
+     * Gets the Bundle namespace.
      *
-     * @return string The Bundle namespace prefix
+     * @return string The Bundle namespace
      */
-    public function getNamespacePrefix()
+    public function getNamespaceName()
     {
         if (null === $this->name) {
             $this->initReflection();
         }
 
-        return $this->namespacePrefix;
+        return $this->namespace;
     }
 
     /**
@@ -119,7 +119,7 @@ abstract class Bundle extends ContainerAware implements BundleInterface
         $finder = new Finder();
         $finder->files()->name('*Extension.php')->in($dir);
 
-        $prefix = $this->namespacePrefix.'\\'.$this->name.'\\DependencyInjection';
+        $prefix = $this->namespace.'\\DependencyInjection';
         foreach ($finder as $file) {
             $class = $prefix.strtr($file->getPath(), array($dir => '', '/' => '\\')).'\\'.$file->getBasename('.php');
 
@@ -146,7 +146,7 @@ abstract class Bundle extends ContainerAware implements BundleInterface
         $finder = new Finder();
         $finder->files()->name('*Command.php')->in($dir);
 
-        $prefix = $this->namespacePrefix.'\\'.$this->name.'\\Command';
+        $prefix = $this->namespace.'\\Command';
         foreach ($finder as $file) {
             $r = new \ReflectionClass($prefix.strtr($file->getPath(), array($dir => '', '/' => '\\')).'\\'.$file->getBasename('.php'));
             if ($r->isSubclassOf('Symfony\\Component\\Console\\Command\\Command') && !$r->isAbstract()) {
@@ -161,10 +161,9 @@ abstract class Bundle extends ContainerAware implements BundleInterface
      */
     protected function initReflection()
     {
-        $tmp = dirname(str_replace('\\', '/', get_class($this)));
-        $this->namespacePrefix = str_replace('/', '\\', dirname($tmp));
-        $this->name = basename($tmp);
         $this->reflection = new \ReflectionObject($this);
+        $this->namespace = $this->reflection->getNamespaceName();
+        $this->name = $this->reflection->getShortName();
         $this->path = str_replace('\\', '/', dirname($this->reflection->getFilename()));
     }
 }

+ 7 - 7
src/Symfony/Component/HttpKernel/bootstrap.php

@@ -8,6 +8,7 @@ use Symfony\Component\Finder\Finder;
 abstract class Bundle extends ContainerAware implements BundleInterface
 {
     protected $name;
+    protected $namespace;
     protected $namespacePrefix;
     protected $path;
     protected $reflection;
@@ -24,12 +25,12 @@ abstract class Bundle extends ContainerAware implements BundleInterface
         }
         return $this->name;
     }
-    public function getNamespacePrefix()
+    public function getNamespaceName()
     {
         if (null === $this->name) {
             $this->initReflection();
         }
-        return $this->namespacePrefix;
+        return $this->namespace;
     }
     public function getPath()
     {
@@ -52,7 +53,7 @@ abstract class Bundle extends ContainerAware implements BundleInterface
         }
         $finder = new Finder();
         $finder->files()->name('*Extension.php')->in($dir);
-        $prefix = $this->namespacePrefix.'\\'.$this->name.'\\DependencyInjection';
+        $prefix = $this->namespace.'\\DependencyInjection';
         foreach ($finder as $file) {
             $class = $prefix.strtr($file->getPath(), array($dir => '', '/' => '\\')).'\\'.$file->getBasename('.php');
             $container->registerExtension(new $class());
@@ -65,7 +66,7 @@ abstract class Bundle extends ContainerAware implements BundleInterface
         }
         $finder = new Finder();
         $finder->files()->name('*Command.php')->in($dir);
-        $prefix = $this->namespacePrefix.'\\'.$this->name.'\\Command';
+        $prefix = $this->namespace.'\\Command';
         foreach ($finder as $file) {
             $r = new \ReflectionClass($prefix.strtr($file->getPath(), array($dir => '', '/' => '\\')).'\\'.$file->getBasename('.php'));
             if ($r->isSubclassOf('Symfony\\Component\\Console\\Command\\Command') && !$r->isAbstract()) {
@@ -75,10 +76,9 @@ abstract class Bundle extends ContainerAware implements BundleInterface
     }
     protected function initReflection()
     {
-        $tmp = dirname(str_replace('\\', '/', get_class($this)));
-        $this->namespacePrefix = str_replace('/', '\\', dirname($tmp));
-        $this->name = basename($tmp);
         $this->reflection = new \ReflectionObject($this);
+        $this->namespace = $this->reflection->getNamespaceName();
+        $this->name = $this->reflection->getShortName();
         $this->path = str_replace('\\', '/', dirname($this->reflection->getFilename()));
     }
 }