By Matthias Noback
This package contains a Symfony bundle and some tools which enable you to use Symfony Form types to define and interactively process user input from the CLI.
composer require matthiasnoback/symfony-console-form
Enable Matthias\SymfonyConsoleForm\Bundle\SymfonyConsoleFormBundle
in the kernel of your Symfony application.
<?php
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(
// ...
new Matthias\SymfonyConsoleForm\Bundle\SymfonyConsoleFormBundle(),
);
}
Follow the steps below or just clone this project, then run:
php test/console.php form:demo
<?php
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Validator\Constraints\Country;
use Symfony\Component\Validator\Constraints\Email;
class DemoType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'name',
'text',
[
'label' => 'Your name',
'required' => true,
'data' => 'Matthias'
]
)
...
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(['data_class' => 'Matthias\SymfonyConsoleForm\Tests\Data\Demo']);
}
public function getName()
{
return 'test';
}
}
The corresponding Demo
class looks like this:
<?php
class Demo
{
public $name;
...
}
<?php
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Matthias\SymfonyConsoleForm\Console\Helper\FormHelper;
class TestCommand extends Command
{
protected function configure()
{
$this->setName('form:demo');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$formHelper = $this->getHelper('form');
/** @var FormHelper $formHelper */
$formData = $formHelper->interactUsingForm(DemoType::class, $input, $output);
// $formData is the valid and populated form data object/array
...
}
}
When you provide command-line options with the names of the form fields, those values will be used as default values.
If you add the --no-interaction
option when running the command, it will submit the form using the input options you provided.
If the submitted data is invalid the command will fail.
<?php
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Matthias\SymfonyConsoleForm\Console\Helper\FormHelper;
class TestCommand extends Command
{
protected function configure()
{
$this->setName('form:demo');
$this->addOption('custom-option', null, InputOption::VALUE_OPTIONAL, 'Your custom option', 'option1')
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$formHelper = $this->getHelper('form');
/** @var FormHelper $formHelper */
$formData = $formHelper->interactUsingNamedForm('custom-option', ChoiceType::class, $input, $output, [
'label' => 'Your label',
'help' => 'Additional information to help the interaction',
'choices' => [
'Default value label' => 'option1',
'Another value Label' => 'option2',
]
]);
// $formData will be "option1" or "option2" and option "--custom-option" will be used as default value
...
}
}
If you have a complex compound form, you can define options and reference form children using square brackets:
<?php
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Matthias\SymfonyConsoleForm\Console\Helper\FormHelper;
class TestCommand extends Command
{
protected function configure()
{
$this
->addOption('user[username]', null, InputOption::VALUE_OPTIONAL)
->addOption('user[email]', null, InputOption::VALUE_OPTIONAL)
->addOption('user[address][street]', null, InputOption::VALUE_OPTIONAL)
->addOption('user[address][city]', null, InputOption::VALUE_OPTIONAL)
->addOption('acceptTerms', null, InputOption::VALUE_OPTIONAL)
;
}
...
}
- Maybe: provide a way to submit a form at once, possibly using a JSON-encoded array
- Add more functional tests
- Show form label of root form
- Show nesting in form hierarchy using breadcrumbs
- When these things have been provided, release this as a package (or multiple packages for stand-alone use)