Support the ongoing development of Laravel.io →
Database Eloquent

As I have asked a few times before, I'm developing a website/CMS to a game server for which I can not change the behaviour. The developers of the game have defined a character is not deleted if it's deletion field (as opposed to deleted_at, but this is easily solvable) is set to 0, and not null.

The problem is with this second part. Laravel treats deleted records as those with static::DELETED_AT set to null, and this behaviour is not easily solvable. It produces the following query:

update `players` set `deletion` = ? where `players`.`deletion` is null and `id` = ? and `deletion` = ?

where it should be

update `players` set `deletion` = ? where `players`.`deletion` = 0 and `id` = ? and `deletion` = ?

(? are the bind parameters)

How do I override this behaviour, interfering the least with built-in classes? I want to keep it simple, so at first sight I discarded rewriting the whole soft-deleting things, but then I could not find a solution messing only with the model itself.

Last updated 3 years ago.
0

you can try rewrite you model fromDateTime method

public function fromDateTime($value) {

    //you should  judge here
    if($value=='0000-00-00 00:00:00')
        return $value;
    $format = $this->getDateFormat();

    // If the value is already a DateTime instance, we will just skip the rest of
    // these checks since they will be a waste of time, and hinder performance
    // when checking the field. We will just return the DateTime right away.
    if ($value instanceof DateTime)
    {
        //
    }

    // If the value is totally numeric, we will assume it is a UNIX timestamp and
    // format the date as such. Once we have the date in DateTime form we will
    // format it according to the proper format for the database connection.
    elseif (is_numeric($value))
    {
        $value = Carbon::createFromTimestamp($value);
    }

    // If the value is in simple year, month, day format, we will format it using
    // that setup. This is for simple "date" fields which do not have hours on
    // the field. This conveniently picks up those dates and format correct.
    elseif (preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $value))
    {
        $value = Carbon::createFromFormat('Y-m-d', $value)->startOfDay();
    }

    // If this value is some other type of string, we'll create the DateTime with
    // the format used by the database connection. Once we get the instance we
    // can return back the finally formatted DateTime instances to the devs.
    elseif ( ! $value instanceof DateTime)
    {
        $value = Carbon::createFromFormat($format, $value);
    }

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

}

Last updated 3 years ago.
0

trigged said:

you can try rewrite you model fromDateTime method

The query is not affected, it still searches for deletion is null...

Last updated 3 years ago.
0

You could look at creating your own base model class which extends eloquent and override the delete methods (or anything that uses the deleted_at column)

Alternatively you could add a deleted column in addition to deleted_at, which is updated by an event attached to 'delete' to keep it in sync with the deleted_at column.

Last updated 3 years ago.
0

Hey, I had the same problem with a legacy db, I've extended the Eloquent Model class to override the methods that work with the deleted_at column, my code looks like this.

https://gist.github.com/itsgoingd/9617096

Last updated 3 years ago.
0

That's good code, @itsgoingd. Since the trouble is just with one model, I didn't want to extend Eloquent, so I just overriden one method:

protected function performDeleteOnModel() {
	$query = $this->newQuery()->withTrashed()->where(static::DELETED_AT, 0)->where($this->getKeyName(), $this->getKey());
	if ($this->softDelete) {
		$time = $this->freshTimestamp();
		$this->{static::DELETED_AT} = $time->timestamp;
		$query->update(array(static::DELETED_AT => $time->timestamp));
	} else {
		$query->delete();
	}
}

Since Laravel searches with deleted_at as null when we do not use withTrashed(), this just works :D

Last updated 3 years ago.
0

One more fix: when I use relations (such as hasMany specifically in this case), they get broken since the relation will just load the not deleted records. So I had to override this behavior:

public function newQuery($excludeDeleted = true) {
	$builder = $this->newEloquentBuilder($this->newBaseQueryBuilder());

	// Once we have the query builders, we will set the model instances so the
	// builder can easily access any information it may need from the model
	// while it is constructing and executing various queries against it.
	$builder->setModel($this)->with($this->with);

	if ($excludeDeleted && $this->softDelete) {
		// Here I changed whereNull() to where() with column at zero :)
		$builder->where($this->getQualifiedDeletedAtColumn(), 0);
	}
	return $builder;
}
Last updated 3 years ago.
0

Sign in to participate in this thread!

Eventy

Your banner here too?

ranisalt ranisalt Joined 10 Feb 2014

Moderators

We'd like to thank these amazing companies for supporting us

Your logo here?

Laravel.io

The Laravel portal for problem solving, knowledge sharing and community building.

© 2025 Laravel.io - All rights reserved.