Framework: Validate unique field with where clause and null value

Created on 29 Aug 2018  路  5Comments  路  Source: laravel/framework

  • Laravel Version: 5.6.23
  • PHP Version: PHP 7.2.4 (cli) (built: Mar 28 2018 04:27:01) ( ZTS MSVC15 (Visual C++ 2017) x64 )
  • Database Driver & Version: MYSQL 5.7.21

Description:

When you use unique validation rule with "where" clause and a"null" value cause an error in laravel\framework\src\Illuminate\Validation\Concerns\ValidatesAttributes.php in getExtraConditions
because the 'null' value is deleted from array $segments

image

Steps To Reproduce:

Rules to validate.

return [
    'name' => Rule::unique('lodgings')->where('type_id', $this->type),
    'type' => 'required',
];

When not pass type_id attribute cause a error.

But this, work.

return [
    'name' => Rule::unique('lodgings')->where('type_id', $this->type ?? 'null'),
    'type' => 'required',
];

Most helpful comment

I don't understand your first solution. Why would you ignore a null constraint?

We could call whereNull():

public function where($column, $value)
{
    if (is_array($value)) {
        return $this->whereIn($column, $value);
    }

    if ($column instanceof Closure) {
        return $this->using($column);
    }

    if (is_null($value)) {
        return $this->whereNull($column);
    }

    return $this;
}

All 5 comments

I don't know which is the better solution...

If the value is null, do not add the condition where

https://github.com/laravel/framework/blob/a784efcc17b1c683bb64b6e0916c4e2a6cea231c/src/Illuminate/Validation/Rules/DatabaseRule.php#L57

//framework\src\Illuminate\Validation\Rules\DatabaseRule.php

/**
 * Set a "where" constraint on the query.
 *
 * @param  string|\Closure  $column
 * @param  array|string $value
 * @return $this
 */
public function where($column, $value)
{
    if (is_array($value)) {
        return $this->whereIn($column, $value);
    }

    if ($column instanceof Closure) {
        return $this->using($column);
    }

    if (!is_null($value)) {
        $this->wheres[] = compact('column', 'value');
    }

    return $this;
}

or if null add null as a value.

https://github.com/laravel/framework/blob/a784efcc17b1c683bb64b6e0916c4e2a6cea231c/src/Illuminate/Validation/Rules/DatabaseRule.php#L166

//framework\src\Illuminate\Validation\Rules\DatabaseRule.php

/**
 * Format the where clauses.
 *
 * @return string
 */
protected function formatWheres()
{
    return collect($this->wheres)->map(function ($where) {
        return $where['column'].','. ($where['value'] ?? 'null');
    })->implode(',');
}

I don't understand your first solution. Why would you ignore a null constraint?

We could call whereNull():

public function where($column, $value)
{
    if (is_array($value)) {
        return $this->whereIn($column, $value);
    }

    if ($column instanceof Closure) {
        return $this->using($column);
    }

    if (is_null($value)) {
        return $this->whereNull($column);
    }

    return $this;
}

I think that is better use null (null) to ignore condition and 'null' (string) to filter by null.

This will be ignore.

$type = null;

Rule::unique('lodgings')->where('type_id', $type),

And this will be compare with null.

Rule::unique('lodgings')->whereNull('type_id'),

I think @staudenmeir's suggestion is the correct solution. This probably needs to be sent to master to avoid breaking people's validation.

This will be fixed in the next major release.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Xerotherm1c picture Xerotherm1c  路  70Comments

rafaelrenanpacheco picture rafaelrenanpacheco  路  64Comments

mrahmadt picture mrahmadt  路  61Comments

robjbrain picture robjbrain  路  64Comments

Demers94 picture Demers94  路  88Comments