Skip to content

[Form] Support "{{ label }}" placeholder in error messages #12238

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

Closed
webmozart opened this issue Oct 16, 2014 · 15 comments
Closed

[Form] Support "{{ label }}" placeholder in error messages #12238

webmozart opened this issue Oct 16, 2014 · 15 comments

Comments

@webmozart
Copy link
Contributor

Origin of this ticket: #5714

Currently, it is not possible to write error messages that contain the name of the field that they concern. Technically, that's logical, since the Validator component is not aware of the Form component.

However, it would be quite simple to support "{{ label }}" placeholders (or similar). These could be set by the validator to the field's name by default ("title" in the below example), and overwritten in the Form context by the corresponding field's label:

class Article
{
    /**
     * @Assert\NotBlank(message="The field {{ label }} should not be blank.")
     */
    private $title;
}
@linaori
Copy link
Contributor

linaori commented Oct 17, 2014

👍 If it also goes through trans()

@timglabisch
Copy link

+1

2 similar comments
@sstok
Copy link
Contributor

sstok commented Oct 20, 2014

👍

@nurikabe
Copy link

👍

@ErikTrapman
Copy link

Where exactly in the process should this be converted do you think? The ViolationMapper adds the FormError with the $message/$messageTemplate. I suppose the message should be transformed/translated at that point or earlier?

@cleentfaar
Copy link

Sad to see this issue has become a bit outdated, we could really use this functionality in our projects! With a few pointers on the approach I'd be happy to submit a PR for this so this can be fixed.

@webmozart would you know if @ErikTrapman suggestion is on the right track? I can have a go with that to start with.

@antonch1989
Copy link
Contributor

so there is still no pull request? I would work on this issue if no one objects

@xabbuh
Copy link
Member

xabbuh commented Aug 3, 2019

Please do and do not hesitate to ask if you need any help. :)

@gmponos
Copy link
Contributor

gmponos commented Aug 3, 2019

Wow.. I just discovered this issue.. I thought that not supporting {{ label }} was by design/on purpose..

Let me know also.. otherwise I would also be willing to work on this...

@antonch1989
Copy link
Contributor

working on this already, I'll give a feedback in case there will be any problems

@v20100v
Copy link

v20100v commented Nov 6, 2019

If you look the Symfony\Component\Validator\Constraints\Notblank class is empty, but you can add a custom placeholder.... by extends it and create yout custom validator like this.

According to the documentation (https://symfony.com/doc/current/validation/custom_constraint.html), first we create a Constraint class by extends NotBlank.

// src/Validator/Constraints/NotBlankWithPlaceholder.php

namespace App\Validator\Constraints;
use Symfony\Component\Validator\Constraints\NotBlank;

/**
 * @Annotation
 */
class NotBlankWithPlaceholder extends NotBlank
{
    /**
     * @var string
     */
    public $placeholder;
}

After we create (into the same folder of custom constraint class, the validator like this

// src/Validator/Constraints/NotBlankWithPlaceholderValidator.php

namespace App\Validator\Constraints;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;

class NotBlankWithPlaceholderValidator extends ConstraintValidator
{
    public function validate($value, Constraint $constraint)
    {
        if (!$constraint instanceof NotBlankWithPlaceholder) {
            throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\NotBlankWithPlaceholder');
        }

        if (false === $value || (empty($value) && '0' != $value)) {
            $this->context->buildViolation($constraint->message)
                ->setParameter('{{ value }}', $this->formatValue($value))
                ->setParameter('{{ placeholder }}', $constraint->placeholder)
                ->setCode(NotBlankWithPlaceholder::IS_BLANK_ERROR)
                ->addViolation();
        }
    }
}

After we use translate validation constraint messages by creating a validators catalog into the translations directory (see https://symfony.com/doc/current/validation/translations.html)

# translations/validators.fr.yaml
code:
  not_blank:
    male: Le code d'un {{ placeholder }} ne peut être vide !
    female: Le code d'une {{ placeholder }} ne peut être vide !

And finaly we can use the custom validator into your entity like this. Don't forget to add namespace of your custom contraint with use App\Validator\Constraints as AppAssert;

// src/Entity/Domaine.php

/**
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="App\Repository\DomaineRepository")
 */
class Domaine
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=10)
     * @AppAssert\NotBlankWithPlaceholder(
     *     message = "code.not_blank.male",
     *     placeholder = "domaine"
     * )
     */
    private $code;

You can change placeholder with label, and you can imagine with an array collection placeholders in order to pass multiple variables, as you can do with sprintf.

^^.

@gmponos
Copy link
Contributor

gmponos commented Nov 6, 2019

Yes we did the same thing...

@v20100v if I am not mistaken one more problem with the above approach is that the placeholder is not translated.

This enforced us to inject in each validator the translator which made the code ugly.

@a-menshchikov
Copy link
Contributor

What behavior is implied if the validation runs manually, not through form component? Maybe we should add new constraint option, such as form-message? Because it will contains message in terms of forms that not actual in other contexts.

@a-menshchikov
Copy link
Contributor

After some research I can offer such a solution.
To add into ExecutionContext $parameters property that will be used in buildViolation method for be merged with passed to this method parameters. In FormValidator we can collect these parameters and set into context while making validator object (https://github.com/symfony/form/blob/master/Extension/Validator/Constraints/FormValidator.php#L43). After that we can use these parameters in constraints messages. The only caveat is that constraint message of any property will be able to use label of any other property. But I find this feature rather useful than harmful, because it makes me able to show message like «The field "City" should be filled if "Street" was given». Parameters can be named like "{{ form.city.label }}" (form.[field name].label).

@xabbuh what do you think about this?

@BruceGitHub
Copy link

It Is possible ti work on this ?

@fabpot fabpot closed this as completed Sep 1, 2020
fabpot added a commit that referenced this issue Sep 1, 2020
…in constraint messages (a-menshchikov)

This PR was squashed before being merged into the 5.2-dev branch.

Discussion
----------

Added support for using the "{{ label }}" placeholder in constraint messages

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | #12238
| License       | MIT
| Doc PR        |

- [ ] Add docs PR

Commits
-------

0d9f442 Added support for using the "{{ label }}" placeholder in constraint messages
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