Commit 0e00fe7
v5: PHP 8.4+, Laravel 11+, modernized API (#1452)
* Implement v5: require PHP 8.4+/Laravel 11+, modernize API
Breaking changes:
- Rename activities() to activitiesAsSubject(), actions() to activitiesAsCauser()
- Add HasActivity trait that combines LogsActivity + CausesActivity
- Rename ActivityLogStatus to ActivitylogStatus (consistent casing)
- Rename dontSubmitEmptyLogs() to dontLogEmptyChanges()
- Rename withoutLogs() to withoutLogging()
- Make getActivitylogOptions() optional (defaults to LogOptions::defaults())
- Require PHP 8.4+ and Laravel 11+
- Consolidate 3 migrations into single migration
New features:
- ActivityEvent enum (Created, Updated, Deleted, Restored)
- CauserResolver::withCauser() for scoped causer overrides
- Global default_except_attributes config option
- LogOptions serialization safety (strips closures)
- Boost v2 guidelines file
Modernization:
- Use Str::uuid() instead of ramsey/uuid
- Use array_find() (PHP 8.4) instead of Arr::first()
- Casts as methods on Activity model
- Strict comparisons, short nullable notation, typed parameters
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix styling
* Update documentation for v5
- Update version references from v4 to v5
- Update requirements to PHP 8.4+ and Laravel 11+
- Document optional getActivitylogOptions() (no config needed for basic usage)
- Document HasActivity trait combining LogsActivity and CausesActivity
- Document ActivityEvent enum
- Document CauserResolver::withCauser() for scoped causer overrides
- Document default_except_attributes config option
- Rename dontSubmitEmptyLogs to dontLogEmptyChanges
- Rename withoutLogs to withoutLogging
- Rename actions() to activitiesAsCauser()
- Update LogOptions API reference with new property/method names
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Drop Pest 3 support, require Pest 4+
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Use id() shorthand and drop down() method in migration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Add Activity::defaultCauser() as friendly API for causer resolution
Provides a cleaner alternative to using CauserResolver directly:
Activity::defaultCauser($admin, fn() => ...); // scoped
Activity::defaultCauser($admin); // global
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Add Activity::batch(), remove CauserResolver facade, add UPGRADING.md
- Add Activity::batch(fn) as friendly API for batching activities
- Remove CauserResolver facade (use Activity::defaultCauser() instead)
- Update tests to use CauserResolver class directly
- Add v4 to v5 upgrade guide to UPGRADING.md
- Update docs for new API surface
- Update Boost skill guidelines
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Remove batch system, separate changes from properties
Schema changes:
- Add attribute_changes column for tracked model changes
- Remove batch_uuid column (batch system dropped)
- properties column now stores only custom user data
Removed:
- LogBatch class and LogBatch facade
- Activity::batch() method
- scopeHasBatch() and scopeForBatch() scopes
- Batch-related tests and documentation
Renamed:
- getExtraProperty() to getProperty()
- $activity->changes() to $activity->attribute_changes
The properties column is now clean user-owned space. Model attribute
tracking (attributes/old) is stored in the dedicated attribute_changes
column, eliminating the previous mixing of change data and user data.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Drop Laravel 11, simplify Activity contract
- Require Laravel 12+ (for future attribute support)
- Remove scopes from Activity contract interface (scopes are a query
builder concern, not a model contract concern)
- Contract now only requires: subject(), causer(), getProperty()
- Custom Activity models no longer need to implement scope methods
Note: #[Scope] attribute was investigated but doesn't work with
Activity::inLog() static calls (PHP resolves the non-static method
directly). Keeping scope prefix convention for now.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix docs: Laravel 12+ requirement, attribute_changes references
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix CI: update workflow for PHP 8.4+/Laravel 12+, fix class name
- Update run-tests.yml matrix to only PHP 8.4/8.5 and Laravel 12/13
- Remove nesbot/carbon constraint from CI
- Keep ActivityLogStatus class name (php-cs-fixer enforces it)
- Update all references to use ActivityLogStatus consistently
- Remove class rename from UPGRADING.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix README, remove dead CouldNotLogChanges exception
- Update README to use getProperty() and attribute_changes
- Remove CouldNotLogChanges exception class (never thrown anywhere)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix issues found in full review
Source:
- Fix getProperty() signature mismatch between contract and model
- Add withChanges() to Activity facade docblock
- Remove duplicate import in ActivitylogServiceProvider
Tests:
- Remove unused getActivitylogOptions() function in DetectsChangesTest
Docs:
- Fix typo "litte" in introduction.md
- Fix "Pretty Zonda" in logging-model-events.md
- Fix key order in introduction.md attribute_changes example
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix styling
* Fix null safety in getProperty() when properties is null
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Simplify config: rename keys, remove table_name and database_connection
Config changes:
- Rename env var ACTIVITY_LOGGER_ENABLED to ACTIVITYLOG_ENABLED
- Rename delete_records_older_than_days to clean_after_days
- Rename subject_returns_soft_deleted_models to include_soft_deleted_subjects
- Remove table_name and database_connection options (use custom model instead)
- Fix default_except_attributes comment (merged, not overridden)
Activity model:
- Hardcode $table = 'activity_log' instead of reading from config
- Remove constructor that read config (custom table/connection via subclass)
Migration:
- Hardcode table name instead of reading from config
Updated docs, UPGRADING.md, Boost skill, and tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Extract LogActivityAction and CleanActivityLogAction
Core operations are now handled by action classes with small overridable
protected methods, following the Spatie action pattern.
New files:
- src/Actions/LogActivityAction.php (resolveDescription, tapActivity, save)
- src/Actions/CleanActivityLogAction.php (getCutOffDate, deleteOldActivities)
- src/ActivitylogConfig.php (resolves action classes from config, validates they extend base)
Both actions are configurable via config/activitylog.php and validated
by ActivitylogConfig to ensure custom classes extend the originals.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Use Model type-hint in LogActivityAction instead of Activity contract
The action calls save(), accesses attributes, and reads relationships,
which are all Model concerns. The Activity contract is too narrow for
what the action actually needs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Rename tapActivity to beforeActivityLogged
Clearer name that describes when it runs, following Laravel's
beforeSave/beforeDelete naming convention.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Replace compound conditions with early returns and small methods
Split all && and || conditions into separate if statements with early
returns. Extracted helper methods for better readability:
- resolveModelForLogging() - determines which model instance to log
- shouldLogOnlyDirtyAttributes() - checks if dirty filtering applies
- filterDirtyAttributes() - performs the actual dirty diff
- isUpdatedEvent() / isDeletedEvent() - named event checks
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Update Boost skill for Enums namespace move
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Move config resolution to ActivitylogConfig, clean up ServiceProvider
- Move determineActivityModel/getActivityModelInstance from ServiceProvider
to ActivitylogConfig as activityModel()/activityModelInstance()
- Extract shared resolveAction() to reduce duplication
- ServiceProvider now only handles package registration and bindings
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Move CleanActivitylogCommand to Commands namespace
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Update docs, UPGRADING.md and Boost skill for Support namespace moves
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Remove LoggablePipe contract
Pipes for addLogChange() no longer need to implement an interface.
Any class with a handle(EventLogBag, Closure) method works (standard
Laravel pipeline convention).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* wip
* Restructure tests to mirror src directory layout
- Support/ -> ActivityLoggerTest, CauserResolverTest
- Models/ -> ActivityModelTest, CustomActivityModelTest, CustomDatabaseConnectionActivityModelTest, CustomTableNameModelTest
- Commands/ -> CleanActivitylogCommandTest
- Traits/ -> LogsActivityTest, CausesActivityTest, DetectsChangesTest
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Extract ChangeDetector, simplify LogsActivity trait
Extract pure logic into ChangeDetector support class:
- resolveRelatedAttribute() for dot-notation relations
- resolveJsonAttribute() for JSON arrow-notation
- resolveRelationName() for relation method discovery
- filterDirty() and compareValues() for dirty attribute diffing
Simplify LogsActivity trait:
- attributesToBeLogged() now uses collection pipeline
- Split into fillableAttributes(), unguardedAttributes(), explicitAttributes(), excludedAttributes()
- buildChanges() replaces attributeValuesToBeLogged()
- runChangesPipeline() extracts pipeline logic from boot
- shouldSkipEmptyLog() replaces inline check
- hasChangedAttributesBeyondIgnored() extracts dirty check
- formatAttributeValue() checks casts before dates (fixes custom date cast order)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Update docs for Traits -> Models/Concerns namespace move
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Remove pipe system, use LogActivityAction::transformChanges() instead
Removed:
- addLogChange() static method
- $changesPipes static array
- EventLogBag DTO
- LoggablePipe contract
- runChangesPipeline() method
- Pipeline dependency in LogsActivity trait
- 3 pipe-related tests
- manipulate-changes-array.md docs page
- event-bag.md API docs page
Users who need to transform the changes array before saving should
override transformChanges() on a custom LogActivityAction instead.
This is simpler (one method override vs registering pipe classes)
and consistent with the action pattern used throughout v5.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix CI: regenerate PHPStan baseline, run pint
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* wip
* wip
* Fix isRestoring() to handle Laravel 13 restore behavior
Laravel 13 may touch updated_at during restore, making more than just
deleted_at dirty. Instead of checking dirty count === 1, check that
deleted_at was previously non-null and is now null.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* wip
* v5
* wip
* Fix styling
* wip
* wip
* wip
* Fix styling
* wip
* wip
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: freekmurze <483853+freekmurze@users.noreply.github.com>1 parent 9165cd8 commit 0e00fe7
93 files changed
Lines changed: 3221 additions & 2724 deletions
File tree
- .github/workflows
- config
- database/migrations
- docs
- advanced-usage
- api
- basic-usage
- resources/boost/guidelines
- src
- Actions
- Commands
- Contracts
- Enums
- Exceptions
- Facades
- Models
- Concerns
- Support
- Traits
- tests
- Commands
- Models
- Support
- Traits
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
This file was deleted.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
Lines changed: 11 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
| 6 | + | |
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
| 11 | + | |
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
16 | | - | |
| 15 | + | |
| 16 | + | |
17 | 17 | | |
18 | | - | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
19 | 25 | | |
20 | 26 | | |
21 | 27 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
7 | | - | |
8 | 6 | | |
9 | 7 | | |
10 | 8 | | |
| |||
15 | 13 | | |
16 | 14 | | |
17 | 15 | | |
18 | | - | |
19 | | - | |
| 16 | + | |
| 17 | + | |
20 | 18 | | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
28 | | - | |
29 | | - | |
30 | | - | |
31 | | - | |
32 | | - | |
33 | | - | |
34 | | - | |
35 | | - | |
36 | | - | |
37 | | - | |
38 | 19 | | |
39 | 20 | | |
40 | 21 | | |
| |||
51 | 32 | | |
52 | 33 | | |
53 | 34 | | |
54 | | - | |
| 35 | + | |
55 | 36 | | |
56 | 37 | | |
57 | 38 | | |
| |||
This file was deleted.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
19 | | - | |
| 19 | + | |
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | | - | |
| 46 | + | |
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
| |||
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
63 | | - | |
| 63 | + | |
64 | 64 | | |
65 | 65 | | |
66 | 66 | | |
67 | 67 | | |
68 | 68 | | |
69 | | - | |
| 69 | + | |
70 | 70 | | |
71 | 71 | | |
72 | 72 | | |
73 | | - | |
| 73 | + | |
74 | 74 | | |
75 | 75 | | |
76 | 76 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
1 | 158 | | |
2 | 159 | | |
3 | 160 | | |
| |||
17 | 174 | | |
18 | 175 | | |
19 | 176 | | |
20 | | - | |
| 177 | + | |
21 | 178 | | |
22 | 179 | | |
23 | 180 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
34 | | - | |
35 | | - | |
36 | | - | |
37 | | - | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
42 | | - | |
43 | | - | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
44 | 46 | | |
45 | 47 | | |
46 | 48 | | |
| |||
0 commit comments