Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

newbie360's avatar

Factory bug? ->trashed() method generate a -1 day datetime

Open Tinker

Post::factory()->trashed()->create();

//    "created_at" => "2025-03-03 20:57:00"
//    "updated_at" => "2025-03-03 20:57:00"
//    "deleted_at" => "2025-03-02 20:57:00"

can anyone confirm this ?

0 likes
10 replies
tykus's avatar

It is deliberate, but you can explicitly specify an alternative deleted_at date

// vendor/laravel/framework/src/Illuminate/Database/Eloquent/Factories/Factory.php
if ($method === 'trashed' && in_array(SoftDeletes::class, class_uses_recursive($this->modelName()))) {
    return $this->state([
        $this->newModel()->getDeletedAtColumn() => $parameters[0] ?? Carbon::now()->subDay(),
    ]);
}
newbie360's avatar

@tykus Sorry, i don't understand why it use ->subDay()

in the real world, deleted_at shouldn't be before to created_at

can you explain more details about this behavior

so it means what situation the deleted_at need to subDay

1 like
tykus's avatar
tykus
Best Answer
Level 104

@newbie360 I didn't implement the feature, and this choice is not explained in the PR; so, I would be speculating.

As I mentioned, you can override this default subDay implementation with your own date

newbie360's avatar

@tykus Yep, i can't see any reason of this PR https://github.com/laravel/framework/pull/42414

in the first place, deleted_at before to created_at is not make sense o.0

i think need to avoid use ->trashed() method, because it might cause unexpected behavior

function livewireComponent(bool $trashed = false): array {
    $post = Post::factory()
        ->when($trashed, fn ($factory) => $factory->trashed())
        ->create();

    $component = Livewire::test(EditPost::class, [
        'record' => $post->getRouteKey(),
    ]);

    return [$component, $post];
}

test('has a form', function () {
    [$component] = livewireComponent();

    $component->assertFormExists();
});

test('can restore a deleted post', function () {
    [$component, $trashedPost] = livewireComponent(trashed: true);

    // ...
});
martinbean's avatar

in the real world, deleted_at shouldn't be before to created_at

@newbie360 You’re using a factory to create a “trashed” record. So Laravel ensures the record is “trashed” by setting the deleted_at value to a date in the past. It doesn’t care what your created or updated timestamps are; it just sets deleted_at to a past date and time so that when you work with your models, that record is treated as being “trashed”.

newbie360's avatar

@martinbean I just confuse why not the default behavior is use now, and override it by the needs

tykus's avatar

@newbie360 do you have a specific test/implementation where these seemingly out-of-step dates are causing an issue?

newbie360's avatar

@tykus so far no problem, but i can imagine if any logic based on the deleted_at will cause problem

in one of my project, an actor birth date should be before or equal to the movie released date

when i validate the birth date value, i need to ensure the value is before or equal to

$actor?->movies()->min('released_date');

just like in human language, i can't say I was born at tomorrow =)

tykus's avatar

@newbie360 I don't know if this is an absolute truth...

any logic based on the deleted_at will cause problem

For the most part, we check that the deleted_at date is not null; the when rarely matters, and especially compared to the created_at date. The example you provided above is not relevant IMHO.

In any event, these Factories are intended for testing purposes where you set up the world as you want it in order to test implementation(s) that you write/wrote; that is still the case... you can choose to use trashed method or not if it is an issue. You can choose to define your own Factory States, or not. You can choose to PR the framework if you feel strongly enough!

newbie360's avatar

@tykus no problem dude, i know what you mean, but is LAW even it is factory xD, is ok fine, happy coding.

Please or to participate in this conversation.