Make console commands pluggable

This commit is contained in:
Frederic Guillot
2016-05-29 20:33:48 -04:00
parent b69eb5f993
commit fb642b76bb
8 changed files with 107 additions and 48 deletions

View File

@@ -4,6 +4,7 @@ namespace Kanboard\Console;
use Kanboard\Core\Plugin\Installer; use Kanboard\Core\Plugin\Installer;
use Kanboard\Core\Plugin\PluginInstallerException; use Kanboard\Core\Plugin\PluginInstallerException;
use LogicException;
use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
@@ -21,7 +22,7 @@ class PluginInstallCommand extends BaseCommand
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output)
{ {
if (!Installer::isConfigured()) { if (!Installer::isConfigured()) {
$output->writeln('<error>Kanboard is not configured to install plugins itself</error>'); throw new LogicException('Kanboard is not configured to install plugins itself');
} }
try { try {

View File

@@ -4,6 +4,7 @@ namespace Kanboard\Console;
use Kanboard\Core\Plugin\Installer; use Kanboard\Core\Plugin\Installer;
use Kanboard\Core\Plugin\PluginInstallerException; use Kanboard\Core\Plugin\PluginInstallerException;
use LogicException;
use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
@@ -21,7 +22,7 @@ class PluginUninstallCommand extends BaseCommand
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output)
{ {
if (!Installer::isConfigured()) { if (!Installer::isConfigured()) {
$output->writeln('<error>Kanboard is not configured to remove plugins itself</error>'); throw new LogicException('Kanboard is not configured to install plugins itself');
} }
try { try {

View File

@@ -5,6 +5,7 @@ namespace Kanboard\Console;
use Kanboard\Core\Plugin\Base as BasePlugin; use Kanboard\Core\Plugin\Base as BasePlugin;
use Kanboard\Core\Plugin\Directory; use Kanboard\Core\Plugin\Directory;
use Kanboard\Core\Plugin\Installer; use Kanboard\Core\Plugin\Installer;
use LogicException;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
@@ -21,7 +22,7 @@ class PluginUpgradeCommand extends BaseCommand
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output)
{ {
if (!Installer::isConfigured()) { if (!Installer::isConfigured()) {
$output->writeln('<error>Kanboard is not configured to upgrade plugins itself</error>'); throw new LogicException('Kanboard is not configured to install plugins itself');
} }
$installer = new Installer($this->container); $installer = new Installer($this->container);

View File

@@ -140,6 +140,7 @@ use Pimple\Container;
* @property \Psr\Log\LoggerInterface $logger * @property \Psr\Log\LoggerInterface $logger
* @property \PicoDb\Database $db * @property \PicoDb\Database $db
* @property \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher * @property \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher
* @property \Symfony\Component\Console\Application $cli
* @property \JsonRPC\Server $api * @property \JsonRPC\Server $api
*/ */
abstract class Base abstract class Base

View File

@@ -0,0 +1,62 @@
<?php
namespace Kanboard\ServiceProvider;
use Kanboard\Console\CronjobCommand;
use Kanboard\Console\LocaleComparatorCommand;
use Kanboard\Console\LocaleSyncCommand;
use Kanboard\Console\PluginInstallCommand;
use Kanboard\Console\PluginUninstallCommand;
use Kanboard\Console\PluginUpgradeCommand;
use Kanboard\Console\ProjectDailyColumnStatsExportCommand;
use Kanboard\Console\ProjectDailyStatsCalculationCommand;
use Kanboard\Console\ResetPasswordCommand;
use Kanboard\Console\ResetTwoFactorCommand;
use Kanboard\Console\SubtaskExportCommand;
use Kanboard\Console\TaskExportCommand;
use Kanboard\Console\TaskOverdueNotificationCommand;
use Kanboard\Console\TaskTriggerCommand;
use Kanboard\Console\TransitionExportCommand;
use Kanboard\Console\WorkerCommand;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
use Symfony\Component\Console\Application;
/**
* Class CommandProvider
*
* @package Kanboard\ServiceProvider
* @author Frederic Guillot
*/
class CommandProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
*
* @param Container $container
* @return Container
*/
public function register(Container $container)
{
$application = new Application('Kanboard', APP_VERSION);
$application->add(new TaskOverdueNotificationCommand($container));
$application->add(new SubtaskExportCommand($container));
$application->add(new TaskExportCommand($container));
$application->add(new ProjectDailyStatsCalculationCommand($container));
$application->add(new ProjectDailyColumnStatsExportCommand($container));
$application->add(new TransitionExportCommand($container));
$application->add(new LocaleSyncCommand($container));
$application->add(new LocaleComparatorCommand($container));
$application->add(new TaskTriggerCommand($container));
$application->add(new CronjobCommand($container));
$application->add(new WorkerCommand($container));
$application->add(new ResetPasswordCommand($container));
$application->add(new ResetTwoFactorCommand($container));
$application->add(new PluginUpgradeCommand($container));
$application->add(new PluginInstallCommand($container));
$application->add(new PluginUninstallCommand($container));
$container['cli'] = $application;
return $container;
}
}

View File

@@ -48,4 +48,5 @@ $container->register(new Kanboard\ServiceProvider\AvatarProvider());
$container->register(new Kanboard\ServiceProvider\FilterProvider()); $container->register(new Kanboard\ServiceProvider\FilterProvider());
$container->register(new Kanboard\ServiceProvider\QueueProvider()); $container->register(new Kanboard\ServiceProvider\QueueProvider());
$container->register(new Kanboard\ServiceProvider\ApiProvider()); $container->register(new Kanboard\ServiceProvider\ApiProvider());
$container->register(new Kanboard\ServiceProvider\CommandProvider());
$container->register(new Kanboard\ServiceProvider\PluginProvider()); $container->register(new Kanboard\ServiceProvider\PluginProvider());

View File

@@ -110,8 +110,8 @@ public function getClasses()
{ {
return array( return array(
'Plugin\Budget\Model' => array( 'Plugin\Budget\Model' => array(
'HourlyRate', 'HourlyRateModel',
'Budget', 'BudgetModel',
) )
); );
} }
@@ -120,11 +120,42 @@ public function getClasses()
Now, if you use a class that extends from `Core\Base`, you can access directly to those class instance: Now, if you use a class that extends from `Core\Base`, you can access directly to those class instance:
```php ```php
$this->hourlyRate->remove(123); $this->hourlyRateModel->remove(123);
$this->budget->getDailyBudgetBreakdown(456); $this->budgetModel->getDailyBudgetBreakdown(456);
// It's the same thing as using the container: // It's the same thing as using the container:
$this->container['hourlyRate']->getAll(); $this->container['hourlyRateModel']->getAll();
``` ```
Keys of the containers are unique across the application. If you override an existing class, you will change the default behavior. Keys of the containers are unique across the application. If you override an existing class, you will change the default behavior.
Add new API methods
-------------------
Kanboard use this library [JSON-RPC](https://github.com/fguillot/JsonRPC) to handle API calls.
To add a new method you can do something like that from your plugin:
```php
$this->api->getProcedureHandler()->withCallback('my_method', function() {
return 'foobar';
});
```
`$this->container['api']` or `$this->api` expose an instance of the object `JsonRPC\Server`.
Read the library documentation for more information.
Add new console commands
------------------------
Kanboard use the library [Symfony Console](http://symfony.com/doc/current/components/console/introduction.html) to handle local command lines.
Kanboard expose an instance of the object `Symfony\Component\Console\Application` via `$this->cli`.
You can add new commands from your plugin:
```php
$this->cli->add(new MyCommand());
```
Read the library documentation for more information.

View File

@@ -1,51 +1,12 @@
#!/usr/bin/env php #!/usr/bin/env php
<?php <?php
use Kanboard\Console\PluginInstallCommand;
use Kanboard\Console\PluginUninstallCommand;
use Kanboard\Console\PluginUpgradeCommand;
use Kanboard\Console\ResetPasswordCommand;
use Kanboard\Console\ResetTwoFactorCommand;
use Kanboard\Console\WorkerCommand;
use Symfony\Component\Console\Application;
use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\Event;
use Kanboard\Console\TaskOverdueNotificationCommand;
use Kanboard\Console\SubtaskExportCommand;
use Kanboard\Console\TaskExportCommand;
use Kanboard\Console\ProjectDailyStatsCalculationCommand;
use Kanboard\Console\ProjectDailyColumnStatsExportCommand;
use Kanboard\Console\TransitionExportCommand;
use Kanboard\Console\LocaleSyncCommand;
use Kanboard\Console\LocaleComparatorCommand;
use Kanboard\Console\TaskTriggerCommand;
use Kanboard\Console\CronjobCommand;
try { try {
require __DIR__.'/app/common.php'; require __DIR__.'/app/common.php';
$container['dispatcher']->dispatch('app.bootstrap', new Event); $container['dispatcher']->dispatch('app.bootstrap', new Event);
$container['cli']->run();
$application = new Application('Kanboard', APP_VERSION);
$application->add(new TaskOverdueNotificationCommand($container));
$application->add(new SubtaskExportCommand($container));
$application->add(new TaskExportCommand($container));
$application->add(new ProjectDailyStatsCalculationCommand($container));
$application->add(new ProjectDailyColumnStatsExportCommand($container));
$application->add(new TransitionExportCommand($container));
$application->add(new LocaleSyncCommand($container));
$application->add(new LocaleComparatorCommand($container));
$application->add(new TaskTriggerCommand($container));
$application->add(new CronjobCommand($container));
$application->add(new WorkerCommand($container));
$application->add(new ResetPasswordCommand($container));
$application->add(new ResetTwoFactorCommand($container));
$application->add(new PluginUpgradeCommand($container));
$application->add(new PluginInstallCommand($container));
$application->add(new PluginUninstallCommand($container));
$application->run();
} catch (Exception $e) { } catch (Exception $e) {
echo $e->getMessage().PHP_EOL; echo $e->getMessage().PHP_EOL;
exit(255); exit(255);