Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose validation rules #46409

Closed
xepozz opened this issue May 19, 2022 · 12 comments
Closed

Expose validation rules #46409

xepozz opened this issue May 19, 2022 · 12 comments

Comments

@xepozz
Copy link
Contributor

xepozz commented May 19, 2022

Description

Problem

I want to sync my backend and frontend validation rules. Frontend will receive some structure and apply it as rules. But this is another story.
So I want to expose all form/dto rules into API and take it all in client side.

Implementation

I see you have \Symfony\Component\Validator\Command\DebugCommand that dumps rules, but it works only with console.

What do you think to leave it also as a separated class?

P.S.
It's already exist in Yii and it's useful, but in Symfony project I need the same feature.

Example

The implementation, naming or etc don't matter, but I think it will look like the following snippet:

class UserController
{
    #[Route('/user', methods: ['post'])]
    public function create(
        UserDTO $dto,
        ValidatorInterface $validator,
    )  {
        $errors = $validator->validate($dto);
        // if (count($errors) > 0) { ... }
        // etc.
    }

    #[Route('/user/form', methods: ['get'])]
    public function dump(
        UserDTO $dto,
        ValidationConstraintsDumper $dumper,
    )  {
        $validationConstraints = $dumper->dump($dto);
        // map constraints into needed structure
        // return $validationConstraints;
    }
}
@stof
Copy link
Member

stof commented May 19, 2022

The whole issues lies in this comment: // map constraints into needed structure.
There is no standard for a representation of validation constraints to allow the frontend code to run them. And so there is no way to provide such feature in Symfony itself.

@xepozz
Copy link
Contributor Author

xepozz commented May 19, 2022

Ok I got you.

@tarlepp
Copy link
Contributor

tarlepp commented May 19, 2022

I have something like this:

if ($errors->count() > 0) {
    throw new ValidatorException($dto::class, $errors);
}

ValidatorException.php:

<?php
declare(strict_types = 1);

namespace App\Exception;

use App\Exception\interfaces\ClientErrorInterface;
use App\Exception\models\ValidatorError;
use Symfony\Component\Validator\ConstraintViolationInterface;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use Symfony\Component\Validator\Exception\ValidatorException as BaseValidatorException;

class ValidatorException extends BaseValidatorException implements ClientErrorInterface
{
    public function __construct(string $target, ConstraintViolationListInterface $errors)
    {
        parent::__construct(
            json_encode(
                array_map(
                    static fn (ConstraintViolationInterface $error): ValidatorError =>
                        new ValidatorError($error, $target),
                    iterator_to_array($errors),
                ),
            ),
        );
    }

    public function getStatusCode(): int
    {
        return 400;
    }
}

ValidatorError.php:

<?php
declare(strict_types = 1);

namespace App\Exception\models;

use Stringable;
use Symfony\Component\Validator\ConstraintViolationInterface;

class ValidatorError
{
    public string | Stringable $message;
    public string $propertyPath;
    public string $target;
    public string | null $code;

    public function __construct(ConstraintViolationInterface $error, string $target)
    {
        $this->message = $error->getMessage();
        $this->propertyPath = $error->getPropertyPath();
        $this->target = str_replace('\\', '.', $target);
        $this->code = $error->getCode();
    }
}

@xepozz
Copy link
Contributor Author

xepozz commented May 20, 2022

But it's not parameters for constraints, it's error serialisation.

Btw, we also don't have any standards for this functionality, but for some reasons Symfony allows us to use it with custom mapping only.

@garak
Copy link
Contributor

garak commented May 22, 2022

Maybe contracts can fit your needs. Take a look to phpacto library

@andinger
Copy link

What about using JSON Schema for this case?

@carsonbot
Copy link

Thank you for this suggestion.
There has not been a lot of activity here for a while. Would you still like to see this feature?

@xepozz
Copy link
Contributor Author

xepozz commented Dec 5, 2022

Yes, sure

@carsonbot carsonbot removed the Stalled label Dec 5, 2022
@BoShurik
Copy link
Contributor

BoShurik commented Mar 3, 2023

As a workaround you can use something like this: https://gist.github.com/BoShurik/009cdeef1fb7a43fc1856feaaf317062

@carsonbot
Copy link

Thank you for this suggestion.
There has not been a lot of activity here for a while. Would you still like to see this feature?

@carsonbot
Copy link

Hello? This issue is about to be closed if nobody replies.

@carsonbot
Copy link

Hey,

I didn't hear anything so I'm going to close it. Feel free to comment if this is still relevant, I can always reopen!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants