framework: Soft delete ignored with exists validation rule

I would like to make sure a resource exists using the exists validation rule like normal however I would like to not include soft deleted resources. Since the database will only check against null it doesn’t seem to work since the rule will use a string. For now I have hacked in…

$extra[$segments[$i]] = $segments[$i + 1] == '{NULL}' ? null : $segments[$i + 1];

into getExtraExistConditions and have my rule have {NULL} but obviously that isn’t a good solution, wondering if something can be done about this?

About this issue

  • Original URL
  • State: closed
  • Created 11 years ago
  • Comments: 29 (14 by maintainers)

Most upvoted comments

You can pass extra conditions to exists… passing “NULL” will do a whereNull check.

Like:

'exists:table,column,deleted_at,NULL'

Do note the difference in argument order for unique and exists, I don’t know for what reason - it seems rather silly and apparently @robclancy is the one who suggested it.

exists:table,column,extra_column,1,extra_column_two,2 unique:table,column,1,extra_column,extra_column_two,2

I even told you the code! What the hell. exists:table,email,deleted_at,NULL. No where does it say to do exists:table,email,NULL,deleted_at. Are you high?

No? You are doing it wrong. The docs are fine. You would think column NULL not found is pretty clear on what you are doing wrong. Basically, you have the NULL on the column field, so it is not found.

Nope docs are right. I need more sleep. (if you read the reply I just deleted, I quit life).

You do exists:table,email,deleted_at,NULL.

This doesn’t work. Throws an error column NULL not found

You can pass extra conditions to exists… passing “NULL” will do a whereNull check.

Like:

'exists:table,column,deleted_at,NULL'

You may also use the following construction, for me, it looks clearer:

Rule::exists(ClassName::class, 'id')->withoutTrashed()

Thanks, @heroselohim . Your answer really helpful.

For those who want to implement these rule to global scope. Here’s how to do it :

  1. Open file app/Providers/AppServiceProviders.php.
  2. Add heroselohim’s answer to boot() method.
public function boot(){
// Put the code here
}
  1. Done. Now you can call that rules in every form validation.
'user_id' => ['exists_soft:users,id']

Tips If you want to customize validation message, you should do:

  1. Open resources/lang/en/validation.php.
  2. Add exists_soft to array validation. (I prefer copy from exists rule and change it to exists_soft)
...
'exists' => 'The selected :attribute is invalid.',
'exists_soft' => 'The selected :attribute is invalid.',
...

Works perfectly;

Rule::unique('users')
    ->ignore($userId)
    ->whereNull('deleted_at'),

I know this is a really old topic, but I looked everywhere for something like this with no results. It m8 be of use to someone.

This is the laravel validator for Exists && Not Soft Deleted rule

exists_soft:user,id

\Validator::extend('exists_soft',
	function($attribute, $value, $parameters)
	{
		if (!isset($parameters[0])) {
			throw new \Exception('Validator "exists_soft" missing tablename.');
		}
		$tableName = $parameters[0];
		$columnName = isset($parameters[1])?$parameters[1]:null;
		$validator = \Validator::make([$attribute => $value],
		[
			$attribute => [
				Rule::exists($tableName, $columnName)
					->where(function ($query) {
					$query->whereNull('deleted_at');
				}),
			]
		]);
		return $validator->passes();
	});

Yes I have tried the code that is in the docs. I use it in a production environment, hence requesting the feature.

'user_id' => 'exists:users,id,deleted_at,NULL' will check if there is a user exists at the id and that deleted_at is not null (so they aren’t soft deleted).

'user_id' => 'exists:users,id,deleted_at,NULL,type,douche' will check that a user at id exists with deleted_at null and type == ‘douche’.

So for example if @anlutro was the user clearly the type would be douche and it would come back as a pass 😉

For exists:table,email,deleted_at,NULL throws column NULL does not exist. One question, what does id in this example (from the doc) do?

'email' => 'unique:users,email_address,NULL,id,account_id,1'

In the above I would like to do

unique:table,email,NULL, deleted_at,deleted_at,NULL

and it works but doesn’t make sense.

Rule::unique("table", "column")->whereNull("deleted_at")