zenstruck / console-extra

A modular set of features to reduce configuration boilerplate for your Symfony commands.
MIT License
78 stars 3 forks source link

argument and option validation? #40

Open tacman opened 2 years ago

tacman commented 2 years ago

Can the invokable commands use validation? That is

Since you're looking at Closures for auto-completion, I wanted to brainstorm about the idea of assertions / validations in the commands.

One approach:

#[Argument(description: 'path to image directory', assert: fn(string $path) => is_dir($path), msg: "%s is not a valid path")]
string $path,

// to replace

): void {

    if (!is_dir($path)) {
        throw new \LogicException("$path is not a directory");
    }

Perhaps the assertion could also take a Symfony Expression?

It's not just individual elements that need validation, it might be the whole set (like a form validation).

#[Argument(description: 'image to process', assert: [$this, 'fileExists'])]
?string $imageFilename,

private function fileExists() {
    $pathToImage = $this->path . $this->imageFilename;
    if (!file_exists($pathToImage)) {
        throw new \LogicException("$pathToImage is not a file");
    }

Of course, even better would be to use the Symfony validators that already exist:

#[AsCommand('app:create-record', 'Create an image record with associated PDF')]
final class MyCommand extends InvokableServiceCommand
{
    use ConfigureWithAttributes, RunsCommands, RunsProcesses;

    public function __invoke(
        IO      $io,

        #[Argument(description: 'path to pdf')]
        #[Assert\File(
            mimeTypes: ['application/pdf', 'application/x-pdf'],
            mimeTypesMessage: 'Please provide a valid PDF',
        )]
        string  $pdf,

        #[Argument(description: 'image filename')]
        #[Assert\Image()]
        string  $image,

        #[Option(description: 'path to pdf')]
        #[Assert\File()]
        ?string $pdfPath="~/Documents/",

The Constraint would need to be extended, to allow for the property: \Attribute::TARGET_PARAMETER

#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE | \Attribute::TARGET_PARAMETER)]
class File extends Constraint

Again, just brainstorming. It feels like there's an elegant solution in here somewhere.