Thanks to visit codestin.com
Credit goes to github.com

Skip to content

AllValidator should not throw when not traversable is passed #26477

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
wants to merge 1 commit into from

Conversation

zerkms
Copy link
Contributor

@zerkms zerkms commented Mar 9, 2018

Q A
Branch? master
Bug fix? no
New feature? no
BC breaks? behavior change
Deprecations? no
Tests pass? yes
Fixed tickets #26463
License MIT

The same way AllValidator does not throw for empty values, and the same way every other validator does not throw but skips or returns a violation instead - the AllValidator should return null in case if not an array or a traversable passed.

@Destroy666x
Copy link

Destroy666x commented Mar 12, 2018

What's the use case of this change? The reason of returning when value is empty is that there's NotBlank validator. Which is already kind of clunky, IMO. I'd expect an exception when passing a string as shown in the test.

EDIT: oh, the use case is in the issue, I see your point. But I don't agree with your approach of loose variables that store simple stuff like E-mails as you've shown in the example. Maybe a better example that's not easily achievable with type hinting would change my mind.

Also, regardless of that it requires a change to a lot of validators for consistency as you mentioned. And it's definitely not a bug.

@ogizanagi
Copy link
Contributor

ogizanagi commented Mar 12, 2018

I understand everyone's points here, but I really think requiring to use group sequences to workaround this is really bad DX for such a simple case (so I'd be in favor of removing this exception).
However, the suggested implementation has a drawback that should clearly not be ignored: it means current code missing a proper Type("array") (or similar) constraint will pass validation successfully whereas previously an exception was thrown preventing from invalid data (but generating a 500...).

So instead, shouldn't we just add a violation?
Or perhaps we should introduce a new UnexpectedValueTypeException extending UnexpectedTypeException that'll be caught and transformed into a violation by the component.
We should also inspect more thoroughly other validators.

Anyway, thanks @zerkms for opening this issue & PR. I had this in my todo list since few months but haven't taken the time to report it yet.

@nicolas-grekas nicolas-grekas added this to the 4.1 milestone Mar 12, 2018
@zerkms
Copy link
Contributor Author

zerkms commented Mar 12, 2018

Maybe a better example that's not easily achievable with type hinting would change my mind.

@Destroy666x that's trivial: implement an API that accepts a JSON object with a user account:

  1. First Name
  2. Last Name
  3. Email
  4. A list of addresses

None of 1-4 items can be validated reliably (without the using the groups in a weird way)

@zerkms
Copy link
Contributor Author

zerkms commented Mar 12, 2018

However, the suggested implementation has a drawback that should clearly not be ignored: it means current code missing a proper Type("array") (or similar) constraint will pass validation successfully whereas previously an exception was thrown preventing from invalid data (but generating a 500...).

@ogizanagi Currently it would also pass validation if you pass an empty value (or don't pass it at all) unless you have a NotBlank validator. To me - the cases of having mandatory NotBlank to check blank values is the same as having mandatory Type("array") to ensure it's an array.

In either case - I personally think the validator should never throw: literally any arbitrary input should either return 0 or N violation errors.

@ogizanagi
Copy link
Contributor

Currently it would also pass validation if you pass an empty value (or don't pass it at all) unless you have a NotBlank validator. To me - the cases of having mandatory NotBlank to check blank values is the same as having mandatory Type("array") to ensure it's an array.

True. I'm just saying this implementation might be dangerous for existing applications not having proper Type constraints and for which validation will now be successful and might jeopardize data integrity without further warning. The harm is done. To me, we should account for this and it won't look a bad solution to me for the AllValidator to add a violation in such case.

@zerkms
Copy link
Contributor Author

zerkms commented Mar 12, 2018

In that case I'm glad I've raised an awareness :-) Do we close this?

@ogizanagi
Copy link
Contributor

Let's wait for more feedback. No need to close anyway if you're still up to provide a solution regarding the original issue, even if the implementation may differ.

@Destroy666x
Copy link

Destroy666x commented Mar 13, 2018

None of 1-4 items can be validated reliably

@zerkms why not? You just deserialize it properly into a class and pass corresponding properties to proper validators. I've validated a lot of such JSONs with no problem.

I surely agree with NotBlank/NotNull inconsistencies being improper though - comparing that to having to use Type is fair.

@zerkms
Copy link
Contributor Author

zerkms commented Mar 13, 2018

@Destroy666x

for the very same reason I reported an issue: if a type mismatches - an exception is thrown. So you don't have a viloations list, just an exception.

Try to create the validator that validates those 4 fields and validate this: {"email":[]}

@ostrolucky
Copy link
Contributor

Another possible solution is to deprecate this constraint in favor of new Each constraint, as was planned long time ago #9888 This new constraint can be made to not throw exception

@zerkms
Copy link
Contributor Author

zerkms commented Apr 2, 2018

@ostrolucky the problem is much deeper: a lot of validators throw. It must be fixed everywhere.

@nicolas-grekas nicolas-grekas modified the milestones: 4.1, next Apr 20, 2018
symfony-splitter pushed a commit to symfony/messenger that referenced this pull request May 7, 2018
…ing (ogizanagi)

This PR was squashed before being merged into the 4.1-dev branch (closes #26945).

Discussion
----------

[Messenger] Support configuring messages when dispatching

| Q             | A
| ------------- | ---
| Branch?       | master <!-- see below -->
| Bug fix?      | no
| New feature?  | yes <!-- don't forget to update src/**/CHANGELOG.md files -->
| BC breaks?    | no     <!-- see https://symfony.com/bc -->
| Deprecations? | no <!-- don't forget to update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tests pass?   | see CI checks    <!-- please add some, will be required by reviewers -->
| Fixed tickets | N/A   <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | todo

For now, this is mainly a RFC to get your opinion on such a feature (so it misses proper tests).
Supporting wrapped messages out-of-the-box would mainly allow to easily create middlewares that should act only or be configured differently for specific messages (by using wrappers instead of making messages implements specific interfaces and without requiring dedicated buses). For instance, I might want to track specific messages and expose metrics about it.

The Symfony Serializer transport (relates to #26900) and Validator middleware serve as guinea pigs for sample purpose here. But despite message validation usually is simple as it matches one use-case and won't require specific validation groups in most cases, I still think it can be useful sometimes. Also there is the case of the [`AllValidator` which currently requires using a `GroupSequence`](symfony/symfony#26477) as a workaround, but that could also be specified directly in message metadata instead.

## Latest updates

PR updated to use a flat version of configurations instead of wrappers, using an `Envelope` wrapper and a list of envelope items.
Usage:

```php
$message = Envelope::wrap(new DummyMessage('Hello'))
    ->with(new SerializerConfiguration(array(ObjectNormalizer::GROUPS => array('foo'))))
    ->with(new ValidationConfiguration(array('foo', 'bar')))
;
```

~~By default, Messenger protagonists receive the original message. But each of them can opt-in to receive the envelope instead, by implementing `EnvelopeReaderInterface`.
Then, they can read configurations from it and forward the original message or the envelope to another party.~~

Senders, encoders/decoders & receivers always get an `Envelope`.
Middlewares & handlers always get a message. But middlewares can opt-in to receive the envelope instead, by implementing `EnvelopeReaderInterface`.

Commits
-------

749054a1e8 [Messenger] Support configuring messages when dispatching
sroze added a commit that referenced this pull request May 7, 2018
…ing (ogizanagi)

This PR was squashed before being merged into the 4.1-dev branch (closes #26945).

Discussion
----------

[Messenger] Support configuring messages when dispatching

| Q             | A
| ------------- | ---
| Branch?       | master <!-- see below -->
| Bug fix?      | no
| New feature?  | yes <!-- don't forget to update src/**/CHANGELOG.md files -->
| BC breaks?    | no     <!-- see https://symfony.com/bc -->
| Deprecations? | no <!-- don't forget to update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tests pass?   | see CI checks    <!-- please add some, will be required by reviewers -->
| Fixed tickets | N/A   <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | todo

For now, this is mainly a RFC to get your opinion on such a feature (so it misses proper tests).
Supporting wrapped messages out-of-the-box would mainly allow to easily create middlewares that should act only or be configured differently for specific messages (by using wrappers instead of making messages implements specific interfaces and without requiring dedicated buses). For instance, I might want to track specific messages and expose metrics about it.

The Symfony Serializer transport (relates to #26900) and Validator middleware serve as guinea pigs for sample purpose here. But despite message validation usually is simple as it matches one use-case and won't require specific validation groups in most cases, I still think it can be useful sometimes. Also there is the case of the [`AllValidator` which currently requires using a `GroupSequence`](#26477) as a workaround, but that could also be specified directly in message metadata instead.

## Latest updates

PR updated to use a flat version of configurations instead of wrappers, using an `Envelope` wrapper and a list of envelope items.
Usage:

```php
$message = Envelope::wrap(new DummyMessage('Hello'))
    ->with(new SerializerConfiguration(array(ObjectNormalizer::GROUPS => array('foo'))))
    ->with(new ValidationConfiguration(array('foo', 'bar')))
;
```

~~By default, Messenger protagonists receive the original message. But each of them can opt-in to receive the envelope instead, by implementing `EnvelopeReaderInterface`.
Then, they can read configurations from it and forward the original message or the envelope to another party.~~

Senders, encoders/decoders & receivers always get an `Envelope`.
Middlewares & handlers always get a message. But middlewares can opt-in to receive the envelope instead, by implementing `EnvelopeReaderInterface`.

Commits
-------

749054a [Messenger] Support configuring messages when dispatching
@ogizanagi
Copy link
Contributor

Closing, since #27917 is merged and should solve the issue with AllValidator.
Cheers! (and thanks @xabbuh)

@ogizanagi ogizanagi closed this Oct 24, 2018
@nicolas-grekas nicolas-grekas modified the milestones: next, 4.2 Nov 1, 2018
@zerkms zerkms deleted the ALL_VALIDATOR_NULL_NOT_ARRAY branch June 27, 2019 10:07
symfony-splitter pushed a commit to symfony/messenger that referenced this pull request Jan 28, 2020
…ing (ogizanagi)

This PR was squashed before being merged into the 4.1-dev branch (closes #26945).

Discussion
----------

[Messenger] Support configuring messages when dispatching

| Q             | A
| ------------- | ---
| Branch?       | master <!-- see below -->
| Bug fix?      | no
| New feature?  | yes <!-- don't forget to update src/**/CHANGELOG.md files -->
| BC breaks?    | no     <!-- see https://symfony.com/bc -->
| Deprecations? | no <!-- don't forget to update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tests pass?   | see CI checks    <!-- please add some, will be required by reviewers -->
| Fixed tickets | N/A   <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | todo

For now, this is mainly a RFC to get your opinion on such a feature (so it misses proper tests).
Supporting wrapped messages out-of-the-box would mainly allow to easily create middlewares that should act only or be configured differently for specific messages (by using wrappers instead of making messages implements specific interfaces and without requiring dedicated buses). For instance, I might want to track specific messages and expose metrics about it.

The Symfony Serializer transport (relates to #26900) and Validator middleware serve as guinea pigs for sample purpose here. But despite message validation usually is simple as it matches one use-case and won't require specific validation groups in most cases, I still think it can be useful sometimes. Also there is the case of the [`AllValidator` which currently requires using a `GroupSequence`](symfony/symfony#26477) as a workaround, but that could also be specified directly in message metadata instead.

## Latest updates

PR updated to use a flat version of configurations instead of wrappers, using an `Envelope` wrapper and a list of envelope items.
Usage:

```php
$message = Envelope::wrap(new DummyMessage('Hello'))
    ->with(new SerializerConfiguration(array(ObjectNormalizer::GROUPS => array('foo'))))
    ->with(new ValidationConfiguration(array('foo', 'bar')))
;
```

~~By default, Messenger protagonists receive the original message. But each of them can opt-in to receive the envelope instead, by implementing `EnvelopeReaderInterface`.
Then, they can read configurations from it and forward the original message or the envelope to another party.~~

Senders, encoders/decoders & receivers always get an `Envelope`.
Middlewares & handlers always get a message. But middlewares can opt-in to receive the envelope instead, by implementing `EnvelopeReaderInterface`.

Commits
-------

749054a1e8 [Messenger] Support configuring messages when dispatching
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants