mikebronner / laravel-model-caching

Eloquent model-caching made easy.
MIT License
2.22k stars 212 forks source link

Since 0.12.4 I get error "GeneaLabs\LaravelModelCaching\CacheKey::processEnum(): Argument #1 ($value) must be of type BackedEnum|UnitEnum|string, null given, called in ...\vendor\genealabs\laravel-model-caching\src\CacheKey.php on line 409" #443

Closed Restingo closed 6 months ago

Restingo commented 1 year ago

Describe the bug Since the version 0.12.4 I get error GeneaLabs\LaravelModelCaching\CacheKey::processEnum(): Argument #1 ($value) must be of type BackedEnum|UnitEnum|string, null given, called in ...\vendor\genealabs\laravel-model-caching\src\CacheKey.php on line 409 when querying a relationship on a new model that is currently empty.

Eloquent Query

$project = new Project;

$project->currency->symbol;

Stack Trace

[previous exception] [object] (TypeError(code: 0): GeneaLabs\\LaravelModelCaching\\CacheKey::processEnum(): Argument #1 ($value) must be of type BackedEnum|UnitEnum|string, null given, called in ...\\vendor\\genealabs\\laravel-model-caching\\src\\CacheKey.php on line 409 at ...\\vendor\\genealabs\\laravel-model-caching\\src\\CacheKey.php:396)
[stacktrace]
#0 ...\\vendor\\genealabs\\laravel-model-caching\\src\\CacheKey.php(409): GeneaLabs\\LaravelModelCaching\\CacheKey->processEnum(NULL)
#1 [internal function]: GeneaLabs\\LaravelModelCaching\\CacheKey->GeneaLabs\\LaravelModelCaching\\{closure}(NULL)
#2 ...\\vendor\\genealabs\\laravel-model-caching\\src\\CacheKey.php(409): array_map(Object(Closure), Array)
#3 ...\\vendor\\genealabs\\laravel-model-caching\\src\\CacheKey.php(289): GeneaLabs\\LaravelModelCaching\\CacheKey->processEnums(Array)
#4 ...\\vendor\\genealabs\\laravel-model-caching\\src\\CacheKey.php(267): GeneaLabs\\LaravelModelCaching\\CacheKey->getValuesFromWhere(Array)
#5 ...\\vendor\\genealabs\\laravel-model-caching\\src\\CacheKey.php(192): GeneaLabs\\LaravelModelCaching\\CacheKey->getValuesClause(Array)
#6 ...\\vendor\\genealabs\\laravel-model-caching\\src\\CacheKey.php(330): GeneaLabs\\LaravelModelCaching\\CacheKey->getOtherClauses(Array)
#7 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Collections\\Traits\\EnumeratesValues.php(734): GeneaLabs\\LaravelModelCaching\\CacheKey->GeneaLabs\\LaravelModelCaching\\{closure}(NULL, Array, 0)
#8 ...\\vendor\\genealabs\\laravel-model-caching\\src\\CacheKey.php(333): Illuminate\\Support\\Collection->reduce(Object(Closure))
#9 ...\\vendor\\genealabs\\laravel-model-caching\\src\\CacheKey.php(48): GeneaLabs\\LaravelModelCaching\\CacheKey->getWhereClauses()
#10 ...\\vendor\\genealabs\\laravel-model-caching\\src\\Traits\\Caching.php(182): GeneaLabs\\LaravelModelCaching\\CacheKey->make(Array, NULL, '-first')
#11 ...\\vendor\\genealabs\\laravel-model-caching\\src\\Traits\\Buildable.php(86): GeneaLabs\\LaravelModelCaching\\CachedBuilder->makeCacheKey(Array, NULL, '-first')
#12 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Eloquent\\Relations\\BelongsTo.php(81): GeneaLabs\\LaravelModelCaching\\CachedBuilder->first()
#13 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Eloquent\\Concerns\\HasAttributes.php(594): Illuminate\\Database\\Eloquent\\Relations\\BelongsTo->getResults()
#14 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Eloquent\\Concerns\\HasAttributes.php(532): Illuminate\\Database\\Eloquent\\Model->getRelationshipFromMethod('currency')
#15 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Eloquent\\Concerns\\HasAttributes.php(457): Illuminate\\Database\\Eloquent\\Model->getRelationValue('currency')
#16 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Eloquent\\Model.php(2222): Illuminate\\Database\\Eloquent\\Model->getAttribute('currency')
#17 ...\\vendor\\genealabs\\laravel-model-caching\\src\\Traits\\ModelCaching.php(25): Illuminate\\Database\\Eloquent\\Model->__get('currency')
#18 ...\\storage\\framework\\views\\b57eb96d08ca47b8783d337fa7b675c82ebde915.php(309): App\\Models\\Project->__get('currency')
#19 ...\\vendor\\livewire\\livewire\\src\\ComponentConcerns\\RendersLivewireComponents.php(83): include('......')
#20 ...\\vendor\\livewire\\livewire\\src\\ComponentConcerns\\RendersLivewireComponents.php(84): App\\Http\\Livewire\\Projects->Livewire\\ComponentConcerns\\{closure}()
#21 ...\\vendor\\livewire\\livewire\\src\\ComponentConcerns\\RendersLivewireComponents.php(59): Livewire\\LivewireViewCompilerEngine->evaluatePath('......', Array)
#22 ...\\vendor\\laravel\\framework\\src\\Illuminate\\View\\View.php(195): Livewire\\LivewireViewCompilerEngine->get('......', Array)
#23 ...\\vendor\\laravel\\framework\\src\\Illuminate\\View\\View.php(178): Illuminate\\View\\View->getContents()
#24 ...\\vendor\\laravel\\framework\\src\\Illuminate\\View\\View.php(147): Illuminate\\View\\View->renderContents()
#25 ...\\vendor\\livewire\\livewire\\src\\Component.php(235): Illuminate\\View\\View->render()
#26 ...\\vendor\\livewire\\livewire\\src\\HydrationMiddleware\\RenderView.php(14): Livewire\\Component->output()
#27 ...\\vendor\\livewire\\livewire\\src\\LifecycleManager.php(154): Livewire\\HydrationMiddleware\\RenderView::dehydrate(Object(App\\Http\\Livewire\\Projects), Object(Livewire\\Response))
#28 ...\\vendor\\livewire\\livewire\\src\\Connection\\ConnectionHandler.php(15): Livewire\\LifecycleManager->dehydrate()
#29 ...\\vendor\\livewire\\livewire\\src\\Controllers\\HttpConnectionHandler.php(21): Livewire\\Connection\\ConnectionHandler->handle(Array)
#30 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\ControllerDispatcher.php(46): Livewire\\Controllers\\HttpConnectionHandler->__invoke('projects')
#31 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Route.php(260): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(Livewire\\Controllers\\HttpConnectionHandler), '__invoke')
#32 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Route.php(205): Illuminate\\Routing\\Route->runController()
#33 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(798): Illuminate\\Routing\\Route->run()
#34 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(141): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#35 ...\\app\\Http\\Middleware\\CheckIfUserIsActive.php(29): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#36 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): App\\Http\\Middleware\\CheckIfUserIsActive->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#37 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Middleware\\SubstituteBindings.php(50): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#38 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Routing\\Middleware\\SubstituteBindings->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#39 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\VerifyCsrfToken.php(78): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#40 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\VerifyCsrfToken->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#41 ...\\vendor\\laravel\\framework\\src\\Illuminate\\View\\Middleware\\ShareErrorsFromSession.php(49): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#42 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\View\\Middleware\\ShareErrorsFromSession->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#43 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Session\\Middleware\\StartSession.php(121): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#44 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Session\\Middleware\\StartSession.php(64): Illuminate\\Session\\Middleware\\StartSession->handleStatefulRequest(Object(Illuminate\\Http\\Request), Object(Illuminate\\Session\\Store), Object(Closure))
#45 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Session\\Middleware\\StartSession->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#46 ...\\app\\Http\\Middleware\\NoSessionForBots.php(24): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#47 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): App\\Http\\Middleware\\NoSessionForBots->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#48 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse.php(37): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#49 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#50 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Cookie\\Middleware\\EncryptCookies.php(67): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#51 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Cookie\\Middleware\\EncryptCookies->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#52 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#53 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(799): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))
#54 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(776): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))
#55 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(740): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))
#56 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(729): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))
#57 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php(190): Illuminate\\Routing\\Router->dispatch(Object(Illuminate\\Http\\Request))
#58 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(141): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))
#59 ...\\vendor\\livewire\\livewire\\src\\DisableBrowserCache.php(19): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#60 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Livewire\\DisableBrowserCache->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#61 ...\\vendor\\barryvdh\\laravel-debugbar\\src\\Middleware\\InjectDebugbar.php(66): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#62 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Barryvdh\\Debugbar\\Middleware\\InjectDebugbar->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#63 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#64 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#65 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull.php(27): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#66 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#67 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TrimStrings.php(36): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#68 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\TrimStrings->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#69 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize.php(27): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#70 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#71 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance.php(86): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#72 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#73 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Http\\Middleware\\HandleCors.php(49): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#74 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Http\\Middleware\\HandleCors->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#75 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Http\\Middleware\\TrustProxies.php(39): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#76 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Http\\Middleware\\TrustProxies->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#77 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#78 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php(165): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))
#79 ...\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php(134): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))
#80 ...\\public\\index.php(53): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))
#81 {main}

Environment

Additional context Tried downgrading to 0.12.3 to test and with this version it works.

mikebronner commented 1 year ago

Hi @Restingo, could you provide a repository with sample code that reproduces this issue?

roelVerdonschot commented 1 year ago

I have the same problem, this happens when you have a hasMany() relationship and the local key is null

garrettgjb commented 1 year ago

This is also happening to me. I've been stuck on 0.12.3

Ham3D commented 11 months ago

same problem in the latest version which is 0.13

@mikebronner is there any plan to fix this, or maybe a workaround?

i also tries to install a lower version (0.12.2) but it has problem with latest version of laravel.

wolfpack4417 commented 10 months ago

I'm having the same issue after upgrading to Laravel 10.

Restingo commented 10 months ago

Looks like #432 is related.

Restingo commented 10 months ago

@Ham3D @wolfpack4417 are you able to reproduce and paste the code or snippet here? I fixed it somehow in my env but don't know how. If you can give me the reproducible code I'll create a fix. Thank you.

roelVerdonschot commented 10 months ago

@Restingo It's been a while since we had this issue and what I can remember if you have a setup like the snippet below and local_id in classB is null in the database you get this error.

class classA extends Model {
    protected $fillable = [
        'foreign_id',
    ];
}

class classB extends Model {
    protected $fillable = [
        'local_id',
    ];

    public function classA(): HasMany
    {
        return $this->hasMany(classA::class, 'foreign_id', 'local_id');
    }
}

(I wrote this from head so you might need to tweek it)

wolfpack4417 commented 10 months ago

@Restingo I'm getting this error when trying to delete an entity that also has soft cascading deletes via this package : askedio/laravel-soft-cascade

This is the code:

`class FuelCard extends BaseModel { protected $table = 'fuel_cards'; protected $fillable = ['account_id', 'fcp', 'driver_id', 'vehicle_id', 'unique_identifier', 'fuel_type', 'driver_resource_id'];

protected $softCascade = ['fuelTransactions'];

public static function boot() {
    parent::boot();

    static::deleting(function($fuel_card) {
        $fuel_card->fuelTransactions()->delete();
    });
}

public function account()
{
    return $this->belongsTo(Account::class);
}

public function fuelTransactions()
{
    return $this->hasMany(FuelTransaction::class);
}

} `

And it fails here:

$fuel_card->fuelTransactions()->delete();

Let me know if you need any more information from me, and thanks for helping with this!

Restingo commented 10 months ago

@wolfpack4417 would it be possible to push a small repo with the needed code in it to reproduce? Thx.

mikebronner commented 10 months ago

or submit a PR with a failing test, either would be great

peter-brennan commented 8 months ago

@mikebronner I am facing this issue now with a nullable one-to-many relationship Package Version: 0.13.4 Laravel: 10.8 PHP: 8.2

I was able to get around this issue by adding a null cast type and null return type to vendor/genealabs/laravel-model-caching/src/CacheKey.php processEnum() method. Could someone be able to have a look and make sure this doesn't cause any negative effects. I tried creating a PR but i'm a PR Rookie and couldn't figure out how to push it... i kept getting permission errors.

private function processEnum(\BackedEnum|\UnitEnum|Expression|string|null $value): string|null
    {
        if ($value instanceof \BackedEnum) {
            return $value->value;
        } elseif ($value instanceof \UnitEnum) {
            return $value->name;
        } elseif ($value instanceof Expression) {
            return $this->expressionToString($value);
        }
        return $value;
    }
mikebronner commented 8 months ago

@peter-brennan thanks for submitting additional details. I will take a look at this.

peter-brennan commented 8 months ago

I figured out how to create a PR hahaha, I made that change for you. #456

mikebronner commented 8 months ago

Nice, that helps a lot, thanks @peter-brennan !

Flobbos commented 6 months ago

Any news? I am facing the same issue and have been waiting for a fix.

emptyrealm commented 6 months ago

How is the progress? I'm facing the same issue and have been waiting for a fix.

mikebronner commented 6 months ago

Reviewing the PR now ... hopefully I can get it merged this morning.

mikebronner commented 6 months ago

This should be fixed now. Thanks for your patience.

emptyrealm commented 6 months ago

Thank you very much and wish you a Merry Christmas in advance.

emptyrealm commented 6 months ago

@mikebronner My PHP version is 8.0 and I can only use version 0.12.5. I want to fix this problem in version 0.12.5, Can you create a branch based on tag 0.12.5? So can I create a pull request to merge into this branch and then have you create a 0.12.6 tag?

mikebronner commented 6 months ago

Hi @emptyrealm, I would recommend you create a fork for your use, downgrade PHP in your fork, then return to using the package once you are back on a supported PHP version. At this time I won't be adding back-support to older versions of PHP or Laravel.

However, once this package gets to version 1.0 (hopefully by or before Laravel 12), we will be maintaining LTS version support for Laravel, and Active/Security supported versions of PHP.

emptyrealm commented 6 months ago

@mikebronner OK, I'll try it, thank you for your patience reply.

This Package is really useful, thank you.