Find this useful? Enter your email to receive occasional updates for securing PHP code.

Signing you up...

Thank you for signing up!

PHP Decode

<?php use Carbon\Carbon; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Fou..

Decoded Output download

<?php

use Carbon\Carbon;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Application;
use Illuminate\Support\Collection;
use Spatie\Activitylog\LogOptions;
use Spatie\Activitylog\Models\Activity;
use Spatie\Activitylog\Test\Enums\NonBackedEnum;
use Spatie\Activitylog\Test\Models\Article;
use Spatie\Activitylog\Test\Models\ArticleWithLogDescriptionClosure;
use Spatie\Activitylog\Test\Models\Issue733;
use Spatie\Activitylog\Test\Models\User;
use Spatie\Activitylog\Traits\LogsActivity;

beforeEach(function () {
    $this->article = new class() extends Article {
        use LogsActivity;
        use SoftDeletes;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults();
        }
    };

    $this->user = new class() extends User {
        use LogsActivity;
        use SoftDeletes;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults();
        }
    };

    $this->assertCount(0, Activity::all());
});

it('will log the creation of the model', function () {
    $article = $this->createArticle();
    $this->assertCount(1, Activity::all());

    $this->assertInstanceOf(get_class($this->article), $this->getLastActivity()->subject);
    $this->assertEquals($article->id, $this->getLastActivity()->subject->id);
    $this->assertEquals('created', $this->getLastActivity()->description);
    $this->assertEquals('created', $this->getLastActivity()->event);
});

it('can skip logging model events if asked to', function () {
    $article = new $this->article();
    $article->disableLogging();
    $article->name = 'my name';

    $article->save();

    $this->assertCount(0, Activity::all());
    $this->assertNull($this->getLastActivity());
});

it('can switch on activity logging after disabling it', function () {
    $article = new $this->article();

    $article->disableLogging();
    $article->name = 'my name';
    $article->save();

    $article->enableLogging();
    $article->name = 'my new name';
    $article->save();

    $this->assertCount(1, Activity::all());
    $this->assertInstanceOf(get_class($this->article), $this->getLastActivity()->subject);
    $this->assertEquals($article->id, $this->getLastActivity()->subject->id);
    $this->assertEquals('updated', $this->getLastActivity()->description);
    $this->assertEquals('updated', $this->getLastActivity()->event);
});

it('can skip logging if asked to for update method', function () {
    $article = new $this->article();
    $article->disableLogging()->update(['name' => 'How to log events']);

    $this->assertCount(0, Activity::all());
    $this->assertNull($this->getLastActivity());
});

it('will log an update of the model', function () {
    $article = $this->createArticle();

    $article->name = 'changed name';
    $article->save();

    $this->assertCount(2, Activity::all());

    $this->assertInstanceOf(get_class($this->article), $this->getLastActivity()->subject);
    $this->assertEquals($article->id, $this->getLastActivity()->subject->id);
    $this->assertEquals('updated', $this->getLastActivity()->description);
    $this->assertEquals('updated', $this->getLastActivity()->event);
});

it('it will log the replication of a model with softdeletes', function () {
    $article = $this->createArticle();

    $replicatedArticle = $this->article::find($article->id)->replicate();
    $replicatedArticle->save();

    $activityItems = Activity::all();

    $this->assertCount(2, $activityItems);

    $this->assertTrue($activityItems->every(fn (Activity $item): bool => $item->event === 'created' &&
        $item->description === 'created' &&
        get_class($this->article) === $item->subject_type &&
        in_array($item->subject_id, [$article->id, $replicatedArticle->id])));

    $this->assertEquals($article->id, $activityItems->first()->subject_id);
    $this->assertEquals($replicatedArticle->id, $activityItems->last()->subject_id);
});

it('will log the deletion of a model without softdeletes', function () {
    $articleClass = new class() extends Article {
        use LogsActivity;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()->logOnly(['name']);
        }
    };

    $article = new $articleClass();
    $article->name = 'my name';
    $article->save();

    $this->assertEquals('created', $this->getLastActivity()->description);
    $this->assertEquals('created', $this->getLastActivity()->event);

    $article->delete();

    $activity = $this->getLastActivity();

    $this->assertEquals('deleted', $activity->description);
    $this->assertArrayHasKey('old', $activity->changes());
    $this->assertEquals('my name', $activity->changes()['old']['name']);
    $this->assertArrayNotHasKey('attributes', $activity->changes());

    $this->assertEquals('deleted', $activity->description);
    $this->assertEquals('deleted', $activity->event);
});

it('will log the deletion of a model with softdeletes', function () {
    $article = $this->createArticle();

    $article->delete();

    $this->assertCount(2, Activity::all());

    $this->assertEquals(get_class($this->article), $this->getLastActivity()->subject_type);
    $this->assertEquals($article->id, $this->getLastActivity()->subject_id);
    $this->assertEquals('deleted', $this->getLastActivity()->description);
    $this->assertEquals('deleted', $this->getLastActivity()->event);

    $article->forceDelete();

    $this->assertCount(3, Activity::all());

    $this->assertEquals('deleted', $this->getLastActivity()->description);
    $this->assertEquals('deleted', $this->getLastActivity()->event);
    $this->assertNull($article->fresh());
});

it('will log the restoring of a model with softdeletes', function () {
    $article = $this->createArticle();

    $article->delete();

    $article->restore();

    $this->assertCount(3, Activity::all());

    $this->assertEquals(get_class($this->article), $this->getLastActivity()->subject_type);
    $this->assertEquals($article->id, $this->getLastActivity()->subject_id);
    $this->assertEquals('restored', $this->getLastActivity()->description);
    $this->assertEquals('restored', $this->getLastActivity()->event);
});

it('can fetch all activity for a model', function () {
    $article = $this->createArticle();

    $article->name = 'changed name';
    $article->save();

    $activities = $article->activities;

    $this->assertCount(2, $activities);
});

it('can fetch soft deleted models', function () {
    app()['config']->set('activitylog.subject_returns_soft_deleted_models', true);

    $article = $this->createArticle();

    $article->name = 'changed name';
    $article->save();

    $article->delete();

    $activities = $article->activities;

    $this->assertCount(3, $activities);

    $this->assertEquals(get_class($this->article), $this->getLastActivity()->subject_type);
    $this->assertEquals($article->id, $this->getLastActivity()->subject_id);
    $this->assertEquals('deleted', $this->getLastActivity()->description);
    $this->assertEquals('deleted', $this->getLastActivity()->event);
    $this->assertEquals('changed name', $this->getLastActivity()->subject->name);
});

it('can log activity to log named in the model', function () {
    $articleClass = new class() extends Article {
        use LogsActivity;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()
            ->useLogName('custom_log');
        }
    };

    $article = new $articleClass();
    $article->name = 'my name';
    $article->save();

    $this->assertSame('custom_log', Activity::latest()->first()->log_name);
});

it('will not log an update of the model if only ignored attributes are changed', function () {
    $articleClass = new class() extends Article {
        use LogsActivity;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()
            ->dontLogIfAttributesChangedOnly(['text']);
        }
    };

    $article = new $articleClass();
    $article->name = 'my name';
    $article->save();

    $article->text = 'ignore me';
    $article->save();

    $this->assertCount(1, Activity::all());

    $this->assertInstanceOf(get_class($articleClass), $this->getLastActivity()->subject);
    $this->assertEquals($article->id, $this->getLastActivity()->subject->id);
    $this->assertEquals('created', $this->getLastActivity()->description);
    $this->assertEquals('created', $this->getLastActivity()->event);
});

it('will not fail if asked to replace from empty attribute', function () {
    $model = new class() extends Article {
        use LogsActivity;
        use SoftDeletes;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()
            ->setDescriptionForEvent(fn (string $eventName): string => ":causer.name $eventName");
        }
    };

    $entity = new $model();
    $entity->save();
    $entity->name = 'my name';
    $entity->save();

    $activities = $entity->activities;

    $this->assertCount(2, $activities);
    $this->assertEquals($entity->id, $activities[0]->subject->id);
    $this->assertEquals($entity->id, $activities[1]->subject->id);
    $this->assertEquals(':causer.name created', $activities[0]->description);
    $this->assertEquals(':causer.name updated', $activities[1]->description);
});

it('can log activity on subject by same causer', function () {
    $user = $this->loginWithFakeUser();

    $user->name = 'LogsActivity Name';
    $user->save();

    $this->assertCount(1, Activity::all());

    $this->assertInstanceOf(get_class($this->user), $this->getLastActivity()->subject);
    $this->assertEquals($user->id, $this->getLastActivity()->subject->id);
    $this->assertEquals($user->id, $this->getLastActivity()->causer->id);
    $this->assertCount(1, $user->activities);
    $this->assertCount(1, $user->actions);
});

it('can log activity when attributes are changed with tap', function () {
    $model = new class() extends Article {
        use LogsActivity;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults();
        }

        protected $properties = [
            'property' => [
                'subProperty' => 'value',
            ],
        ];

        public function tapActivity(Activity $activity, string $eventName)
        {
            $properties = $this->properties;
            $properties['event'] = $eventName;
            $activity->properties = collect($properties);
            $activity->created_at = Carbon::yesterday()->startOfDay();
        }
    };

    $entity = new $model();
    $entity->save();

    $firstActivity = $entity->activities()->first();

    $this->assertInstanceOf(Collection::class, $firstActivity->properties);
    $this->assertEquals('value', $firstActivity->getExtraProperty('property.subProperty'));
    $this->assertEquals('created', $firstActivity->description);
    $this->assertEquals('created', $firstActivity->event);
    $this->assertEquals(Carbon::yesterday()->startOfDay()->format('Y-m-d H:i:s'), $firstActivity->created_at->format('Y-m-d H:i:s'));
});

it('can log activity when description is changed with tap', function () {
    $model = new class() extends Article {
        use LogsActivity;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults();
        }

        public function tapActivity(Activity $activity, string $eventName)
        {
            $activity->description = 'my custom description';
        }
    };

    $entity = new $model();
    $entity->save();

    $firstActivity = $entity->activities()->first();

    $this->assertEquals('my custom description', $firstActivity->description);
});

it('can log activity when event is changed with tap', function () {
    $model = new class() extends Article {
        use LogsActivity;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults();
        }

        public function tapActivity(Activity $activity, string $eventName)
        {
            $activity->event = 'my custom event';
        }
    };

    $entity = new $model();
    $entity->save();

    $firstActivity = $entity->activities()->first();

    $this->assertEquals('my custom event', $firstActivity->event);
});

it('will not submit log when there is no changes', function () {
    $model = new class() extends Article {
        use LogsActivity;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()
            ->logOnly(['text'])
            ->dontSubmitEmptyLogs()
            ->logOnlyDirty();
        }
    };

    $entity = new $model(['text' => 'test']);
    $entity->save();

    $this->assertCount(1, Activity::all());

    $entity->name = 'my name';
    $entity->save();

    $this->assertCount(1, Activity::all());
});

it('will submit a log with json changes', function () {
    $model = new class() extends Article {
        use LogsActivity;

        protected $casts = [
            'json' => 'collection',
        ];

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()
            ->logOnly(['text', 'json->data'])
            ->dontSubmitEmptyLogs()
            ->logOnlyDirty();
        }
    };

    $entity = new $model([
        'text' => 'test',
        'json' => [
            'data' => 'oldish',
        ],
    ]);

    $entity->save();

    $this->assertCount(1, Activity::all());

    $entity->json = [
        'data' => 'chips',
        'irrelevant' => 'should not be',
    ];

    $entity->save();

    $expectedChanges = [
        'attributes' => [
            'json' => [
                'data' => 'chips',
            ],
        ],
        'old' => [
            'json' => [
                'data' => 'oldish',
            ],
        ],
    ];

    $changes = $this->getLastActivity()->changes()->toArray();

    $this->assertCount(2, Activity::all());
    $this->assertSame($expectedChanges, $changes);
});

it('will log the retrieval of the model', function () {
    $article = Issue733::create(['name' => 'my name']);

    $retrieved = Issue733::whereKey($article->getKey())->first();
    $this->assertTrue($article->is($retrieved));

    $activity = $this->getLastActivity();

    $this->assertInstanceOf(get_class($article), $activity->subject);
    $this->assertTrue($article->is($activity->subject));
    $this->assertEquals('retrieved', $activity->description);
});

it('will not log casted attribute of the model if attribute raw values is used', function () {
    $articleClass = new class() extends Article {
        use LogsActivity;

        protected $casts = [
            'name' => 'encrypted',
        ];

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()->logOnly(['name'])->useAttributeRawValues(['name']);
        }
    };

    $article = new $articleClass();
    $article->name = 'my name';
    $article->save();

    $this->assertInstanceOf(get_class($articleClass), $this->getLastActivity()->subject);
    $this->assertEquals($article->id, $this->getLastActivity()->subject->id);
    $this->assertNotEquals($article->name, $this->getLastActivity()->properties['attributes']['name']);
    $this->assertEquals('created', $this->getLastActivity()->description);
    $this->assertEquals('created', $this->getLastActivity()->event);
});

it('can be serialized', function () {
    $model = ArticleWithLogDescriptionClosure::create(['name' => 'foo']);

    $this->assertNotNull(serialize($model));
});

it('logs non backed enum casted attribute', function () {
    $articleClass = new class() extends Article {
        use LogsActivity;

        protected $casts = [
            'status' => NonBackedEnum::class,
        ];

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()->logOnly(['status']);
        }
    };

    $article = new $articleClass();
    $article->status = NonBackedEnum::Draft;
    $article->save();

    $this->assertInstanceOf(get_class($articleClass), $this->getLastActivity()->subject);
    $this->assertEquals($article->id, $this->getLastActivity()->subject->id);
    $this->assertSame('Draft', $this->getLastActivity()->properties['attributes']['status']);
    $this->assertEquals('created', $this->getLastActivity()->description);
    $this->assertEquals('created', $this->getLastActivity()->event);
})->skip(
    version_compare(PHP_VERSION, '8.1', '<') || version_compare(Application::VERSION, '9.0', '<'),
    "PHP < 8.1 doesn't support enums && Laravel < 9.0 doesn't support non-backed-enum casting"
);

it('logs int backed enum casted attribute', function () {
    $articleClass = new class() extends Article {
        use LogsActivity;

        protected $casts = [
            'status' => \Spatie\Activitylog\Test\Enums\IntBackedEnum::class,
        ];

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()->logOnly(['status']);
        }
    };

    $article = new $articleClass();
    $article->status = \Spatie\Activitylog\Test\Enums\IntBackedEnum::Published;
    $article->save();

    $this->assertInstanceOf(get_class($articleClass), $this->getLastActivity()->subject);
    $this->assertEquals($article->id, $this->getLastActivity()->subject->id);
    $this->assertSame(1, $this->getLastActivity()->properties['attributes']['status']);
    $this->assertEquals('created', $this->getLastActivity()->description);
    $this->assertEquals('created', $this->getLastActivity()->event);
})->skip(version_compare(PHP_VERSION, '8.1', '<'), "PHP < 8.1 doesn't support enum");

it('logs string backed enum casted attribute', function () {
    $articleClass = new class() extends Article {
        use LogsActivity;

        protected $casts = [
            'status' => \Spatie\Activitylog\Test\Enums\StringBackedEnum::class,
        ];

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()->logOnly(['status']);
        }
    };

    $article = new $articleClass();
    $article->status = \Spatie\Activitylog\Test\Enums\StringBackedEnum::Draft;
    $article->save();

    $this->assertInstanceOf(get_class($articleClass), $this->getLastActivity()->subject);
    $this->assertEquals($article->id, $this->getLastActivity()->subject->id);
    $this->assertSame('draft', $this->getLastActivity()->properties['attributes']['status']);
    $this->assertEquals('created', $this->getLastActivity()->description);
    $this->assertEquals('created', $this->getLastActivity()->event);
})->skip(version_compare(PHP_VERSION, '8.1', '<'), "PHP < 8.1 doesn't support enum");
 ?>

Did this file decode correctly?

Original Code

<?php

use Carbon\Carbon;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Application;
use Illuminate\Support\Collection;
use Spatie\Activitylog\LogOptions;
use Spatie\Activitylog\Models\Activity;
use Spatie\Activitylog\Test\Enums\NonBackedEnum;
use Spatie\Activitylog\Test\Models\Article;
use Spatie\Activitylog\Test\Models\ArticleWithLogDescriptionClosure;
use Spatie\Activitylog\Test\Models\Issue733;
use Spatie\Activitylog\Test\Models\User;
use Spatie\Activitylog\Traits\LogsActivity;

beforeEach(function () {
    $this->article = new class() extends Article {
        use LogsActivity;
        use SoftDeletes;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults();
        }
    };

    $this->user = new class() extends User {
        use LogsActivity;
        use SoftDeletes;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults();
        }
    };

    $this->assertCount(0, Activity::all());
});

it('will log the creation of the model', function () {
    $article = $this->createArticle();
    $this->assertCount(1, Activity::all());

    $this->assertInstanceOf(get_class($this->article), $this->getLastActivity()->subject);
    $this->assertEquals($article->id, $this->getLastActivity()->subject->id);
    $this->assertEquals('created', $this->getLastActivity()->description);
    $this->assertEquals('created', $this->getLastActivity()->event);
});

it('can skip logging model events if asked to', function () {
    $article = new $this->article();
    $article->disableLogging();
    $article->name = 'my name';

    $article->save();

    $this->assertCount(0, Activity::all());
    $this->assertNull($this->getLastActivity());
});

it('can switch on activity logging after disabling it', function () {
    $article = new $this->article();

    $article->disableLogging();
    $article->name = 'my name';
    $article->save();

    $article->enableLogging();
    $article->name = 'my new name';
    $article->save();

    $this->assertCount(1, Activity::all());
    $this->assertInstanceOf(get_class($this->article), $this->getLastActivity()->subject);
    $this->assertEquals($article->id, $this->getLastActivity()->subject->id);
    $this->assertEquals('updated', $this->getLastActivity()->description);
    $this->assertEquals('updated', $this->getLastActivity()->event);
});

it('can skip logging if asked to for update method', function () {
    $article = new $this->article();
    $article->disableLogging()->update(['name' => 'How to log events']);

    $this->assertCount(0, Activity::all());
    $this->assertNull($this->getLastActivity());
});

it('will log an update of the model', function () {
    $article = $this->createArticle();

    $article->name = 'changed name';
    $article->save();

    $this->assertCount(2, Activity::all());

    $this->assertInstanceOf(get_class($this->article), $this->getLastActivity()->subject);
    $this->assertEquals($article->id, $this->getLastActivity()->subject->id);
    $this->assertEquals('updated', $this->getLastActivity()->description);
    $this->assertEquals('updated', $this->getLastActivity()->event);
});

it('it will log the replication of a model with softdeletes', function () {
    $article = $this->createArticle();

    $replicatedArticle = $this->article::find($article->id)->replicate();
    $replicatedArticle->save();

    $activityItems = Activity::all();

    $this->assertCount(2, $activityItems);

    $this->assertTrue($activityItems->every(fn (Activity $item): bool => $item->event === 'created' &&
        $item->description === 'created' &&
        get_class($this->article) === $item->subject_type &&
        in_array($item->subject_id, [$article->id, $replicatedArticle->id])));

    $this->assertEquals($article->id, $activityItems->first()->subject_id);
    $this->assertEquals($replicatedArticle->id, $activityItems->last()->subject_id);
});

it('will log the deletion of a model without softdeletes', function () {
    $articleClass = new class() extends Article {
        use LogsActivity;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()->logOnly(['name']);
        }
    };

    $article = new $articleClass();
    $article->name = 'my name';
    $article->save();

    $this->assertEquals('created', $this->getLastActivity()->description);
    $this->assertEquals('created', $this->getLastActivity()->event);

    $article->delete();

    $activity = $this->getLastActivity();

    $this->assertEquals('deleted', $activity->description);
    $this->assertArrayHasKey('old', $activity->changes());
    $this->assertEquals('my name', $activity->changes()['old']['name']);
    $this->assertArrayNotHasKey('attributes', $activity->changes());

    $this->assertEquals('deleted', $activity->description);
    $this->assertEquals('deleted', $activity->event);
});

it('will log the deletion of a model with softdeletes', function () {
    $article = $this->createArticle();

    $article->delete();

    $this->assertCount(2, Activity::all());

    $this->assertEquals(get_class($this->article), $this->getLastActivity()->subject_type);
    $this->assertEquals($article->id, $this->getLastActivity()->subject_id);
    $this->assertEquals('deleted', $this->getLastActivity()->description);
    $this->assertEquals('deleted', $this->getLastActivity()->event);

    $article->forceDelete();

    $this->assertCount(3, Activity::all());

    $this->assertEquals('deleted', $this->getLastActivity()->description);
    $this->assertEquals('deleted', $this->getLastActivity()->event);
    $this->assertNull($article->fresh());
});

it('will log the restoring of a model with softdeletes', function () {
    $article = $this->createArticle();

    $article->delete();

    $article->restore();

    $this->assertCount(3, Activity::all());

    $this->assertEquals(get_class($this->article), $this->getLastActivity()->subject_type);
    $this->assertEquals($article->id, $this->getLastActivity()->subject_id);
    $this->assertEquals('restored', $this->getLastActivity()->description);
    $this->assertEquals('restored', $this->getLastActivity()->event);
});

it('can fetch all activity for a model', function () {
    $article = $this->createArticle();

    $article->name = 'changed name';
    $article->save();

    $activities = $article->activities;

    $this->assertCount(2, $activities);
});

it('can fetch soft deleted models', function () {
    app()['config']->set('activitylog.subject_returns_soft_deleted_models', true);

    $article = $this->createArticle();

    $article->name = 'changed name';
    $article->save();

    $article->delete();

    $activities = $article->activities;

    $this->assertCount(3, $activities);

    $this->assertEquals(get_class($this->article), $this->getLastActivity()->subject_type);
    $this->assertEquals($article->id, $this->getLastActivity()->subject_id);
    $this->assertEquals('deleted', $this->getLastActivity()->description);
    $this->assertEquals('deleted', $this->getLastActivity()->event);
    $this->assertEquals('changed name', $this->getLastActivity()->subject->name);
});

it('can log activity to log named in the model', function () {
    $articleClass = new class() extends Article {
        use LogsActivity;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()
            ->useLogName('custom_log');
        }
    };

    $article = new $articleClass();
    $article->name = 'my name';
    $article->save();

    $this->assertSame('custom_log', Activity::latest()->first()->log_name);
});

it('will not log an update of the model if only ignored attributes are changed', function () {
    $articleClass = new class() extends Article {
        use LogsActivity;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()
            ->dontLogIfAttributesChangedOnly(['text']);
        }
    };

    $article = new $articleClass();
    $article->name = 'my name';
    $article->save();

    $article->text = 'ignore me';
    $article->save();

    $this->assertCount(1, Activity::all());

    $this->assertInstanceOf(get_class($articleClass), $this->getLastActivity()->subject);
    $this->assertEquals($article->id, $this->getLastActivity()->subject->id);
    $this->assertEquals('created', $this->getLastActivity()->description);
    $this->assertEquals('created', $this->getLastActivity()->event);
});

it('will not fail if asked to replace from empty attribute', function () {
    $model = new class() extends Article {
        use LogsActivity;
        use SoftDeletes;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()
            ->setDescriptionForEvent(fn (string $eventName): string => ":causer.name $eventName");
        }
    };

    $entity = new $model();
    $entity->save();
    $entity->name = 'my name';
    $entity->save();

    $activities = $entity->activities;

    $this->assertCount(2, $activities);
    $this->assertEquals($entity->id, $activities[0]->subject->id);
    $this->assertEquals($entity->id, $activities[1]->subject->id);
    $this->assertEquals(':causer.name created', $activities[0]->description);
    $this->assertEquals(':causer.name updated', $activities[1]->description);
});

it('can log activity on subject by same causer', function () {
    $user = $this->loginWithFakeUser();

    $user->name = 'LogsActivity Name';
    $user->save();

    $this->assertCount(1, Activity::all());

    $this->assertInstanceOf(get_class($this->user), $this->getLastActivity()->subject);
    $this->assertEquals($user->id, $this->getLastActivity()->subject->id);
    $this->assertEquals($user->id, $this->getLastActivity()->causer->id);
    $this->assertCount(1, $user->activities);
    $this->assertCount(1, $user->actions);
});

it('can log activity when attributes are changed with tap', function () {
    $model = new class() extends Article {
        use LogsActivity;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults();
        }

        protected $properties = [
            'property' => [
                'subProperty' => 'value',
            ],
        ];

        public function tapActivity(Activity $activity, string $eventName)
        {
            $properties = $this->properties;
            $properties['event'] = $eventName;
            $activity->properties = collect($properties);
            $activity->created_at = Carbon::yesterday()->startOfDay();
        }
    };

    $entity = new $model();
    $entity->save();

    $firstActivity = $entity->activities()->first();

    $this->assertInstanceOf(Collection::class, $firstActivity->properties);
    $this->assertEquals('value', $firstActivity->getExtraProperty('property.subProperty'));
    $this->assertEquals('created', $firstActivity->description);
    $this->assertEquals('created', $firstActivity->event);
    $this->assertEquals(Carbon::yesterday()->startOfDay()->format('Y-m-d H:i:s'), $firstActivity->created_at->format('Y-m-d H:i:s'));
});

it('can log activity when description is changed with tap', function () {
    $model = new class() extends Article {
        use LogsActivity;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults();
        }

        public function tapActivity(Activity $activity, string $eventName)
        {
            $activity->description = 'my custom description';
        }
    };

    $entity = new $model();
    $entity->save();

    $firstActivity = $entity->activities()->first();

    $this->assertEquals('my custom description', $firstActivity->description);
});

it('can log activity when event is changed with tap', function () {
    $model = new class() extends Article {
        use LogsActivity;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults();
        }

        public function tapActivity(Activity $activity, string $eventName)
        {
            $activity->event = 'my custom event';
        }
    };

    $entity = new $model();
    $entity->save();

    $firstActivity = $entity->activities()->first();

    $this->assertEquals('my custom event', $firstActivity->event);
});

it('will not submit log when there is no changes', function () {
    $model = new class() extends Article {
        use LogsActivity;

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()
            ->logOnly(['text'])
            ->dontSubmitEmptyLogs()
            ->logOnlyDirty();
        }
    };

    $entity = new $model(['text' => 'test']);
    $entity->save();

    $this->assertCount(1, Activity::all());

    $entity->name = 'my name';
    $entity->save();

    $this->assertCount(1, Activity::all());
});

it('will submit a log with json changes', function () {
    $model = new class() extends Article {
        use LogsActivity;

        protected $casts = [
            'json' => 'collection',
        ];

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()
            ->logOnly(['text', 'json->data'])
            ->dontSubmitEmptyLogs()
            ->logOnlyDirty();
        }
    };

    $entity = new $model([
        'text' => 'test',
        'json' => [
            'data' => 'oldish',
        ],
    ]);

    $entity->save();

    $this->assertCount(1, Activity::all());

    $entity->json = [
        'data' => 'chips',
        'irrelevant' => 'should not be',
    ];

    $entity->save();

    $expectedChanges = [
        'attributes' => [
            'json' => [
                'data' => 'chips',
            ],
        ],
        'old' => [
            'json' => [
                'data' => 'oldish',
            ],
        ],
    ];

    $changes = $this->getLastActivity()->changes()->toArray();

    $this->assertCount(2, Activity::all());
    $this->assertSame($expectedChanges, $changes);
});

it('will log the retrieval of the model', function () {
    $article = Issue733::create(['name' => 'my name']);

    $retrieved = Issue733::whereKey($article->getKey())->first();
    $this->assertTrue($article->is($retrieved));

    $activity = $this->getLastActivity();

    $this->assertInstanceOf(get_class($article), $activity->subject);
    $this->assertTrue($article->is($activity->subject));
    $this->assertEquals('retrieved', $activity->description);
});

it('will not log casted attribute of the model if attribute raw values is used', function () {
    $articleClass = new class() extends Article {
        use LogsActivity;

        protected $casts = [
            'name' => 'encrypted',
        ];

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()->logOnly(['name'])->useAttributeRawValues(['name']);
        }
    };

    $article = new $articleClass();
    $article->name = 'my name';
    $article->save();

    $this->assertInstanceOf(get_class($articleClass), $this->getLastActivity()->subject);
    $this->assertEquals($article->id, $this->getLastActivity()->subject->id);
    $this->assertNotEquals($article->name, $this->getLastActivity()->properties['attributes']['name']);
    $this->assertEquals('created', $this->getLastActivity()->description);
    $this->assertEquals('created', $this->getLastActivity()->event);
});

it('can be serialized', function () {
    $model = ArticleWithLogDescriptionClosure::create(['name' => 'foo']);

    $this->assertNotNull(serialize($model));
});

it('logs non backed enum casted attribute', function () {
    $articleClass = new class() extends Article {
        use LogsActivity;

        protected $casts = [
            'status' => NonBackedEnum::class,
        ];

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()->logOnly(['status']);
        }
    };

    $article = new $articleClass();
    $article->status = NonBackedEnum::Draft;
    $article->save();

    $this->assertInstanceOf(get_class($articleClass), $this->getLastActivity()->subject);
    $this->assertEquals($article->id, $this->getLastActivity()->subject->id);
    $this->assertSame('Draft', $this->getLastActivity()->properties['attributes']['status']);
    $this->assertEquals('created', $this->getLastActivity()->description);
    $this->assertEquals('created', $this->getLastActivity()->event);
})->skip(
    version_compare(PHP_VERSION, '8.1', '<') || version_compare(Application::VERSION, '9.0', '<'),
    "PHP < 8.1 doesn't support enums && Laravel < 9.0 doesn't support non-backed-enum casting"
);

it('logs int backed enum casted attribute', function () {
    $articleClass = new class() extends Article {
        use LogsActivity;

        protected $casts = [
            'status' => \Spatie\Activitylog\Test\Enums\IntBackedEnum::class,
        ];

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()->logOnly(['status']);
        }
    };

    $article = new $articleClass();
    $article->status = \Spatie\Activitylog\Test\Enums\IntBackedEnum::Published;
    $article->save();

    $this->assertInstanceOf(get_class($articleClass), $this->getLastActivity()->subject);
    $this->assertEquals($article->id, $this->getLastActivity()->subject->id);
    $this->assertSame(1, $this->getLastActivity()->properties['attributes']['status']);
    $this->assertEquals('created', $this->getLastActivity()->description);
    $this->assertEquals('created', $this->getLastActivity()->event);
})->skip(version_compare(PHP_VERSION, '8.1', '<'), "PHP < 8.1 doesn't support enum");

it('logs string backed enum casted attribute', function () {
    $articleClass = new class() extends Article {
        use LogsActivity;

        protected $casts = [
            'status' => \Spatie\Activitylog\Test\Enums\StringBackedEnum::class,
        ];

        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()->logOnly(['status']);
        }
    };

    $article = new $articleClass();
    $article->status = \Spatie\Activitylog\Test\Enums\StringBackedEnum::Draft;
    $article->save();

    $this->assertInstanceOf(get_class($articleClass), $this->getLastActivity()->subject);
    $this->assertEquals($article->id, $this->getLastActivity()->subject->id);
    $this->assertSame('draft', $this->getLastActivity()->properties['attributes']['status']);
    $this->assertEquals('created', $this->getLastActivity()->description);
    $this->assertEquals('created', $this->getLastActivity()->event);
})->skip(version_compare(PHP_VERSION, '8.1', '<'), "PHP < 8.1 doesn't support enum");

Function Calls

None

Variables

None

Stats

MD5 0fb43ec094280edaf609388bee4b7f76
Eval Count 0
Decode Time 105 ms