laravel / framework

The Laravel Framework.
https://laravel.com
MIT License
32.21k stars 10.9k forks source link

Validator::make alters data in specific cases using wildcard syntax #25138

Closed apreiml closed 4 years ago

apreiml commented 6 years ago

Description:

Validator::make alters data in specific cases using wildcard syntax.

Steps To Reproduce:

<?php

$stores = json_decode('[{
    "address": {
        "town": "TestTown"
    }
}]');

$values = [
    'stores' => $stores
];

dump($values);

$v = \Validator::make($values, [
    'stores.*.address.town' => 'string|required',
]);

dump($values);

The town gets erased:

array:1 [
  "stores" => array:1 [
    0 => {#3647
      +"address": {#3646
        +"town": "TestTown"
      }
    }
  ]
]
array:1 [
  "stores" => array:1 [
    0 => {#3647
      +"address": {#3646
        +"town": null
      }
    }
  ]
]
apreiml commented 6 years ago

This seems to be the line, the change happens: https://github.com/laravel/framework/blob/df5e681c811d15cee257242b802a8b6f3cf1fffc/src/Illuminate/Validation/ValidationData.php#L43

staudenmeir commented 6 years ago

This happens because json_decode() returns objects by default (#3646, #3647). When the validator modifies these objects, the input data gets changed (Objects and references).

It works if you use json_decode(..., true) to return arrays instead of objects. Does this solve your problem?

apreiml commented 6 years ago

@staudenmeir I put the json_decode here only for generating test data. I'm aware that this works for arrays. I was surprised about the object behavior. I'm not sure if objects like those are supported in the validator, but if they are, this may not be the expected behavior.

staudenmeir commented 6 years ago

I guess this hasn't been a problem so far because there aren't many situations where object data like this is validated.

A fix definitely wouldn't hurt, but I don't see an easy solution.

apreiml commented 6 years ago

@staudenmeir I'm curious why overwrite is set to true on the data_set line. Shouldn't the function fill missing attributes? If I disable overwrite there it works fine.

staudenmeir commented 6 years ago

It's necessary for cases like this:

\Validator::make(['companies' => ['spark']], ['companies.*.name' => 'required'])->passes();
taylorotwell commented 4 years ago

No plans to modify this behavior just because it seems to have little interest from the community and is not very common to validate objects in that way. If we did ever want to fix it we could consider cloning the data before validating.

pxlrbt commented 1 month ago

@taylorotwell I think you are right when looking at this from the classic request() data. With Livewire's Wireables and Synthesizers and an increasing usage of Data Objects, I feel like there will be more occasions of validation data containing objects, though.