Add ability to add custom commands through plugins

This commit is contained in:
Romain Neutron
2013-07-02 18:37:20 +02:00
parent 89b53e50d2
commit 67d571e309
15 changed files with 213 additions and 39 deletions

View File

@@ -33,7 +33,7 @@ use Alchemy\Phrasea\Command\Setup\XSendFileMappingDumper;
require_once __DIR__ . '/../lib/autoload.php';
try {
$app = new CLI("
$cli = new CLI("
_____ _ _ _____ _____ ______ _ _ ______ _______
| __ \| | | | __ \ /\ / ____| ____| /\ | \ | | ____|__ __|
| |__) | |__| | |__) | / \ | (___ | |__ / \ | \| | |__ | |
@@ -51,55 +51,59 @@ try {
under certain conditions; type `about:license' for details.\n\n"
. ' KONSOLE KOMMANDER', Version::getName() . ' ' . Version::getNumber());
if (!$app['phraseanet.configuration-tester']->isInstalled()) {
if (!$cli['phraseanet.configuration-tester']->isInstalled()) {
throw new \RuntimeException('Phraseanet is not installed, use setup command instead');
}
if (!$app['phraseanet.configuration-tester']->isUpToDate()) {
if (!$cli['phraseanet.configuration-tester']->isUpToDate()) {
throw new \RuntimeException('Phraseanet is not up-to-date, use setup command instead');
}
$app->command(new \module_console_aboutAuthors('about:authors'));
$app->command(new \module_console_aboutLicense('about:license'));
$cli->command(new \module_console_aboutAuthors('about:authors'));
$cli->command(new \module_console_aboutLicense('about:license'));
$app->command(new \module_console_checkExtension('check:extension'));
$app->command(new CheckConfig('check:config'));
$cli->command(new \module_console_checkExtension('check:extension'));
$cli->command(new CheckConfig('check:config'));
$app->command(new UpgradeDBDatas('system:upgrade-datas'));
$cli->command(new UpgradeDBDatas('system:upgrade-datas'));
$app->command(new \module_console_sphinxGenerateSuggestion('sphinx:generate-suggestions'));
$cli->command(new \module_console_sphinxGenerateSuggestion('sphinx:generate-suggestions'));
$app->command(new \module_console_systemMailCheck('system:mail-check'));
$app->command(new \module_console_systemBackupDB('system:backup-db'));
$app->command(new \module_console_systemClearCache('system:clear-cache'));
$app->command(new \module_console_systemTemplateGenerator('system:template-generator'));
$app->command(new \module_console_systemExport('system:export'));
$cli->command(new \module_console_systemMailCheck('system:mail-check'));
$cli->command(new \module_console_systemBackupDB('system:backup-db'));
$cli->command(new \module_console_systemClearCache('system:clear-cache'));
$cli->command(new \module_console_systemTemplateGenerator('system:template-generator'));
$cli->command(new \module_console_systemExport('system:export'));
$app->command(new \module_console_taskrun('task:run'));
$app->command(new \module_console_tasklist('task:list'));
$app->command(new \module_console_taskState('task:state'));
$app->command(new \module_console_schedulerState('scheduler:state'));
$app->command(new \module_console_schedulerStop('scheduler:stop'));
$app->command(new \module_console_schedulerStart('scheduler:start'));
$cli->command(new \module_console_taskrun('task:run'));
$cli->command(new \module_console_tasklist('task:list'));
$cli->command(new \module_console_taskState('task:state'));
$cli->command(new \module_console_schedulerState('scheduler:state'));
$cli->command(new \module_console_schedulerStop('scheduler:stop'));
$cli->command(new \module_console_schedulerStart('scheduler:start'));
$app->command(new Mailtest('mail:test'));
$cli->command(new Mailtest('mail:test'));
$app->command(new \module_console_fieldsList('fields:list'));
$app->command(new \module_console_fieldsDelete('fields:delete'));
$app->command(new \module_console_fieldsRename('fields:rename'));
$app->command(new \module_console_fieldsMerge('fields:merge'));
$cli->command(new \module_console_fieldsList('fields:list'));
$cli->command(new \module_console_fieldsDelete('fields:delete'));
$cli->command(new \module_console_fieldsRename('fields:rename'));
$cli->command(new \module_console_fieldsMerge('fields:merge'));
$app->command(new CreateCollection('collection:create'));
$cli->command(new CreateCollection('collection:create'));
$app->command(new RecordAdd('records:add'));
$app->command(new RescanTechnicalDatas('records:rescan-technical-datas'));
$app->command(new BuildMissingSubdefs('records:build-missing-subdefs'));
$cli->command(new RecordAdd('records:add'));
$cli->command(new RescanTechnicalDatas('records:rescan-technical-datas'));
$cli->command(new BuildMissingSubdefs('records:build-missing-subdefs'));
$app->command(new AddPlugin());
$app->command(new RemovePlugin());
$app->command(new Configuration());
$app->command(new XSendFileMappingDumper());
$cli->command(new AddPlugin());
$cli->command(new RemovePlugin());
$cli->command(new Configuration());
$cli->command(new XSendFileMappingDumper());
$result_code = is_int($app->run()) ? : 1;
call_user_func(function ($cli) {
require $cli['plugins.directory'] . '/commands.php';
}, $cli);
$result_code = is_int($cli->run()) ? : 1;
} catch (\Exception $e) {
$result_code = 1;
echo sprintf("\nAn error occured :\n\n\t\033[0;31m%s\033[0;37m\n\n", $e->getMessage());

View File

@@ -11,6 +11,7 @@
namespace Alchemy\Phrasea;
use Alchemy\Phrasea\Command\CommandInterface;
use Symfony\Component\Console;
/**
@@ -73,9 +74,9 @@ class CLI extends Application
*
* If a command with the same name already exists, it will be overridden.
*
* @param \Cilex\Command\Command $command A Command object
* @param CommandInterface $command A Command object
*/
public function command(Command\Command $command)
public function command(CommandInterface $command)
{
$command->setContainer($this);
$this['console']->add($command);

View File

@@ -23,7 +23,7 @@ use Symfony\Component\Console\Output\OutputInterface;
* @license http://opensource.org/licenses/gpl-3.0 GPLv3
* @link www.phraseanet.com
*/
abstract class Command extends SymfoCommand
abstract class Command extends SymfoCommand implements CommandInterface
{
/**
* @var Application
@@ -120,4 +120,12 @@ abstract class Command extends SymfoCommand
return $duration;
}
/**
* {@inheritdoc}
*/
public static function create()
{
return new static();
}
}

View File

@@ -0,0 +1,29 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2013 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Command;
use Alchemy\Phrasea\Application;
interface CommandInterface
{
/**
* Inject the container in the command.
*
* @param Application $container
*/
public function setContainer(Application $container);
/**
* Factory for the command.
*/
public static function create();
}

View File

@@ -26,7 +26,8 @@ class AutoloaderGenerator
{
$this
->doWrite('autoload.php', $this->createLoader($manifests))
->doWrite('services.php', $this->createServices($manifests));
->doWrite('services.php', $this->createServices($manifests))
->doWrite('commands.php', $this->createCommands($manifests));
return $this;
}
@@ -100,6 +101,39 @@ EOF;
return \$app;
}, \$app);
EOF;
return $buffer;
}
private function createCommands($manifests)
{
$buffer = <<<EOF
<?php
// This file is automatically generated, please do not edit it.
// To update configuration, use bin/console plugins:* commands.
use Alchemy\Phrasea\CLI;
return call_user_func(function (CLI \$cli) {
EOF;
foreach ($manifests as $manifest) {
foreach ($manifest->getCommands() as $command) {
$class = $command['class'];
$buffer .= <<<EOF
\$cli->command($class::create());
EOF;
}
}
$buffer .= <<<EOF
return \$cli;
}, \$cli);
EOF;
return $buffer;

View File

@@ -70,6 +70,11 @@ class Manifest
return $this->get('services');
}
public function getCommands()
{
return $this->get('commands') ? : array();
}
public function getExtra()
{
return $this->get('extra');

View File

@@ -14,6 +14,11 @@
"version" : "0.1",
"minimum-phraseanet-version": "3.8",
"maximum-phraseanet-version": "3.9",
"Commands" : [
{
"class": "Vendor\\Connector\\CustomCommand"
}
],
"services" : [
{
"class": "Vendor\\Connector\\PluginServiceInterface"

View File

@@ -70,6 +70,20 @@
"type": "string",
"description": "The maximum phraseanet version for the plugin, excluding the one provided"
},
"commands": {
"type": "array",
"description": "An array of commands to register.",
"items": {
"type": "object",
"description": "A command",
"properties": {
"class": {
"type": "string",
"description": "The plugin command name"
}
}
}
},
"services": {
"type": "array",
"description": "An array of services to register.",

7
plugins/commands.php Normal file
View File

@@ -0,0 +1,7 @@
<?php
use Alchemy\Phrasea\CLI;
return call_user_func(function (CLI $cli) {
return $cli;
}, $cli);

View File

@@ -19,6 +19,11 @@
"class": "Vendor\\PluginService"
}
],
"commands" : [
{
"class": "Vendor\\CustomCommand"
}
],
"extra" : {
"property" : "value"
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Vendor;
use Alchemy\Phrasea\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class CustomCommand extends Command
{
public function __construct()
{
parent::__construct('hello:world');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->write('Hello World');
return 0;
}
}

View File

@@ -18,5 +18,10 @@
{
"class": "Vendor\\PluginService"
}
],
"commands" : [
{
"class": "Vendor\\CustomCommand"
}
]
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Vendor;
use Alchemy\Phrasea\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class CustomCommand extends Command
{
public function __construct()
{
parent::__construct('hello:world');
}
protected function doExecute(InputInterface $input, OutputInterface $output)
{
$output->write('Hello World');
return 0;
}
}

View File

@@ -3,6 +3,7 @@
namespace Alchemy\Tests\Phrasea\Plugin\Management;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\CLI;
use Alchemy\Phrasea\Plugin\Management\AutoloaderGenerator;
use Alchemy\Phrasea\Plugin\Schema\Manifest;
use Symfony\Component\Process\ProcessBuilder;
@@ -15,7 +16,11 @@ class AutoloaderGeneratorTest extends \PHPUnit_Framework_TestCase
$pluginDir = __DIR__ . '/../Fixtures/PluginDirInstalled/TestPlugin';
$pluginsDir = __DIR__ . '/../Fixtures/PluginDirInstalled';
$files = array($pluginsDir . '/services.php', $pluginsDir . '/autoload.php');
$files = array(
$pluginsDir . '/services.php',
$pluginsDir . '/autoload.php',
$pluginsDir . '/commands.php',
);
$this->cleanup($files);
@@ -49,6 +54,13 @@ class AutoloaderGeneratorTest extends \PHPUnit_Framework_TestCase
$this->assertSame($app, $retrievedApp);
$this->assertEquals('hello world', $app['plugin-test']);
// load services
$cli = new CLI('test');
$retrievedCli = require $pluginsDir . '/commands.php';
$this->assertSame($cli, $retrievedCli);
$this->assertInstanceOf('Vendor\CustomCommand', $cli['console']->find('hello:world'));
$this->cleanup($files);
}

View File

@@ -24,6 +24,7 @@ class ManifestTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('0.1', $manifest->getVersion());
$this->assertEquals('3.8', $manifest->getMinimumPhraseanetVersion());
$this->assertEquals('3.9', $manifest->getMaximumPhraseanetVersion());
$this->assertEquals(array(array('class' => 'Vendor\CustomCommand')), $manifest->getCommands());
$this->assertEquals(array(array('class' => 'Vendor\PluginService')), $manifest->getServices());
$this->assertEquals(array('property' => 'value'), $manifest->getExtra());
}