laravel / framework

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

Request rule validation doesn't work with multi-level key based array config/database file #26578

Closed samdevbr closed 5 years ago

samdevbr commented 5 years ago

In order to validate data against database using rule validations, you may specify the correct database to use, unique:connection.table.

Theoretically we would have a database config file like this.

    'connections' => [
        'cooldb1' => [...]
    ]

And we would setup the rule like this unique:cooldb1.table,column

BUT now comes the problem, if we have multi-level key based array to store db configs, something like this

    'connections' => [
        'mysql' => [
               'cooldb1' => [...],
               'cooldb2' => [...]
        ],
        'cassandra' => [...],
        'redis' => [...]
    ]

And try to setup the rule based on the your db config file, we should have something like this unique:mysql.cooldb1.table,column, but unfortunately it doesn't work, we get an Undefined index: driver error.

I tried to google the solve for this problem, but no luck with that, but as many developers i'm cursed to the eternity to debug and try to find the solution, and I figured out that the function (\Illuminate\Validation\Concerns\ValidatesAttributes::parseTable) that parses the table and the db config, exploding the "table string" if it has ".", and getting the 2 first values, as we can see below.

    /**
     * Parse the connection / table for the unique / exists rules.
     *
     * @param  string  $table
     * @return array
     */
    protected function parseTable($table)
    {
        return Str::contains($table, '.') ? explode('.', $table, 2) : [null, $table];
    }

Based on my rule unique:mysql.cooldb1.table,column, the result would be.

array:2 [
  0 => "mysql" // Database
  1 => "cooldb1.table" // Table
]

And when the validator passes the config to DatabaseManager, and the db manager tries to get the config from config/database.php, it well get mysql key, instead of ['mysql']['cooldb1'], and that's when we get Undefined index: driver, because mysql key doesn't have db configs, only another keys, and these keys has db configs

To solve this problem, I changed the function on the server with nano, the solution was.

    /**
     * Parse the connection / table for the unique / exists rules.
     *
     * @param  string  $table
     * @return array
     */
    protected function parseTable($table)
    {
        if (Str::contains($table, '.')) {
            $settings = explode('.', $table);
            $table = last($settings);

            unset($settings[count($settings) - 1]);

            $connection = implode('.', $settings);

            return [$connection, $table];
        }

        return [null, $table];
    }

Important to remind that my current config/database.php file works fine with other services, only rule validators has problems to parse it.

I'm not sure if it's a known issue, or something, but I think would be cool if the validator could be able to parse multi-level key array configuration from config/database just as other services like Eloquent, Query Builder and etc, I've tested with Laravel and Lumen, same problem and same fix.

If everything is ok, I would happily create PR's for illuminate/validation (for Lumen) and laravel/framework (for Laravel) with the fix.

driesvints commented 5 years ago

At the moment I don't think it's meant to work like this. The fact that it works for the query builder and eloquent is a side effect I believe. If you can point me to a spot in the docs where this is documented or in the test suite where this is tested then I'll be happy to re-open this.

But if you believe this would be a nice feature to be added then it's best to post this at the laravel/ideas repository to get support for your idea. After that you may send a PR to the framework.