From redaxo-core
Builds Symfony Console commands for REDAXO addons using rex_console_command. Covers file structure, class naming, package.yml registration, and SymfonyStyle helpers. Use for CLI tools, diagnostics, cronjobs, replacing standalone scripts.
npx claudepluginhub friendsofredaxo/claude-marketplace --plugin redaxo-coreThis skill uses the workspace's default tool permissions.
For any CLI / diagnostic / maintenance task in an addon, build a **console command** — not a standalone PHP bootstrap script. REDAXO uses Symfony Console under the hood; the bootstrap (autoloading, addon init, package order) only works correctly through `bin/console`.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Guides code writing, review, and refactoring with Karpathy-inspired rules to avoid overcomplication, ensure simplicity, surgical changes, and verifiable success criteria.
Executes ctx7 CLI to fetch up-to-date library documentation, manage AI coding skills (install/search/generate/remove/suggest), and configure Context7 MCP. Useful for current API refs, skill handling, or agent setup.
Share bugs, ideas, or general feedback.
For any CLI / diagnostic / maintenance task in an addon, build a console command — not a standalone PHP bootstrap script. REDAXO uses Symfony Console under the hood; the bootstrap (autoloading, addon init, package order) only works correctly through bin/console.
// bin/_my_check.php — WRONG
require __DIR__ . '/../src/core/boot.php'; // missing path provider
$client = rex_elasticsearch_client::factory(); // wrong API
Standalone scripts like this either fail to boot, or end up using APIs that don't exist. Even if you get them working, they're invisible in bin/console list, can't run as cronjobs, and aren't reviewable as part of the addon.
src/addons/<addon>/lib/command/<name>.phprex_<addon>_command_<name> — subcommand : becomes _ (e.g. command ndcg:detail → class rex_elasticsearchtools_command_ndcg_detail)rex_console_command (REDAXO's wrapper around Symfony\Component\Console\Command\Command)package.yml under console_commands: — without this REDAXO won't expose the command. Autoloading alone is not enough.<?php
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Usage:
* bin/console addon:topic:action --option=value
*/
final class rex_addon_command_topic_action extends rex_console_command
{
protected function configure(): void
{
$this
->setDescription('One-line description shown in `bin/console list`')
->addOption('alias', 'a', InputOption::VALUE_REQUIRED, 'Index alias', 'default_alias')
->addOption('query', null, InputOption::VALUE_REQUIRED, 'Search query', 'test');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = $this->getStyle($input, $output); // SymfonyStyle helper
$io->title('My Command');
$alias = (string) $input->getOption('alias');
// SQL access works as usual
$sql = rex_sql::factory();
$rows = $sql->getArray(
'SELECT COUNT(*) AS c FROM ' . rex::getTable('table') . ' WHERE state = 7'
);
$io->table(['Header'], [['row1'], ['row2']]);
$io->success('Done');
return 0; // 0 = success, non-zero = failure
}
}
package.ymlconsole_commands:
addon:topic:action: rex_addon_command_topic_action
addon:topic:other: rex_addon_command_topic_other
The command name uses : as namespace separator. The class name uses _ everywhere.
$io)$this->getStyle($input, $output) returns a SymfonyStyle instance:
| Method | Use for |
|---|---|
$io->title($t) | Big heading |
$io->section($t) | Subheading |
$io->writeln($msg) | Plain output |
$io->note($msg) | Informational box |
$io->success($msg) | Green success box |
$io->error($msg) | Red error box |
$io->warning($msg) | Yellow warning box |
$io->table($headers, $rows) | Formatted table |
$io->progressStart($total) / progressAdvance() / progressFinish() | Progress bar |
$io->ask($q) / confirm($q) / choice($q, $opts) | Interactive prompts |
bin/console list | grep <addon>
If the command isn't there, the package.yml entry is missing or the class name doesn't match the file path / case.
$items = MyTable::query()->where('status', 1)->find();
foreach ($items as $item) {
$io->writeln($item->getValue('name'));
}
In package.yml of the cronjob addon's host configuration (or via the cronjob backend UI), schedule a system command:
bin/console addon:topic:action --alias=production
console_commands: entry in package.yml – the file is autoloaded but never registered, so bin/console list doesn't show it.MyAddonCommandThing instead of rex_my_addon_command_thing) – autoload silently fails.execute() – Symfony Console treats anything other than 0 (or the Command::SUCCESS/FAILURE constants on newer versions) as a failure.echo instead of $output->writeln() / $io->writeln() – Symfony's --quiet flag has no effect.setDescription() – bin/console list shows no help text, future-you won't remember what it does.rex::getUser() – there's no logged-in user in CLI context. It returns null. For permission checks, gate on --user flags or environment.