Open tacman opened 2 years ago
Can you describe more what you're looking for from this library?
From this library (console-extra), I don't have any specific things I'm looking for, though the V2 list #29 looks good.
From the bundle, I'm just thinking of something that acts like make:entity, but generates an invokable controller.
So bin/console make:invokable-controller create:book --description "Creates or updates a book in the database" --arg book --arg isbn --arg author
would generate
#[AsCommand('create:book', 'Creates or updates a book in the database')]
final class CreateBookCommand extends InvokableServiceCommand
{
use ConfigureWithAttributes;
public function __invoke(
IO $io,
#[Argument]
string $author,
#[Argument]
string $isbn,
#[Argument]
string $author,
): void {
$io->success('Finished');
}
}
Maybe instead of --arg, it could be --string, --array, etc.
Just brainstorming.
Of course, I'd want to use the model factories from zenstruck/foundry.
Oh ok, you refer to a maker for an invokable controller (make:invokable-controller
) but you actually mean an invokable command maker (make:invokable-command
).
Indeed, I think this is a good idea. I have an open issue related to this: #3.
To start, maybe make:invokable-command --arg book --arg isbn --arg author --option foo
would generate string
properties for the --arg
's and bool
properties for the --options
as that's probably the most common types. We could then possibly add --arg-array
, --option-array
, etc...
Trying to think how best to wire such a maker. This library doesn't include a bundle so it seems a bit much to create a bundle just for wiring the maker in dev. What about a contrib-recipe that wires the maker service?
What about a contrib-recipe that wires the maker service?
I'm not sure how that would work. contrib-recipe is one of the few parts of the Symfony ecosystem that I dislike. But I'm sure there's a solution there.
Alternatively, there could be a make-invokable-bundle, that would provide makers for both controllers and commands.
One maker that's been missing (IMHO) is a make:dto. Given your experience with make:factory, it seems like there's some overlap. IF you were to create something like that, then perhaps you could have a zenstruck-maker-bundle for all of these.
OR, if Foundry is not specific to Model Factories, you could move bundle to there, since it's already got the maker and such.
Again, just brainstorming.
I took a stab at this in my own maker-bundle. Feedback welcome.
symfony new --webapp make-invokable-command-demo && cd make-invokable-command-demo
composer req survos/maker-bundle --dev
bin/console survos:make:command app:test "Just a silly test" --arg name --arg code --oint-arg size --obool-arg force
Generates
<?php
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Zenstruck\Console\Attribute\Argument;
use Zenstruck\Console\Attribute\Option;
use Zenstruck\Console\ConfigureWithAttributes;
use Zenstruck\Console\IO;
use Zenstruck\Console\InvokableServiceCommand;
use Zenstruck\Console\RunsCommands;
use Zenstruck\Console\RunsProcesses;
#[AsCommand('app:test', 'Just a silly test')]
final class AppTestCommand extends InvokableServiceCommand
{
use ConfigureWithAttributes, RunsCommands, RunsProcesses;
public function __invoke(
IO $io,
// custom injections
// UserRepository $repo,
// expand the arguments and options
#[Argument(description: 'string')]
string $name,
#[Argument(description: 'string')]
string $code,
#[Argument(description: '?int')]
?int $size,
#[Argument(description: '?bool')]
?bool $force,
#[Option(name: 'role', shortcut: 'r')]
array $roles,
): void {
$io->note(sprintf("string %s %s", 'name', $name) ?? 'null');
$io->note(sprintf("string %s %s", 'code', $code) ?? 'null');
$io->note(sprintf("?int %s %s", 'size', $size) ?? 'null');
$io->note(sprintf("?bool %s %s", 'force', $force) ?? 'null');
// $this->runCommand('another:command');
// $this->runProcess('/some/script');
$io->success('app:test success.');
}
}
And works as expected:
bin/console app:test --help
Description:
Just a silly test
Usage:
app:test [options] [--] <name> <code> [<size> [<force>]]
Arguments:
name string
code string
size ?int
force ?bool
Options:
-r, --role=ROLE (multiple values allowed)
-h, --help Display help for the given command. When no command is given display help for the list command
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi|--no-ansi Force (or disable --no-ansi) ANSI output
-n, --no-interaction Do not ask any interactive question
-e, --env=ENV The Environment name. [default: "dev"]
--no-debug Switch off debug mode.
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
tac@pop-os:~/survos/play/make-invokable-command-demo$
tac@pop-os:~/survos/play/make-invokable-command-demo$ bin/console app:test "Bob Smith" smith_robert 15
! [NOTE] string name Bob Smith
! [NOTE] string code smith_robert
! [NOTE] ?int size 15
! [NOTE] ?bool force
[OK] app:test success.
Still a work in progress. Creating the options from the command line isn't implemented yet, and still some polish to do.
Cool! I like this.
What do you think about the following syntax for arguments (special type prefix - defaults to string)?
bin/console make:invokable-command app:test name code ?int:size ?bool:force --description="Just a silly test"
For args:
name
: string $name
?name
: ?string $name
?int:name
: ?int $name
name[]
: array $name
We could do something similar for options.
Additional, making it interactive like make:entity
would be very useful I think!
I like that format, I'll play around with it.
I wonder if ?bool should be handled differently, since it's really a flag to the command. That is, generate the equivalent of:
->addOption('force', InputOption::VALUE_NONE|InputOption::VALUE_NEGATABLE)
On Fri, Sep 30, 2022 at 10:54 AM Kevin Bond @.***> wrote:
Cool! I like this.
What do you think about the following syntax for arguments (special type prefix - defaults to string)?
bin/console make:invokable-command app:test name code ?int:size ?bool:force --description="Just a silly test"
For args:
- name: string $name
- ?name: ?string $name
- ?int:name: ?int $name
- name[]: array $name
We could do something similar for options.
Additional, making it interactive like make:entity would be very useful I think!
— Reply to this email directly, view it on GitHub https://github.com/zenstruck/console-extra/issues/31#issuecomment-1263680773, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAEXIQIAS4IP6NLERFU4EWTWA35LFANCNFSM57FNRKAA . You are receiving this because you authored the thread.Message ID: @.***>
I wonder if ?bool should be handled differently, since it's really a flag
Good point!
I do want to deprecate/remove docblock/@command
syntax, but this might be helpful to determine the syntax for a maker.
I've played around some more, this is now working, though the internals are kinda ugly.
bin/console survos:make:command app:greet \
string:message:"What do you want to say?" \
array:names:"Who do you want to greet (separate multiple names with a space)?" \
int:iterations-i?:"How many times should the message be printed?" \
array:colors?:"Which colors do you like?" \
bool:yell?
bin/console app:greet --help
Usage:
app:greet [options] [--] <message> <names>...
Arguments:
message What do you want to say?
names Who do you want to greet (separate multiple names with a space)?
Options:
-i, --iterations=ITERATIONS How many times should the message be printed?
--colors=COLORS Which colors do you like? (multiple values allowed)
--yell (bool)
The syntax rules
type // If a ? preceeds the type, then it's an optional argument
:
name // if the name ends in ?, then it's an option. If the name has a hyphenated suffix, use that is the shortcut.
:
description
I played around with a few ways to do default, I think the best way is to parse an = in the name, e.g.
int:iterations-i?=7:"How many times should the message be printed?" \
Additional, making it interactive like
make:entity
would be very useful I think!
This is how I incorporate make:entity into a script with multiple fields:
cat <<'EOF' | sed "s/:/\n/g" | bin/console make:entity Country
name:string:55:no
alpha2:string:2:no
alpha3:string:3:yes
EOF
I don't love it, I prefer the approach we've been working on here, but perhaps the better solution is to implement the interactive approach like make:entity and use this pipe approach.
I think, at the end of the day, an ugly syntax/internals is ok because the expectation would be to use the maker interactively.
Yeah, my use case is a bit funky -- I want to have a single bash script that can create a complete application (and related tutorial), without ever opening an IDE.
So the workflow I'm playing with now, for creating a demo application of a bundle I'm working on, is
The primary reason I want to do this from symfony new to symfony run entirely from the command line is because often I can't figure out how to use a bundle from within my application. Often demos don't work with the latest version of Symfony or PHP, so before I even get started I'm running rector and composer recipes:update and the like, tweaking security.yaml and doctrine_migrations.yaml, etc.
Anyway, not particularly relevant, but I quite like the elegance of your invokable controllers (and your twig components, but that's a topic for another place).
What a cool library!
Sometimes instead of loading fixtures, I want a simple command that let's me create/update an object. For example:
Obviously, I can create that now using Symfony's
make:command
, but I like how tight the code is using console-extra.Perhaps Symfony 7 will incorporate this structure into make:command, but in the meantime, it'd be nice to have something that facilitated create it.