laravel / ideas

Issues board used for Laravel internals discussions.
938 stars 28 forks source link

Add "comma separated values" validation rule #1138

Open chimit opened 6 years ago

chimit commented 6 years ago

It would be very useful to validate comma separated values like arrays:

$this->validate($request, [
    'book_ids'   => 'csv',
    'book_ids.*' => 'integer',
]);
microwavekonijn commented 6 years ago

Why not use regex validation rule like /^[0-9]+(\s*\,\s*[0-9]+)*$/g?

Also it is possible to write your own validation rules: https://laravel.com/docs/5.6/validation#custom-validation-rules

chimit commented 6 years ago

I think comma separated values is a popular case enough to make a special validation rule.

staudenmeir commented 6 years ago

The array-like validation looks rather complicated to implement. I think it's only doable if you parse the CSV string into an array, validate it and then turn it back into a string.

Also, I'm not sure a lot of people require this kind of validation that can't be done with a regex rule.

powelski commented 6 years ago

CSV is very popular format of data storage, but it’s not frequently written by hand, so I don’t see any reason to include it as a validation rule in the framework. That’s rather exotic request, so it’s a perfect case for custom validation rule.

chimit commented 6 years ago

In APIs it's a common situation when CSV are used instead of arrays:

GET /groups?type=public,private

and

GET /groups?type[0]=public&type[1]=private
powelski commented 6 years ago

Believe me or not, but this is not real CSV. Core part of CSV are delimiters, which I bet are not handled in your code. This is just keywords separated by comma, which is not the same thing. How do you want to validate it? It is always valid, maybe with exception when there are empty values (if you want it to be invalid). If you pass @&*#+%^{ there, is it invalid? Just explode this value by comma and validate each passed token.

rajkananirk commented 3 years ago

Solved

chimit commented 3 years ago

I use a custom middleware to turn comma-separated values into arrays and validate them as arrays.

namespace App\Http\Middleware;

use Closure;

class CsvToArray
{
    /**
     * Handle the incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  array  $fields
     * @return mixed
     */
    public function handle($request, Closure $next, ...$fields)
    {
        $data = collect($request->all())->map(function ($value, $key) use ($fields) {
            if (in_array($key, $fields)) {
                return array_map('trim', explode(',', $value));
            }

            return $value;
        })->all();

        $request->merge($data);

        return $next($request);
    }
}
// app/Http/Kernel.php
protected $routeMiddleware = [
    // ...
    'csv' => \App\Http\Middleware\CsvToArray::class,
];
// routes/api.php
Route::get('/something', [SomeController::class, 'getSomething'])->middleware('csv:role');
$this->validate($request, [
    'role' => 'array',
    'role.*' => 'alpha_dash',
]);