Browse Source

allow plugin-name short aliases in cli

Instead of forcing/telling users to type:

	Console/cake PluginName.plugin_name

Allow:

	Console/cake PluginName

And:

	Console/cake plugin_name

Also be case insensitive/consistent when resolving aliases
AD7six 11 years ago
parent
commit
fb6b739df3
2 changed files with 136 additions and 18 deletions
  1. 82 18
      src/Console/ShellDispatcher.php
  2. 54 0
      tests/TestCase/Console/ShellDispatcherTest.php

+ 82 - 18
src/Console/ShellDispatcher.php

@@ -18,6 +18,7 @@ use Cake\Console\Exception\MissingShellException;
 use Cake\Core\App;
 use Cake\Core\Configure;
 use Cake\Core\Exception\Exception;
+use Cake\Core\Plugin;
 use Cake\Utility\Inflector;
 
 /**
@@ -68,12 +69,27 @@ class ShellDispatcher {
  *
  * If you re-use an alias the last alias set will be the one available.
  *
+ * ### Usage
+ *
+ * Aliasing a shell named ClassName:
+ *
+ * `$this->alias('alias', 'ClassName');`
+ *
+ * Getting the original name for a given alias:
+ *
+ * `$this->alias('alias');`
+ *
  * @param string $short The new short name for the shell.
- * @param string $original The original full name for the shell.
- * @return void
+ * @param string|null $original The original full name for the shell.
+ * @return string|false The aliased class name, or false if the alias does not exist
  */
-	public static function alias($short, $original) {
-		static::$_aliases[$short] = $original;
+	public static function alias($short, $original = null) {
+		$short = Inflector::camelize($short);
+		if ($original) {
+			static::$_aliases[$short] = $original;
+		}
+
+		return isset(static::$_aliases[$short]) ?  static::$_aliases[$short] : false;
 	}
 
 /**
@@ -157,6 +173,10 @@ class ShellDispatcher {
 			return true;
 		}
 
+		if (!self::$_aliases) {
+			$this->addShortPluginAliases();
+		}
+
 		$Shell = $this->findShell($shell);
 
 		$Shell->initialize();
@@ -164,9 +184,26 @@ class ShellDispatcher {
 	}
 
 /**
+ * For all loaded plugins, add a short alias
+ *
+ * This permits a plugin which implements a shell of the same name to be accessed
+ * Using the plugin name alone
+ *
+ * @return void
+ */
+	public function addShortPluginAliases() {
+		$plugins = Plugin::loaded();
+
+		foreach ($plugins as $plugin) {
+			self::alias($plugin, "$plugin.$plugin");
+		}
+	}
+
+/**
  * Get shell to use, either plugin shell or application shell
  *
- * All paths in the loaded shell paths are searched.
+ * All paths in the loaded shell paths are searched, handles alias
+ * dereferencing
  *
  * @param string $shell Optionally the name of a plugin
  * @return \Cake\Console\Shell A shell instance.
@@ -174,19 +211,34 @@ class ShellDispatcher {
  */
 	public function findShell($shell) {
 		$className = $this->_shellExists($shell);
-		if (!$className && isset(static::$_aliases[$shell])) {
-			$shell = static::$_aliases[$shell];
+		if (!$className) {
+			$shell = $this->_handleAlias($shell);
 			$className = $this->_shellExists($shell);
 		}
-		if ($className) {
-			list($plugin) = pluginSplit($shell);
-			$instance = new $className();
-			$instance->plugin = Inflector::camelize(trim($plugin, '.'));
-			return $instance;
+
+		if (!$className) {
+			throw new MissingShellException([
+				'class' => $shell,
+			]);
+		}
+
+		return $this->_createShell($className, $shell);
+	}
+
+/**
+ * If the input matches an alias, return the aliased shell name
+ *
+ * @param string $shell Optionally the name of a plugin or alias
+ * @return string Shell name with plugin prefix
+ */
+	protected function _handleAlias($shell) {
+		$aliased = static::alias($shell);
+		if ($aliased) {
+			$shell = $aliased;
 		}
-		throw new MissingShellException([
-			'class' => $shell,
-		]);
+
+		$class = array_map('Cake\Utility\Inflector::camelize', explode('.', $shell));
+		return implode('.', $class);
 	}
 
 /**
@@ -196,9 +248,7 @@ class ShellDispatcher {
  * @return string|bool Either the classname or false.
  */
 	protected function _shellExists($shell) {
-		$class = array_map('Cake\Utility\Inflector::camelize', explode('.', $shell));
-		$class = implode('.', $class);
-		$class = App::className($class, 'Shell', 'Shell');
+		$class = App::className($shell, 'Shell', 'Shell');
 		if (class_exists($class)) {
 			return $class;
 		}
@@ -206,6 +256,20 @@ class ShellDispatcher {
 	}
 
 /**
+ * Create the given shell name, and set the plugin property
+ *
+ * @param string $className The class name to instanciate
+ * @param string $shortName The plugin-prefixed shell name
+ * @return \Cake\Console\Shell A shell instance.
+ */
+	protected function _createShell($className, $shortName) {
+		list($plugin) = pluginSplit($shortName);
+		$instance = new $className();
+		$instance->plugin = trim($plugin, '.');
+		return $instance;
+	}
+
+/**
  * Removes first argument and shifts other arguments up
  *
  * @return mixed Null if there are no arguments otherwise the shifted argument

+ 54 - 0
tests/TestCase/Console/ShellDispatcherTest.php

@@ -169,6 +169,60 @@ class ShellDispatcherTest extends TestCase {
 	}
 
 /**
+ * Verify you can dispatch a plugin's main shell with the plugin name alone
+ *
+ * @return void
+ */
+	public function testDispatchShortPluginAlias() {
+		$dispatcher = $this->getMock(
+			'Cake\Console\ShellDispatcher',
+			['_shellExists', '_createShell']
+		);
+		$Shell = $this->getMock('Cake\Console\Shell');
+
+		$dispatcher->expects($this->at(1))
+			->method('_shellExists')
+			->with('TestPlugin.TestPlugin')
+			->will($this->returnValue('TestPlugin\Console\Command\TestPluginShell'));
+
+		$dispatcher->expects($this->at(2))
+			->method('_createShell')
+			->with('TestPlugin\Console\Command\TestPluginShell', 'TestPlugin.TestPlugin')
+			->will($this->returnValue($Shell));
+
+		$dispatcher->args = array('test_plugin');
+		$result = $dispatcher->dispatch();
+		$this->assertEquals(1, $result);
+	}
+
+/**
+ * Ensure short plugin shell usage is case/camelized insensitive
+ *
+ * @return void
+ */
+	public function testDispatchShortPluginAliasCamelized() {
+		$dispatcher = $this->getMock(
+			'Cake\Console\ShellDispatcher',
+			['_shellExists', '_createShell']
+		);
+		$Shell = $this->getMock('Cake\Console\Shell');
+
+		$dispatcher->expects($this->at(1))
+			->method('_shellExists')
+			->with('TestPlugin.TestPlugin')
+			->will($this->returnValue('TestPlugin\Console\Command\TestPluginShell'));
+
+		$dispatcher->expects($this->at(2))
+			->method('_createShell')
+			->with('TestPlugin\Console\Command\TestPluginShell', 'TestPlugin.TestPlugin')
+			->will($this->returnValue($Shell));
+
+		$dispatcher->args = ['TestPlugin'];
+		$result = $dispatcher->dispatch();
+		$this->assertEquals(1, $result);
+	}
+
+/**
  * Verify shifting of arguments
  *
  * @return void