From f8807120a2a161c762fc854b908d209789653fd4 Mon Sep 17 00:00:00 2001 From: roncodes <816371+roncodes@users.noreply.github.com> Date: Sat, 20 Dec 2025 22:42:11 -0500 Subject: [PATCH 1/4] Fix: Critical cache key collision bug - include all query parameters in cache key Previously, generateQueryCacheKey() only included a hardcoded whitelist of 11 parameters, causing cache key collisions when different filter values were used (e.g., type=customer vs type=contact generated the same cache key). This fix includes ALL query parameters in the cache key generation, excluding only internal/cache-busting parameters like '_', 'timestamp', 'nocache', and '_method'. Impact: - Fixes data integrity issue where different queries returned cached results from other queries - Ensures accurate cache HIT/MISS behavior for all filter combinations - Backward compatible - existing cache keys will naturally expire and regenerate Example: Before: /contacts?type=customer and /contacts?type=contact had SAME cache key After: /contacts?type=customer and /contacts?type=contact have DIFFERENT cache keys --- src/Support/ApiModelCache.php | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/Support/ApiModelCache.php b/src/Support/ApiModelCache.php index 4869542d..2a45c38f 100644 --- a/src/Support/ApiModelCache.php +++ b/src/Support/ApiModelCache.php @@ -58,21 +58,22 @@ public static function generateQueryCacheKey(Model $model, Request $request, arr $table = $model->getTable(); $companyUuid = static::getCompanyUuid($request); - // Get all relevant query parameters - $params = [ - 'limit' => $request->input('limit'), - 'offset' => $request->input('offset'), - 'page' => $request->input('page'), - 'sort' => $request->input('sort'), - 'order' => $request->input('order'), - 'query' => $request->input('query'), - 'search' => $request->input('search'), - 'filter' => $request->input('filter'), - 'with' => $request->input('with'), - 'expand' => $request->input('expand'), - 'columns' => $request->input('columns'), + // Get ALL query parameters from the request + // This ensures different filters (e.g., type=customer vs type=contact) generate different cache keys + $params = $request->query(); + + // Remove internal/non-cacheable parameters that shouldn't affect cache key + $excludedParams = [ + '_', // Cache-busting timestamp + 'timestamp', // Cache-busting timestamp + 'nocache', // Explicit cache bypass + '_method', // Laravel method override ]; + foreach ($excludedParams as $excluded) { + unset($params[$excluded]); + } + // Merge additional parameters $params = array_merge($params, $additionalParams); From 320193156678f9bf8907fc3fb629cd7411fb746e Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Sun, 21 Dec 2025 11:45:44 +0800 Subject: [PATCH 2/4] Fix: Critical cache key collision bug in ApiModelCache --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 81b7cba3..17009135 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "fleetbase/core-api", - "version": "1.6.29", + "version": "1.6.30", "description": "Core Framework and Resources for Fleetbase API", "keywords": [ "fleetbase", From 850e70a5abd8597a07c6fc5b7bee166ad094ede2 Mon Sep 17 00:00:00 2001 From: roncodes <816371+roncodes@users.noreply.github.com> Date: Sat, 20 Dec 2025 22:52:08 -0500 Subject: [PATCH 3/4] Fix: BadMethodCallException for getDeletedAtColumn() on models without SoftDeletes Issue: shouldQualifyColumn() method was unconditionally calling getDeletedAtColumn() which only exists on models using the SoftDeletes trait. This caused a fatal error when querying models like Permission that don't use soft deletes. Error: BadMethodCallException: Call to undefined method Fleetbase\Models\Permission::getDeletedAtColumn() Fix: Check if the method exists before calling it using method_exists(). Only include deleted_at column in qualifiable columns if the model uses SoftDeletes. Impact: - Fixes fatal error when querying Permission and other non-soft-deletable models - Maintains backward compatibility with models that do use SoftDeletes - No functional changes to soft-delete behavior --- src/Traits/HasApiModelBehavior.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Traits/HasApiModelBehavior.php b/src/Traits/HasApiModelBehavior.php index 1cc9ee56..0cef2a8f 100644 --- a/src/Traits/HasApiModelBehavior.php +++ b/src/Traits/HasApiModelBehavior.php @@ -1125,12 +1125,18 @@ private function applyOperators($builder, $column_name, $op_key, $op_type, $valu */ public function shouldQualifyColumn($column_name) { - return in_array($column_name, [ + $qualifiableColumns = [ $this->getKey() ?? 'uuid', $this->getCreatedAtColumn() ?? 'created_at', $this->getUpdatedAtColumn() ?? 'updated_at', - $this->getDeletedAtColumn() ?? 'deleted_at', - ]); + ]; + + // Only include deleted_at column if model uses SoftDeletes trait + if (method_exists($this, 'getDeletedAtColumn')) { + $qualifiableColumns[] = $this->getDeletedAtColumn(); + } + + return in_array($column_name, $qualifiableColumns); } /** From 9b36e810b28b42be7f1f48e6fd029d03b84bed61 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Sun, 21 Dec 2025 11:56:09 +0800 Subject: [PATCH 4/4] Added caching to permission model --- src/Models/Permission.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Models/Permission.php b/src/Models/Permission.php index 73105893..550609c3 100644 --- a/src/Models/Permission.php +++ b/src/Models/Permission.php @@ -4,6 +4,7 @@ use Fleetbase\Traits\Filterable; use Fleetbase\Traits\HasApiModelBehavior; +use Fleetbase\Traits\HasApiModelCache; use Fleetbase\Traits\HasUuid; use Fleetbase\Traits\Searchable; use Illuminate\Support\Collection; @@ -13,6 +14,7 @@ class Permission extends BasePermission { use HasUuid; use HasApiModelBehavior; + use HasApiModelCache; use Searchable; use Filterable;