laravel-activitylog
laravel-activitylog copied to clipboard
Composite primary key "Illegal offset type error"
Describe the bug When saving a new row for a specific model with a composite primary key, it throws the following error:
[2022-07-17 09:26:26] local.ERROR: Illegal offset type {"userId":3,"exception":"[object] (TypeError(code: 0): Illegal offset type at /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:1134)
[stacktrace]
#0 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1122): Illuminate\\Database\\Eloquent\\Model->getKeyForSelectQuery()
#1 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1561): Illuminate\\Database\\Eloquent\\Model->setKeysForSelectQuery()
#2 /var/www/gdpr/vendor/spatie/laravel-activitylog/src/Traits/LogsActivity.php(276): Illuminate\\Database\\Eloquent\\Model->fresh()
#3 /var/www/gdpr/vendor/spatie/laravel-activitylog/src/Traits/LogsActivity.php(54): App\\CompanyRightRequestDefaultAssignee->attributeValuesToBeLogged()
To Reproduce My model looks like below, if I comment the activity log part, it works fine. On my other models, where I don't use composite keys, it works great:
<?php
namespace App;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Spatie\Activitylog\Traits\LogsActivity;
use Spatie\Activitylog\LogOptions;
use App\Traits\HasCompositePrimaryKeyTrait;
class CompanyRightRequestDefaultAssignee extends Model
{
use HasFactory, HasCompositePrimaryKeyTrait;
public $incrementing = false;
protected $primaryKey = ['company_id', 'user_id', 'group_code', 'type_code'];
use LogsActivity;
public function getActivitylogOptions(): LogOptions
{
return LogOptions::defaults()->logOnly(['*'])->logOnlyDirty()->dontLogIfAttributesChangedOnly(['updated_at'])->dontSubmitEmptyLogs();
}
}
Expected behavior That it behaves as with other models
Versions (please complete the following information)
- PHP: 8.1
- Database: 8.0
- Laravel: 9.0
- Package: "spatie/laravel-activitylog": "^4.3"
Stack Trace
[2022-07-17 09:26:26] local.ERROR: Illegal offset type {"userId":3,"exception":"[object] (TypeError(code: 0): Illegal offset type at /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:1134)
[stacktrace]
#0 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1122): Illuminate\\Database\\Eloquent\\Model->getKeyForSelectQuery()
#1 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1561): Illuminate\\Database\\Eloquent\\Model->setKeysForSelectQuery()
#2 /var/www/gdpr/vendor/spatie/laravel-activitylog/src/Traits/LogsActivity.php(276): Illuminate\\Database\\Eloquent\\Model->fresh()
#3 /var/www/gdpr/vendor/spatie/laravel-activitylog/src/Traits/LogsActivity.php(54): App\\CompanyRightRequestDefaultAssignee->attributeValuesToBeLogged()
#4 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(421): App\\CompanyRightRequestDefaultAssignee::Spatie\\Activitylog\\Traits\\{closure}()
#5 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(249): Illuminate\\Events\\Dispatcher->Illuminate\\Events\\{closure}()
#6 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php(189): Illuminate\\Events\\Dispatcher->dispatch()
#7 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1108): Illuminate\\Database\\Eloquent\\Model->fireModelEvent()
#8 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1019): Illuminate\\Database\\Eloquent\\Model->performUpdate()
#9 /var/www/gdpr/app/Http/Controllers/CompanyController.php(712): Illuminate\\Database\\Eloquent\\Model->save()
#10 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(54): App\\Http\\Controllers\\CompanyController->postRightRequestDefaultAssignee()
#11 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): Illuminate\\Routing\\Controller->callAction()
#12 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Routing/Route.php(268): Illuminate\\Routing\\ControllerDispatcher->dispatch()
#13 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Routing/Route.php(211): Illuminate\\Routing\\Route->runController()
#14 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Routing/Router.php(725): Illuminate\\Routing\\Route->run()
#15 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(141): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}()
#16 /var/www/gdpr/app/Http/Middleware/HasRights.php(54): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#17 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): App\\Http\\Middleware\\HasRights->handle()
#18 /var/www/gdpr/app/Http/Middleware/Locale.php(33): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#19 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): App\\Http\\Middleware\\Locale->handle()
#20 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php(50): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#21 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Routing\\Middleware\\SubstituteBindings->handle()
#22 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#23 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse->handle()
#24 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(126): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#25 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(62): Illuminate\\Routing\\Middleware\\ThrottleRequests->handleRequest()
#26 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Routing\\Middleware\\ThrottleRequests->handle()
#27 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php(44): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#28 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Auth\\Middleware\\Authenticate->handle()
#29 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php(49): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#30 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\View\\Middleware\\ShareErrorsFromSession->handle()
#31 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(121): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#32 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(64): Illuminate\\Session\\Middleware\\StartSession->handleStatefulRequest()
#33 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Session\\Middleware\\StartSession->handle()
#34 /var/www/gdpr/vendor/laravel/sanctum/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php(33): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#35 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(141): Laravel\\Sanctum\\Http\\Middleware\\EnsureFrontendRequestsAreStateful->Laravel\\Sanctum\\Http\\Middleware\\{closure}()
#36 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php(78): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#37 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\VerifyCsrfToken->handle()
#38 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(121): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#39 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(64): Illuminate\\Session\\Middleware\\StartSession->handleStatefulRequest()
#40 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Session\\Middleware\\StartSession->handle()
#41 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#42 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse->handle()
#43 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(67): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#44 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Cookie\\Middleware\\EncryptCookies->handle()
#45 /var/www/gdpr/vendor/laravel/sanctum/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php(26): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#46 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(162): Laravel\\Sanctum\\Http\\Middleware\\EnsureFrontendRequestsAreStateful->Laravel\\Sanctum\\Http\\Middleware\\{closure}()
#47 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#48 /var/www/gdpr/vendor/laravel/sanctum/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php(34): Illuminate\\Pipeline\\Pipeline->then()
#49 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Laravel\\Sanctum\\Http\\Middleware\\EnsureFrontendRequestsAreStateful->handle()
#50 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#51 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Routing/Router.php(726): Illuminate\\Pipeline\\Pipeline->then()
#52 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Routing/Router.php(703): Illuminate\\Routing\\Router->runRouteWithinStack()
#53 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Routing/Router.php(667): Illuminate\\Routing\\Router->runRoute()
#54 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Routing/Router.php(656): Illuminate\\Routing\\Router->dispatchToRoute()
#55 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(167): Illuminate\\Routing\\Router->dispatch()
#56 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(141): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}()
#57 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#58 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php(31): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
#59 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull->handle()
#60 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#61 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php(40): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
#62 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\TrimStrings->handle()
#63 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#64 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize->handle()
#65 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(86): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#66 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance->handle()
#67 /var/www/gdpr/vendor/fruitcake/laravel-cors/src/HandleCors.php(52): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#68 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Fruitcake\\Cors\\HandleCors->handle()
#69 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php(39): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#70 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Http\\Middleware\\TrustProxies->handle()
#71 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#72 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(142): Illuminate\\Pipeline\\Pipeline->then()
#73 /var/www/gdpr/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(111): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter()
#74 /var/www/gdpr/public/index.php(55): Illuminate\\Foundation\\Http\\Kernel->handle()
#75 {main}
"}
Hello @seifti
Acutally the issue is not related to the package. This issue caused because Eloquent doens't support composite primary keys. See https://github.com/laravel/framework/issues/5355.
I have composite primary keys in many models, I'm just using the following trait @Elsenosy
<?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Builder;
trait HasCompositePrimaryKeyTrait{
//Get the value indicating whether the IDs are incrementing.
public function getIncrementing(){
return false;
}
//Set the keys for a save update query.
protected function setKeysForSaveQuery($query){ //edit Builder $query to $query
foreach ($this->getKeyName() as $key) {
// UPDATE: Added isset() per devflow's comment.
if (isset($this->$key)){
$query->where($key, '=', $this->$key);
}else
throw new Exception(__METHOD__ . 'Missing part of the primary key: ' . $key);
}
return $query;
}
protected function getKeyForSaveQuery($keyName = null)
{
if(is_null($keyName)){
$keyName = $this->getKeyName();
}
if (isset($this->original[$keyName])) {
return $this->original[$keyName];
}
return $this->getAttribute($keyName);
}
public static function find($ids, $columns = ['*']){
$me = new self;
$query = $me->newQuery();
foreach ($me->getKeyName() as $key) {
$query->where($key, '=', $ids[$key]);
}
return $query->first($columns);
}
}
@seifti
Yes, the trait HasCompositePrimaryKeyTrait
works fine with saving and retrieving data, but what about the model fresh
method? did you test it? ActivityLogger
use the fresh
method to get logging data.
The second thing you have to worry about that the ActivityLogger
model has morph relationship for the causer
and subject
models. The subject
model in your case is the 'CompanyRightRequestDefaultAssignee' model which has composite keys, so when using morph relationship for the subject
, a specific one -and only one- key is used to determine the relationship, in our case you are using array of keys in CompanyRightRequestDefaultAssignee
model and here where the problem lies. So back again to our main point: Eloquent doesn't support composite keys.
Regards.
Like said it's not a bug with the package but your trait and composite keys at all.