You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix BelongsToMany cache handling with custom implementation
Introduced `CachingBelongsToMany` to ensure proper cache invalidation after operations like attach, detach, sync, and updateExistingPivot. Updated the `ModelRelationships` trait to utilize this custom implementation, resolving bugs caused by reliance on non-existent Laravel events. Updated documentation to reflect these changes.
Copy file name to clipboardExpand all lines: CHANGELOG.md
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,6 +2,12 @@
2
2
3
3
All notable changes to `laravel-model-cache` will be documented in this file.
4
4
5
+
## [1.1.2] - 2025-05-21
6
+
7
+
### Fixed
8
+
- Fixed implementation of the `ModelRelationships` trait to properly handle BelongsToMany operations. Replaced the event-based approach (which was relying on non-existent Laravel events) with a custom BelongsToMany relationship class that flushes the cache after attach, detach, sync, syncWithoutDetaching, and updateExistingPivot operations.
9
+
- Updated `CachingBelongsToMany` class to properly extend Laravel's BelongsToMany class and maintain the relationship contract. This resolves the "must return a relationship instance" error when accessing relationship properties after operations like attach() and detach().
* Flush the model cache after a relationship operation.
135
+
*
136
+
* @param string $operation
137
+
* @return void
138
+
*/
139
+
protectedfunctionflushCache($operation)
140
+
{
141
+
if (method_exists($this->cacheableParent, 'flushModelCache')) {
142
+
$this->cacheableParent->flushModelCache();
143
+
} else {
144
+
if (method_exists($this->cacheableParent, 'flushCache')) {
145
+
$this->cacheableParent->flushCache();
146
+
} else {
147
+
thrownew \Exception('The parent model must have a flushCache() or flushModelCache() method defined. Make sure your model uses the HasCachedQueries trait. The ModelRelationships trait should be used in conjunction with the HasCachedQueries trait. See the documentation for more information.');
148
+
}
149
+
}
150
+
151
+
if (config('model-cache.debug_mode', false) && function_exists('logger')) {
152
+
logger()->info("Cache flushed after {$operation} operation for model: " . get_class($this->cacheableParent));
logger()->info("Cache flushed after relationship operation for model: " . get_class($model));
57
-
}
47
+
// Generate table name if not provided
48
+
if (is_null($table)) {
49
+
$table = $this->joiningTable($related);
58
50
}
51
+
52
+
// Create our caching BelongsToMany relationship
53
+
returnnewCachingBelongsToMany(
54
+
$instance->newQuery(),
55
+
$this,
56
+
$table,
57
+
$foreignPivotKey,
58
+
$relatedPivotKey,
59
+
$parentKey ?: $this->getKeyName(),
60
+
$relatedKey ?: $instance->getKeyName(),
61
+
$relation,
62
+
$this
63
+
);
59
64
}
60
65
61
66
/**
@@ -77,12 +82,18 @@ public function syncRelationshipAndFlushCache($relation, array $ids, $detaching
77
82
// Flush the cache
78
83
if (method_exists($this, 'flushModelCache')) {
79
84
$this->flushModelCache();
80
-
81
-
if (config('model-cache.debug_mode', false) && function_exists('logger')) {
82
-
logger()->info("Cache flushed after sync operation for model: " . get_class($this));
85
+
} else {
86
+
if (method_exists($this->cacheableParent, 'flushCache')) {
87
+
$this->cacheableParent->flushCache();
88
+
} else {
89
+
thrownew \Exception('The parent model must have a flushCache() or flushModelCache() method defined. Make sure your model uses the HasCachedQueries trait. The ModelRelationships trait should be used in conjunction with the HasCachedQueries trait. See the documentation for more information.');
83
90
}
84
91
}
85
92
93
+
if (config('model-cache.debug_mode', false) && function_exists('logger')) {
94
+
logger()->info("Cache flushed after detach operation for model: " . get_class($this));
95
+
}
96
+
86
97
return$result;
87
98
}
88
99
@@ -106,11 +117,17 @@ public function attachRelationshipAndFlushCache($relation, $ids, array $attribut
106
117
// Flush the cache
107
118
if (method_exists($this, 'flushModelCache')) {
108
119
$this->flushModelCache();
109
-
110
-
if (config('model-cache.debug_mode', false) && function_exists('logger')) {
111
-
logger()->info("Cache flushed after attach operation for model: " . get_class($this));
120
+
} else {
121
+
if (method_exists($this->cacheableParent, 'flushCache')) {
122
+
$this->cacheableParent->flushCache();
123
+
} else {
124
+
thrownew \Exception('The parent model must have a flushCache() or flushModelCache() method defined. Make sure your model uses the HasCachedQueries trait. The ModelRelationships trait should be used in conjunction with the HasCachedQueries trait. See the documentation for more information.');
112
125
}
113
126
}
127
+
128
+
if (config('model-cache.debug_mode', false) && function_exists('logger')) {
129
+
logger()->info("Cache flushed after detach operation for model: " . get_class($this));
130
+
}
114
131
}
115
132
116
133
/**
@@ -132,12 +149,30 @@ public function detachRelationshipAndFlushCache($relation, $ids = null, $touch =
132
149
// Flush the cache
133
150
if (method_exists($this, 'flushModelCache')) {
134
151
$this->flushModelCache();
135
-
136
-
if (config('model-cache.debug_mode', false) && function_exists('logger')) {
137
-
logger()->info("Cache flushed after detach operation for model: " . get_class($this));
152
+
} else {
153
+
if (method_exists($this->cacheableParent, 'flushCache')) {
154
+
$this->cacheableParent->flushCache();
155
+
} else {
156
+
thrownew \Exception('The parent model must have a flushCache() or flushModelCache() method defined. Make sure your model uses the HasCachedQueries trait. The ModelRelationships trait should be used in conjunction with the HasCachedQueries trait. See the documentation for more information.');
138
157
}
139
158
}
140
159
160
+
if (config('model-cache.debug_mode', false) && function_exists('logger')) {
161
+
logger()->info("Cache flushed after detach operation for model: " . get_class($this));
0 commit comments