Skip to content

Commit

Permalink
Added reversable form builder to the laravel installer
Browse files Browse the repository at this point in the history
  • Loading branch information
Fermin committed Jun 20, 2024
1 parent 30a4682 commit 530d422
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 182 deletions.
15 changes: 9 additions & 6 deletions src/FormBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@

namespace Laravel\Installer\Console;

use Illuminate\Support\Traits\Conditionable;
use Laravel\Prompts\FormBuilder as BaseFormBuilder;
use Closure;

class FormBuilder extends BaseFormBuilder
class FormBuilder extends \Laravel\Prompts\FormBuilder
{
use Conditionable;
public function addWithCondition(Closure $step, ?string $name = null, bool $ignoreWhenReverting = false, bool|Closure $condition = true): self
{
$this->steps[] = new \Laravel\Prompts\FormStep($step, $condition, $name, $ignoreWhenReverting);
return $this;
}

public static function make(): self
public function getStepsCount()
{
return new self();
return count($this->steps);
}
}
313 changes: 137 additions & 176 deletions src/NewCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
use function Laravel\Prompts\multiselect;
use function Laravel\Prompts\select;
use function Laravel\Prompts\text;
use function Laravel\Prompts\form;

class NewCommand extends Command
{
Expand All @@ -32,11 +31,6 @@ class NewCommand extends Command
*/
protected $composer;

/**
* @var FormBuilder
*/
protected $form;

/**
* Configure the command options.
*
Expand Down Expand Up @@ -82,97 +76,89 @@ protected function interact(InputInterface $input, OutputInterface $output)
parent::interact($input, $output);

$this->configurePrompts($input, $output);

$this->form = FormBuilder::make();

$this->form->add(
fn () => $output->write(PHP_EOL.' <fg=red> _ _
$output->write(PHP_EOL.' <fg=red> _ _
| | | |
| | __ _ _ __ __ ___ _____| |
| | / _` | \'__/ _` \ \ / / _ \ |
| |___| (_| | | | (_| |\ V / __/ |
|______\__,_|_| \__,_| \_/ \___|_|</>'.PHP_EOL.PHP_EOL),
ignoreWhenReverting: true
)->when(
!$input->getArgument('name'),
fn () => $this->form->add(
fn () => text(
label: 'What is the name of your project?',
placeholder: 'E.g. example-app',
required: 'The project name is required.',
validate: function ($value) use ($input) {
if (preg_match('/[^\pL\pN\-_.]/', $value) !== 0) {
return 'The name may only contain letters, numbers, dashes, underscores, and periods.';
}

if ($input->getOption('force') !== true) {
try {
$this->verifyApplicationDoesntExist($this->getInstallationDirectory($value));
} catch (RuntimeException $e) {
return 'Application already exists.';
}
|______\__,_|_| \__,_| \_/ \___|_|</>'.PHP_EOL.PHP_EOL);
(new FormBuilder())->addWithCondition(
fn () => $input->setArgument('name', text(
label: 'What is the name of your project?',
placeholder: 'E.g. example-app',
required: 'The project name is required.',
validate: function ($value) use ($input) {
if (preg_match('/[^\pL\pN\-_.]/', $value) !== 0) {
return 'The name may only contain letters, numbers, dashes, underscores, and periods.';
}

if ($input->getOption('force') !== true) {
try {
$this->verifyApplicationDoesntExist($this->getInstallationDirectory($value));
} catch (RuntimeException $e) {
return 'Application already exists.';
}
},
),
name: 'name',
)->add(fn ($responses) => $input->setArgument('name', $responses['name']), ignoreWhenReverting: true)
)->when(
$input->getOption('force') !== true,
fn () => $this->form->add(
fn () => $this->verifyApplicationDoesntExist(
$this->getInstallationDirectory($input->getArgument('name'))
),
ignoreWhenReverting: true
)
)->when(
!$input->getOption('breeze') && !$input->getOption('jet'),
fn () => $this->form->add(
fn () => select(
label: 'Would you like to install a starter kit?',
options: [
'none' => 'No starter kit',
'breeze' => 'Laravel Breeze',
'jetstream' => 'Laravel Jetstream',
],
default: 'none',
),
name: 'starterKit',
)->add(
fn ($responses) => match ($responses['starterKit']) {
}
},
)),
condition: !$input->getArgument('name')
)->addWithCondition(
fn () => $this->verifyApplicationDoesntExist(
$this->getInstallationDirectory($input->getArgument('name'))
),
ignoreWhenReverting: true,
condition: $input->getOption('force') !== true,
)->addWithCondition(
function ($reponses, $previousResponse) use ($input) {
if ($previousResponse) {
$input->setOption('breeze', false);
$input->setOption('jet', false);
$input->setOption('stack', false);
}
match (select(
label: 'Would you like to install a starter kit?',
options: [
'none' => 'No starter kit',
'breeze' => 'Laravel Breeze',
'jetstream' => 'Laravel Jetstream',
],
default: 'none',
)) {
'breeze' => $input->setOption('breeze', true),
'jetstream' => $input->setOption('jet', true),
default => null,
},
ignoreWhenReverting: true
)
)->when(
$input->getOption('breeze'),
fn () => $this->promptForBreezeOptions($input)
)->when(
$input->getOption('jet'),
fn () => $this->promptForJetstreamOptions($input)
)->when(
! $input->getOption('phpunit') && ! $input->getOption('pest'),
fn () => $this->form->add(
fn () => select(
};

return true;
},
condition: !$input->getOption('breeze') && !$input->getOption('jet')
)->addWithCondition(
function () use($input) {
$this->promptForBreezeOptions($input);
},
condition: fn () => $input->getOption('breeze')
)->addWithCondition(
function () use($input) {
$this->promptForJetstreamOptions($input);
},
condition: fn () => $input->getOption('jet')
)->addWithCondition(
function () use($input) {
$input->setOption('pest', select(
label: 'Which testing framework do you prefer?',
options: ['Pest', 'PHPUnit'],
default: 'Pest',
) === 'Pest',
name: 'pest',
)->add(
fn ($responses) => $input->setOption('pest', $responses['pest'])
)
)->when(
! $input->getOption('git') && $input->getOption('github') === false && Process::fromShellCommandline('git --version')->run() === 0,
fn () => $this->form->add(
fn () => confirm(label: 'Would you like to initialize a Git repository?', default: false),
name: 'git',
)->add(
fn ($responses) => $input->setOption('git', $responses['git'])
)
)
->submit();
) === 'Pest');
},
condition: ! $input->getOption('phpunit') && ! $input->getOption('pest')
)->addWithCondition(
function () use($input) {
$input->setOption('git', confirm(label: 'Would you like to initialize a Git repository?', default: false));
},
condition: ! $input->getOption('git')
&& $input->getOption('github') === false
&& Process::fromShellCommandline('git --version')->run() === 0
)->submit();
}

/**
Expand Down Expand Up @@ -550,57 +536,41 @@ protected function databaseOptions(): array
*/
protected function promptForBreezeOptions(InputInterface $input)
{
$this->form->when(
! $input->getOption('stack'),
fn () => $this->form->add(
fn () => select(
label: 'Which Breeze stack would you like to install?',
options: [
'blade' => 'Blade with Alpine',
'livewire' => 'Livewire (Volt Class API) with Alpine',
'livewire-functional' => 'Livewire (Volt Functional API) with Alpine',
'react' => 'React with Inertia',
'vue' => 'Vue with Inertia',
'api' => 'API only',
],
default: 'blade',
),
name: 'stack',
)->add(
fn ($responses) => $input->setOption('stack', $responses['stack'])
)
)->add(function () use ($input) {
if (in_array($input->getOption('stack'), ['react', 'vue']) && (! $input->getOption('dark') || ! $input->getOption('ssr'))) {
$this->form->add(
fn () => multiselect(
label: 'Would you like any optional features?',
options: [
'dark' => 'Dark mode',
'ssr' => 'Inertia SSR',
'typescript' => 'TypeScript',
],
default: array_filter([
$input->getOption('dark') ? 'dark' : null,
$input->getOption('ssr') ? 'ssr' : null,
$input->getOption('typescript') ? 'typescript' : null,
]),
),
name: 'features',
)->add (
fn ($responses) => collect($responses['features'])->each(fn ($feature) => $input->setOption($feature, true))
);
} elseif (in_array($input->getOption('stack'), ['blade', 'livewire', 'livewire-functional']) && ! $input->getOption('dark')) {
$this->form->add(
fn () => confirm(
label: 'Would you like dark mode support?',
default: false,
),
name: 'supportDarkMode',
)->add(
fn ($responses) => $input->setOption('dark', $responses['supportDarkMode'])
);
}
});
if (! $input->getOption('stack')) {
$input->setOption('stack', select(
label: 'Which Breeze stack would you like to install?',
options: [
'blade' => 'Blade with Alpine',
'livewire' => 'Livewire (Volt Class API) with Alpine',
'livewire-functional' => 'Livewire (Volt Functional API) with Alpine',
'react' => 'React with Inertia',
'vue' => 'Vue with Inertia',
'api' => 'API only',
],
default: 'blade',
));
}

if (in_array($input->getOption('stack'), ['react', 'vue']) && (! $input->getOption('dark') || ! $input->getOption('ssr'))) {
collect(multiselect(
label: 'Would you like any optional features?',
options: [
'dark' => 'Dark mode',
'ssr' => 'Inertia SSR',
'typescript' => 'TypeScript',
],
default: array_filter([
$input->getOption('dark') ? 'dark' : null,
$input->getOption('ssr') ? 'ssr' : null,
$input->getOption('typescript') ? 'typescript' : null,
]),
))->each(fn ($option) => $input->setOption($option, true));
} elseif (in_array($input->getOption('stack'), ['blade', 'livewire', 'livewire-functional']) && ! $input->getOption('dark')) {
$input->setOption('dark', confirm(
label: 'Would you like dark mode support?',
default: false,
));
}
}

/**
Expand All @@ -611,45 +581,36 @@ protected function promptForBreezeOptions(InputInterface $input)
*/
protected function promptForJetstreamOptions(InputInterface $input)
{
$this->form->when(
! $input->getOption('stack'),
fn () => $this->form->add(
fn () => select(
label: 'Which Jetstream stack would you like to install?',
options: [
'livewire' => 'Livewire',
'inertia' => 'Vue with Inertia',
],
default: 'livewire',
),
name: 'jetStreamStack',
)->add(
fn ($responses) => $input->setOption('stack', $responses['jetStreamStack'])
)
)->add(
fn () => $this->form->multiselect(
label: 'Would you like any optional features?',
options: collect([
'api' => 'API support',
'dark' => 'Dark mode',
'verification' => 'Email verification',
'teams' => 'Team support',
])->when(
$input->getOption('stack') === 'inertia',
fn ($options) => $options->put('ssr', 'Inertia SSR')
)->all(),
default: array_filter([
$input->getOption('api') ? 'api' : null,
$input->getOption('dark') ? 'dark' : null,
$input->getOption('teams') ? 'teams' : null,
$input->getOption('verification') ? 'verification' : null,
$input->getOption('stack') === 'inertia' && $input->getOption('ssr') ? 'ssr' : null,
]),
),
name: 'features',
)->add(
fn ($responses) => collect($responses['features'])->each(fn ($feature) => $input->setOption($feature, true))
);
if (! $input->getOption('stack')) {
$input->setOption('stack', select(
label: 'Which Jetstream stack would you like to install?',
options: [
'livewire' => 'Livewire',
'inertia' => 'Vue with Inertia',
],
default: 'livewire',
));
}

collect(multiselect(
label: 'Would you like any optional features?',
options: collect([
'api' => 'API support',
'dark' => 'Dark mode',
'verification' => 'Email verification',
'teams' => 'Team support',
])->when(
$input->getOption('stack') === 'inertia',
fn ($options) => $options->put('ssr', 'Inertia SSR')
)->all(),
default: array_filter([
$input->getOption('api') ? 'api' : null,
$input->getOption('dark') ? 'dark' : null,
$input->getOption('teams') ? 'teams' : null,
$input->getOption('verification') ? 'verification' : null,
$input->getOption('stack') === 'inertia' && $input->getOption('ssr') ? 'ssr' : null,
]),
))->each(fn ($option) => $input->setOption($option, true));
}

/**
Expand Down
Loading

0 comments on commit 530d422

Please sign in to comment.