occ commands
Nextcloud apps can register custom occ commands that administrators can run from the command line. Commands are built on top of Symfony Console, so the full Symfony Console API is available.
Note
The OCP\Command\ICommand interface is deprecated since Nextcloud 33 and must not
be used for new commands. Extend Symfony\Component\Console\Command\Command directly
as shown below.
Registering a command
List every command class in appinfo/info.xml under the <commands> element:
<info>
...
<commands>
<command>OCA\MyApp\Command\Greet</command>
</commands>
</info>
Nextcloud reads this list at startup and wires each class through the dependency injection container, so constructor injection works automatically.
Creating a command class
Place command classes in lib/Command/. Each class must extend
Symfony\Component\Console\Command\Command and implement two methods:
configure()— declare the name, description, arguments, and options.execute()— run the command logic and return an exit code.
<?php
declare(strict_types=1);
namespace OCA\MyApp\Command;
use OCP\IUserManager;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class Greet extends Command {
public function __construct(
private IUserManager $userManager,
) {
parent::__construct();
}
#[\Override]
protected function configure(): void {
$this
->setName('myapp:greet')
->setDescription('Print a greeting for a Nextcloud user')
->addArgument(
'user-id',
InputArgument::REQUIRED,
'The user to greet',
)
->addOption(
'shout',
null,
InputOption::VALUE_NONE,
'Print the greeting in uppercase',
);
}
#[\Override]
protected function execute(InputInterface $input, OutputInterface $output): int {
$userId = $input->getArgument('user-id');
$user = $this->userManager->get($userId);
if ($user === null) {
$output->writeln("<error>User \"$userId\" not found.</error>");
return self::FAILURE;
}
$greeting = 'Hello, ' . $user->getDisplayName() . '!';
if ($input->getOption('shout')) {
$greeting = strtoupper($greeting);
}
$output->writeln($greeting);
return self::SUCCESS;
}
}
Command naming
Use appid:command-name as the command name. For apps with many commands, group them
with an extra segment: appid:group:command-name. Names must be lowercase and use
hyphens as word separators.
Arguments and options
Arguments are positional. Options are prefixed with --.
Constant |
Meaning |
|---|---|
|
Argument must be provided |
|
Argument may be omitted |
|
Argument accepts multiple values |
|
Flag — present or absent, no value |
|
Option requires a value |
|
Option value is optional |
|
Option can be repeated |
See the Symfony Console documentation for the full reference.
Return codes
execute() must return an integer. Use the constants defined by
Symfony\Component\Console\Command\Command:
self::SUCCESS(0) — command completed successfully.self::FAILURE(1) — command encountered an error.self::INVALID(2) — command was called with invalid input.
Interactive commands
Commands can ask for confirmation or prompt for values using Symfony’s question helper:
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Question\ConfirmationQuestion;
// In execute():
/** @var QuestionHelper $helper */
$helper = $this->getHelper('question');
$question = new ConfirmationQuestion('Are you sure? (y/n) ', false);
if (!$helper->ask($input, $output, $question)) {
$output->writeln('Aborted.');
return self::FAILURE;
}
Note
Interactive prompts are skipped when occ is run non-interactively (e.g. from a
cron job). Guard against this with $input->isInteractive() or use
--yes/--no options so administrators can automate the command.