Skip to content

Commit

Permalink
allow plugin-name short aliases in cli
Browse files Browse the repository at this point in the history
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
  • Loading branch information
AD7six committed Sep 10, 2014
1 parent b60031b commit fb6b739
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 18 deletions.
100 changes: 82 additions & 18 deletions src/Console/ShellDispatcher.php
Expand Up @@ -18,6 +18,7 @@
use Cake\Core\App;
use Cake\Core\Configure;
use Cake\Core\Exception\Exception;
use Cake\Core\Plugin;
use Cake\Utility\Inflector;

/**
Expand Down Expand Up @@ -68,12 +69,27 @@ public function __construct($args = [], $bootstrap = true) {
*
* 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;
}

/**
Expand Down Expand Up @@ -157,36 +173,72 @@ protected function _dispatch() {
return true;
}

if (!self::$_aliases) {
$this->addShortPluginAliases();
}

$Shell = $this->findShell($shell);

$Shell->initialize();
return $Shell->runCommand($this->args, true);
}

/**
* 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.
* @throws \Cake\Console\Exception\MissingShellException when errors are encountered.
*/
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);
}

/**
Expand All @@ -196,15 +248,27 @@ public function findShell($shell) {
* @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;
}
return false;
}

/**
* 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
*
Expand Down
54 changes: 54 additions & 0 deletions tests/TestCase/Console/ShellDispatcherTest.php
Expand Up @@ -168,6 +168,60 @@ public function testDispatchShellWithoutMain() {
$this->assertEquals(0, $result);
}

/**
* 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
*
Expand Down

0 comments on commit fb6b739

Please sign in to comment.